Revs on the BBC Micro

# Car geometry: MovePlayerOnTrack

```       Name: MovePlayerOnTrack                                       [Show more]
Type: Subroutine
Category: Car geometry
Summary: Update the position of the player's car within the current track
segment
Deep dive: Placing cars on the track
Context: See this subroutine in context in the source code
References: This subroutine is called as follows:
* MainDrivingLoop (Part 2 of 5) calls MovePlayerOnTrack

This routine sets the racing line and progress for the player's car.

.MovePlayerOnTrack

\ We start by calculating the player's heading within
\ the current segment, so we know which direction the
\ car is heading in, and therefore how to alter the
\ car's position with the track segment

LDA edgeYawAngle       \ Set A = edgeYawAngle - playerHeading
SEC                    \
SBC playerHeading      \ So A contains the yaw angle of the closest segment,
\ from the point of view of the player's car

JSR Absolute8Bit       \ Set A = |A|
\
\ So the angle is now like this:
\
\            0
\            |   32
\            |  /
\            | /
\            |/
\            +----- 64
\            |\
\            | \
\            |  \
\            |   96
\           127

CMP #64                \ If A < 64, clear the C flag, if A >= 64, set the C
\ flag

ROR playerPastSegment  \ Store the C flag in bit 7 of playerPastSegment, so
\ this will be set if the yaw angle is >= 64, which is
\ 90 degrees
\
\ So bit 7 will be set if the closest segment is at a
\ yaw angle of more than 90 degrees from the point of
\ view of the player - in other words, when the player
\ has driven past the segment

BPL mseg1              \ If bit 7 of playerPastSegment is clear, i.e. the C
\ flag is clear, then A < 64 and the player has not gone

\ The player has gone past the closest segment, so A is
\ in the range 64 to 127, with the higher figure
\ indicating that the segment is way behind us, so we
\ now flip that around to the range 63 to 0, where 0
\ indicates that the segment is way behind us, and 63
\ indicates that we've just passed it
\
\ We use this value later to calculate the player's
\ carProgress

EOR #%01111111         \ Negate A using two's complement, leaving bit 7 alone
CLC                    \ to leave the result in the range 63 to 0, so the angle
ADC #1                 \ is now like this:
\
\            0
\            |   32
\            |  /
\            | /
\            |/
\            +----- 64
\            |\
\            | \
\            |  \
\            |   32
\            0
\
\ So the value of A is zero if the player's car is
\ pointing straight along the track segment, or 64 if
\ the car is pointing sideways, towards the verge

.mseg1

PHA                    \ Store the player's direction in A on the stack, which
\ we retrieve below to use when calculating carProgress
\ for the player's car

\ We now calculate the carRacingLine value for the
\ player's car, which is the left-right position within
\ the track

LDY #186               \ Set A = edgeDistanceLo * (A' / 256) * (186 / 256)
JSR GetCarInSegment    \
\ where A' is A, scaled by the ScaleCarInSegment routine

LDX edgeSegmentPointer \ Set X to the index of the segment within the track
\ verge buffer that is closest to the player's car

CPX #40                \ If X < 40, then the segment is along the inner edge of
BCC mseg2              \ the track, so jump to mseg2 to skip the following
\ instruction

EOR #&FF               \ Set A = ~A

.mseg2

LDX currentPlayer      \ Set X to the driver number of the current player

BIT directionFacing    \ Set the sign of A to that of directionFacing, so A
JSR Absolute8Bit       \ gets negated when we are facing backwards

\ The value in A is the updated value of carRacingLine
\ for the player, but before we store it, we need to use
\ it to calculate the player's drift

PHA                    \ Store A on the stack, so we can retrieve bit below
\ when storing it as the updated carRacingLine for the
\ player's car

\ Next, we set bit 7 of playerDrift according to the
\ amount of sideways movement of the player's car, with
\ a set bit 7 meaning the player's car is drifting
\ sideways by more than 22 in this iteration around the
\ main driving loop (where the full track width is 256)

SBC carRacingLine,X    \ Set A = A - the racing line for the player
\
\ So A contains the distance that the car has moved in
\ terms of racing line, i.e. left to right

BCS mseg3              \ If the subtraction didn't underflow, jump to mseg3 to
\ skip the following instruction

EOR #&FF               \ If we get here, then A < then player's racing line and
\ the subtraction underflowed, so set A = ~A to make
\ A positive, so A = |A|

.mseg3

CMP #22                \ If A < 22, clear the C flag, if A >= 22, set the C
\ flag

IF _ACORNSOFT OR _4TRACKS

ROR playerDrift        \ Store the C flag in bit 7 of playerDrift, so this will
\ be set if A >= 22

ELIF _SUPERIOR OR _REVSPLUS

JSR SetPlayerDriftSup  \ Set bit 7 of playerDrift if both A >= 22 and the
\ objSectionSegmt for the player is >= 3, so the
\ Superior version does not record drift in the first
\ three segments of a new track section

ENDIF

PLA                    \ Set carRacingLine,X to the second value we stored on
STA carRacingLine,X    \ the stack above

\ Finally, we calculate the carProgress value for the
\ player's car, which is the progress within the segment

PLA                    \ Set A to the first value we stored on the stack above,
\ which is the player's direction, where A is zero if
\ the player's car is pointing straight along the track
\ segment, or 64 if the car is pointing sideways,
\ towards the verge

EOR #&FF               \ Set A = 64 - A
CLC                    \
ADC #65                \ This works because ~A = -A - 1, so we have:
\
\   A = ~A + 65
\     = -A - 1 + 65
\     = 64 - A
\
\ So A is now in the range 0 to 64, where 64 means the
\ car is pointing forwards along the segment, and 0
\ means it's pointing sideways

LDY #136               \ Set A = edgeDistanceLo * (A' / 256) * (136 / 256)
JSR GetCarInSegment    \
\ where A' is A, scaled by the ScaleCarInSegment routine

ASL A                  \ Set A = A * 2
ASL A

BIT playerPastSegment  \ If bit 7 of playerPastSegment is set, jump to mseg4
BMI mseg4

EOR #&FF               \ Set A = ~A

.mseg4

STA carProgress,X      \ Set the car's progress to A

RTS                    \ Return from the subroutine
```