.tact5 \ We jump here with the distance between driver X and \ driver Y in A, which is positive as driver Y is ahead \ of driver X CMP #5 \ If A >= 5, then the cars are not very close, so jump BCS tact4 \ to tact18 via tact4 to update the car status byte for \ this driver to N = 0, and then move on to the next \ driver LDA carSpeedLo,X \ Set A to the high byte of the following subtraction: CLC \ SBC carSpeedLo,Y \ driver X speed - driver Y speed - 1 LDA carSpeedHi,X SBC carSpeedHi,Y ROR V \ Rotate the C flag into bit 7 of V, so bit 7 is set if \ driver X is going faster than driver Y (so driver X is \ catching up), and it's clear if driver Y is running \ away with it BPL tact4 \ If bit 7 of the ROR result is clear, i.e. the C flag \ is clear, i.e. if driver Y is driving as fast as or \ faster than driver X, jump to tact18 via tact4 to \ update the car status byte for this driver to N = 0, \ and then move on to the next driver \ If we get here then driver X is behind driver Y but is \ driving faster than driver Y, so we need to think \ about steering driver X \ \ We also know that A is positive, as the above \ subtraction didn't underflow LSR A \ Set A = A / 2 CMP #30 \ If A < 30, jump to tact6 to skip the following BCC tact6 \ instruction LDA #30 \ Set A = 30, so A is a maximum of 30 .tact6 CMP #4 \ If A >= 4, jump to tact7 to skip the following BCS tact7 \ instruction LDA #4 \ Set A = 4, so A is a minimum of 4 .tact7 STA SS \ Store A in SS, which we will use below as the amount \ of steering to apply, in the range 4 to 30, with more \ steering being applied when the cars have a bigger \ speed gap LDA T \ Set A to the number of the driver we are currently \ processing, which we stored in T in part 1 (though the \ same number is still in X, so this could be done more \ efficiently with a TXA instruction) CMP #4 \ Set the C flag if A >= 4, clear the C flag if A < 4 LDA carStatus,Y \ Set A to just bit 6 of driver Y's car status byte, AND #%01000000 \ which is the acceleration flag BEQ tact9 \ If bit 6 of driver Y's car status byte is clear, then \ driver Y is not accelerating, so jump to tact9 \ If we get here then driver Y is accelerating, so we \ get driver X to follow driver Y's racing line BCS tact8 \ If the C flag is set, then the driver number of the \ driver we are currently processing is 4 or greater, so \ jump to tact8 to skip the following instruction ORA #%10000000 \ We are currently processing one of drivers 0 to 3, who \ are the four best drivers, so set bit 7 of A to apply \ the brakes, overriding the acceleration flag in bit 6 .tact8 STA N \ Store the updated flags in N, so bit 6 of driver X \ matches driver Y's bit 6 (so their acceleration status \ matches), and bit 7 (braking) set if X = 0 to 3 LDA carRacingLine,X \ If the racing line for driver X >= the racing line for CMP carRacingLine,Y \ driver Y, set the C flag, otherwise clear it \ \ In other words, the C flag is set if driver X is to \ the left of driver Y ROR T \ Rotate the C flag into bit 7 of T, so we can use this \ bit to determine the direction that driver X should \ steer \ \ This steers driver X to the right (bit 7 set) when \ driver X is to the left of driver Y - in other words, \ it steers driver X towards driver Y's racing line, \ into driver Y's slipstream JMP tact15 \ Jump to tact15 to apply the steering direction in T to \ the amount of steering in SS .tact9 \ If we get here then driver Y is not accelerating, so \ we get driver X to move to overtake driver Y BCS tact10 \ If the C flag is set, then the driver number of the \ driver we are currently processing is 4 or greater, so \ jump to tact10 LDA #%01000000 \ Set N so it only has bit 6 set (so driver X will be STA N \ set to accelerate) LDA carRacingLine,Y \ If the racing line for driver Y >= the racing line for CMP carRacingLine,X \ driver X, set the C flag, otherwise clear it \ \ In other words, the C flag is set if driver X is to \ the right of driver Y ROR T \ Rotate the C flag into bit 7 of T, so we can use this \ bit to determine the direction that driver X should \ steer \ \ This steers driver X to the right (bit 7 set) when \ driver X is to the right of driver Y - in other words, \ it steers driver X away from driver Y's racing line, \ into an overtaking position AND #&FF \ This instruction doesn't change any values, but it \ does set the N flag according to the current value of \ A, so the call to Absolute8Bit will return |A| rather \ than being affected by the result of the ROR \ instruction JSR Absolute8Bit \ Set A = |A| \ \ As A is the racing line, this gives the distance of \ driver Y from the edge of the track, with 0 being on \ the verge, and 127 being in the centre CMP #60 \ If A < 60, then driver Y is close to the verge, so BCC tact11 \ jump to tact11 to steer driver X into the other half \ of the track to driver Y BCS tact12 \ Otherwise we steer driver X away from driver Y's \ racing line, by jumping to tact12 (this BCS is \ effectively a JMP as we just passed through a BCC) .tact10 LSR V \ Clear bit 7 of V, so we never end up applying the \ brakes in tact12 or tact14 below .tact11 LDA carRacingLine,Y \ Set T to the racing line for driver Y, specifically STA T \ so we can extract the top bit to determine which side \ of the track driver Y is on (0 = right, 1 = left), \ and to steer in the opposite direction .tact12 LDA objectStatus,X \ If bit 7 of driver X's object status byte is clear, BPL tact13 \ then the car is visible, so jump to tact13 \ If we get here then driver X is not visible LDA VIA+&68 \ Read 6522 User VIA T1C-L timer 2 low-order counter \ (SHEILA &68), which decrements one million times a \ second and will therefore be pretty random AND #31 \ Reduce the random number to the range 0 to 31 BNE tact18 \ If A is non-zero, jump to tact18 to update the car \ status byte for this driver to N, and then move on \ to the next driver \ If we get here then A is zero, which has a 3.125% \ chance of happening LDA V \ Set A to N, but with bit 7 set to bit 7 of V, so bit 7 AND #%10000000 \ of N gets set if driver X is going faster than driver ORA N \ Y, which means driver X slams on the brakes JMP tact17 \ Jump to tact17 to update the car status byte for this \ driver to the value of A, and then move on to the next \ driver .tact13 \ If we get here then driver X is visible LDA carRacingLine,Y \ Set A to the difference between the racing lines for SEC \ driver X and driver Y SBC carRacingLine,X BCS tact14 \ If the subtraction didn't underflow, jump to tact14 to \ skip the following instruction EOR #&FF \ The subtraction underflowed, so flip all the bits in \ the result to change it from negative to positive, so \ A contains the difference between the two drivers' \ racing lines, made positive .tact14 CMP #100 \ If A >= 100, then the cars are far apart in terms of BCS tact18 \ left-right spacing, so jump to tact18 to skip applying \ any steering, and instead just update the car status \ byte for this driver to N, before moving on to the \ next driver CMP #80 \ If A >= 80, then the cars are slightly closer, so jump BCS tact16 \ to tact16 to set bit 4 of driver X's car status byte \ (so driver X applies the steering we've been \ calculating) CMP #60 \ If A >= 60, then the cars are even closer, so jump to BCS tact15 \ tact15 to steer driver X in the direction in T, which \ we set above to the side of the track driver Y is on \ (0 = right, 1 = left) \ \ This therefore steers driver X away from driver Y, as \ in terms of steering 0 = steer left, 1 = steer right \ If we get here then the cars are really close, so we \ get driver X to slam on the brakes, as well as \ steering away from driver Y LDA V \ Store the bit 7 of V in bit 7 of the car status flag AND #%10000000 \ byte we are building in N, so driver X applies the ORA N \ brakes when bit 7 of V is set STA N .tact15 LDA T \ Set the steering for this driver to SS, with the top AND #%10000000 \ bit (i.e. the direction of the steering) set to the ORA SS \ sign bit of T (0 = steer left, 1 = steer right) STA carSteering,X .tact16 LDA N \ Set bit 4 of the car status flag byte we are building ORA #%00010000 \ in N, so the car does not automatically follow the \ segment's steering line in segmentSteering, and \ instead applies the steering we've been calculating .tact17 STA N \ Store A in N to use as the car status flags for this \ driverName: ProcessOvertaking (Part 2 of 3) [Show more] Type: Subroutine Category: Tactics Summary: The car we are processing has not overtaken the car in front of it, so if applicable, we can keep manoeuvring into positionContext: See this subroutine in context in the source code References: No direct references to this subroutine in this source file
[X]
Subroutine Absolute8Bit (category: Maths (Arithmetic))
Calculate the absolute value (modulus) of an 8-bit number
[X]
Configuration variable VIA = &FE00
Memory-mapped space for accessing internal hardware, such as the video ULA, 6845 CRTC and 6522 VIAs (also known as SHEILA)
[X]
Variable carRacingLine in workspace Stack variables
Each car's position on the track in the x-axis
[X]
Variable carSpeedHi in workspace Stack variables
High byte of each car's forward speed
[X]
Variable carSpeedLo (category: Car geometry)
Low byte of each car's forward speed
[X]
Variable carStatus in workspace Stack variables
Each car's status byte
[X]
Variable carSteering in workspace Stack variables
Contains the steering to apply to each car
[X]
Variable objectStatus in workspace Stack variables
Various status flags for each object
[X]
Label tact10 is local to this routine
[X]
Label tact11 is local to this routine
[X]
Label tact12 is local to this routine
[X]
Label tact13 is local to this routine
[X]
Label tact14 is local to this routine
[X]
Label tact15 is local to this routine
[X]
Label tact16 is local to this routine
[X]
Label tact17 is local to this routine
[X]
Label tact18 in subroutine ProcessOvertaking (Part 3 of 3)
[X]
Label tact4 in subroutine ProcessOvertaking (Part 1 of 3)
[X]
Label tact6 is local to this routine
[X]
Label tact7 is local to this routine
[X]
Label tact8 is local to this routine
[X]
Label tact9 is local to this routine