diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index e0971ee06..2c00f48f5 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -535,7 +535,7 @@ function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth, AddHeight ) local Vec2 = self:GetVec2() AddHeight = AddHeight or 0 - + Points = Points and Points or 360 local Angle @@ -1431,12 +1431,16 @@ end -- @param #ZONE_POLYGON_BASE self -- @param Utilities.Utils#FLARECOLOR FlareColor The flare color. -- @param #number Segments (Optional) Number of segments within boundary line. Default 10. +-- @param DCS#Azimuth Azimuth (optional) Azimuth The azimuth of the flare. +-- @param #number AddHeight (optional) The height to be added for the smoke. -- @return #ZONE_POLYGON_BASE self -function ZONE_POLYGON_BASE:FlareZone( FlareColor, Segments ) +function ZONE_POLYGON_BASE:FlareZone( FlareColor, Segments, Azimuth, AddHeight ) self:F2(FlareColor) Segments=Segments or 10 + AddHeight = AddHeight or 0 + local i=1 local j=#self._.Polygon @@ -1449,7 +1453,7 @@ function ZONE_POLYGON_BASE:FlareZone( FlareColor, Segments ) for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line. local PointX = self._.Polygon[i].x + ( Segment * DeltaX / Segments ) local PointY = self._.Polygon[i].y + ( Segment * DeltaY / Segments ) - POINT_VEC2:New( PointX, PointY ):Flare(FlareColor) + POINT_VEC2:New( PointX, PointY, AddHeight ):Flare(FlareColor, Azimuth) end j = i i = i + 1 diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index cf12e05c8..cbe9403d2 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -600,7 +600,7 @@ AIRBOSS.CarrierType={ -- @field #number wire4 Distance in meters from carrier position to fourth wire. -- @field #number rwylength Length of the landing runway in meters. -- @field #number rwywidth Width of the landing runway in meters. --- @field #number totlenght Total length of carrier. +-- @field #number totlength Total length of carrier. -- @field #number totwidthstarboard Total with of the carrier from stern position to starboard side (asymmetric carriers). -- @field #number totwidthport Total with of the carrier from stern position to port side (asymmetric carriers). @@ -1128,7 +1128,7 @@ AIRBOSS.MenuF10={} --- Airboss class version. -- @field #string version -AIRBOSS.version="0.5.9w" +AIRBOSS.version="0.6.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -1203,11 +1203,13 @@ function AIRBOSS:New(carriername, alias) return nil end + --[[ self.Debug=true BASE:TraceOnOff(true) BASE:TraceClass(self.ClassName) BASE:TraceLevel(1) - + ]] + -- Set some string id for output to DCS.log file. self.lid=string.format("AIRBOSS %s | ", carriername) @@ -1223,8 +1225,10 @@ function AIRBOSS:New(carriername, alias) -- Create carrier beacon. self.beacon=BEACON:New(self.carrier) - -- Defaults: - + ------------- + --- Defaults: + ------------- + -- Set up Airboss radio. self.MarshalRadio=RADIO:New(self.carrier) self.MarshalRadio:SetAlias("MARSHAL") @@ -1312,7 +1316,7 @@ function AIRBOSS:New(carriername, alias) local stern=self:_GetSternCoord() -- Bow pos. - local bow=stern:Translate(self.carrierparam.totlenght, hdg) + local bow=stern:Translate(self.carrierparam.totlength, hdg) -- End of rwy. local rwy=stern:Translate(self.carrierparam.rwylength, FB, true) @@ -1339,11 +1343,11 @@ function AIRBOSS:New(carriername, alias) rwy:FlareRed() -- Right 30 meters from stern. - local cR=stern:Translate(self.carrierparam.totstarboard, hdg+90) + local cR=stern:Translate(self.carrierparam.totwidthstarboard, hdg+90) cR:FlareYellow() -- Left 40 meters from stern. - local cL=stern:Translate(self.carrierparam.totport, hdg-90) + local cL=stern:Translate(self.carrierparam.totwidthport, hdg-90) cL:FlareYellow() --[[ @@ -1356,9 +1360,15 @@ function AIRBOSS:New(carriername, alias) w3:FlareWhite() w4:FlareYellow() ]] - + + + local cbox=self:_GetZoneCarrierBox() + local rbox=self:_GetZoneRunwayBox() + cbox:FlareZone(FLARECOLOR.Green, 5, nil, self.carrierparam.deckheight) + rbox:FlareZone(FLARECOLOR.White, 5, nil, self.carrierparam.deckheight) end + SCHEDULER:New(nil, flareme, {}, 1, 1) end @@ -2500,7 +2510,7 @@ function AIRBOSS:_InitStennis() self.carrierparam.deckheight = 19 -- Total size of the carrier (approx as rectangle). - self.carrierparam.totlenght=310 -- Wiki says 332.8 meters overall length. + self.carrierparam.totlength=310 -- Wiki says 332.8 meters overall length. self.carrierparam.totwidthport=40 -- Wiki says 76.8 meters overall beam. self.carrierparam.totwidthstarboard=30 @@ -5486,7 +5496,7 @@ function AIRBOSS:_Groove(playerData) -------------------------------------------------------- -- Player infront of the carrier X>~77 m. - if X>self.carrierparam.totlenght+self.carrierparam.sterndist then + if X>self.carrierparam.totlength+self.carrierparam.sterndist then if playerData.waveoff then @@ -5990,13 +6000,13 @@ function AIRBOSS:_GetZoneCarrierBox() p[1]=S:Translate(self.carrierparam.totwidthstarboard, hdg+90) -- Starboard bow point. - p[2]=p[1]:Translate(self.carrierparam.totlenght, hdg) + p[2]=p[1]:Translate(self.carrierparam.totlength, hdg) -- Port bow point. p[3]=p[2]:Translate(self.carrierparam.totwidthstarboard+self.carrierparam.totwidthport, hdg-90) -- Port stern point. - p[4]=p[3]:Translate(self.carrierparam.totlegth, hdg-180) + p[4]=p[3]:Translate(self.carrierparam.totlength, hdg-180) -- Convert to vec2. local vec2={} @@ -6164,16 +6174,6 @@ function AIRBOSS:_Glideslope(unit, optangle) -- Default is 0. optangle=optangle or 0 - - --[[ - -- Glideslope. Wee need to correct for the height of the deck. The ideal glide slope is 3.5 degrees. - local h=unit:GetAltitude()-self.carrierparam.deckheight - -- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier) - local X, Z, rho, phi = self:_GetDistances(unit) - -- Distance correction. - local offx=self.carrierparam.wire3 or self.carrierparam.sterndist - local x=math.abs(self.carrierparam.wire3-X) - ]] -- Stern coordinate. local stern=self:_GetSternCoord() @@ -6190,9 +6190,12 @@ function AIRBOSS:_Glideslope(unit, optangle) local h=unit:GetAltitude() -- Glide slope. - local glideslope=math.atan(h/x) + local glideslope=math.atan(h/x) + + -- Glide slope (error) in degrees. + local gs=math.deg(glideslope)-optangle - return math.deg(glideslope)-optangle + return gs end --- Get line up of player wrt to carrier. @@ -6200,69 +6203,59 @@ end -- @param Wrapper.Unit#UNIT unit Aircraft unit. -- @param #boolean runway If true, include angled runway. -- @return #number Line up with runway heading in degrees. 0 degrees = perfect line up. +1 too far left. -1 too far right. -function AIRBOSS:_Lineup(unit, runway) - - --[[ - - -- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier) - local X, Z, rho, phi = self:_GetDistances(unit) +function AIRBOSS:_Lineup(unit, runway) - -- Position at the end of the deck. From there we calculate the angle. - local b={x=self.carrierparam.sterndist, z=0} + -- Vector to carrier. + local A=self:_GetSternCoord():GetVec3() - -- Position of the aircraft wrt carrier coordinates. - local a={x=X, z=Z} - - -- Vector from plane to ref point on boad. - local c={x=b.x-a.x, y=0, z=b.z-a.z} - - -- Stern coordinate. - local stern=self:_GetSternCoord() + -- Vector to player. + local B=unit:GetVec3() - -- Position of aircraft. - local coord=unit:GetCoordinate() + -- Vector from player to carrier. + local C=UTILS.VecSubstract(A, B) - -- Vector from stern to aircraft. - local c={x=stern.x-coord.x, y=0, z=stern.z-coord.z} + -- Only in 2D plane. + C.y=0 - - -- Current line up and error wrt to final heading of the runway. - local lineup=math.deg(math.atan2(c.z, c.x)) - - -- Include runway. - if runway then - lineup=lineup-self.carrierparam.rwyangle - end - - ]] - - --- New stuff - - -- Carrier Orientation. - local X=COORDINATE:NewFromVec3(self.carrier:GetOrientationX()) + -- Orientation of carrier. + local X=self.carrier:GetOrientationX() -- Rotate orientation to angled runway. if runway then - X=X:Rotate2D(self.carrierparams.rwyangle) + X=UTILS.Rotate2D(X, -self.carrierparam.rwyangle) end - -- Stern coordinate. - local S=self:_GetSternCoord() - S.y=0 -- 2D only + -- Projection of player pos on x component. + local x=UTILS.VecDot(X, C) - -- Plane coordinate. - local P=unit:GetCoordinate() - P.y=0 -- 2D only + -- Orientation of carrier. + local Z=self.carrier:GetOrientationZ() - -- Vector from Plane to Stern V=S-P - local V=UTILS.VecSubstract(S, P) + -- Rotate orientation to angled runway. + if runway then + Z=UTILS.Rotate2D(Z, -self.carrierparam.rwyangle) + end - -- Angle between carrier orientation and - local alpha=UTILS.VecAngle(X,V) + -- Projection of player pos on z component. + local z=UTILS.VecDot(Z, C) - env.info("FF lineup = "..lineup) + --- - return lineup + -- Position of the aircraft in the new coordinate system. + local a={x=x, y=0, z=z} + + -- Stern position in the new coordinate system, which is simply the origin. + local b={x=0, y=0, z=0} + + -- Vector from plane to ref point on the boat. + local c=UTILS.VecSubstract(a, b) + + -- Current line up and error wrt to final heading of the runway. + local lineup=math.deg(math.atan2(c.z, c.x)) + + --env.info(string.format("FF lineup 2 = %.1f", lineup)) + + return lineup end --- Get true (or magnetic) heading of carrier. @@ -7228,14 +7221,19 @@ function AIRBOSS:_Debrief(playerData) -- LSO grade: (OK) 3.0 PT - LURIM local text=string.format("%s %.1f PT - %s", grade, points, analysis) - -- Wire trapped. Not if pattern WI. - if playerData.wire and not playerData.patternwo then - text=text..string.format(" %d-wire", playerData.wire) - end + -- Wire and Groove time only if not pattern WO. + if not playerData.patternwo then - -- Time in the groove. Only Case I/II and not pattern WO. - if playerData.Tgroove and playerData.case<3 and not playerData.patternwo then - text=text..string.format("\nYour detailed debriefing can be found via the F10 radio menu.") + -- Wire trapped. Not if pattern WI. + if playerData.wire then + text=text..string.format(" %d-wire", playerData.wire) + end + + -- Time in the groove. Only Case I/II and not pattern WO. + if playerData.Tgroove and playerData.Tgroovey<=60 and playerData.case<3 then + text=text..string.format("\nTime in the groove %d seconds.", playerData.Tgroove) + end + end -- Info text. @@ -7250,6 +7248,7 @@ function AIRBOSS:_Debrief(playerData) -- Set step to undefined and check. playerData.step=AIRBOSS.PatternStep.UNDEFINED + -- Check what happened? if playerData.patternwo then diff --git a/Moose Development/Moose/Ops/RecoveryTanker.lua b/Moose Development/Moose/Ops/RecoveryTanker.lua index 93d171680..929db1163 100644 --- a/Moose Development/Moose/Ops/RecoveryTanker.lua +++ b/Moose Development/Moose/Ops/RecoveryTanker.lua @@ -701,7 +701,7 @@ function RECOVERYTANKER:onafterStart(From, Event, To) local dist=-self.distStern+UTILS.NMToMeters(4) -- Coordinate behind the carrier and slightly port. - local Carrier=self.carrier:GetCoordinate():SetAltitude(self.altitude):Translate(dist, hdg+190) + local Carrier=self.carrier:GetCoordinate():Translate(dist, hdg+190):SetAltitude(self.altitude) -- Orientation of spawned group. Spawn:InitHeading(hdg+10) @@ -853,11 +853,11 @@ function RECOVERYTANKER:onafterPatternUpdate(From, Event, To) local Carrier=self.carrier:GetCoordinate() -- Define race-track pattern. - local p0=self.tanker:GetCoordinate():Translate(UTILS.NMToMeters(1), self.tanker:GetHeading()) + local p0=self.tanker:GetCoordinate():Translate(UTILS.NMToMeters(1), self.tanker:GetHeading(), true) -- Racetrack pattern points. - local p1=Carrier:SetAltitude(self.altitude):Translate(self.distStern, hdg) - local p2=Carrier:SetAltitude(self.altitude):Translate(self.distBow, hdg) + local p1=Carrier:Translate(self.distStern, hdg):SetAltitude(self.altitude) + local p2=Carrier:Translate(self.distBow, hdg):SetAltitude(self.altitude) -- Set orbit task. local taskorbit=self.tanker:TaskOrbit(p1, self.altitude, self.speed, p2) diff --git a/Moose Development/Moose/Ops/RescueHelo.lua b/Moose Development/Moose/Ops/RescueHelo.lua index 2d229a1ef..dca4caab2 100644 --- a/Moose Development/Moose/Ops/RescueHelo.lua +++ b/Moose Development/Moose/Ops/RescueHelo.lua @@ -782,7 +782,7 @@ function RESCUEHELO:onafterStart(From, Event, To) local dist=UTILS.NMToMeters(0.2) -- Coordinate behind the carrier. Altitude at least 100 meters for spawning because it drops down a bit. - local Carrier=self.carrier:GetCoordinate():SetAltitude(math.max(140, self.altitude)):Translate(dist, hdg) + local Carrier=self.carrier:GetCoordinate():Translate(dist, hdg):SetAltitude(math.max(140, self.altitude)) -- Orientation of spawned group. Spawn:InitHeading(hdg) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 879680676..ca20c1b7f 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -733,6 +733,28 @@ function UTILS.VecAngle(a, b) return math.deg(alpha) end +--- Rotate 3D vector in the 2D (x,z) plane. y-component (usually altitude) unchanged. +-- @param DCS#Vec3 a Vector in 3D with x, y, z components. +-- @param #number angle Rotation angle in degrees. +-- @return DCS#Vec3 Vector rotated in the (x,z) plane. +function UTILS.Rotate2D(a, angle) + + local phi=math.rad(angle) + + local x=a.z + local y=a.x + + local Z=x*math.cos(phi)-y*math.sin(phi) + local X=x*math.sin(phi)+y*math.cos(phi) + local Y=a.y + + local A={x=X, y=Y, z=Z} + + return A +end + + + --- Converts a TACAN Channel/Mode couple into a frequency in Hz. -- @param #number TACANChannel The TACAN channel, i.e. the 10 in "10X". -- @param #string TACANMode The TACAN mode, i.e. the "X" in "10X".