Skip to navigation

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

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 CMP carSectionSpeed,X \ carSectionSpeed then jump to mcar11 to skip changing 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 \ trackDriverSpeed > carSpeedHi, so jump to mcar3 to \ 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 \ objSectionSegmt >= trackSectionTurn, so jump to mcar11 \ 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 JMP mcar9 \ Jump to mcar9 .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) ADC carSpeedLo,X \ STA carSpeedLo,X \ starting with the low bytes LDA U \ And then the high bytes ADC carSpeedHi,X 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 ADC carProgress,X STA carProgress,X BCC mcar13 \ If the addition didn't overflow, jump to mcar13 to do \ the next loop JSR MoveObjectForward \ The addition overflowed, so carProgress has filled up \ and we need to move the car forwards by one segment .mcar13 DEC V \ Decrement the loop counter in V BPL mcar12 \ Loop back until we have added carSpeedHi twice