mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
CT v0.0.3
This commit is contained in:
@@ -55,7 +55,7 @@ CARRIERTRAINER = {
|
|||||||
|
|
||||||
--- Carrier trainer class version.
|
--- Carrier trainer class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CARRIERTRAINER.version="0.0.2"
|
CARRIERTRAINER.version="0.0.3"
|
||||||
|
|
||||||
--- Player data table holding all important parameters for each player.
|
--- Player data table holding all important parameters for each player.
|
||||||
-- @type CARRIERTRAINER.PlayerData
|
-- @type CARRIERTRAINER.PlayerData
|
||||||
@@ -72,6 +72,7 @@ CARRIERTRAINER.version="0.0.2"
|
|||||||
-- @field #string summary Result summary text.
|
-- @field #string summary Result summary text.
|
||||||
-- @field Wrapper.Client#CLIENT Client object of player.
|
-- @field Wrapper.Client#CLIENT Client object of player.
|
||||||
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Constructor
|
-- Constructor
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -281,11 +282,6 @@ end
|
|||||||
-- @param #CARRIERTRAINER self
|
-- @param #CARRIERTRAINER self
|
||||||
function CARRIERTRAINER:_CheckPlayerStatus()
|
function CARRIERTRAINER:_CheckPlayerStatus()
|
||||||
|
|
||||||
if self.players==nil then
|
|
||||||
self:I(self.lid.."No players yet.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Loop over all players.
|
-- Loop over all players.
|
||||||
for _playerName,_playerData in pairs(self.players) do
|
for _playerName,_playerData in pairs(self.players) do
|
||||||
local playerData = _playerData --#CARRIERTRAINER.PlayerData
|
local playerData = _playerData --#CARRIERTRAINER.PlayerData
|
||||||
@@ -303,11 +299,6 @@ function CARRIERTRAINER:_CheckPlayerStatus()
|
|||||||
self:_DetailedPlayerStatus(playerData)
|
self:_DetailedPlayerStatus(playerData)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check long down wind leg.
|
|
||||||
if playerData.step == 6 and not playerData.longDownwindDone and unit:IsInZone(self.giantZone) then
|
|
||||||
self:_CheckForLongDownwind(playerData)
|
|
||||||
end
|
|
||||||
|
|
||||||
if playerData.step==0 and unit:IsInZone(self.giantZone) and unit:InAir() then
|
if playerData.step==0 and unit:IsInZone(self.giantZone) and unit:InAir() then
|
||||||
self:_NewRound(playerData)
|
self:_NewRound(playerData)
|
||||||
elseif playerData.step == 1 and unit:IsInZone(self.startZone) then
|
elseif playerData.step == 1 and unit:IsInZone(self.startZone) then
|
||||||
@@ -321,6 +312,10 @@ function CARRIERTRAINER:_CheckPlayerStatus()
|
|||||||
elseif playerData.step == 5 and unit:IsInZone(self.giantZone) then
|
elseif playerData.step == 5 and unit:IsInZone(self.giantZone) then
|
||||||
self:_Abeam(playerData)
|
self:_Abeam(playerData)
|
||||||
elseif playerData.step == 6 and unit:IsInZone(self.giantZone) then
|
elseif playerData.step == 6 and unit:IsInZone(self.giantZone) then
|
||||||
|
-- Check long down wind leg.
|
||||||
|
if not playerData.longDownwindDone then
|
||||||
|
self:_CheckForLongDownwind(playerData)
|
||||||
|
end
|
||||||
self:_Ninety(playerData)
|
self:_Ninety(playerData)
|
||||||
elseif playerData.step == 7 and unit:IsInZone(self.giantZone) then
|
elseif playerData.step == 7 and unit:IsInZone(self.giantZone) then
|
||||||
self:_Wake(playerData)
|
self:_Wake(playerData)
|
||||||
@@ -337,6 +332,37 @@ function CARRIERTRAINER:_CheckPlayerStatus()
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get name of the current pattern step.
|
||||||
|
-- @param #CARRIERTRAINER self
|
||||||
|
-- @param #number step Step
|
||||||
|
-- @return #string Name of the step
|
||||||
|
function CARRIERTRAINER:_StepName(step)
|
||||||
|
|
||||||
|
local name="unknown"
|
||||||
|
if step==0 then
|
||||||
|
name="Unregistered"
|
||||||
|
elseif step==1 then
|
||||||
|
name="entering pattern"
|
||||||
|
elseif step==2 then
|
||||||
|
name="on upwind leg"
|
||||||
|
elseif step==3 then
|
||||||
|
name="early break"
|
||||||
|
elseif step==4 then
|
||||||
|
name="late break"
|
||||||
|
elseif step==5 then
|
||||||
|
name="abeam"
|
||||||
|
elseif step==6 then
|
||||||
|
name="at the wake"
|
||||||
|
elseif step==7 then
|
||||||
|
name="at the ninety"
|
||||||
|
elseif step==8 then
|
||||||
|
name="in the groove"
|
||||||
|
elseif step==9 then
|
||||||
|
name="trapped"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Provide info about player status on the fly.
|
--- Provide info about player status on the fly.
|
||||||
-- @param #CARRIERTRAINER self
|
-- @param #CARRIERTRAINER self
|
||||||
-- @param #CARRIERTRAINER.PlayerData playerData Player data.
|
-- @param #CARRIERTRAINER.PlayerData playerData Player data.
|
||||||
@@ -345,12 +371,11 @@ function CARRIERTRAINER:_DetailedPlayerStatus(playerData)
|
|||||||
local unit=playerData.unit
|
local unit=playerData.unit
|
||||||
|
|
||||||
local aoa=unit:GetAoA()
|
local aoa=unit:GetAoA()
|
||||||
|
local yaw=unit:GetYaw()
|
||||||
|
local roll=unit:GetRoll()
|
||||||
|
local pitch=unit:GetPitch()
|
||||||
local dist=playerData.unit:GetCoordinate():Get2DDistance(self.carrier:GetCoordinate())
|
local dist=playerData.unit:GetCoordinate():Get2DDistance(self.carrier:GetCoordinate())
|
||||||
local dz,dx=self:_GetDistances(unit)
|
local dx,dz=self:_GetDistances(unit)
|
||||||
|
|
||||||
local text=string.format("%s, current AoA=%.1f\n", playerData.callsign, aoa)
|
|
||||||
text=text..string.format("Carrier distance: d=%d m\n", dist)
|
|
||||||
text=text..string.format("Carrier distance: z=%d m x=%d m sum=%d", dz, dx, math.abs(dz)+math.abs(dx))
|
|
||||||
|
|
||||||
-- Player and carrier position vector.
|
-- Player and carrier position vector.
|
||||||
local playerPosition = playerData.unit:GetVec3()
|
local playerPosition = playerData.unit:GetVec3()
|
||||||
@@ -358,11 +383,17 @@ function CARRIERTRAINER:_DetailedPlayerStatus(playerData)
|
|||||||
|
|
||||||
local diffZ = playerPosition.z - carrierPosition.z
|
local diffZ = playerPosition.z - carrierPosition.z
|
||||||
local diffX = playerPosition.x - carrierPosition.x
|
local diffX = playerPosition.x - carrierPosition.x
|
||||||
|
|
||||||
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
|
||||||
diffZ, diffX = self:_GetDistances(playerData.unit)
|
|
||||||
|
|
||||||
MESSAGE:New(text, 5, nil ,true):ToClient(playerData.client)
|
local heading=unit:GetCoordinate():HeadingTo(self.startZone:GetCoordinate())
|
||||||
|
|
||||||
|
local text=string.format("%s, current AoA=%.1f\n", playerData.callsign, aoa)
|
||||||
|
text=text..string.format("roll=%.1f yaw=%.1f pitch=%.1f\n", roll, yaw, pitch)
|
||||||
|
text=text..string.format("current step = %d %s\n", playerData.step, self:_StepName(playerData.step))
|
||||||
|
text=text..string.format("Carrier distance: d=%d m\n", dist)
|
||||||
|
text=text..string.format("Carrier distance: x=%d m z=%d m sum=%d (old)", diffX, diffZ, math.abs(diffX)+math.abs(diffZ))
|
||||||
|
text=text..string.format("Carrier distance: x=%d m z=%d m sum=%d (new)", dx, dz, math.abs(dz)+math.abs(dx))
|
||||||
|
|
||||||
|
MESSAGE:New(text, 1, nil ,true):ToClient(playerData.client)
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -386,7 +417,7 @@ end
|
|||||||
-- @param #CARRIERTRAINER self
|
-- @param #CARRIERTRAINER self
|
||||||
-- @param #CARRIERTRAINER.PlayerData playerData Player data table.
|
-- @param #CARRIERTRAINER.PlayerData playerData Player data table.
|
||||||
function CARRIERTRAINER:_Start(playerData)
|
function CARRIERTRAINER:_Start(playerData)
|
||||||
local hint = "Entering the pattern, " .. playerData.callsign .. "! Aim for 800 feet and 350-400 kts on the upwind."
|
local hint = string.format("Entering the pattern, %s! Aim for 800 feet and 350-400 kts on the upwind.", playerData.callsign)
|
||||||
self:_SendMessageToPlayer(hint, 8, playerData)
|
self:_SendMessageToPlayer(hint, 8, playerData)
|
||||||
playerData.score = 0
|
playerData.score = 0
|
||||||
playerData.step = 2
|
playerData.step = 2
|
||||||
@@ -405,52 +436,56 @@ function CARRIERTRAINER:_Upwind(playerData)
|
|||||||
local diffX = position.x - carrierPosition.x
|
local diffX = position.x - carrierPosition.x
|
||||||
|
|
||||||
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
||||||
diffZ, diffX = self:_GetDistances(playerData.unit)
|
diffX, diffZ = self:_GetDistances(playerData.unit)
|
||||||
|
|
||||||
if(diffZ > 500 or diffZ < 0 or diffX < -4000) then
|
-- Too far away.
|
||||||
|
-- Should be between 0-500 meters right of carrier.
|
||||||
|
-- TODO Should be withing 4 km behind carrier. Why?
|
||||||
|
if (diffZ > 500 or diffZ < 0 or diffX < -4000) then
|
||||||
self:_AbortPattern(playerData)
|
self:_AbortPattern(playerData)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if (diffX < 0) then
|
-- Now before the boat.
|
||||||
return
|
if diffX > 0 then
|
||||||
end
|
|
||||||
|
|
||||||
local idealAltitude = 800
|
local idealAltitude = 800
|
||||||
local altitude = UTILS.Round( UTILS.MetersToFeet( position.y ) )
|
local altitude = UTILS.MetersToFeet(position.y)
|
||||||
|
|
||||||
local hint = ""
|
|
||||||
local score = 0
|
|
||||||
|
|
||||||
if (altitude > 850) then
|
|
||||||
score = 5
|
|
||||||
hint = "You're high on the upwind."
|
|
||||||
elseif (altitude > 830) then
|
|
||||||
score = 7
|
|
||||||
hint = "You're slightly high on the upwind."
|
|
||||||
elseif (altitude < 750) then
|
|
||||||
score = 5
|
|
||||||
hint = "You're low on the upwind."
|
|
||||||
elseif (altitude < 770) then
|
|
||||||
score = 7
|
|
||||||
hint = "You're slightly low on the upwind."
|
|
||||||
else
|
|
||||||
score = 10
|
|
||||||
hint = "Good altitude on the upwind."
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Increase score.
|
|
||||||
self:_IncreaseScore(playerData, score)
|
|
||||||
|
|
||||||
self:_SendMessageToPlayer(hint, 8, playerData)
|
|
||||||
|
|
||||||
self:_PrintAltitudeFeedback(altitude, idealAltitude, playerData)
|
|
||||||
self:_PrintScore(score, playerData, true)
|
|
||||||
|
|
||||||
self:_AddToSummary(playerData, hint)
|
local hint = ""
|
||||||
|
local score = 0
|
||||||
-- Set step.
|
|
||||||
playerData.step = 3
|
if (altitude > 850) then
|
||||||
|
score = 5
|
||||||
|
hint = "You're high on the upwind."
|
||||||
|
elseif (altitude > 830) then
|
||||||
|
score = 7
|
||||||
|
hint = "You're slightly high on the upwind."
|
||||||
|
elseif (altitude < 750) then
|
||||||
|
score = 5
|
||||||
|
hint = "You're low on the upwind."
|
||||||
|
elseif (altitude < 770) then
|
||||||
|
score = 7
|
||||||
|
hint = "You're slightly low on the upwind."
|
||||||
|
else
|
||||||
|
score = 10
|
||||||
|
hint = "Good altitude on the upwind."
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Increase score.
|
||||||
|
self:_IncreaseScore(playerData, score)
|
||||||
|
|
||||||
|
self:_SendMessageToPlayer(hint, 8, playerData)
|
||||||
|
|
||||||
|
self:_PrintAltitudeFeedback(altitude, idealAltitude, playerData)
|
||||||
|
self:_PrintScore(score, playerData, true)
|
||||||
|
|
||||||
|
self:_AddToSummary(playerData, hint)
|
||||||
|
|
||||||
|
-- Set step.
|
||||||
|
playerData.step = 3
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Calculate distances between carrier and player unit.
|
--- Calculate distances between carrier and player unit.
|
||||||
@@ -482,20 +517,31 @@ function CARRIERTRAINER:_Break(playerData, part)
|
|||||||
local diffX = playerPosition.x - carrierPosition.x
|
local diffX = playerPosition.x - carrierPosition.x
|
||||||
|
|
||||||
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
||||||
diffZ, diffX = self:_GetDistances(playerData.unit)
|
diffX, diffZ = self:_GetDistances(playerData.unit)
|
||||||
|
|
||||||
if(diffZ > 1500 or diffZ < -3700 or diffX < -500) then
|
-- Abort when
|
||||||
|
-- > 1.5 km right of carrier
|
||||||
|
-- > 3.7 km left of carrier
|
||||||
|
-- > 0.5 km behind carrier
|
||||||
|
if (diffZ > 1500 or diffZ < -3700 or diffX < -500) then
|
||||||
self:_AbortPattern(playerData)
|
self:_AbortPattern(playerData)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Break
|
||||||
|
-- z= -370
|
||||||
|
-- y= 800
|
||||||
|
-- x> -500
|
||||||
|
|
||||||
local limit = -370
|
local limit = -370 --0.2 NM
|
||||||
|
|
||||||
if part == "late" then
|
if part == "late" then
|
||||||
limit = -1470
|
limit = -1470 -- 0.8 NM
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--
|
||||||
if diffZ < limit then
|
if diffZ < limit then
|
||||||
|
|
||||||
local idealAltitude = 800
|
local idealAltitude = 800
|
||||||
local altitude = UTILS.Round( UTILS.MetersToFeet( playerPosition.y ) )
|
local altitude = UTILS.Round( UTILS.MetersToFeet( playerPosition.y ) )
|
||||||
|
|
||||||
@@ -546,17 +592,27 @@ function CARRIERTRAINER:_Abeam(playerData)
|
|||||||
local diffX = playerPosition.x - carrierPosition.x
|
local diffX = playerPosition.x - carrierPosition.x
|
||||||
|
|
||||||
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
||||||
diffZ, diffX = self:_GetDistances(playerData.unit)
|
diffX, diffZ = self:_GetDistances(playerData.unit)
|
||||||
|
|
||||||
|
-- Abort if
|
||||||
|
-- less than 1.0 km left of boat (no closer than 1 km to boat
|
||||||
|
-- more than 3.7 km left of boat
|
||||||
if (diffZ > -1000 or diffZ < -3700) then
|
if (diffZ > -1000 or diffZ < -3700) then
|
||||||
self:_AbortPattern(playerData)
|
self:_AbortPattern(playerData)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Abeam pos:
|
||||||
|
-- x= -200
|
||||||
|
-- z=-2160
|
||||||
|
-- y= 600
|
||||||
|
|
||||||
|
-- Abeam pos 200 meters behind ship
|
||||||
local limit = -200
|
local limit = -200
|
||||||
|
|
||||||
if diffX < limit then
|
if diffX < limit then
|
||||||
--local aoa = math.deg(mist.getAoA(playerData.mistUnit))
|
|
||||||
|
-- Get AoA.
|
||||||
local aoa = playerData.unit:GetAoA()
|
local aoa = playerData.unit:GetAoA()
|
||||||
local aoaFeedback = self:_PrintAoAFeedback(aoa, 8.1, playerData)
|
local aoaFeedback = self:_PrintAoAFeedback(aoa, 8.1, playerData)
|
||||||
|
|
||||||
@@ -594,7 +650,7 @@ function CARRIERTRAINER:_Abeam(playerData)
|
|||||||
|
|
||||||
local roundedNm = UTILS.Round(nm, 2)
|
local roundedNm = UTILS.Round(nm, 2)
|
||||||
|
|
||||||
if(nm < 1.0) then
|
if (nm < 1.0) then
|
||||||
distanceScore = 0
|
distanceScore = 0
|
||||||
distanceHint = "too close to the boat (" .. roundedNm .. " nm)"
|
distanceHint = "too close to the boat (" .. roundedNm .. " nm)"
|
||||||
elseif(nm < 1.1) then
|
elseif(nm < 1.1) then
|
||||||
@@ -628,21 +684,23 @@ end
|
|||||||
-- @param #CARRIERTRAINER self
|
-- @param #CARRIERTRAINER self
|
||||||
-- @param #CARRIERTRAINER.PlayerData playerData Player data table.
|
-- @param #CARRIERTRAINER.PlayerData playerData Player data table.
|
||||||
function CARRIERTRAINER:_CheckForLongDownwind(playerData)
|
function CARRIERTRAINER:_CheckForLongDownwind(playerData)
|
||||||
|
|
||||||
local playerPosition = playerData.unit:GetVec3()
|
local playerPosition = playerData.unit:GetVec3()
|
||||||
local carrierPosition = self.carrier:GetVec3()
|
local carrierPosition = self.carrier:GetVec3()
|
||||||
|
|
||||||
local limit = 1500
|
local limit = -1500
|
||||||
|
|
||||||
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
||||||
local diffZ, diffX = self:_GetDistances(playerData.unit)
|
local diffX, diffZ = self:_GetDistances(playerData.unit)
|
||||||
|
|
||||||
--TODO if diffX
|
--if carrierPosition.x - playerPosition.x > limit then
|
||||||
|
if diffX > limit then
|
||||||
|
|
||||||
if carrierPosition.x - playerPosition.x > limit then
|
local headingPlayer = playerData.unit:GetHeading()
|
||||||
|
local headingCarrier = self.carrier:GetHeading()
|
||||||
local heading = playerData.unit:GetHeading()
|
--TODO: Take carrier heading != 0 into account!
|
||||||
|
if (headingPlayer > 170) then
|
||||||
|
|
||||||
if (heading > 170) then
|
|
||||||
local hint = "Too long downwind. Turn final earlier next time."
|
local hint = "Too long downwind. Turn final earlier next time."
|
||||||
self:_SendMessageToPlayer( hint, 8, playerData )
|
self:_SendMessageToPlayer( hint, 8, playerData )
|
||||||
local score = -40
|
local score = -40
|
||||||
@@ -651,6 +709,7 @@ function CARRIERTRAINER:_CheckForLongDownwind(playerData)
|
|||||||
self:_AddToSummary(playerData, hint)
|
self:_AddToSummary(playerData, hint)
|
||||||
playerData.longDownwindDone = true
|
playerData.longDownwindDone = true
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -665,7 +724,7 @@ function CARRIERTRAINER:_Ninety(playerData)
|
|||||||
local diffX = playerPosition.x - carrierPosition.x
|
local diffX = playerPosition.x - carrierPosition.x
|
||||||
|
|
||||||
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
||||||
diffZ, diffX = self:_GetDistances(playerData.unit)
|
diffX, diffZ = self:_GetDistances(playerData.unit)
|
||||||
|
|
||||||
if(diffZ < -3700 or diffX < -3700 or diffX > 0) then
|
if(diffZ < -3700 or diffX < -3700 or diffX > 0) then
|
||||||
self:_AbortPattern(playerData)
|
self:_AbortPattern(playerData)
|
||||||
@@ -728,7 +787,7 @@ function CARRIERTRAINER:_Wake(playerData)
|
|||||||
local diffX = playerPosition.x - carrierPosition.x
|
local diffX = playerPosition.x - carrierPosition.x
|
||||||
|
|
||||||
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
||||||
diffZ, diffX = self:_GetDistances(playerData.unit)
|
diffX, diffZ = self:_GetDistances(playerData.unit)
|
||||||
|
|
||||||
if(diffZ < -2000 or diffX < -4000 or diffX > 0) then
|
if(diffZ < -2000 or diffX < -4000 or diffX > 0) then
|
||||||
self:_AbortPattern(playerData)
|
self:_AbortPattern(playerData)
|
||||||
@@ -788,20 +847,25 @@ function CARRIERTRAINER:_Groove(playerData)
|
|||||||
|
|
||||||
--TODO -100?!
|
--TODO -100?!
|
||||||
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
|
||||||
diffZ, diffX = self:_GetDistances(playerData.unit)
|
diffX, diffZ = self:_GetDistances(playerData.unit)
|
||||||
|
|
||||||
if(diffX > 0 or diffX < -4000) then
|
diffX=diffX+100
|
||||||
|
|
||||||
|
-- In front of carrier or more than 4 km behind carrier.
|
||||||
|
if (diffX > 0 or diffX < -4000) then
|
||||||
self:_AbortPattern(playerData)
|
self:_AbortPattern(playerData)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if(diffX > -500) then --Reached in close before groove
|
--TODO:
|
||||||
|
if (diffX > -500) then --Reached in close before groove
|
||||||
local hint = "You're too far left and never reached the groove."
|
local hint = "You're too far left and never reached the groove."
|
||||||
self:_SendMessageToPlayer( hint, 8, playerData )
|
self:_SendMessageToPlayer( hint, 8, playerData )
|
||||||
self:_PrintScore(0, playerData, true)
|
self:_PrintScore(0, playerData, true)
|
||||||
self:_AddToSummary(playerData, hint)
|
self:_AddToSummary(playerData, hint)
|
||||||
playerData.step = 9
|
playerData.step = 9
|
||||||
else
|
else
|
||||||
|
|
||||||
local limitDeg = 8.0
|
local limitDeg = 8.0
|
||||||
|
|
||||||
local fraction = diffZ / (-diffX)
|
local fraction = diffZ / (-diffX)
|
||||||
@@ -958,7 +1022,8 @@ end
|
|||||||
-- @param #number idealAltitude Ideal altitude.
|
-- @param #number idealAltitude Ideal altitude.
|
||||||
-- @param #CARRIERTRAINER.PlayerData playerData Player data.
|
-- @param #CARRIERTRAINER.PlayerData playerData Player data.
|
||||||
function CARRIERTRAINER:_PrintAltitudeFeedback(altitude, idealAltitude, playerData)
|
function CARRIERTRAINER:_PrintAltitudeFeedback(altitude, idealAltitude, playerData)
|
||||||
self:_SendMessageToPlayer( "Alt: " .. altitude .. " (Target: " .. idealAltitude .. ")", 8, playerData )
|
local text=string.format("Alt: %d feet (Target: %d feet)", altitude, idealAltitude)
|
||||||
|
self:_SendMessageToPlayer(text, 8, playerData)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Score for correct AoA.
|
--- Score for correct AoA.
|
||||||
|
|||||||
@@ -696,6 +696,105 @@ function POSITIONABLE:GetAoA()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the unit's climb or descent angle.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return #number Climb or descent angle in degrees.
|
||||||
|
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
|
||||||
|
|
||||||
|
return math.asin(unitvel.y/UTILS.VecNorm(unitvel))
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the pitch angle of a unit.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return #number Pitch ange in degrees.
|
||||||
|
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
|
||||||
|
|
||||||
|
--- Returns the roll angle of a unit.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return #number Pitch ange in degrees.
|
||||||
|
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
|
||||||
|
local cp = UTILS.VecCross(unitpos.x, {x = 0, y = 1, z = 0})
|
||||||
|
|
||||||
|
--now, get dot product of of this cross product with unitpos.z
|
||||||
|
local dp = UTILS.VecDot(cp, unitpos.z)
|
||||||
|
|
||||||
|
--now get the magnitude of the roll (magnitude of the angle between two vectors is acos(vec1.vec2/|vec1||vec2|)
|
||||||
|
local Roll = math.acos(dp/(UTILS.VecNorm(cp)*UTILS.VecNorm(unitpos.z)))
|
||||||
|
|
||||||
|
--now, have to get sign of roll.
|
||||||
|
-- by convention, making right roll positive
|
||||||
|
-- to get sign of roll, use the y component of unitpos.z. For right roll, y component is negative.
|
||||||
|
|
||||||
|
if unitpos.z.y > 0 then -- left roll, flip the sign of the roll
|
||||||
|
Roll = -Roll
|
||||||
|
end
|
||||||
|
|
||||||
|
return math.deg(Roll)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the yaw angle of a unit.
|
||||||
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
|
-- @return #number Yaw ange in degrees.
|
||||||
|
function POSITIONABLE:GetYaw()
|
||||||
|
|
||||||
|
local unitpos = self:GetPosition()
|
||||||
|
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
|
||||||
|
end
|
||||||
|
return Yaw
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns the message text with the callsign embedded (if there is one).
|
--- Returns the message text with the callsign embedded (if there is one).
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
|
|||||||
Reference in New Issue
Block a user