From 26a935c29c71b46c5e73e7216ecf2c9dd4c5c00f Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 1 Sep 2020 17:30:26 +0200 Subject: [PATCH] RANGE etc RANGE v2.2.3 - Added relay unit option. TIMER - Fixed bug. Minor other stuff --- Moose Development/Moose/Core/Point.lua | 6 +- Moose Development/Moose/Core/Timer.lua | 34 +- Moose Development/Moose/Functional/Range.lua | 43 +- Moose Development/Moose/Wrapper/Airbase.lua | 2 +- Moose Development/Moose/Wrapper/Group.lua | 15 +- Moose Development/Moose/Wrapper/Marker.lua | 272 ++++++------ .../Moose/Wrapper/Positionable.lua | 416 +++++++++--------- Moose Development/Moose/Wrapper/Unit.lua | 14 +- 8 files changed, 431 insertions(+), 371 deletions(-) diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index 97f0fb280..ca1529950 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -561,7 +561,8 @@ do -- COORDINATE return self else --env.info("FF translate with NEW coordinate T="..timer.getTime()) - return COORDINATE:New(x, y, z) + local coord=COORDINATE:New(x, y, z) + return coord end end @@ -761,7 +762,8 @@ do -- COORDINATE -- Move the vector to start at the end of A. vec=UTILS.VecAdd(self, vec) - return self:New(vec.x,vec.y,vec.z) + local coord=COORDINATE:New(vec.x,vec.y,vec.z) + return coord end --- Return the 2D distance in meters between the target COORDINATE and the COORDINATE. diff --git a/Moose Development/Moose/Core/Timer.lua b/Moose Development/Moose/Core/Timer.lua index cbf739fa3..9b8a9200b 100644 --- a/Moose Development/Moose/Core/Timer.lua +++ b/Moose Development/Moose/Core/Timer.lua @@ -38,6 +38,8 @@ -- -- The TIMER class is the little sister of the SCHEDULER class. It does the same thing but is a bit easier to use and has less overhead. It should be sufficient in many cases. -- +-- It provides an easy interface to the DCS [timer.scheduleFunction](https://wiki.hoggitworld.com/view/DCS_func_scheduleFunction). +-- -- # Construction -- -- A new TIMER is created by the @{#TIMER.New}(*func*, *...*) function @@ -100,6 +102,12 @@ TIMER = { lid = nil, } +--- Timer ID. +_TIMERID=0 + +--- Timer data base. +--_TIMERDB={} + --- TIMER class version. -- @field #string version TIMER.version="0.1.0" @@ -124,8 +132,6 @@ function TIMER:New(Function, ...) -- Inherit BASE. local self=BASE:Inherit(self, BASE:New()) --#TIMER - - self.lid="TIMER | " -- Function to call. self.func=Function @@ -136,6 +142,18 @@ function TIMER:New(Function, ...) -- Number of function calls. self.ncalls=0 + -- Increase counter + _TIMERID=_TIMERID+1 + + -- Set UID. + self.uid=_TIMERID + + -- Log id. + self.lid=string.format("TIMER UID=%d | ", self.uid) + + -- Add to DB. + --_TIMERDB[self.uid]=self + return self end @@ -151,7 +169,7 @@ function TIMER:Start(Tstart, dT, Duration) local Tnow=timer.getTime() -- Start time in sec. - self.Tstart=Tstart or Tnow + self.Tstart=Tstart and Tnow+Tstart or Tnow+0.001 -- one millisecond delay if Tstart=nil -- Set time interval. self.dT=dT @@ -162,10 +180,10 @@ function TIMER:Start(Tstart, dT, Duration) end -- Call DCS timer function. - self.tid=timer.scheduleFunction(TIMER._Function, self, self.Tstart) + self.tid=timer.scheduleFunction(self._Function, self, self.Tstart) -- Set log id. - self.lid=string.format("TIMER ID=%d | ", self.tid) + self.lid=string.format("TIMER UID=%d/%d | ", self.uid, self.tid) -- Debug info. self:T(self.lid..string.format("Starting Timer in %.3f sec, dT=%s, Tstop=%s", self.Tstart-Tnow, tostring(self.dT), tostring(self.Tstop))) @@ -186,8 +204,14 @@ function TIMER:Stop(Delay) else if self.tid then + + -- Remove timer function. self:T(self.lid..string.format("Stopping timer by removing timer function after %d calls!", self.ncalls)) timer.removeFunction(self.tid) + + -- Remove DB entry. + --_TIMERDB[self.uid]=nil + end end diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 6b292f2fd..0f4b164fe 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -93,6 +93,8 @@ -- @field Core.RadioQueue#RADIOQUEUE instructor Instructor radio queue. -- @field #number rangecontrolfreq Frequency on which the range control transmitts. -- @field Core.RadioQueue#RADIOQUEUE rangecontrol Range control radio queue. +-- @field #string rangecontrolrelayname Name of relay unit. +-- @field #string instructorrelayname Name of relay unit. -- @field #string soundpath Path inside miz file where the sound files are located. Default is "Range Soundfiles/". -- @extends Core.Fsm#FSM @@ -516,7 +518,7 @@ RANGE.MenuF10Root=nil --- Range script version. -- @field #string version -RANGE.version="2.2.2" +RANGE.version="2.2.3" --TODO list: --TODO: Verbosity level for messages. @@ -770,6 +772,7 @@ function RANGE:onafterStart() -- Set location where the messages are transmitted from. self.rangecontrol:SetSenderCoordinate(self.location) + self.rangecontrol:SetSenderUnitName(self.rangecontrolrelayname) -- Start range control radio queue. self.rangecontrol:Start(1, 0.1) @@ -794,6 +797,7 @@ function RANGE:onafterStart() -- Set location where the messages are transmitted from. self.instructor:SetSenderCoordinate(self.location) + self.instructor:SetSenderUnitName(self.instructorrelayname) -- Start instructor radio queue. self.instructor:Start(1, 0.1) @@ -1067,18 +1071,22 @@ end --- Enable range control and set frequency. -- @param #RANGE self -- @param #number frequency Frequency in MHz. Default 256 MHz. +-- @param #string relayunitname Name of the unit used for transmission. -- @return #RANGE self -function RANGE:SetRangeControl(frequency) +function RANGE:SetRangeControl(frequency, relayunitname) self.rangecontrolfreq=frequency or 256 + self.rangecontrolrelayname=relayunitname return self end --- Enable instructor radio and set frequency. -- @param #RANGE self -- @param #number frequency Frequency in MHz. Default 305 MHz. +-- @param #string relayunitname Name of the unit used for transmission. -- @return #RANGE self -function RANGE:SetInstructorRadio(frequency) +function RANGE:SetInstructorRadio(frequency, relayunitname) self.instructorfreq=frequency or 305 + self.instructorrelayname=relayunitname return self end @@ -1908,8 +1916,35 @@ end -- @param #string To To state. function RANGE:onafterStatus(From, Event, To) + local fsmstate=self:GetState() + + local text=string.format("Range status: %s", fsmstate) + + if self.instructor then + local alive="N/A" + if self.instructorrelayname then + local relay=UNIT:FindByName(self.instructorrelayname) + if relay then + alive=tostring(relay:IsAlive()) + end + end + text=text..string.format(", Instructor %.3f MHz (Relay=%s alive=%s)", self.instructorfreq, tostring(self.instructorrelayname), alive) + end + + if self.rangecontrol then + local alive="N/A" + if self.rangecontrolrelayname then + local relay=UNIT:FindByName(self.rangecontrolrelayname) + if relay then + alive=tostring(relay:IsAlive()) + end + end + text=text..string.format(", Control %.3f MHz (Relay=%s alive=%s)", self.rangecontrolfreq, tostring(self.rangecontrolrelayname), alive) + end + + -- Check range status. - self:I(self.id..string.format("Range status: %s", self:GetState())) + self:I(self.id..text) -- Check player status. self:_CheckPlayers() diff --git a/Moose Development/Moose/Wrapper/Airbase.lua b/Moose Development/Moose/Wrapper/Airbase.lua index 3e3d7de16..4eb391ac8 100644 --- a/Moose Development/Moose/Wrapper/Airbase.lua +++ b/Moose Development/Moose/Wrapper/Airbase.lua @@ -1377,7 +1377,7 @@ function AIRBASE:GetRunwayData(magvar, mark) runway.endpoint=c2 -- Debug info. - self:I(string.format("Airbase %s: Adding runway id=%s, heading=%03d, length=%d m i=%d j=%d", self:GetName(), runway.idx, runway.heading, runway.length, i, j)) + --self:I(string.format("Airbase %s: Adding runway id=%s, heading=%03d, length=%d m i=%d j=%d", self:GetName(), runway.idx, runway.heading, runway.length, i, j)) -- Debug mark if mark then diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua index 7ceb235af..34172a162 100644 --- a/Moose Development/Moose/Wrapper/Group.lua +++ b/Moose Development/Moose/Wrapper/Group.lua @@ -951,7 +951,8 @@ function GROUP:GetVec2() local Unit=self:GetUnit(1) if Unit then - return Unit:GetVec2() + local vec2=Unit:GetVec2() + return vec2 end end @@ -965,7 +966,8 @@ function GROUP:GetVec3() local unit=self:GetUnit(1) if unit then - return unit:GetVec3() + local vec3=unit:GetVec3() + return vec3 end self:E("ERROR: Cannot get Vec3 of group "..tostring(self.GroupName)) @@ -996,13 +998,11 @@ end -- @param Wrapper.Group#GROUP self -- @return Core.Point#COORDINATE The COORDINATE of the GROUP. function GROUP:GetCoordinate() - self:F2( self.PositionableName ) local FirstUnit = self:GetUnit(1) if FirstUnit then local FirstUnitCoordinate = FirstUnit:GetCoordinate() - self:T3(FirstUnitCoordinate) return FirstUnitCoordinate end @@ -1176,7 +1176,7 @@ do -- Is Zone methods --- Check if any unit of a group is inside a @{Zone}. -- @param #GROUP self -- @param Core.Zone#ZONE_BASE Zone The zone to test. --- @return #boolean Returns true if at least one unit is inside the zone or false if no unit is inside. +-- @return #boolean Returns `true` if *at least one unit* is inside the zone or `false` if *no* unit is inside. function GROUP:IsInZone( Zone ) if self:IsAlive() then @@ -1184,7 +1184,10 @@ function GROUP:IsInZone( Zone ) for UnitID, UnitData in pairs(self:GetUnits()) do local Unit = UnitData -- Wrapper.Unit#UNIT - if Zone:IsVec3InZone(Unit:GetVec3()) then + -- Get 2D vector. That's all we need for the zone check. + local vec2=Unit:GetVec2() + + if Zone:IsVec2InZone(vec2) then return true -- At least one unit is in the zone. That is enough. else -- This one is not but another could be. diff --git a/Moose Development/Moose/Wrapper/Marker.lua b/Moose Development/Moose/Wrapper/Marker.lua index 5d65d3fbe..88a868501 100644 --- a/Moose Development/Moose/Wrapper/Marker.lua +++ b/Moose Development/Moose/Wrapper/Marker.lua @@ -1,5 +1,5 @@ --- **Wrapper** - Markers On the F10 map. --- +-- -- **Main Features:** -- -- * Convenient handling of markers via multiple user API functions. @@ -8,7 +8,7 @@ -- * Retrieve data such as text and coordinate. -- * Marker specific FSM events when a marker is added, removed or changed. -- * Additional FSM events when marker text or position is changed. --- +-- -- === -- -- ### Author: **funkyfranky** @@ -36,104 +36,104 @@ -- ![Banner Image](..\Presentations\MARKER\Marker_Main.jpg) -- -- # The MARKER Class Idea --- +-- -- The MARKER class simplifies creating, updating and removing of markers on the F10 map. --- +-- -- # Create a Marker --- +-- -- -- Create a MARKER object at Batumi with a trivial text. -- local Coordinate=AIRBASE:FindByName("Batumi"):GetCoordinate() -- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield") --- --- Now this does **not** show the marker yet. We still need to specifiy to whom it is shown. There are several options, i.e. +-- +-- Now this does **not** show the marker yet. We still need to specifiy to whom it is shown. There are several options, i.e. -- show the marker to everyone, to a speficic coaliton only, or only to a specific group. --- +-- -- ## For Everyone --- +-- -- If the marker should be visible to everyone, you can use the :ToAll() function. -- -- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield"):ToAll() --- +-- -- ## For a Coaliton --- +-- -- If the maker should be visible to a specific coalition, you can use the :ToCoalition() function. --- +-- -- mymarker=MARKER:New(Coordinate, "I am Batumi Airfield"):ToCoaliton(coaliton.side.BLUE) --- +-- -- ### To Blue Coaliton --- +-- -- ### To Red Coalition --- +-- -- This would show the marker only to the Blue coaliton. --- +-- -- ## For a Group --- --- +-- +-- -- # Removing a Marker --- --- +-- +-- -- # Updating a Marker --- +-- -- The marker text and coordinate can be updated easily as shown below. --- +-- -- However, note that **updateing involves to remove and recreate the marker if either text or its coordinate is changed**. --- *This is a DCS scripting engine limitation.* --- +-- *This is a DCS scripting engine limitation.* +-- -- ## Update Text --- +-- -- If you created a marker "mymarker" as shown above, you can update the dispayed test by --- +-- -- mymarker:UpdateText("I am the new text at Batumi") --- +-- -- The update can also be delayed by, e.g. 90 seconds, using --- +-- -- mymarker:UpdateText("I am the new text at Batumi", 90) --- +-- -- ## Update Coordinate --- +-- -- If you created a marker "mymarker" as shown above, you can update its coordinate on the F10 map by --- +-- -- mymarker:UpdateCoordinate(NewCoordinate) --- +-- -- The update can also be delayed by, e.g. 60 seconds, using --- +-- -- mymarker:UpdateCoordinate(NewCoordinate, 60) --- +-- -- # Retrieve Data --- +-- -- The important data as the displayed text and the coordinate of the marker can be retrieved easily. --- +-- -- ## Text --- +-- -- local text=mymarker:GetText() -- env.info("Marker Text = " .. text) --- +-- -- ## Coordinate --- +-- -- local Coordinate=mymarker:GetCoordinate() -- env.info("Marker Coordinate LL DSM = " .. Coordinate:ToStringLLDMS()) --- --- +-- +-- -- # FSM Events --- +-- -- Moose creates addditonal events, so called FSM event, when markers are added, changed, removed, and text or the coordianteis updated. --- +-- -- These events can be captured and used for processing via OnAfter functions as shown below. --- +-- -- ## Added --- +-- -- ## Changed --- +-- -- ## Removed --- +-- -- ## TextUpdate --- +-- -- ## CoordUpdate --- --- +-- +-- -- # Examples --- --- +-- +-- -- @field #MARKER MARKER = { ClassName = "MARKER", @@ -170,29 +170,29 @@ MARKER.version="0.1.0" --- Create a new MARKER class object. -- @param #MARKER self -- @param Core.Point#COORDINATE Coordinate Coordinate where to place the marker. --- @param #string Text Text displayed on the mark panel. +-- @param #string Text Text displayed on the mark panel. -- @return #MARKER self function MARKER:New(Coordinate, Text) -- Inherit everything from FSM class. local self=BASE:Inherit(self, FSM:New()) -- #MARKER - + self.coordinate=Coordinate - + self.text=Text - + -- Defaults self.readonly=false self.message="" - - -- New marker ID. This is not the one of the actual marker. + + -- New marker ID. This is not the one of the actual marker. _MARKERID=_MARKERID+1 - + self.myid=_MARKERID - + -- Log ID. self.lid=string.format("Marker #%d | ", self.myid) - + -- Start State. self:SetStartState("Invisible") @@ -201,7 +201,7 @@ function MARKER:New(Coordinate, Text) self:AddTransition("Invisible", "Added", "Visible") -- Marker was added. self:AddTransition("Visible", "Removed", "Invisible") -- Marker was removed. self:AddTransition("*", "Changed", "*") -- Marker was changed. - + self:AddTransition("*", "TextUpdate", "*") -- Text updated. self:AddTransition("*", "CoordUpdate", "*") -- Coordinates updated. @@ -304,8 +304,8 @@ function MARKER:New(Coordinate, Text) self:HandleEvent(EVENTS.MarkAdded) self:HandleEvent(EVENTS.MarkRemoved) self:HandleEvent(EVENTS.MarkChange) - - return self + + return self end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -318,7 +318,7 @@ end function MARKER:ReadOnly() self.readonly=true - + return self end @@ -329,7 +329,7 @@ end function MARKER:Message(Text) self.message=Text or "" - + return self end @@ -349,14 +349,14 @@ function MARKER:ToAll(Delay) self.togroup=nil self.groupname=nil self.groupid=nil - + -- First remove an existing mark. - if self.shown then - self:Remove() + if self.shown then + self:Remove() end - + self.mid=UTILS.GetMarkID() - + -- Call DCS function. trigger.action.markToAll(self.mid, self.text, self.coordinate:GetVec3(), self.readonly, self.message) @@ -377,25 +377,25 @@ function MARKER:ToCoalition(Coalition, Delay) else self.coalition=Coalition - + self.tocoaliton=true self.toall=false self.togroup=false self.groupname=nil self.groupid=nil - + -- First remove an existing mark. - if self.shown then - self:Remove() + if self.shown then + self:Remove() end - + self.mid=UTILS.GetMarkID() - + -- Call DCS function. trigger.action.markToCoalition(self.mid, self.text, self.coordinate:GetVec3(), self.coalition, self.readonly, self.message) - + end - + return self end @@ -440,36 +440,36 @@ function MARKER:ToGroup(Group, Delay) -- Check if group exists. if Group and Group:IsAlive()~=nil then - + self.groupid=Group:GetID() - + if self.groupid then - + self.groupname=Group:GetName() - + self.togroup=true self.tocoaliton=nil self.coalition=nil self.toall=nil - + -- First remove an existing mark. - if self.shown then - self:Remove() + if self.shown then + self:Remove() end - + self.mid=UTILS.GetMarkID() - + -- Call DCS function. trigger.action.markToGroup(self.mid, self.text, self.coordinate:GetVec3(), self.groupid, self.readonly, self.message) - + end - + else - --TODO: Warning! + --TODO: Warning! end - + end - + return self end @@ -482,14 +482,14 @@ function MARKER:UpdateText(Text, Delay) if Delay and Delay>0 then self:ScheduleOnce(Delay, MARKER.UpdateText, self, Text) - else + else self.text=tostring(Text) - + self:Refresh() - + self:TextUpdate(tostring(Text)) - + end return self @@ -504,14 +504,14 @@ function MARKER:UpdateCoordinate(Coordinate, Delay) if Delay and Delay>0 then self:ScheduleOnce(Delay, MARKER.UpdateCoordinate, self, Coordinate) - else + else self.coordinate=Coordinate - + self:Refresh() - + self:CoordUpdate(Coordinate) - + end return self @@ -525,26 +525,26 @@ function MARKER:Refresh(Delay) if Delay and Delay>0 then self:ScheduleOnce(Delay, MARKER.Refresh, self) - else + else if self.toall then - + self:ToAll() - + elseif self.tocoaliton then - + self:ToCoalition(self.coalition) - + elseif self.togroup then - + local group=GROUP:FindByName(self.groupname) - + self:ToGroup(group) - + else self:E(self.lid.."ERROR: unknown To in :Refresh()!") end - + end return self @@ -564,9 +564,9 @@ function MARKER:Remove(Delay) -- Call DCS function. trigger.action.removeMark(self.mid) - + end - + end return self @@ -605,7 +605,7 @@ end --- Check if marker is currently invisible on the F10 map. -- @param #MARKER self --- @return +-- @return function MARKER:IsInvisible() return self:Is("Invisible") end @@ -620,17 +620,17 @@ end function MARKER:OnEventMarkAdded(EventData) if EventData and EventData.MarkID then - + local MarkID=EventData.MarkID - + self:T3(self.lid..string.format("Captured event MarkAdded for Mark ID=%s", tostring(MarkID))) - + if MarkID==self.mid then - + self.shown=true - + self:Added(EventData) - + end end @@ -643,21 +643,21 @@ end function MARKER:OnEventMarkRemoved(EventData) if EventData and EventData.MarkID then - + local MarkID=EventData.MarkID - + self:T3(self.lid..string.format("Captured event MarkAdded for Mark ID=%s", tostring(MarkID))) - + if MarkID==self.mid then - + self.shown=false - + self:Removed(EventData) - + end end - + end --- Event function when a MARKER changed. @@ -666,17 +666,17 @@ end function MARKER:OnEventMarkChange(EventData) if EventData and EventData.MarkID then - + local MarkID=EventData.MarkID - + self:T3(self.lid..string.format("Captured event MarkChange for Mark ID=%s", tostring(MarkID))) - + if MarkID==self.mid then - + self:Changed(EventData) - + self:TextChanged(tostring(EventData.MarkText)) - + end end @@ -696,7 +696,7 @@ end function MARKER:onafterAdded(From, Event, To, EventData) -- Debug info. - local text=string.format("Captured event MarkAdded for myself:\n") + local text=string.format("Captured event MarkAdded for myself:\n") text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID)) text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition)) text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID)) @@ -716,7 +716,7 @@ end function MARKER:onafterRemoved(From, Event, To, EventData) -- Debug info. - local text=string.format("Captured event MarkRemoved for myself:\n") + local text=string.format("Captured event MarkRemoved for myself:\n") text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID)) text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition)) text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID)) @@ -736,7 +736,7 @@ end function MARKER:onafterChanged(From, Event, To, EventData) -- Debug info. - local text=string.format("Captured event MarkChange for myself:\n") + local text=string.format("Captured event MarkChange for myself:\n") text=text..string.format("Marker ID = %s\n", tostring(EventData.MarkID)) text=text..string.format("Coalition = %s\n", tostring(EventData.MarkCoalition)) text=text..string.format("Group ID = %s\n", tostring(EventData.MarkGroupID)) @@ -768,7 +768,7 @@ end function MARKER:onafterCoordUpdate(From, Event, To, Coordinate) self:T(self.lid..string.format("New Marker Coordinate in LL DMS: %s", Coordinate:ToStringLLDMS())) - + end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 5097935bb..f7632d687 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -1,13 +1,13 @@ --- **Wrapper** -- POSITIONABLE wraps DCS classes that are "positionable". --- +-- -- === --- +-- -- ### Author: **FlightControl** --- +-- -- ### Contributions: **Hardcard**, **funkyfranky** --- +-- -- === --- +-- -- @module Wrapper.Positionable -- @image Wrapper_Positionable.JPG @@ -27,23 +27,23 @@ -- * Manage the "state" of the POSITIONABLE. -- -- ## POSITIONABLE constructor --- +-- -- The POSITIONABLE class provides the following functions to construct a POSITIONABLE instance: -- -- * @{#POSITIONABLE.New}(): Create a POSITIONABLE instance. --- +-- -- ## Get the current speed --- +-- -- There are 3 methods that can be used to determine the speed. -- Use @{#POSITIONABLE.GetVelocityKMH}() to retrieve the current speed in km/h. Use @{#POSITIONABLE.GetVelocityMPS}() to retrieve the speed in meters per second. -- The method @{#POSITIONABLE.GetVelocity}() returns the speed vector (a Vec3). --- +-- -- ## Get the current altitude --- +-- -- Altitude can be retrieved using the method @{#POSITIONABLE.GetHeight}() and returns the current altitude in meters from the orthonormal plane. --- --- --- @field #POSITIONABLE +-- +-- +-- @field #POSITIONABLE POSITIONABLE = { ClassName = "POSITIONABLE", PositionableName = "", @@ -76,7 +76,7 @@ end --- Destroys the POSITIONABLE. -- @param #POSITIONABLE self -- @param #boolean GenerateEvent (Optional) true if you want to generate a crash or dead event for the unit. --- @return #nil The DCS Unit is not existing or alive. +-- @return #nil The DCS Unit is not existing or alive. -- @usage -- -- Air unit example: destroy the Helicopter and generate a S_EVENT_CRASH for each unit in the Helicopter group. -- Helicopter = UNIT:FindByName( "Helicopter" ) @@ -89,23 +89,23 @@ end -- -- Ship unit example: destroy the Ship silently. -- Ship = STATIC:FindByName( "Ship" ) -- Ship:Destroy() --- +-- -- @usage -- -- Destroy without event generation example. -- Ship = STATIC:FindByName( "Boat" ) -- Ship:Destroy( false ) -- Don't generate an event upon destruction. --- +-- function POSITIONABLE:Destroy( GenerateEvent ) self:F2( self.ObjectName ) local DCSObject = self:GetDCSObject() - + if DCSObject then - + local UnitGroup = self:GetGroup() local UnitGroupName = UnitGroup:GetName() self:F( { UnitGroupName = UnitGroupName } ) - + if GenerateEvent and GenerateEvent == true then if self:IsAir() then self:CreateEventCrash( timer.getTime(), DCSObject ) @@ -117,7 +117,7 @@ function POSITIONABLE:Destroy( GenerateEvent ) else self:CreateEventRemoveUnit( timer.getTime(), DCSObject ) end - + USERFLAG:New( UnitGroupName ):Set( 100 ) DCSObject:destroy() end @@ -140,19 +140,19 @@ function POSITIONABLE:GetPosition() self:F2( self.PositionableName ) local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then local PositionablePosition = DCSPositionable:getPosition() self:T3( PositionablePosition ) return PositionablePosition end - + BASE:E( { "Cannot GetPositionVec3", Positionable = self, Alive = self:IsAlive() } ) - return nil + return nil end --- Returns a {@DCS#Vec3} table of the objects current orientation in 3D space. X, Y, Z values are unit vectors defining the objects orientation. --- X is the orientation parallel to the movement of the object, Z perpendicular and Y vertical orientation. +-- X is the orientation parallel to the movement of the object, Z perpendicular and Y vertical orientation. -- @param Wrapper.Positionable#POSITIONABLE self -- @return DCS#Vec3 X orientation, i.e. parallel to the direction of movement. -- @return DCS#Vec3 Y orientation, i.e. vertical. @@ -164,7 +164,7 @@ function POSITIONABLE:GetOrientation() else BASE:E( { "Cannot GetOrientation", Positionable = self, Alive = self:IsAlive() } ) return nil, nil, nil - end + end end --- Returns a {@DCS#Vec3} table of the objects current X orientation in 3D space, i.e. along the direction of movement. @@ -177,7 +177,7 @@ function POSITIONABLE:GetOrientationX() else BASE:E( { "Cannot GetOrientationX", Positionable = self, Alive = self:IsAlive() } ) return nil - end + end end --- Returns a {@DCS#Vec3} table of the objects current Y orientation in 3D space, i.e. vertical orientation. @@ -190,7 +190,7 @@ function POSITIONABLE:GetOrientationY() else BASE:E( { "Cannot GetOrientationY", Positionable = self, Alive = self:IsAlive() } ) return nil - end + end end --- Returns a {@DCS#Vec3} table of the objects current Z orientation in 3D space, i.e. perpendicular to direction of movement. @@ -203,24 +203,24 @@ function POSITIONABLE:GetOrientationZ() else BASE:E( { "Cannot GetOrientationZ", Positionable = self, Alive = self:IsAlive() } ) return nil - end + end end --- Returns the @{DCS#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self -- @return DCS#Position The 3D position vectors of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. +-- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetPositionVec3() self:F2( self.PositionableName ) local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then local PositionablePosition = DCSPositionable:getPosition().p self:T3( PositionablePosition ) return PositionablePosition end - + BASE:E( { "Cannot GetPositionVec3", Positionable = self, Alive = self:IsAlive() } ) return nil @@ -228,22 +228,22 @@ end --- Returns the @{DCS#Vec3} vector indicating the 3D vector of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self --- @return DCS#Vec3 The 3D point vector of the POSITIONABLE or `nil` if it is not existing or alive. +-- @return DCS#Vec3 The 3D point vector of the POSITIONABLE or `nil` if it is not existing or alive. function POSITIONABLE:GetVec3() local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then - + local vec3=DCSPositionable:getPoint() - + if vec3 then return vec3 else self:E("ERROR: Cannot get vec3!") end end - + -- ERROR! self:E( { "Cannot GetVec3", Positionable = self, Alive = self:IsAlive() } ) return nil @@ -255,14 +255,14 @@ end function POSITIONABLE:GetVec2() local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then - + local Vec3=DCSPositionable:getPoint() --DCS#Vec3 - + return {x=Vec3.x, y=Vec3.z} end - + self:E( { "Cannot GetVec2", Positionable = self, Alive = self:IsAlive() } ) return nil @@ -271,21 +271,21 @@ end --- Returns a POINT_VEC2 object indicating the point in 2D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self -- @return Core.Point#POINT_VEC2 The 2D point vector of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. +-- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetPointVec2() self:F2( self.PositionableName ) local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then local PositionableVec3 = DCSPositionable:getPosition().p - + local PositionablePointVec2 = POINT_VEC2:NewFromVec3( PositionableVec3 ) - + --self:F( PositionablePointVec2 ) return PositionablePointVec2 end - + self:E( { "Cannot GetPointVec2", Positionable = self, Alive = self:IsAlive() } ) return nil @@ -294,35 +294,35 @@ end --- Returns a POINT_VEC3 object indicating the point in 3D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self -- @return Core.Point#POINT_VEC3 The 3D point vector of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. +-- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetPointVec3() local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then - + -- Get 3D vector. local PositionableVec3 = self:GetPositionVec3() - + if false and self.pointvec3 then - -- Update vector. + -- Update vector. self.pointvec3.x=PositionableVec3.x self.pointvec3.y=PositionableVec3.y - self.pointvec3.z=PositionableVec3.z - + self.pointvec3.z=PositionableVec3.z + else - + -- Create a new POINT_VEC3 object. self.pointvec3=POINT_VEC3:NewFromVec3(PositionableVec3) - + end - + return self.pointvec3 end BASE:E( { "Cannot GetPointVec3", Positionable = self, Alive = self:IsAlive() } ) - + return nil end @@ -333,32 +333,32 @@ function POSITIONABLE:GetCoord() -- Get DCS object. local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then - + -- Get the current position. local Vec3 = self:GetVec3() - + if self.coordinate then - -- Update vector. + -- Update vector. self.coordinate.x=Vec3.x self.coordinate.y=Vec3.y - self.coordinate.z=Vec3.z - + self.coordinate.z=Vec3.z + else - + -- New COORDINATE. self.coordinate=COORDINATE:NewFromVec3(Vec3) - + end - + return self.coordinate end - + -- Error message. BASE:E( { "Cannot GetCoordinate", Positionable = self, Alive = self:IsAlive() } ) - + return nil end @@ -369,19 +369,21 @@ function POSITIONABLE:GetCoordinate() -- Get DCS object. local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then - + -- Get the current position. local PositionableVec3 = self:GetVec3() - + + local coord=COORDINATE:NewFromVec3(PositionableVec3) + -- Return a new coordiante object. - return COORDINATE:NewFromVec3(PositionableVec3) + return coord end - + -- Error message. - self:E( { "Cannot GetCoordinate", Positionable = self, Alive = self:IsAlive() } ) + self:E( { "Cannot GetCoordinate", Positionable = self, Alive = self:IsAlive() } ) return nil end @@ -392,7 +394,7 @@ end -- @param #number z Offset in the direction "the wing" of the unit is pointing in meters. z>0 starboard, z<0 port. Default 0 m. -- @return Core.Point#COORDINATE The COORDINATE of the offset with respect to the orientation of the POSITIONABLE. function POSITIONABLE:GetOffsetCoordinate(x,y,z) - + -- Default if nil. x=x or 0 y=y or 0 @@ -402,58 +404,60 @@ function POSITIONABLE:GetOffsetCoordinate(x,y,z) local X=self:GetOrientationX() local Y=self:GetOrientationY() local Z=self:GetOrientationZ() - + -- Offset vector: x meters ahead, z meters starboard, y meters above. local A={x=x, y=y, z=z} - + -- Scale components of orthonormal coordinate vectors. local x={x=X.x*A.x, y=X.y*A.x, z=X.z*A.x} local y={x=Y.x*A.y, y=Y.y*A.y, z=Y.z*A.y} local z={x=Z.x*A.z, y=Z.y*A.z, z=Z.z*A.z} - + -- Add up vectors in the unit coordinate system ==> this gives the offset vector relative the the origin of the map. local a={x=x.x+y.x+z.x, y=x.y+y.y+z.y, z=x.z+y.z+z.z} - + -- Vector from the origin of the map to the unit. local u=self:GetVec3() - + -- Translate offset vector from map origin to the unit: v=u+a. local v={x=a.x+u.x, y=a.y+u.y, z=a.z+u.z} - + + local coord=COORDINATE:NewFromVec3(v) + -- Return the offset coordinate. - return COORDINATE:NewFromVec3(v) + return coord end --- Returns a random @{DCS#Vec3} vector within a range, indicating the point in 3D of the POSITIONABLE within the mission. -- @param Wrapper.Positionable#POSITIONABLE self -- @param #number Radius -- @return DCS#Vec3 The 3D point vector of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. --- @usage +-- @return #nil The POSITIONABLE is not existing or alive. +-- @usage -- -- If Radius is ignored, returns the DCS#Vec3 of first UNIT of the GROUP function POSITIONABLE:GetRandomVec3( Radius ) self:F2( self.PositionableName ) local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then local PositionablePointVec3 = DCSPositionable:getPosition().p - + if Radius then local PositionableRandomVec3 = {} local angle = math.random() * math.pi*2; PositionableRandomVec3.x = PositionablePointVec3.x + math.cos( angle ) * math.random() * Radius; PositionableRandomVec3.y = PositionablePointVec3.y PositionableRandomVec3.z = PositionablePointVec3.z + math.sin( angle ) * math.random() * Radius; - + self:T3( PositionableRandomVec3 ) return PositionableRandomVec3 - else + else self:F("Radius is nil, returning the PointVec3 of the POSITIONABLE", PositionablePointVec3) return PositionablePointVec3 end end - + BASE:E( { "Cannot GetRandomVec3", Positionable = self, Alive = self:IsAlive() } ) return nil @@ -463,12 +467,12 @@ end --- Get the bounding box of the underlying POSITIONABLE DCS Object. -- @param #POSITIONABLE self -- @return DCS#Box3 The bounding box of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. +-- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetBoundingBox() --R2.1 self:F2() local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then local PositionableDesc = DCSPositionable:getDesc() --DCS#Desc if PositionableDesc then @@ -476,7 +480,7 @@ function POSITIONABLE:GetBoundingBox() --R2.1 return PositionableBox end end - + BASE:E( { "Cannot GetBoundingBox", Positionable = self, Alive = self:IsAlive() } ) return nil @@ -484,7 +488,7 @@ end --- Get the object size. --- @param #POSITIONABLE self +-- @param #POSITIONABLE self -- @return DCS#Distance Max size of object in x, z or 0 if bounding box could not be obtained. -- @return DCS#Distance Length x or 0 if bounding box could not be obtained. -- @return DCS#Distance Height y or 0 if bounding box could not be obtained. @@ -493,26 +497,26 @@ function POSITIONABLE:GetObjectSize() -- Get bounding box. local box=self:GetBoundingBox() - + if box then local x=box.max.x+math.abs(box.min.x) --length local y=box.max.y+math.abs(box.min.y) --height local z=box.max.z+math.abs(box.min.z) --width return math.max(x,z), x , y, z end - + return 0,0,0,0 end --- Get the bounding radius of the underlying POSITIONABLE DCS Object. -- @param #POSITIONABLE self --- @param #number mindist (Optional) If bounding box is smaller than this value, mindist is returned. --- @return DCS#Distance The bounding radius of the POSITIONABLE or #nil if the POSITIONABLE is not existing or alive. +-- @param #number mindist (Optional) If bounding box is smaller than this value, mindist is returned. +-- @return DCS#Distance The bounding radius of the POSITIONABLE or #nil if the POSITIONABLE is not existing or alive. function POSITIONABLE:GetBoundingRadius(mindist) self:F2() local Box = self:GetBoundingBox() - + local boxmin=mindist or 0 if Box then local X = Box.max.x - Box.min.x @@ -521,7 +525,7 @@ function POSITIONABLE:GetBoundingRadius(mindist) local CZ = Z / 2 return math.max( math.max( CX, CZ ), boxmin ) end - + BASE:E( { "Cannot GetBoundingRadius", Positionable = self, Alive = self:IsAlive() } ) return nil @@ -530,37 +534,37 @@ end --- Returns the altitude of the POSITIONABLE. -- @param Wrapper.Positionable#POSITIONABLE self -- @return DCS#Distance The altitude of the POSITIONABLE. --- @return #nil The POSITIONABLE is not existing or alive. +-- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetAltitude() self:F2() local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then local PositionablePointVec3 = DCSPositionable:getPoint() --DCS#Vec3 return PositionablePointVec3.y end - + BASE:E( { "Cannot GetAltitude", Positionable = self, Alive = self:IsAlive() } ) return nil -end +end --- Returns if the Positionable is located above a runway. -- @param Wrapper.Positionable#POSITIONABLE self -- @return #boolean true if Positionable is above a runway. --- @return #nil The POSITIONABLE is not existing or alive. +-- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:IsAboveRunway() self:F2( self.PositionableName ) local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then - + local Vec2 = self:GetVec2() local SurfaceType = land.getSurfaceType( Vec2 ) local IsAboveRunway = SurfaceType == land.SurfaceType.RUNWAY - + self:T2( IsAboveRunway ) return IsAboveRunway end @@ -604,7 +608,7 @@ function POSITIONABLE:GetHeading() return PositionableHeading end end - + BASE:E( { "Cannot GetHeading", Positionable = self, Alive = self:IsAlive() } ) return nil @@ -618,19 +622,19 @@ end -- @return #boolean Air category evaluation result. function POSITIONABLE:IsAir() self:F2() - + local DCSUnit = self:GetDCSObject() - + if DCSUnit then local UnitDescriptor = DCSUnit:getDesc() self:T3( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } ) - + local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER ) - + self:T3( IsAirResult ) return IsAirResult end - + return nil end @@ -640,19 +644,19 @@ end -- @return #boolean Ground category evaluation result. function POSITIONABLE:IsGround() self:F2() - + local DCSUnit = self:GetDCSObject() - + if DCSUnit then local UnitDescriptor = DCSUnit:getDesc() self:T3( { UnitDescriptor.category, Unit.Category.GROUND_UNIT } ) - + local IsGroundResult = ( UnitDescriptor.category == Unit.Category.GROUND_UNIT ) - + self:T3( IsGroundResult ) return IsGroundResult end - + return nil end @@ -662,17 +666,17 @@ end -- @return #boolean Ship category evaluation result. function POSITIONABLE:IsShip() self:F2() - + local DCSUnit = self:GetDCSObject() - + if DCSUnit then local UnitDescriptor = DCSUnit:getDesc() - + local IsShip = ( UnitDescriptor.category == Unit.Category.SHIP ) - + return IsShip end - + return nil end @@ -681,7 +685,7 @@ end -- Polymorphic, is overridden in GROUP and UNIT. -- @param Wrapper.Positionable#POSITIONABLE self -- @return #boolean true if in the air. --- @return #nil The POSITIONABLE is not existing or alive. +-- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:InAir() self:F2( self.PositionableName ) @@ -692,39 +696,39 @@ end --- Returns the a @{Velocity} object from the positionable. -- @param Wrapper.Positionable#POSITIONABLE self -- @return Core.Velocity#VELOCITY Velocity The Velocity object. --- @return #nil The POSITIONABLE is not existing or alive. +-- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetVelocity() self:F2( self.PositionableName ) local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then local Velocity = VELOCITY:New( self ) return Velocity end - + BASE:E( { "Cannot GetVelocity", Positionable = self, Alive = self:IsAlive() } ) return nil end - + --- Returns the POSITIONABLE velocity Vec3 vector. -- @param Wrapper.Positionable#POSITIONABLE self -- @return DCS#Vec3 The velocity Vec3 vector --- @return #nil The POSITIONABLE is not existing or alive. +-- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetVelocityVec3() self:F2( self.PositionableName ) local DCSPositionable = self:GetDCSObject() - + if DCSPositionable and DCSPositionable:isExist() then local PositionableVelocityVec3 = DCSPositionable:getVelocity() self:T3( PositionableVelocityVec3 ) return PositionableVelocityVec3 end - + BASE:E( { "Cannot GetVelocityVec3", Positionable = self, Alive = self:IsAlive() } ) return nil @@ -736,12 +740,12 @@ end -- @return #number Relative velocity in m/s. function POSITIONABLE:GetRelativeVelocity(positionable) self:F2( self.PositionableName ) - + local v1=self:GetVelocityVec3() local v2=positionable:GetVelocityVec3() - + local vtot=UTILS.VecAdd(v1,v2) - + return UTILS.VecNorm(vtot) end @@ -749,12 +753,12 @@ end --- Returns the POSITIONABLE height in meters. -- @param Wrapper.Positionable#POSITIONABLE self -- @return DCS#Vec3 The height of the positionable. --- @return #nil The POSITIONABLE is not existing or alive. +-- @return #nil The POSITIONABLE is not existing or alive. function POSITIONABLE:GetHeight() --R2.1 self:F2( self.PositionableName ) local DCSPositionable = self:GetDCSObject() - + if DCSPositionable then local PositionablePosition = DCSPositionable:getPosition() if PositionablePosition then @@ -763,7 +767,7 @@ function POSITIONABLE:GetHeight() --R2.1 return PositionableHeight end end - + return nil end @@ -775,7 +779,7 @@ function POSITIONABLE:GetVelocityKMH() self:F2( self.PositionableName ) local DCSPositionable = self:GetDCSObject() - + if DCSPositionable and DCSPositionable:isExist() then local VelocityVec3 = self:GetVelocityVec3() local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec @@ -783,7 +787,7 @@ function POSITIONABLE:GetVelocityKMH() self:T3( Velocity ) return Velocity end - + return 0 end @@ -794,14 +798,14 @@ function POSITIONABLE:GetVelocityMPS() self:F2( self.PositionableName ) local DCSPositionable = self:GetDCSObject() - + if DCSPositionable and DCSPositionable:isExist() then local VelocityVec3 = self:GetVelocityVec3() local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec self:T3( Velocity ) return Velocity end - + return 0 end @@ -820,42 +824,42 @@ function POSITIONABLE:GetAoA() -- Get position of the unit. local unitpos = self:GetPosition() - + if unitpos then - + -- Get velocity vector of the unit. local unitvel = self:GetVelocityVec3() - + if unitvel and UTILS.VecNorm(unitvel)~=0 then - + -- Get wind vector including turbulences. local wind=self:GetCoordinate():GetWindWithTurbulenceVec3() - - -- Include wind vector. + + -- Include wind vector. unitvel.x=unitvel.x-wind.x unitvel.y=unitvel.y-wind.y unitvel.z=unitvel.z-wind.z - + -- Unit velocity transformed into aircraft axes directions. local AxialVel = {} - + -- Transform velocity components in direction of aircraft axes. AxialVel.x = UTILS.VecDot(unitpos.x, unitvel) AxialVel.y = UTILS.VecDot(unitpos.y, unitvel) AxialVel.z = UTILS.VecDot(unitpos.z, unitvel) - + -- AoA is angle between unitpos.x and the x and y velocities. local AoA = math.acos(UTILS.VecDot({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = AxialVel.y, z = 0})/UTILS.VecNorm({x = AxialVel.x, y = AxialVel.y, z = 0})) - + --Set correct direction: if AxialVel.y > 0 then AoA = -AoA end - + -- Return AoA value in degrees. return math.deg(AoA) end - + end return nil @@ -868,24 +872,24 @@ function POSITIONABLE:GetClimbAngle() -- Get position of the unit. local unitpos = self:GetPosition() - + if unitpos then - + -- Get velocity vector of the unit. local unitvel = self:GetVelocityVec3() - + if unitvel and UTILS.VecNorm(unitvel)~=0 then -- Calculate climb angle. local angle=math.asin(unitvel.y/UTILS.VecNorm(unitvel)) - + -- Return angle in degrees. return math.deg(angle) else return 0 end end - + return nil end @@ -896,11 +900,11 @@ function POSITIONABLE:GetPitch() -- Get position of the unit. local unitpos = self:GetPosition() - + if unitpos then return math.deg(math.asin(unitpos.x.y)) end - + return nil end @@ -911,7 +915,7 @@ function POSITIONABLE:GetRoll() -- Get position of the unit. local unitpos = self:GetPosition() - + if unitpos then --first, make a vector that is perpendicular to y and unitpos.x with cross product @@ -930,8 +934,8 @@ function POSITIONABLE:GetRoll() if unitpos.z.y > 0 then -- left roll, flip the sign of the roll Roll = -Roll end - - return math.deg(Roll) + + return math.deg(Roll) end end @@ -944,19 +948,19 @@ function POSITIONABLE:GetYaw() if unitpos then -- get unit velocity local unitvel = self:GetVelocityVec3() - + if unitvel and UTILS.VecNorm(unitvel) ~= 0 then --must have non-zero velocity! local AxialVel = {} --unit velocity transformed into aircraft axes directions - + --transform velocity components in direction of aircraft axes. AxialVel.x = UTILS.VecDot(unitpos.x, unitvel) AxialVel.y = UTILS.VecDot(unitpos.y, unitvel) AxialVel.z = UTILS.VecDot(unitpos.z, unitvel) - + --Yaw is the angle between unitpos.x and the x and z velocities --define right yaw as positive local Yaw = math.acos(UTILS.VecDot({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = 0, z = AxialVel.z})/UTILS.VecNorm({x = AxialVel.x, y = 0, z = AxialVel.z})) - + --now set correct direction: if AxialVel.z > 0 then Yaw = -Yaw @@ -964,7 +968,7 @@ function POSITIONABLE:GetYaw() return Yaw end end - + end @@ -1048,7 +1052,7 @@ function POSITIONABLE:MessageToCoalition( Message, Duration, MessageCoalition, N self:F2( { Message, Duration } ) local Name = Name or "" - + local DCSObject = self:GetDCSObject() if DCSObject then self:GetMessage( Message, Duration, Name ):ToCoalition( MessageCoalition ) @@ -1069,7 +1073,7 @@ function POSITIONABLE:MessageTypeToCoalition( Message, MessageType, MessageCoali self:F2( { Message, MessageType } ) local Name = Name or "" - + local DCSObject = self:GetDCSObject() if DCSObject then self:GetMessageType( Message, MessageType, Name ):ToCoalition( MessageCoalition ) @@ -1153,7 +1157,7 @@ function POSITIONABLE:MessageToGroup( Message, Duration, MessageGroup, Name ) BASE:E( { "Message not sent to Group; Positionable is not alive ...", Message = Message, Positionable = self, MessageGroup = MessageGroup } ) end end - + return nil end @@ -1194,7 +1198,7 @@ function POSITIONABLE:MessageToSetGroup( Message, Duration, MessageSetGroup, Nam MessageSetGroup:ForEachGroupAlive( function( MessageGroup ) self:GetMessage( Message, Duration, Name ):ToGroup( MessageGroup ) - end + end ) end end @@ -1219,13 +1223,13 @@ function POSITIONABLE:Message( Message, Duration, Name ) return nil end ---- Create a @{Core.Radio#RADIO}, to allow radio transmission for this POSITIONABLE. +--- Create a @{Core.Radio#RADIO}, to allow radio transmission for this POSITIONABLE. -- Set parameters with the methods provided, then use RADIO:Broadcast() to actually broadcast the message -- @param #POSITIONABLE self -- @return Core.Radio#RADIO Radio function POSITIONABLE:GetRadio() --R2.1 self:F2(self) - return RADIO:New(self) + return RADIO:New(self) end --- Create a @{Core.Radio#BEACON}, to allow this POSITIONABLE to broadcast beacon signals @@ -1233,7 +1237,7 @@ end -- @return Core.Radio#RADIO Radio function POSITIONABLE:GetBeacon() --R2.1 self:F2(self) - return BEACON:New(self) + return BEACON:New(self) end --- Start Lasing a POSITIONABLE @@ -1254,9 +1258,9 @@ function POSITIONABLE:LaseUnit( Target, LaserCode, Duration ) --R2.1 self.Spot = SPOT:New( self ) -- Core.Spot#SPOT self.Spot:LaseOn( Target, LaserCode, Duration) self.LaserCode = LaserCode - + return self.Spot - + end --- Start Lasing a COORDINATE. @@ -1269,11 +1273,11 @@ function POSITIONABLE:LaseCoordinate(Coordinate, LaserCode, Duration) self:F2() LaserCode = LaserCode or math.random(1000, 9999) - + self.Spot = SPOT:New(self) -- Core.Spot#SPOT self.Spot:LaseOnCoordinate(Coordinate, LaserCode, Duration) self.LaserCode = LaserCode - + return self.Spot end @@ -1298,7 +1302,7 @@ function POSITIONABLE:IsLasing() --R2.1 self:F2() local Lasing = false - + if self.Spot then Lasing = self.Spot:IsLasing() end @@ -1310,7 +1314,7 @@ end -- @param #POSITIONABLE self -- @return Core.Spot#SPOT The Spot function POSITIONABLE:GetSpot() --R2.1 - + return self.Spot end @@ -1318,7 +1322,7 @@ end -- @param #POSITIONABLE self -- @return #number The laser code function POSITIONABLE:GetLaserCode() --R2.1 - + return self.LaserCode end @@ -1332,16 +1336,16 @@ do -- Cargo self.__.Cargo[Cargo] = Cargo return self end - + --- Get all contained cargo. -- @param #POSITIONABLE self -- @return #POSITIONABLE function POSITIONABLE:GetCargo() return self.__.Cargo end - - - + + + --- Remove cargo. -- @param #POSITIONABLE self -- @param Core.Cargo#CARGO Cargo @@ -1350,20 +1354,20 @@ do -- Cargo self.__.Cargo[Cargo] = nil return self end - + --- Returns if carrier has given cargo. -- @param #POSITIONABLE self -- @return Core.Cargo#CARGO Cargo function POSITIONABLE:HasCargo( Cargo ) return self.__.Cargo[Cargo] end - + --- Clear all cargo. -- @param #POSITIONABLE self function POSITIONABLE:ClearCargo() self.__.Cargo = {} end - + --- Is cargo bay empty. -- @param #POSITIONABLE self function POSITIONABLE:IsCargoEmpty() @@ -1374,7 +1378,7 @@ do -- Cargo end return IsEmpty end - + --- Get cargo item count. -- @param #POSITIONABLE self -- @return Core.Cargo#CARGO Cargo @@ -1385,7 +1389,7 @@ do -- Cargo end return ItemCount end - + -- --- Get Cargo Bay Free Volume in m3. -- -- @param #POSITIONABLE self -- -- @return #number CargoBayFreeVolume @@ -1396,18 +1400,18 @@ do -- Cargo -- end -- return self.__.CargoBayVolumeLimit - CargoVolume -- end --- - +-- + --- Get Cargo Bay Free Weight in kg. -- @param #POSITIONABLE self -- @return #number CargoBayFreeWeight function POSITIONABLE:GetCargoBayFreeWeight() - + -- When there is no cargo bay weight limit set, then calculate this for this positionable! if not self.__.CargoBayWeightLimit then self:SetCargoBayWeightLimit() end - + local CargoWeight = 0 for CargoName, Cargo in pairs( self.__.Cargo ) do CargoWeight = CargoWeight + Cargo:GetWeight() @@ -1426,29 +1430,29 @@ do -- Cargo -- @param #POSITIONABLE self -- @param #number WeightLimit function POSITIONABLE:SetCargoBayWeightLimit( WeightLimit ) - + if WeightLimit then self.__.CargoBayWeightLimit = WeightLimit elseif self.__.CargoBayWeightLimit~=nil then -- Value already set ==> Do nothing! else -- If weightlimit is not provided, we will calculate it depending on the type of unit. - + -- When an airplane or helicopter, we calculate the weightlimit based on the descriptor. if self:IsAir() then local Desc = self:GetDesc() self:F({Desc=Desc}) - local Weights = { + local Weights = { ["C-17A"] = 35000, --77519 cannot be used, because it loads way too much apcs and infantry., ["C-130"] = 22000 --The real value cannot be used, because it loads way too much apcs and infantry., - } + } self.__.CargoBayWeightLimit = Weights[Desc.typeName] or ( Desc.massMax - ( Desc.massEmpty + Desc.fuelMassMax ) ) else local Desc = self:GetDesc() - local Weights = { + local Weights = { ["M1126 Stryker ICV"] = 9, ["M-113"] = 9, ["AAV7"] = 25, @@ -1484,7 +1488,7 @@ do -- Cargo ["Ural-4320-31"] = 14, ["Ural-4320T"] = 14, } - + local CargoBayWeightLimit = ( Weights[Desc.typeName] or 0 ) * 95 self.__.CargoBayWeightLimit = CargoBayWeightLimit end @@ -1548,7 +1552,7 @@ function POSITIONABLE:Smoke( SmokeColor, Range, AddHeight ) Vec3.y = Vec3.y + AddHeight or 0 trigger.action.smoke( self:GetVec3(), SmokeColor ) end - + end --- Smoke the POSITIONABLE Green. @@ -1596,8 +1600,8 @@ function POSITIONABLE:IsInZone( Zone ) if self:IsAlive() then local IsInZone = Zone:IsVec3InZone( self:GetVec3() ) - - return IsInZone + + return IsInZone end return false end @@ -1611,9 +1615,9 @@ function POSITIONABLE:IsNotInZone( Zone ) if self:IsAlive() then local IsNotInZone = not Zone:IsVec3InZone( self:GetVec3() ) - - return IsNotInZone + + return IsNotInZone else return false end -end \ No newline at end of file +end diff --git a/Moose Development/Moose/Wrapper/Unit.lua b/Moose Development/Moose/Wrapper/Unit.lua index a7b2316b9..fe1c86e15 100644 --- a/Moose Development/Moose/Wrapper/Unit.lua +++ b/Moose Development/Moose/Wrapper/Unit.lua @@ -258,8 +258,7 @@ end --- Returns if the unit is activated. -- @param #UNIT self --- @return #boolean true if Unit is activated. --- @return #nil The DCS Unit is not existing or alive. +-- @return #boolean `true` if Unit is activated. `nil` The DCS Unit is not existing or alive. function UNIT:IsActive() self:F2( self.UnitName ) @@ -279,9 +278,7 @@ end -- If the Unit is alive and active, true is returned. -- If the Unit is alive but not active, false is returned. -- @param #UNIT self --- @return #boolean true if Unit is alive and active. --- @return #boolean false if Unit is alive but not active. --- @return #nil if the Unit is not existing or is not alive. +-- @return #boolean `true` if Unit is alive and active. `false` if Unit is alive but not active. `nil` if the Unit is not existing or is not alive. function UNIT:IsAlive() self:F3( self.UnitName ) @@ -300,7 +297,6 @@ end --- Returns the Unit's callsign - the localized string. -- @param #UNIT self -- @return #string The Callsign of the Unit. --- @return #nil The DCS Unit is not existing or alive. function UNIT:GetCallsign() self:F2( self.UnitName ) @@ -640,8 +636,7 @@ end --- Returns the unit sensors. -- @param #UNIT self --- @return DCS#Unit.Sensors --- @return #nil The DCS Unit is not existing or alive. +-- @return DCS#Unit.Sensors Table of sensors. function UNIT:GetSensors() self:F2( self.UnitName ) @@ -661,7 +656,6 @@ end --- Returns if the unit has sensors of a certain type. -- @param #UNIT self -- @return #boolean returns true if the unit has specified types of sensors. This function is more preferable than Unit.getSensors() if you don't want to get information about all the unit's sensors, and just want to check if the unit has specified types of sensors. --- @return #nil The DCS Unit is not existing or alive. function UNIT:HasSensors( ... ) self:F2( arg ) @@ -678,7 +672,6 @@ end --- Returns if the unit is SEADable. -- @param #UNIT self -- @return #boolean returns true if the unit is SEADable. --- @return #nil The DCS Unit is not existing or alive. function UNIT:HasSEAD() self:F2() @@ -705,7 +698,6 @@ end -- @param #UNIT self -- @return #boolean Indicates if at least one of the unit's radar(s) is on. -- @return DCS#Object The object of the radar's interest. Not nil only if at least one radar of the unit is tracking a target. --- @return #nil The DCS Unit is not existing or alive. function UNIT:GetRadar() self:F2( self.UnitName )