# Flight model: ApplyAerodynamics (Part 3 of 3)

```       Name: ApplyAerodynamics (Part 3 of 3)                         [Show more]
Type: Subroutine
Category: Flight model
Summary: Calculate various aerodynamic figures
Deep dive: The flight model
Context: See this subroutine in context in the source code
References: No direct references to this subroutine in this source file

This part calculates the following:

[ xMoments ] = [ yVelocityP * 2 - xTurn * 250 / 256 ]
[ yMoments ] = [ xVelocityP * 2 - yTurn * 250 / 256 ] * maxv * airDensity
[ zMoments ] = [            -zTurn * 2              ]

[ xLiftDrag ] = [ xVelocityP * 2 * 4 ]
[ yLiftDrag ] = [ yVelocityP * 2 * 4 ] * maxv * airDensity
[ zLiftDrag ] = [ zVelocityP * 2     ]

zSlipMoment = xLiftDrag

where:

airDensity = ~yPlaneHi * 2

maxv = max(|xVelocityP|, |yVelocityP|, |zVelocityP|)

If zLiftDrag is positive we also do:

yFlapsLift = zLiftDrag

xMoments = xMoments + (zLiftDrag * 8)       when the flaps are off

xMoments - (zLiftDrag * 4)       when the flaps are on

JSR GetMoments         \ Set the following:
\
\   xTemp3 = yLiftDrag - (xTurn * 250 / 256)
\          = yVelocityP * 2 - (xTurn * 250 / 256)
\
\   yTemp3 = xLiftDrag - (yTurn * 250 / 256)
\          = xVelocityP * 2 - (yTurn * 250 / 256)
\
\   zTemp3 = -zTurn * 2

\ A reminder that we set the following in part 1:
\
\   (SS RR) = max(|velocityP|) * 2 * ~yPlaneHi / 256

LDA RR                 \ Set (S R) = (SS RR) with bit 0 of the low byte cleared
AND #%11111110         \ to convert this into a value with the sign in bit 0
STA R                  \ and the value as follows (we drop the "* 2" as bit 0
LDA SS                 \ is now the sign bit):
STA S                  \
\   (S R) = max(|velocityP|) * ~yPlaneHi / 256

LDX #5                 \ Set X as a loop counter from 5 down to 0

LDA #0                 \ Change the rounding in Multiply16x16Mix so that it
STA mult1+1            \ rounds down, i.e. uses floor to round

.aero12

CPX #3                 \ If X >= 3, jump to aero13 to skip the following
BCS aero13

\ For X = 0 to 2, we now fetch the relevant axis of
\ xTemp3, which we set above to:
\
\   xTemp3 = yVelocityP * 2 - (xTurn * 250 / 256)
\
\   yTemp3 = xVelocityP * 2 - (yTurn * 250 / 256)
\
\   zTemp3 = -zTurn * 2

LDY xTemp3Lo,X         \ Set (A Y) = xTemp3 (or yTemp3 or zTemp3)
LDA xTemp3Hi,X

.aero13

\ For X = 3 to 5, we now fetch the relevant axis of
\ xLiftDrag, which we set in part 1 to:
\
\   xLiftDrag = xVelocityP * 2
\
\   yLiftDrag = yVelocityP * 2
\
\   zLiftDrag = zVelocityP * 2

LDY xMomentsLo,X       \ Set (A Y) = xLiftDrag (or yLiftDrag or zLiftDrag)
LDA xMomentsHi,X

.aero14

STA J                  \ Set (J I) = (A Y)
STY I                  \
\           = xTemp3                for X = 0 to 2
\
\             xVelocityP * 2        for X = 3 to 5

LDA #0                 \ Set K = 0, so Multiply16x16Mix doesn't negate the
STA K                  \ result, and returns the sign of the result in K

STX VV                 \ Store the loop counter in VV, so we can retrieve it
\ below

JSR Multiply16x16Mix   \ Call Multiply16x16Mix to calculate:
\
\   (H G W) = (J I) * (S R) / 256
\
\        = xTemp3         * max(|velocityP|) * ~yPlaneHi
\
\          xVelocityP * 2 * max(|velocityP|) * ~yPlaneHi

LDA K                  \ If the result of the multiplication is positive, jump
BPL aero15             \ to aero15 to skip the following

SEC                    \ The result of the multiplication is negative, so now
LDA #0                 \ we negate (H G W), starting with the low bytes
SBC W
STA W

LDA G                  \ Then the middle bytes
SBC #0
STA G

BCS aero15             \ And finally the high bytes
DEC H

.aero15

LDX VV                 \ Retrieve the value of the loop counter X that we
\ stored in VV above

LDY #0                 \ Set Y = 0 to act as a shift counter in the loop below,
\ so by default it shifts the result left by 1 place

LDA G                  \ Set (H A W) = (H G W)

BCC aero16

BEQ aero16

INY                    \ If we get here then X = 3 or 4, so increment Y to 2 so
INY                    \ the following loop shifts (H A W) left by 3 places

\ We now shift (H A W) left by Y + 1 places

.aero16

ASL W                  \ Set (H A W) = (H A W) << 1
ROL A
ROL H

DEY                    \ Decrement the shift counter

BPL aero16             \ Loop back until we have shifted left by Y + 1 places,
\ so that's the same as:
\
\   (H A W) = (H A W) * 8       if X = 3 or 4
\
\   (H A W) = (H A W) * 2       otherwise

STA xMomentsLo,X       \ Set xMoments or xLiftDrag = (H A)
LDA H
STA xMomentsHi,X

DEX                    \ Decrement the loop counter to move onto the next

BPL aero12             \ Loop back until we have set xMoments to zMoments and
\ xLiftDrag to zLiftDrag, so we now have:
\
\   xMoments = xTemp3 * maxv * ~yPlaneHi * 2
\            = (yVelocityP * 2 - (xTurn * 250 / 256))
\               * maxv * ~yPlaneHi * 2
\
\   yMoments = yTemp3 * maxv * ~yPlaneHi * 2
\            = (xVelocityP * 2 - (yTurn * 250 / 256))
\               * maxv * ~yPlaneHi * 2
\
\   zMoments = zTemp3 * maxv * ~yPlaneHi * 2
\            = -zTurn * 2 * maxv * ~yPlaneHi * 2
\
\   xLiftDrag = xVelocityP * 2 * maxv * ~yPlaneHi * 8
\
\   yLiftDrag = yVelocityP * 2 * maxv * ~yPlaneHi * 8
\
\   zLiftDrag = zVelocityP * 2 * maxv * ~yPlaneHi * 2
\
\ where:
\
\   maxv = max(|xVelocityP|, |yVelocityP|, |zVelocityP|)

LDA #128               \ Change the rounding in Multiply16x16Mix back to the
STA mult1+1            \ default, so it rounds to the nearest integer

LDA xLiftDragLo        \ Set zSlipMoment = xLiftDrag
STA zSlipMomentLo
LDA xLiftDragHi
STA zSlipMomentHi

LDA zLiftDragHi        \ If zLiftDrag is negative, jump to aero19 to return
BMI aero19             \ from the subroutine

\ If zLiftDrag is positive, then we now move on to set
\ yFlapsLift and xMoments

STA W                  \ Set the following:
STA yFlapsLiftHi       \
LDA #0                 \   (G W A) = (0 zLiftDragHi zLiftDragLo)
STA G                  \           = zLiftDrag
LDA zLiftDragLo        \
STA yFlapsLiftLo       \   yFlapsLift = zLiftDrag

LDX #2                 \ Set X = 2 to act as a shift counter in the loop below,
\ so by default it shifts the result left by 3 places

LDA flapsStatus        \ Set A to the current flap status (0 if flaps are off,
\ 1 if they are on)

PHP                    \ Store the flags on the stack, so we can check the flap
\ status later on

BEQ aero17             \ If the flaps are off, skip the following instruction

LDX #1                 \ Set X = 1 so the following loop shifts (G W A) left by
\ 2 places

\ We now shift (G W A) left by X + 1 places, so that's:
\
\   (G W A) = zLiftDrag << 3 if the flaps are off
\
\   (G W A) = zLiftDrag << 2 if the flaps are on

.aero17

ASL A                  \ Set (G W A) = (G W A) << 1
ROL W
ROL G

DEX                    \ Decrement the shift counter

BPL aero17             \ Loop back until we have shifted left by X + 1 places

PLP                    \ Restore the processor flags, so this jumps to aero18
BEQ aero18             \ if flapsStatus is zero, i.e. the flaps are off

SEC                    \ The flaps are on, so negate (G W)
JSR Negate16Bit

.aero18

\ We now have the following:
\
\   (G W A) = zLiftDrag << 3 if the flaps are off
\
\   (G W A) = -zLiftDrag << 2 if the flaps are on

CLC                    \ Set xMoments = xMoments + (G W)
LDA W                  \
ADC xMomentsLo         \ starting with the low bytes
STA xMomentsLo

LDA G                  \ And then the high bytes
STA xMomentsHi

\ So if zLiftDrag is negative, we now have the
\ following:
\
\   xMoments = xMoments + zLiftDrag << 3  when the flaps
\            = xMoments + (zLiftDrag * 8)        are off
\
\   xMoments = xMoments - zLiftDrag << 2  when the flaps
\            = xMoments - (zLiftDrag * 4)         are on

.aero19

RTS                    \ Return from the subroutine
```