diff --git a/Moose Development/Moose/AI/AI_Cargo_APC.lua b/Moose Development/Moose/AI/AI_Cargo_APC.lua index 51f94e4c9..9fbf1566a 100644 --- a/Moose Development/Moose/AI/AI_Cargo_APC.lua +++ b/Moose Development/Moose/AI/AI_Cargo_APC.lua @@ -600,8 +600,6 @@ end -- @param Event -- @param To -- @param Core.Point#COORDINATE Coordinate --- @param #number Speed --- @param #string EndPointFormation The formation at the end point of the action. function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate ) if APC and APC:IsAlive() then @@ -609,7 +607,7 @@ function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate ) if Coordinate then self.RoutePickup = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, APC:GetSpeedMax()*0.8, "Line abreast" ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, APC:GetSpeedMax()*0.5, "Line abreast" ) local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self ) @@ -634,15 +632,13 @@ end -- @param Event -- @param To -- @param Core.Point#COORDINATE Coordinate --- @param #number Speed --- @param #string EndPointFormation The formation at the end point of the action. function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate ) if APC and APC:IsAlive() then self.RouteDeploy = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, 150, "Line abreast" ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, APC:GetSpeedMax()*0.5, "Line abreast" ) local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self ) @@ -662,14 +658,13 @@ end -- @param Event -- @param To -- @param Core.Point#COORDINATE Coordinate --- @param #number Speed function AI_CARGO_APC:onafterHome( APC, From, Event, To, Coordinate ) if APC and APC:IsAlive() ~= nil then self.RouteHome = true - local Waypoints = APC:TaskGroundOnRoad( Coordinate, 120, "Line abreast" ) + local Waypoints = APC:TaskGroundOnRoad( Coordinate, APC:GetSpeedMax()*0.5, "Line abreast" ) self:F({Waypoints = Waypoints}) local Waypoint = Waypoints[#Waypoints] diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua index cd8390f7b..286e4f79f 100644 --- a/Moose Development/Moose/Core/Point.lua +++ b/Moose Development/Moose/Core/Point.lua @@ -777,7 +777,7 @@ do -- COORDINATE -- @param #COORDINATE.WaypointAltType AltType The altitude type. -- @param #COORDINATE.WaypointType Type The route point type. -- @param #COORDINATE.WaypointAction Action The route point action. - -- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. + -- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h. Default is 500 km/h. -- @param #boolean SpeedLocked true means the speed is locked. -- @return #table The route point. function COORDINATE:WaypointAir( AltType, Type, Action, Speed, SpeedLocked ) @@ -887,7 +887,7 @@ do -- COORDINATE --- Build an ground type route point. -- @param #COORDINATE self - -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @param #number Speed (optional) Speed in km/h. The default speed is 20 km/h. -- @param #string Formation (optional) The route point Formation, which is a text string that specifies exactly the Text in the Type of the route point, like "Vee", "Echelon Right". -- @return #table The route point. function COORDINATE:WaypointGround( Speed, Formation ) @@ -935,22 +935,30 @@ do -- COORDINATE return COORDINATE:NewFromVec2(vec2) end - --- Returns a table of coordinates to a destination. + --- Returns a table of coordinates to a destination using only roads. + -- The first point is the closest point on road of the given coordinate. 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. -- @return #table Table of coordinates on road. function COORDINATE:GetPathOnRoad(ToCoord) - local Path={} + + -- DCS API function returning a table of vec2. local path = land.findPathOnRoads("roads", self.x, self.z, ToCoord.x, ToCoord.z) - Path[#Path+1]=COORDINATE:NewFromVec2(path[1]) - Path[#Path+1]=COORDINATE:NewFromVec2(path[#path]) + + --Path[#Path+1]=COORDINATE:NewFromVec2(path[1]) + --Path[#Path+1]=COORDINATE:NewFromVec2(path[#path]) + --Path[#Path+1]=self:GetClosestPointToRoad() + --Path[#Path+1]=ToCoord:GetClosestPointToRoad() -- I've removed this stuff because it severely slows down DCS in case of paths with a lot of segments. -- Just the beginning and the end point is sufficient. --- for i, v in ipairs(path) do --- self:I(v) --- local coord=COORDINATE:NewFromVec2(v) --- Path[#Path+1]=COORDINATE:NewFromVec2(v) --- end + + local Path={} + --Path[#Path+1]=self + for i, v in ipairs(path) do + Path[#Path+1]=COORDINATE:NewFromVec2(v) + end + --Path[#Path+1]=ToCoord + return Path end diff --git a/Moose Development/Moose/Functional/Artillery.lua b/Moose Development/Moose/Functional/Artillery.lua index 1921787ae..f8a210b8e 100644 --- a/Moose Development/Moose/Functional/Artillery.lua +++ b/Moose Development/Moose/Functional/Artillery.lua @@ -2434,16 +2434,18 @@ function ARTY:_Move(group, ToCoord, Speed, OnRoad) -- Route group on road if requested. if OnRoad then + -- Path on road (only first and last points) local _first=cpini:GetClosestPointToRoad() local _last=ToCoord:GetClosestPointToRoad() - local _onroad=_first:GetPathOnRoad(_last) - -- Points on road. - for i=1,#_onroad do - path[#path+1]=_onroad[i]:WaypointGround(Speed, "On road") - task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) - end - + -- First point on road. + path[#path+1]=_first:WaypointGround(Speed, "On road") + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) + + -- Last point on road. + path[#path+1]=_last:WaypointGround(Speed, "On road") + task[#task+1]=group:TaskFunction("ARTY._PassingWaypoint", self, #path-1, false) + end -- Last waypoint at ToCoord. diff --git a/Moose Development/Moose/Functional/Range.lua b/Moose Development/Moose/Functional/Range.lua index 65614ebf5..c21f6656f 100644 --- a/Moose Development/Moose/Functional/Range.lua +++ b/Moose Development/Moose/Functional/Range.lua @@ -70,6 +70,7 @@ -- @field #table bombPlayerResults Table containing the bombing results of each player. -- @field #table PlayerSettings Indiviual player settings. -- @field #number dtBombtrack Time step [sec] used for tracking released bomb/rocket positions. Default 0.005 seconds. +-- @field #number BombtrackThreshold Bombs/rockets/missiles are only tracked if player-range distance is smaller than this threashold [m]. Default 25000 m. -- @field #number Tmsg Time [sec] messages to players are displayed. Default 30 sec. -- @field #number strafemaxalt Maximum altitude above ground for registering for a strafe run. Default is 914 m = 3000 ft. -- @field #number ndisplayresult Number of (player) results that a displayed. Default is 10. @@ -236,6 +237,7 @@ RANGE={ bombPlayerResults = {}, PlayerSettings = {}, dtBombtrack=0.005, + BombtrackThreshold=25000, Tmsg=30, strafemaxalt=914, ndisplayresult=10, @@ -283,7 +285,7 @@ RANGE.id="RANGE | " --- Range script version. -- @field #number version -RANGE.version="1.1.1" +RANGE.version="1.2.0" --TODO list: --TODO: Add custom weapons, which can be specified by the user. @@ -451,6 +453,13 @@ function RANGE:SetRangeRadius(radius) self.rangeradius=radius*1000 or RANGE.Defaults.rangeradius end +--- Set bomb track threshold distance. Bombs/rockets/missiles are only tracked if player-range distance is less than this distance. Default 25 km. +-- @param #RANGE self +-- @param #number distance Threshold distance in km. Default 25 km. +function RANGE:SetBombtrackThreshold(distance) + self.BombtrackThreshold=distance*1000 or 25*1000 +end + --- Set range location. If this is not done, one (random) unit position of the range is used to determine the center of the range. -- @param #RANGE self -- @param Core.Point#COORDINATE coordinate Coordinate of the center of the range. @@ -1081,6 +1090,7 @@ function RANGE:OnEventShot(EventData) local _weaponName = _weaponStrArray[#_weaponStrArray] -- Debug info. + self:T(RANGE.id.."EVENT SHOT: Range "..self.rangename) self:T(RANGE.id.."EVENT SHOT: Ini unit = "..EventData.IniUnitName) self:T(RANGE.id.."EVENT SHOT: Ini group = "..EventData.IniGroupName) self:T(RANGE.id.."EVENT SHOT: Weapon type = ".._weapon) @@ -1097,129 +1107,141 @@ function RANGE:OnEventShot(EventData) -- Check if any condition applies here. local _track = (_bombs and self.trackbombs) or (_rockets and self.trackrockets) or (_missiles and self.trackmissiles) - if _track then + -- Get unit name. + local _unitName = EventData.IniUnitName + + -- Get player unit and name. + local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) - -- Weapon - local _ordnance = EventData.weapon + -- Set this to larger value than the threshold. + local dPR=self.BombtrackThreshold*2 + + -- Distance player to range. + if _unit and _playername then + dPR=_unit:GetCoordinate():Get2DDistance(self.location) + self:T(RANGE.id..string.format("Range %s, player %s, player-range distance = %d km.", self.rangename, _playername, dPR/1000)) + end + + -- Only track if distance player to range is < 25 km. + if _track and dPR<=self.BombtrackThreshold then -- Tracking info and init of last bomb position. - self:T(RANGE.id..string.format("Tracking %s - %s.", _weapon, _ordnance:getName())) + self:T(RANGE.id..string.format("RANGE %s: Tracking %s - %s.", self.rangename, _weapon, EventData.weapon:getName())) -- Init bomb position. local _lastBombPos = {x=0,y=0,z=0} - - -- Get unit name. - local _unitName = EventData.IniUnitName -- Function monitoring the position of a bomb until impact. - local function trackBomb(_previousPos) + local function trackBomb(_ordnance) + + -- When the pcall returns a failure the weapon has hit. + local _status,_bombPos = pcall( + function() + return _ordnance:getPoint() + end) + + self:T3(RANGE.id..string.format("Range %s: Bomb still in air: %s", self.rangename, tostring(_status))) + if _status then - -- Get player unit and name. - local _unit, _playername = self:_GetPlayerUnitAndName(_unitName) - local _callsign=self:_myname(_unitName) + -- Still in the air. Remember this position. + _lastBombPos = {x = _bombPos.x, y = _bombPos.y, z= _bombPos.z } - if _unit and _playername then - - -- When the pcall returns a failure the weapon has hit. - local _status,_bombPos = pcall( - function() - return _ordnance:getPoint() - end) - - if _status then + -- Check again in 0.005 seconds. + return timer.getTime() + self.dtBombtrack - -- Still in the air. Remember this position. - _lastBombPos = {x = _bombPos.x, y = _bombPos.y, z= _bombPos.z } - - -- Check again in 0.005 seconds. - return timer.getTime() + self.dtBombtrack - - else + else + + -- Bomb did hit the ground. + -- Get closet target to last position. + local _closetTarget = nil + local _distance = nil + local _hitquality = "POOR" - -- Bomb did hit the ground. - -- Get closet target to last position. - local _closetTarget = nil - local _distance = nil - local _hitquality = "POOR" - - -- Coordinate of impact point. - local impactcoord=COORDINATE:NewFromVec3(_lastBombPos) - - -- Distance from range. We dont want to smoke targets outside of the range. - local impactdist=impactcoord:Get2DDistance(self.location) - - -- Smoke impact point of bomb. - if self.PlayerSettings[_playername].smokebombimpact and impactdist10 then - table.insert(route, ToCoordinate:WaypointGround(Speed, "Off Road")) - end + -- Defaults. + Speed=Speed or 20 + DelaySeconds=DelaySeconds or 1 + OffRoadFormation=OffRoadFormation or "Off Road" + + -- Get the route task. + local route=self:TaskGroundOnRoad(ToCoordinate, Speed, OffRoadFormation) -- Route controllable to destination. self:Route( route, DelaySeconds ) @@ -1978,39 +1969,43 @@ do -- Route methods end - --- Make a task for a GROUND Controllable to drive towards a specific point using (only) roads. + --- Make a task for a GROUND Controllable to drive towards a specific point using (mostly) roads. -- @param #CONTROLLABLE self -- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to. - -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. - -- @param #string EndPointFormation The formation to achieve at the end point. + -- @param #number Speed (Optional) Speed in km/h. The default speed is 20 km/h. + -- @param #string OffRoadFormation (Optional) The formation at initial and final waypoint. Default is "Off Road". -- @return Task - function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed, EndPointFormation ) + function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed, OffRoadFormation ) + self:F2({ToCoordinate=ToCoordinate, Speed=Speed, OffRoadFormation=OffRoadFormation}) + + -- Defaults. + Speed=Speed or 20 + OffRoadFormation=OffRoadFormation or "Off Road" -- Current coordinate. local FromCoordinate = self:GetCoordinate() - -- Formation is set to on road. - local Formation="On Road" - - -- Path on road from current position to destination coordinate. - local path=FromCoordinate:GetPathOnRoad( ToCoordinate ) + -- First point on road. + local FromOnRoad = FromCoordinate:GetClosestPointToRoad() - -- Route, ground waypoints along roads. - local Route = {} - table.insert( Route, FromCoordinate:WaypointGround( Speed, Formation ) ) + -- Last Point on road. + local ToOnRoad = ToCoordinate:GetClosestPointToRoad() + + -- Route, ground waypoints along road. + local route={} - -- Convert coordinates to ground waypoints and insert into table. - for _, coord in ipairs(path) do - table.insert( Route, coord:WaypointGround( Speed, Formation ) ) - end - - -- Add the final coordinate because the final coordinate in path is last point on road. - local dist=ToCoordinate:Get2DDistance(path[#path]) + -- Create waypoints. + table.insert(route, FromCoordinate:WaypointGround(Speed, OffRoadFormation)) + table.insert(route, FromOnRoad:WaypointGround(Speed, "On Road")) + table.insert(route, ToOnRoad:WaypointGround(Speed, "On Road")) + + -- Add the final coordinate because the final might not be on the road. + local dist=ToCoordinate:Get2DDistance(ToOnRoad) if dist>10 then - table.insert( Route, ToCoordinate:WaypointGround( Speed, EndPointFormation ) ) - end + table.insert(route, ToCoordinate:WaypointGround(Speed, OffRoadFormation)) + end - return Route + return route end @@ -2020,7 +2015,7 @@ do -- Route methods -- @param Core.Point#COORDINATE.RoutePointAltType AltType The altitude type. -- @param Core.Point#COORDINATE.RoutePointType Type The route point type. -- @param Core.Point#COORDINATE.RoutePointAction Action The route point action. - -- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h. + -- @param #number Speed (optional) Speed in km/h. The default speed is 500 km/h. -- @param #number DelaySeconds Wait for the specified seconds before executing the Route. -- @return #CONTROLLABLE The CONTROLLABLE. function CONTROLLABLE:RouteAirTo( ToCoordinate, AltType, Type, Action, Speed, DelaySeconds ) @@ -2043,7 +2038,7 @@ do -- Route methods -- @param #CONTROLLABLE self -- @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. + -- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h. -- @param Base#FORMATION Formation The formation string. function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation ) self:F2( Zone ) @@ -2104,7 +2099,7 @@ do -- Route methods -- A given formation can be given. -- @param #CONTROLLABLE self -- @param #Vec2 Vec2 The Vec2 where to route to. - -- @param #number Speed The speed. + -- @param #number Speed The speed in m/s. Default is 5.555 m/s = 20 km/h. -- @param Base#FORMATION Formation The formation string. function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation ) @@ -2119,7 +2114,7 @@ do -- Route methods PointFrom.y = ControllablePoint.y PointFrom.type = "Turning Point" PointFrom.action = Formation or "Cone" - PointFrom.speed = 20 / 1.6 + PointFrom.speed = 20 / 3.6 local PointTo = {} @@ -2137,7 +2132,7 @@ do -- Route methods if Speed then PointTo.speed = Speed else - PointTo.speed = 60 / 3.6 + PointTo.speed = 20 / 3.6 end local Points = { PointFrom, PointTo }