Skip to navigation

Revs on the BBC Micro

Car geometry: PlaceCarsOnTrack

Name: PlaceCarsOnTrack [Show more] Type: Subroutine Category: Car geometry Summary: Position the cars on the track, ready for a race or qualifying lap
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * ResetVariables calls PlaceCarsOnTrack

This routine places the cars on the track, correctly spaced out and on alternating sides, and populates the track segment buffer so the first entry is 32 segments in front of the current player, and the whole buffer is full of buffered segments.
Arguments: A The distance between each car: * 1 if this is a race * The value of trackCarSpacing if this is practice or qualifying (40 for Silverstone)
.PlaceCarsOnTrack STA V \ Store the value of A in V, so V contains the size of \ the gap that we want to insert between the cars SEC \ Set bit 7 of updateLapTimes, so when we move the cars ROR updateLapTimes \ forward in MoveObjectForward, the lap number and lap \ time are not affected \ We start by incrementing the segment numbers for each \ car, to "move" the cars along the track, stopping when \ driver 0 is on segment 0 (i.e. when it has reached the \ starting line) \ \ Before the call to PlaceCarsOnTrack, we set each car's \ objectSegment to the value of trackStartLine, which is \ 843 for Silverstone \ \ The following loop moves all the cars forwards one \ segment at a time, until objectSegment wraps round to \ zero (which it does when it reaches the value of \ trackLength, which is 1024 for Silverstone, so the \ segment numbers go from 843 to 1023 and then to 0) \ \ In other words, the following moves the cars forward \ by 1024 - 843 segments from the start of section 0, \ or 181 segments, so the starting line at Silverstone \ is at segment 181, and this value is defined by the \ trackStartLine value in the track data file .rcar1 LDX #19 \ Set a loop counter in X to loop through the drivers .rcar2 JSR MoveObjectForward \ Move driver X forwards by one segment DEX \ Decrement the loop counter BPL rcar2 \ Loop back until we have processed all 20 drivers LDA objectSegmentLo \ If objectSegment for driver 0 is non-zero, jump back ORA objectSegmentHi \ to rcar1 to repeat the above loop BNE rcar1 \ The drivers are now all at the starting line (as they \ all started out at the same place before the above \ moves) LDA #&FF \ Set G = -1, so it can be incremented to 0 as the start STA G \ of the outer loop at rcar5 \ We now jump into a nested loop, with an inner loop \ between rcar3 and rcar5 an outer loop between rcar3 \ and rcar6 \ \ We iterate round the outer loop with G from 0 to 19, \ and for each outer iteration, we iterate round the \ inner loop with X from G to 19 \ \ The outer loop runs through each position, while the \ inner loop runs through each car behind that position, \ so the cars get moved backwards around the track as a \ group, with one car being dropped off after each inner \ loop in the correct position \ \ Specifically, the first iteration of the inner loop \ moves the cars in positions 0 to 19 backwards, then \ the cars in positions 1 to 19, then 2 to 19 and so on, \ leaving a trail of cars behind it as it works back \ along the track, so the car in position 0 is first, \ then the car in position 1, and so on to position 19 BNE rcar5 \ Jump to rcar5 (this BNE is effectively a JMP as A is \ never zero) .rcar3 \ This is the start of the inner loop, which runs \ through each position from G to 19, moving each car \ backwards V times (so each car moves backwards by the \ distance in V) LDA V \ Set W = V, so W contains the size of the gap that we STA W \ want to insert between the cars .rcar4 TXA \ Store X on the stack PHA LDA driversInOrder,X \ Set X to the number of the driver in position X TAX JSR MoveObjectBack \ Move driver X backwards along the track PLA \ Retrieve X from the stack TAX DEC W \ Decrement W BPL rcar4 \ Loop back until we have repeated the above W times INX \ Increment the loop counter CPX #20 \ Loop back until we have processed all 20 drivers BCC rcar3 .rcar5 \ This is where we join the loop with G = -1, so the \ following increments G to 0 as soon as we join \ \ This outer part of the loop runs through each position \ in G, from 0 to 19, and calls the inner loop above for \ each value of G INC G \ Increment G LDX G \ Set X = G, so the inner loop does G to 19 CPX #20 \ Loop back until we have done G = 0 to 19 BCC rcar3 \ At this point the cars are spaced out by the correct \ distance, working backwards from position 0 at the end \ of the track (i.e. just before the starting line), to \ position 19 at the back of the pack \ We now use the currently unused object 23 to work out \ the number of track segments we need to initialise in \ front of the current driver, by first moving forwards \ until we are exactly 32 segments in front of the \ current player, then moving backwards by 49 segments, \ and then moving backwards until we reach the start of \ the track section, leaving segmentCounter set to the \ total number of segments we have moved, starting from \ the start position of 32 segments in front of the \ current driver .rcar6 LDX #23 \ Set X to object 23 JSR MoveObjectForward \ Move object 23 forwards by one segment LDY #23 \ Set Y to object 23 LDX currentPlayer \ Set X to the driver number of the current player SEC \ Set the C flag for a 16-bit calculation in the call \ to CompareSegments JSR CompareSegments \ Set A and T to the distance between drivers X and Y BCS rcar6 \ If the C flag is set then the cars are far apart, so \ jump to rcar6 to keep moving object 23 forwards CMP #32 \ If A <> 32, jump to rcar6 to keep moving object 23 BNE rcar6 \ forwards \ At this point, object 23 is a distance of exactly 32 \ segments in front of the current player \ We now move object 23 back by 49 segments LDX #23 \ Set X to object 23 LDA #49 \ Set V = 49, to use as a loop counter from 49 to 1 STA V STA segmentCounter \ Set segmentCounter = 49 .rcar7 JSR MoveObjectBack \ Move object 23 backwards along the track DEC V \ Decrement the loop counter BNE rcar7 \ Loop back until we have moved object 23 backwards by \ 49 segments \ We now move object 23 backwards until it moves into a \ new track section, incrementing segmentCounter for \ each segment moved (which we set to 49 above, so it \ will keep tally of the total number of segments we \ have moved backwards) .rcar8 INC segmentCounter \ Increment segmentCounter JSR MoveObjectBack \ Move object 23 backwards along the track, setting the \ C flag if we move into a new track section BCC rcar8 \ Loop back to keep moving object 23 backwards until it \ moves into a new track section \ \ We don't care where object 23 has ended up, but we \ will use the value of segmentCounter below when \ populating the segment buffer \ We now move the cars to alternating sides of the track \ so the grid is staggered LDA #80 \ Set A to 80, which we will flip between 80 and 175 to \ alternate cars between the right (80) and left (175) \ side of the track, where 0 is full right and 255 is \ full left LDY #19 \ Set a loop counter in Y to loop through the positions .rcar9 LDX driversInOrder,Y \ Set X to the number of the driver in position X EOR #&FF \ Flip A between 80 and 175 STA carRacingLine,X \ Set the racing line of the car on the track (i.e. its \ left-right position) to the value in A DEY \ Decrement the loop counter to move on to the next \ position BPL rcar9 \ Loop back until we have staggered the whole pack LDA #0 \ Set frontSegmentIndex = 0, as the segment buffer is STA frontSegmentIndex \ currently empty (and we are about to fill it, which \ will update frontSegmentIndex accordingly) \ We now call GetTrackSegment segmentCounter times, \ where segmentCounter is the number of times we moved \ object 23 backwards in the above \ \ This populates the track segment buffer, making sure \ it is fully populated by working forwards from where \ object 23 ended up, one segment at a time, all the way \ to 32 segments in front of the current player, which \ is where we want the front segment of the track \ segment buffer to be .rcar10 JSR GetTrackSegment \ Initialise the next track segment in the track segment \ buffer, setting up the track segment indexes \ accordingly DEC segmentCounter \ Decrement the counter in segmentCounter BNE rcar10 \ Loop back until we have called GetTrackSegment \ segmentCounter times, by which time the buffer entry \ at frontSegmentIndex is 32 segments in front of the \ current player, the buffer entry at playerSegmentIndex \ is the current player, and all 40 entries in the \ buffer are populated with the correct segments \ \ So from this point onwards, object 23 is the object \ that corresponds to the front segment of the track \ segment buffer LSR updateLapTimes \ Clear bit 7 of updateLapTimes, so any further calls to \ MoveObjectForward will update the lap number and lap \ time once again RTS \ Return from the subroutine