Revs on the BBC Micro

# Drivers: AwardRacePoints

```       Name: AwardRacePoints                                         [Show more]
Type: Subroutine
Category: Drivers
Summary: Award points following a race
Context: See this subroutine in context in the source code
References: This subroutine is called as follows:
* MainLoop (Part 6 of 6) calls AwardRacePoints

This routine awards points to a driver for finishing in the top six in a race,
or for getting the fastest lap time. The points awarded are based on the
driver's race position, as per the pointsForPlace table:

* 9 points for first place
* 6 points for second place
* 4 points for third place
* 3 points for fourth place
* 2 points for fifth place
* 1 point for sixth place
* 1 point for the fastest lap

In single-player races, the points are awarded as above.

In multi-player races, an algorithm is used to share out the points in a way
that takes the relative skills into consideration. Specifically, the routine
awards this many points:

(U T) * the points from the above list

This is how (U T) is calculated:

* Single-player race:

(U T) = numberOfPlayers = 1, so we award the amount of points shown above

* Multi-player race:

If we are awarding points to the current player:

(U T) = (numberOfPlayers - 1) * numberOfPlayers

If we are awarding points to a human player but not the current player:

(U T) = numberOfPlayers

If we are awarding points to a computer driver:

(U T) = (numberOfPlayers - 1) * 2

I have no idea why the algorithm works like this. It needs more analysis!

Arguments:

X                    The race position to award points to:

* 0 to 5 for the first six places

* 6 for the fastest lap

.AwardRacePoints

LDA #0                 \ Zero the points in (racePointsHi racePointsLo) for
STA racePointsLo,X     \ race position X
STA racePointsHi,X

STA U                  \ Set U = 0, to act as the high byte of (U T)

LDY driversInOrder,X   \ Set Y to the number of the driver in race position X

CPX #6                 \ If we called the routine with X = 0 to 5, then jump to
BNE poin1              \ poin1 to skip the following instruction

LDY driversInOrder     \ We called the routine with X = 6, so set Y to the
\ winning driver's number, i.e. the driver with the
\ fastest lap

.poin1

\ By this point, Y contains the number of the driver we
\ want to give the points to, so now we calculate the
\ number of points to award

LDA numberOfPlayers    \ Set A to the number of players - 1
SEC
SBC #1

BEQ poin3              \ If A = 0 then there is only one player, so jump to
\ poin3 to skip the following

CPY currentPlayer      \ If Y is the number of the current player, jump to
BEQ poin2              \ poin2

CPY lowestPlayerNumber \ If Y >= lowestPlayerNumber then this is a human
BCS poin3              \ player but not the current player, so jump to poin3

\ If we get here then we are awarding points to a
\ computer-controlled driver

ASL A                  \ Double the value of A, to use as the value of T, so
\ we will get:
\
\   (U T) = (0 T)
\         = T
\         = A * 2
\         = (numberOfPlayers - 1) * 2

BNE poin4              \ Jump to poin4 (this BNE is effectively a JMP, as A is
\ never zero)

.poin2

\ If we get here then we are awarding points to the
\ current player

STA U                  \ Set U = A = numberOfPlayers - 1

LDA numberOfPlayers    \ Set A = numberOfPlayers

JSR Multiply8x8        \ Set (A T) = A * U
\           = (numberOfPlayers - 1) * numberOfPlayers

STA U                  \ Set (U T) = (A T)
\           = (numberOfPlayers - 1) * numberOfPlayers

.poin3

\ If we get here then either there is only one player,
\ or we are awarding points to a human player but not
\ the current player

LDA numberOfPlayers    \ Set A to the number of players, to use as the value of
\ T, so we will get:
\
\   (U T) = (0 T)
\         = (0 numberOfPlayers)
\         = numberOfPlayers

BNE poin4              \ This instruction has no effect as poin4 is the next
\ instruction anyway

.poin4

STA T                  \ Store A in T, so this sets (U T) = (U A)

.poin5

SED                    \ Set the D flag to switch arithmetic to Binary Coded
\ Decimal (BCD)

\ We now do the following addition 256 * U + T times, so
\ the total number of points added is:
\
\   (256 * U + T) * (9, 6, 4, 3, 2 or 1)
\
\ or putting it another way:
\
\   (U T) * (9, 6, 4, 3, 2 or 1)

.poin6

LDA pointsForPlace,X   \ Add the X-th entry in pointsForPlace to the X-th entry
CLC                    \ in (racePointsHi racePointsLo),  starting with the low
STA racePointsLo,X

LDA racePointsHi,X     \ And then the high bytes
STA racePointsHi,X

DEC T                  \ Decrement the counter in T

BNE poin6              \ Loop back to poin6 so we do the addition a total of T
\ times

DEC U                  \ Decrement the counter in U

BPL poin6              \ Loop back to poin6 so we do an additional U loops,
\ with the inner loop repeating 256 times as T is now 0,
\ so this does a total of 256 * U additional additions

JSR AddRacePoints      \ Add the race points from above to the accumulated
\ points for driver Y

RTS                    \ Return from the subroutine
```