Aviator on the BBC Micro

# Flight model: ScaleFlightForces

```       Name: ScaleFlightForces                                       [Show more]
Type: Subroutine
Category: Flight model
Summary: Scale the flight forces by the relevant scale factors
Deep dive: The flight model
Ripping the wings off
Context: See this subroutine in context in the source code
References: This subroutine is called as follows:
* ApplyFlightModel (Part 2 of 7) calls ScaleFlightForces

For each of the 11 flight forces, this routine calculates the following:

scaledForce = unscaledForce * forceFactor * 2 ^ scaleFactor

The 11 flight forces are:

* (xMoments, yMoments, zMoments)
* (xLiftDrag, yLiftDrag, zLiftDrag)
* zSlipMoment
* yFlapsLift
* (xControls, yControls, zControls)

The scaled results are stored in xMomentsSc, xLiftDragSc and so on.

This routine also tests for high g-forces, which occur if:

|yLiftDrag| >= 2048 / 39  = 53      if we are stalling
2048 / 156 = 13      if we are not stalling

.ScaleFlightForces

LDX #12                \ We are about to work our way through the flight
\ forces, so set a counter in X to act as an index into
\ these three tables:
\
\   * The unscaled forces from xMoments to zControls
\
\   * The forceFactor table
\
\   * The scaleFactor table
\
\   * The scaled forces from xMomentsSc to zControlsSc
\
\ These three tables have the same structure, so we can
\ iterate through all of them using an index in X that
\ goes from 12 to 0 while skipping over 8 and 9

.scal1

CPX #9                 \ If X <> 9, jump to scal2 to skip the following
BNE scal2              \ instruction

LDX #7                 \ If we get here then X = 9, so set X = 7 so we skip
\ indexes 8 and 9

.scal2

LDA forceFactor,X      \ Set R to the force factor for the X-th force
STA R

LDY xMomentsLo,X       \ Set (A Y) to the X-th unscaled force
LDA xMomentsHi,X

JSR Multiply8x16-6     \ Store X in VV and set (G W V) = (A Y) * R
\
\ Also set A to the high byte of the result in G, so we
\ have:
\
\   (A W V) = (A Y) * R
\
\ so:
\
\   (A W) = (A Y) * R / 256

LDX VV                 \ Retrieve X from VV so it once again contains the loop
\ index

CPX #4                 \ If X <> 4, skip the following section
BNE scal4

\ If we get here then X = 4, and the force factor for
\ yLiftDrag determines whether the plane is stalling
\ (156) or is in normal flight (39)

TAY                    \ If the high byte of (A Y) * R is positive, then jump
BPL scal3              \ to scal3 to skip the following instruction

EOR #&FF               \ Set A = ~A, so A now contains the high byte of the
\ 24-bit result, flipped, so it contains:
\
\   |A Y| * R / 256

.scal3

CMP #8                 \ If A < 8, jump to scal4 to skip the next three
BCC scal4              \ instructions

\ If we get here then A >= 8, so:
\
\   |A Y| * R / 256 >= 8
\
\   |A Y| * R >= 2048
\
\   |A Y| >= 2048 / 39  = 53 if we are stalling
\            2048 / 156 = 13 if we are not stalling
\
\ where |A Y| = |yLiftDrag|

LDA #3                 \ Make sound #3, a long, medium beep that indicates high
JSR MakeSound          \ g-forces are ripping the wings off

LDX #4                 \ Set X = 4 once again, as it will have been corrupted
\ by the call to MakeSound

.scal4

LDY scaleFactor,X      \ Set Y = the X-th entry in the scaleFactor table, which
\ contains the number of places to shift the result,
\ with a negative number meaning a right shift, a
\ positive number meaning a left shift, and a value of
\ zero having no effect
\
\ In other words, we multiply the result in (G W V) by
\ 2^scaleFactor, where scaleFactor is a signed integer

BEQ scal7              \ If the entry is zero, jump to scal7 to write the
\ result to the scaled force

BPL scal6              \ If the entry is positive, jump to scal6 to shift the
\ result to the left

\ If we get here then the entry is negative, so we shift
\ the result to the right

LDA #0                 \ Set R = 0 to use as the byte to feed into the top byte
STA R                  \ when right-shifting (G W V)

LDA G                  \ If the high byte in G is negative, decrement R to &FF
BPL scal5              \ so it feeds in bits of the correct sign
DEC R

.scal5

LSR R                  \ Shift (G W V) right by one place, shifting in bits
ROR G                  \ from R into G
ROR W
ROR V

INY                    \ Increment the shift counter

BNE scal5              \ Loop back until we have shifted right by -Y places

BEQ scal7              \ Jump to scal7 to write the result to the scaled force

.scal6

ASL V                  \ Shift (G W V) left by one place
ROL W
ROL G

DEY                    \ Increment the shift counter

BNE scal6              \ Loop back until we have shifted left by Y places

.scal7

LDA G                  \ Set (xMomentsScTop xMomentsScHi xMomentsScLo)
STA xMomentsScTop,X    \                                          = (G W V)
LDA W                  \
STA xMomentsScHi,X     \ so we have:
LDA V                  \
STA xMomentsScLo,X     \   scaledForce = unscaledForce * forceFactor
\                               * 2 ^ scaleFactor

DEX                    \ Decrement the loop counter to move to the next flight
\ factor

BPL scal1              \ Loop back until we have processed all 13 flight
\ factors

RTS                    \ Return from the subroutine
```