Revs on the BBC Micro

# Driving model: ApplySkidForces

```       Name: ApplySkidForces                                         [Show more]
Type: Subroutine
Category: Driving model
Summary: Calculate the tyre forces when the car is skidding
Deep dive: Skidding
Context: See this subroutine in context in the source code
References: This subroutine is called as follows:
* ApplyTyresAndSkids calls ApplySkidForces

Calculate the following:

* Set xTyreForceNose or xTyreForceRear
= max(wingForce95 << 8, scaled |xVelocity|) * abs(-xVelocity)

* Call GetTyreForces to set (A T), H and (NN MM)

* If the throttle is being applied and we are processing the front tyres,
return from the subroutine

* If A < wingForce95, then:

* If the throttle is being applied, then

zTyreForceNose or zTyreForceRear = (A T) * abs(H)

otherwise set:

zTyreForceNose or zTyreForceRear = max((A T), (NN MM)) * abs(H)

* If A >= wingForce95, then:

* Set (A T) = wingForce95 << 8

* If the throttle is being applied, then

zTyreForceNose or zTyreForceRear = (A T) * abs(H)

otherwise set:

zTyreForceNose or zTyreForceRear = max((A T), (NN MM)) * abs(H)

* If the throttle is being applied and we are processing the rear tyres,
set:

xTyreForceNose or xTyreForceRear = 0

Arguments:

X                    The set of tyres to process:

* 0 = front tyres

* 1 = rear tyres

.ApplySkidForces

LDA #0                 \ Set zTyreForceNose for tyre X to 0
STA zTyreForceNoseHi,X
STA zTyreForceNoseLo,X

LDY #8                 \ Set Y = 8 so the call to Scale16Bit scales xVelocity

JSR Scale16Bit         \ Scale up |xVelocity| by 2^5, capping the result at the
\ maximum possible positive value of &7Fxx, and
\ returning the result in (NN MM)

LDA xVelocityHi        \ Set H = xVelocityHi with the sign flipped, so that
EOR #%10000000         \ abs(H) = abs(-xVelocity)
STA H

LDA #0                 \ Set T = 0
STA T

LDA wingForce95,X      \ Set A to wingForce95 for tyre X

STX G                  \ Set G to the tyre number in X so the ApplyLimitAndSign
\ routine sets xTyreForceNose or xTyreForceRear
\ accordingly

JSR ApplyLimitAndSign  \ Set xTyreForceNose or xTyreForceRear
\                       = max((A T), (NN MM)) * abs(H)
\
\   =   max(wingForce95 << 8, scaled |xVelocity|)
\     * abs(-xVelocity)

JSR GetTyreForces      \ Calculate the tyre forces due to the throttle or
\ brakes:
\
\   * (A T) = the force
\
\   * H = the sign of the force
\
\   * G = X + 2, so the call to ApplyLimitThrottle sets
\     zTyreForceNose or zTyreForceRear accordingly
\
\   * If the throttle is not being applied, (NN MM) is
\     a maximum value for the force
\
\ If the throttle is being applied and we are processing
\ the front tyres, only G is calculated and the C flag
\ is set

BCS skid2              \ If the C flag is set then GetTyreForces did not return
\ the subroutine

CMP wingForce95,X      \ If A < wingForce95 for tyre X, jump to skid1
BCC skid1

LDA #0                 \ Set T = 0
STA T

LDA wingForce95,X      \ Set A to wingForce95 for tyre X, so
\ A = min(A, wingForce95)

JSR ApplyLimitThrottle \ If the throttle is being applied, then set
\ zTyreForceNose or zTyreForceRear to:
\
\   (A T) * abs(H)
\
\ otherwise set it to:
\
\    max((A T), (NN MM)) * abs(H)

LDY throttleBrakeState \ If throttleBrakeState <> 1 then the throttle is not
BNE skid2

CPX #0                 \ If X = 0, then we are processing the front tyres, so

\ If we get here then the throttle is being applied and
\ we are processing the rear tyres

LDA #0                 \ Set xTyreForceNose for tyre X to 0
STA xTyreForceNoseHi,X
STA xTyreForceNoseLo,X

BEQ skid2              \ Jump to skid2 to return from the subroutine (this BEQ
\ is effectively a JMP as A is always zero)

.skid1

JSR ApplyLimitThrottle \ If the throttle is being applied, then set
\ zTyreForceNose or zTyreForceRear to:
\
\   (A T) * abs(H)
\
\ otherwise set it to:
\
\    max((A T), (NN MM)) * abs(H)

.skid2

RTS                    \ Return from the subroutine
```