Tactics: GetSegmentSteering

```       Name: GetSegmentSteering                                      [Show more]
Type: Subroutine
Category: Tactics
Summary: Calculate the optimum steering to take for the current track
segment
Deep dive: Tactics of the non-player drivers
Context: See this subroutine in context in the source code
References: This subroutine is called as follows:
* GetTrackSegment (Part 3 of 3) calls GetSegmentSteering

This routine populates segmentSteering for a track segment, depending on a
large number of factors.

.GetSegmentSteering

LDY objTrackSection+23 \ Set Y to the number * 8 of the track section for the
\ front segment of the track segment buffer

TYA                    \ Set X = Y / 8
LSR A                  \
LSR A                  \ So X contains the number of the track section for the
LSR A                  \ front segment
TAX

LDA turnCounter        \ If turnCounter is non-zero, then a turn is already in

\ We get here if turnCounter is zero

LDA thisSectionFlags   \ If bit 0 of thisSectionFlags is set then this is a
BCS rlin2

LDA objSectionSegmt+23 \ If the front segment's number within the track section
CMP trackSectionTurn,Y \ is >= the trackSectionTurn for the section, jump to
BCS rlin3              \ rlin3 to move on to the next track section

\ If we get here, then:
\
\   * turnCounter is zero
\
\   * Bit 0 of thisSectionFlags is clear, so this is a
\     straight track section
\
\   * The front segment's number within the track
\     section is less than the trackSectionTurn value
\     for the section
\
\ So we are not already turning from a previous call, we
\ are on a straight, and we haven't yet reached the
\ point at the end of the straight where we should be
\ turning
\
\ So now we keep on driving straight

.rlin1

LDA sectionSteering,X  \ Set A to the optimum steering for section X, with
ORA #%01000000         \ bit 6 set, so we do not apply any steering in MoveCars
\ but instead just apply acceleration or braking

BNE rlin7              \ Jump to rlin7 to store A in segmentSteering for this
\ section and return from the subroutine (this BNE is
\ effectively a JMP as A is never zero)

.rlin2

\ If we get here then this is a curved track section and
\ turnCounter is zero

LDA prevDriverSpeed7   \ If bit 7 of prevDriverSpeed7 is set, jump to rlin4
BMI rlin4

\ If we get here then this is a curved track section and
\ turnCounter is zero, and bit 7 of prevDriverSpeed7 is
\ clear

.rlin3

\ If we jump here, then the front segment is past the
\ trackSectionTurn point in this section, so we start
\ looking at the next section for the optimum steering

TYA                    \ Set Y = Y + 8
CLC                    \
ADC #8                 \ So Y contains the number * 8 of the next track section
TAY

INX                    \ Increment X, so X contains the number of the next
\ track section

.rlin4

LDA trackSectionFlag,Y \ If bit 0 of the track section's flag byte is clear,
AND #1                 \ then this is a straight section, so jump to rlin1 to
BEQ rlin1              \ disable steering in MoveCars and keep on driving
\ straight

LDA trackSectionTurn,Y \ Set turnCounter = track section's trackSectionTurn
STA turnCounter

BEQ rlin1              \ If the track section's trackSectionTurn is zero, jump
\ to rlin1 to disable steering in MoveCars and keep on
\ driving straight

LDA trackDriverSpeed,Y \ Set prevDriverSpeed7 = track section's driver speed,
STA prevDriverSpeed7   \ which we only use to check bit 7

AND #%01111111         \ Set prevDriverSpeed06 = bits 0-6 of the track
STA prevDriverSpeed06  \ section's driver speed

LDA sectionSteering,X  \ Set A to the optimum steering for the track section

STA previousSteering   \ Set previousSteering to the optimum steering for the
\ track section

JMP rlin7              \ Jump to rlin7 to store A in segmentSteering for this
\ section and return from the subroutine (this BNE is
\ effectively a JMP as A is never zero)

.rlin5

\ If we get here then turnCounter is non-zero, so a
\ turn is already in progress

DEC turnCounter        \ Decrement the turn counter in turnCounter

LDA turnCounter        \ Set T = turnCounter / 8
LSR A
LSR A
LSR A
STA T

LDA turnCounter        \ Set A = turnCounter - prevDriverSpeed06
SEC
SBC prevDriverSpeed06

BCS rlin6              \ If the subtraction didn't underflow, i.e.
\
\   turnCounter >= prevDriverSpeed06
\
\ previousSteering and return from the subroutine

\ If we get here then turnCounter < prevDriverSpeed06
\ and A is negative

ADC T                  \ Set A = A + T
\       = turnCounter - prevDriverSpeed06
\                     + turnCounter / 8
\       = (turnCounter * 1.125) - prevDriverSpeed06

LDA #0                 \ Set A = 0

BCS rlin7              \ If the addition overflowed, then because A was
\ negative, we must have the following:
\
\   (turnCounter * 1.125) - prevDriverSpeed06 >= 0
\
\ this section and return from the subroutine
\
\ Otherwise store previousSteering in segmentSteering
\ for this section with bit 7 flipped, and return from
\ the subroutine

.rlin6

LDA previousSteering   \ Set A = previousSteering

BCS rlin7              \ If the C flag is clear, flip bit 7 of A
EOR #%10000000

.rlin7

LDY frontSegmentIndex  \ Set segmentSteering for the front segment in the track
STA segmentSteering,Y  \ segment buffer to A

RTS                    \ Return from the subroutine
```