Revs on the BBC Micro

# Car geometry: MoveCars (Part 1 of 2)

```       Name: MoveCars (Part 1 of 2)                                  [Show more]
Type: Subroutine
Category: Car geometry
Summary: Move the cars around the track
Deep dive: Placing cars on the track
Tactics of the non-player drivers
Context: See this subroutine in context in the source code
References: This subroutine is called as follows:
* FinishRace calls MoveCars
* MoveAndDrawCars calls MoveCars
* MoveCars (Part 1 of 2) calls entry point MoveCars-1

This part changes each car's speed. It calculates the speed change in (U A),
and then applies it to the car's speed. It then moves the car round the track
by the speed we just calculated by updating carProgress.

Other entry points:

MoveCars-1           Contains an RTS

.MoveCars

LDA raceStarting       \ If bit 7 of raceStarting is set, then the race is in
BMI MoveCars-1         \ the process of starting and we are on the starting
\ grid, so the cars are not allowed to move, so return
\ from the subroutine (as MoveCars-1 contains an RTS)

LDX #20                \ Set X = 20 to use as a loop counter as we work through
\ all 20 cars

JMP mcar20             \ Jump into the loop at mcar20 to decrement X and start
\ looping through the drivers, looping back to mcar1 for
\ all drivers except the current player

.mcar1

\ This first part of the loop changes the car's speed as
\ required

LDA carStatus,X        \ If bit 7 of driver X's carStatus is set, jump to
BMI mcar8              \ mcar8 to apply the brakes

LDY objTrackSection,X  \ Set Y to the track section number * 8 for driver X

LDA trackSectionFlag,Y \ Set A to the flag byte for the driver's track section

BPL mcar2              \ If bit 7 of this section's flag byte is clear, jump to
\ mcar2

\ If we get here then bit 7 of this section's flag byte
\ is set

LDA carSpeedHi,X       \ If the high byte of the car's speed >= the car's
BCS mcar11             \ the car's speed, as it is already going fast enough
\ for the section

BCC mcar3              \ Otherwise jump to mcar3 to continue with the speed
\ calculation (this BCC is effectively a JMP as we just
\ passed through a BCS)

.mcar2

\ If we get here then bit 7 of this section's flag byte
\ is clear, and A contains this section's flag byte

LSR A                  \ Set the C flag to bit 0 of A, i.e. to bit 0 of this
\ section's flag byte

BCS mcar3              \ If bit 0 of this section's flag byte is set, then this
\ is a curved section, so jump to mcar3 to continue with
\ the speed calculation

\ If we get here then bits 0 and 7 of this section's
\ flag byte are both clear, so this is a straight
\ section and there is no maximum speed set

LDA trackDriverSpeed,Y \ Set carSectionSpeed for this driver to the value of
STA carSectionSpeed,X  \ trackDriverSpeed for this track section

CLC                    \ Set A = trackDriverSpeed - carSpeedHi - 1
SBC carSpeedHi,X

BCS mcar3              \ If the subtraction didn't underflow, then
\ continue with the speed calculation

LSR A                  \ Set T = A >> 2 with bits 6 and 7 set
LSR A                  \
ORA #%11000000         \ As A is negative, this divides A by 4 while keeping
STA T                  \ the sign, so:
\
\   T = A / 4
\     = (trackDriverSpeed - carSpeedHi - 1) / 4

LDA objSectionSegmt,X  \ Set A = objSectionSegmt - trackSectionTurn
SEC                    \
SBC trackSectionTurn,Y \ so this takes the driver's current segment number in
\ the track section and subtracts the trackSectionTurn
\ for this track section

BCS mcar11             \ If the subtraction didn't underflow, then
\ to skip changing the car's speed

CMP T                  \ If A >= T, jump to mcar8 to apply the brakes
BCS mcar8

.mcar3

\ We now set A and T to use in the calculation to work
\ out the level of acceleration we need to apply to the
\ car's speed

LDA carSpeedHi,X       \ Set A to the high byte of the car's current speed

CMP #60                \ If the high byte of the car's speed in A >= 60, jump
BCS mcar4              \ to mcar4 to skip the following instruction

LDA #22                \ Set A = 22

.mcar4

\ By this point, A is either 22 or >= 60

STA T                  \ Set T = A

LDA carStatus,X        \ If bit 6 of driver X's carStatus is clear, then we do
AND #%01000000         \ not accelerate the car, so jump to mcar5 with A = 0
BEQ mcar5

LDA #5                 \ Set A = 5

.mcar5

\ By this point
\
\   * T is carSpeedHi, reduced to 22 if < 60
\
\   * A is either 0 or 5, depending on bit 6 of driver
\     X's carStatus, i.e. whether the car is set to be
\     accelerating

CLC                    \ Set A = A + the driver's average speed, as calculated
ADC driverSpeed,X      \ in the SetDriverSpeed routine

\ So by this point:
\
\   * T is carSpeedHi, reduced to 22 if < 60
\
\   * A is driver X's average speed, + 5 if driver X is
\     accelerating

\ We now apply any trackRaceSlowdown factor from the
\ track data, which allows us to slow down races for
\ debugging purposes (trackRaceSlowdown is set to 0 in
\ in the Silverstone track, so this has no effect)

BIT raceStarted        \ If bit 7 of raceStarted is clear then this is practice
BPL mcar6              \ or qualifying, so jump to mcar6 to skip the following
\ instruction

SBC trackRaceSlowdown  \ This is a race, so set A = A - trackRaceSlowdown
\
\ The value of trackRaceSlowdown for the Silverstone
\ track is zero, so this has no effect, but if it were
\ non-zero then it would reduce the speed of all cars
\ in a race by that amount

.mcar6

\ We now calculate (U A) = A - T to get the speed change
\ to apply to the driver, given the following values:
\
\   * T is carSpeedHi, reduced to 22 if < 60
\
\   * A is driver X's average speed, + 5 if driver X is
\     accelerating, reduced by trackRaceSlowdown if this
\     is a race
\
\ In other words, T is the current speed, while A is the
\ speed we should be aiming for, so
\
\   (U A) = A - T
\
\ will give us the delta that we need to apply to the
\ car's current speed to get to the new speed, with the
\ acceleration much higher when the car's current speed
\ is < 60 (when T is reduced to 22)
\
\ So cars can't accelerate fast once they pass a certain
\ speed (carSpeedHi >= 60)

LDY #0                 \ Set Y = 0, so (Y A) = A

SEC                    \ Set (Y A) = (Y A) - T
SBC T                  \           = A - T
\
\ starting with the low bytes

BCS mcar7              \ And then the high bytes
DEY

.mcar7

STY U                  \ Set (U A) = (Y A)
\           = A - T

.mcar8

\ If we get here then we are applying the brakes, so
\ set (U A) to -256 so we subtract 1024 from the speed
\ in the following

LDA #&FF               \ Set (U A) = -256 (&FF00)
STA U                  \
LDA #0                 \ so the following adds -1024 to the car speed

.mcar9

\ By this point we have calculated the speed change in
\ (U A), so now we apply it

ASL A                  \ Set (U A) = (U A) * 4
ROL U
ASL A
ROL U

CLC                    \ Set (A carSpeedLo) = (carSpeedHi carSpeedLo) + (U A)
STA carSpeedLo,X       \ starting with the low bytes

LDA U                  \ And then the high bytes

CMP #190               \ If the high byte in A < 190, jump to mcar10 to store
BCC mcar10             \ the result in carSpeedHi

LDA #0                 \ Otherwise the car's speed is now a negative value, so
STA carSpeedLo,X       \ we zero the car's speed, starting with the low byte,
\ and setting A = 0 so we also zero the high byte in the
\ next instruction

.mcar10

STA carSpeedHi,X       \ Update the high byte of the car's speed to A

.mcar11

LDA #1                 \ Set V = 1, so we do the following loop twice, which
STA V                  \ updates the car's progress by 2 x carSpeedHi

.mcar12

LDA carSpeedHi,X       \ Add carSpeedHi to carProgress to move the car along
CLC                    \ the track by its speed
STA carProgress,X