# Driving model: ScaleTyreForces

```       Name: ScaleTyreForces                                         [Show more]
Type: Subroutine
Category: Driving model
Summary: Scale the tyre forces and calculate the combined tyre force on the
player
Deep dive: The core driving model
Matching the code to the driving model
Context: See this subroutine in context in the source code
References: This subroutine is called as follows:
* ApplyDrivingModel calls ScaleTyreForces

Calculate the following:

spinYawDelta = (xTyreForceNose - xTyreForceRear) * 0.3

xTyreForceNose = xTyreForceNose >> 2

xTyreForceRear = xTyreForceRear >> 2

zTyreForceNose = zTyreForceNose >> 2

zTyreForceRear = zTyreForceRear >> 2

xPlayerAccel = (xTyreForceRear * 1.5 + xTyreForceNose) * 1.6

zPlayerAccel = (zTyreForceRear * 1.5 + zTyreForceNose) * 1.6

zTyreForceBoth = zPlayerAccelHi

.ScaleTyreForces

LDY #78                \ Set Y = 78

LDA xTyreForceNoseLo   \ Set (A T) = xTyreForceNose - xTyreForceRear
SEC                    \
SBC xTyreForceRearLo   \ starting with the low bytes
STA T

LDA xTyreForceNoseHi   \ And then the high bytes
SBC xTyreForceRearHi

JSR Multiply8x16Signed \ Set:
\
\   (A T) = (A T) * abs(A) * Y / 256
\         = (xTyreForceNose - xTyreForceRear) * 78 / 256
\         = (xTyreForceNose - xTyreForceRear) * 0.3

STA spinYawDeltaHi     \ Set spinYawDelta = (A T)
LDA T                  \              = (xTyreForceNose - xTyreForceRear) * 0.3
STA spinYawDeltaLo

\ We now perform the following shifts, making sure to
\ keep the signs intact:
\
\   xTyreForceNose = xTyreForceNose >> 2
\
\   xTyreForceRear = xTyreForceRear >> 2
\
\   zTyreForceNose = zTyreForceNose >> 2
\
\   zTyreForceRear = zTyreForceRear >> 2

LDY #1                 \ Set Y = 1, to act as a shift counter in the outer loop
\ below, so we right-shift Y + 1 times (i.e. twice)

.forc1

LDX #3                 \ Set X = 3, to act as a variable counter in the inner
\ loop to work through zTyreForceRear, zTyreForceNose,
\ xTyreForceRear and xTyreForceNose (let's call this
\ variableX)

.forc2

LDA xTyreForceNoseHi,X \ Set A to the high byte of variableX

CLC                    \ Clear the C flag, to use if variableX is positive

BPL forc3              \ If A is positive, jump to forc3 to keep the C flag
\ clear

SEC                    \ Otherwise set the C flag, to use if variableX is
\ negative

\ The C flag now contains the sign bit of A

.forc3

ROR xTyreForceNoseHi,X \ Set variableX = variableX >> 1
ROR xTyreForceNoseLo,X \

DEX                    \ Decrement the inner loop counter in X

BPL forc2              \ Loop back to forc2 until we have shifted all four
\ variables to the right by one place

DEY                    \ Decrement the shift counter in Y

BPL forc1              \ Loop back until we have right-shifted Y + 1 times

LDX #2                 \ Set X = 2, to act as a variable counter in the
\ following loop, iterating through values 0 and 2, as
\ X is decremented twice at the end of the loop
\
\ The loop references xTyreForceRear,X and
\ xTyreForceNose,X, so the loop iterates through:
\
\   * zTyreForceRear and zTyreForceNose when X = 2
\
\   * xTyreForceRear and xTyreForceNose when X = 0
\
\ The comments below are for when X = 2

LDA #1                 \ Set G = 1, to use as the index for storing the
STA G                  \ following calculation

.forc4

LDA xTyreForceRearLo,X \ Set (U T) = zTyreForceRear
STA T
LDA xTyreForceRearHi,X
STA U

JSR MultiplyBy1Point5  \ Set (A T) = (U T) * 1.5
\           = zTyreForceRear * 1.5

STA U                  \ Set (U T) = (A T)
\           = zTyreForceRear * 1.5

LDA T                  \ Set (A T) = (U T) + zTyreForceNose
CLC                    \           = zTyreForceRear * 1.5 + zTyreForceNose
STA T                  \ starting with the low bytes

LDY #205               \ Set Y = 205

LDA U                  \ And then the high bytes

JSR Multiply8x16Signed \ Set (A T) = (A T) * abs(A) * Y / 256
\        = (zTyreForceRear * 1.5 + zTyreForceNose)
\            * 205 / 256
\        = (zTyreForceRear * 1.5 + zTyreForceNose) * 0.8

ASL T                  \ Set (A T) = (A T) * 2
ROL A                  \        = (zTyreForceRear * 1.5 + zTyreForceNose) * 1.6

LDY G                  \ Set zPlayerAccel = (A T)
STA xPlayerAccelHi,Y   \        = (zTyreForceRear * 1.5 + zTyreForceNose) * 1.6
LDA T
STA xPlayerAccelLo,Y

DEC G                  \ Decrement G so the next iteration stores the result in
\ xPlayerAccel

DEX                    \ Decrement X twice so the next iteration calculates
DEX                    \ (xTyreForceRear * 1.5 + xTyreForceNose) * 1.6

BPL forc4              \ Loop back until we have calculated both zPlayerAccel
\ and xPlayerAccel

LDA zPlayerAccelHi     \ Set zTyreForceBoth = zPlayerAccelHi
STA zTyreForceBoth

RTS                    \ Return from the subroutine
```