Skip to navigation


Driving model: ApplyGrassOrTrack

Name: ApplyGrassOrTrack [Show more] Type: Subroutine Category: Driving model Summary: Apply the effects of driving or braking on grass Deep dive: The core driving model Driving on grass Matching the code to the driving model
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * ApplyDrivingModel calls ApplyGrassOrTrack

* If all the following are true: * There is grass under at least one side of the car * bumpyGrassHeight = 0 * heightAboveTrack = 0 * Bit 7 of playerDrift is set then calculate the following to make the car jump when it hits the verge: * yGravityDelta = playerSpeedHi / 2 * yJumpHeight = playerSpeedHi / 4 * heightAboveTrack = heightAboveTrack + 1 * spinYawAngleHi = spinYawAngleHi >> 1 with bit 7 set and make the crash/contact sound * If there is grass under at least one side of the car, then: * bumpyGrassHeight = random number in the range 1 to 7 that is higher with higher speeds otherwise: * bumpyGrassHeight = 0 * For each wing, calculate the following: * If the brakes are not being applied, set brakeForce = 0, otherwise set: * brakeForce = -zTyreForceBoth / 8 (front wing) * brakeForce = zTyreForceBoth / 8 (rear wing) * If we are driving on grass on both sides of the car, then set: wingForce = wingForceGrass + brakeForce otherwise calculate: wingForce = wingSetting * min(53, playerSpeedHi) * abs(zVelocity) + wingForceTrack + brakeForce * Set: wingForce95 = wingForce * 243 / 256
.ApplyGrassOrTrack LDA #0 \ Set A = 0 LDY throttleBrakeState \ If throttleBrakeState is non-zero, then the brakes are BNE gras1 \ not being applied, so jump to gras1 to set H = 0 and \ G = 0 \ If we get here then the brakes are being applied LDA zTyreForceBoth \ Set A = zTyreForceBoth PHP \ Store the N flag on the stack, so the PLP below sets \ the N flag according to the value of zTyreForceBoth LSR A \ Set A = A >> 3 LSR A \ = zTyreForceBoth / 8 LSR A PLP \ If zTyreForceBoth is positive, jump to gras1 to skip BPL gras1 \ the following instruction ORA #%11100000 \ Set bits 5-7 of A to ensure that the value of A \ retains the correct sign after being shifted \ By this point, A = zTyreForceBoth / 8 and has the \ correct sign .gras1 STA H \ Set H = A EOR #&FF \ Set G = -A CLC ADC #1 STA G \ So if the brakes are not being applied we have: \ \ * G = 0 \ * H = 0 \ \ and if the brakes are being applied, we have: \ \ * G = -zTyreForceBoth / 8 \ * H = zTyreForceBoth / 8 \ \ G is used in the front wing calculation below, while \ H is used in the rear wing calculation LDA playerSpeedHi \ Set U = playerSpeedHi STA U LDX #0 \ Set X = 0, to store as the value of bumpyGrassHeight \ if we are not driving on grass \ The leftSurface and rightSurface locations are in \ screen memory, and are just to the left or right of \ the dashboard, so: \ \ * If leftSurface = &FF then there is grass under the \ left edge of the dashboard \ \ * If rightSurface = &FF then there is grass under \ the right edge of the dashboard LDA leftSurface \ Set W so it is &FF if there is grass under both edges AND rightSurface \ of the dashboard STA W LDA leftSurface \ If leftSurface = &FF, then there is grass under the CMP #&FF \ left side of the car, so jump to gras2 BEQ gras2 LDA rightSurface \ If rightSurface <> &FF, then there isn't grass under CMP #&FF \ the right side of the car, so jump to gras4 to skip BNE gras4 \ the following and set bumpyGrassHeight to 0 .gras2 \ If we get here then there is grass under at least one \ side of the car, and W = &FF if there is grass under \ both sides 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 JSR Multiply8x8 \ Set (A T) = A * U \ = random * playerSpeedHi \ \ So A is a random number that is higher with higher \ speeds AND #7 \ Set X = A mod 8 TAX BNE gras3 \ If X = 0, set X = 1 INX \ So X is now a random number in the range 1 to 7 that \ is higher with higher speeds .gras3 LDA bumpyGrassHeight \ If bumpyGrassHeight is non-zero, jump to gras4 BNE gras4 LDA bumpyGrassHeight \ If heightAboveTrack is non-zero, jump to gras4 (the ORA heightAboveTrack \ LDA is not required here, so perhaps it's left over BNE gras4 \ from development) BIT playerDrift \ If bit 7 of playerDrift is clear, then the player's BPL gras4 \ car is not moving significantly sideways, so jump to \ gras4 \ If we get here then the player's car is drifting, and \ the car is not jumping on bumpy grass (as \ bumpyGrassHeight = 0) and is glued to the track (as \ heightAboveTrack = 0) JSR ApplyVergeJump \ Calculate the following variables to apply a jump to \ the car when we hit the track verge: \ \ yGravityDelta = playerSpeedHi / 2 \ \ yJumpHeight = playerSpeedHi / 4 \ \ heightAboveTrack = heightAboveTrack + 1 \ \ spinYawAngleHi = spinYawAngleHi >> 1 with bit 7 set \ \ and make the crash/contact sound .gras4 STX bumpyGrassHeight \ Set bumpyGrassHeight = X, so: \ \ * If we are not driving on grass, then \ bumpyGrassHeight = 0 \ \ * If we are driving on grass, then bumpyGrassHeight \ is set to a random number in the range 1 to 7 that \ is higher with higher speeds LDX #1 \ We now run the following loop, once for each wing \ setting, so set X to use as a loop counter, from 1 \ (for the front wing) to 0 (for the rear wing) .gras5 LDA playerSpeedHi \ Set A = playerSpeedHi CMP #53 \ If A < 53, jump to gras6 BCC gras6 LDA #53 \ Set A = 53, so A has a maximum value of 53 .gras6 STA U \ Store A in U, so we now have the following: \ \ U = min(53, playerSpeedHi) LDA wingSetting,X \ Set A to the scaled wing setting for wing X JSR Multiply8x8 \ Set (A T) = A * U \ = wingSetting * min(53, playerSpeedHi) BIT zVelocityHi \ Set the N flag according to the sign in bit 7 of \ zVelocityHi, so the call to Absolute8Bit sets the \ sign of A to the same sign as zVelocity JSR Absolute8Bit \ Set A = A * abs(zVelocity) \ = wingSetting * min(53, playerSpeedHi) \ * abs(zVelocity) CLC \ Set A = A + wingForceTrack for this wing ADC wingForceTrack,X \ = wingSetting * min(53, playerSpeedHi) \ * abs(zVelocity) \ + wingForceTrack LDY #243 \ Set U = 243 to use in the 95% calculation below STY U LDY W \ If W <> &FF, then there is not grass under both sides CPY #&FF \ of the car, so jump to gras7 to skip the following BNE gras7 LDA wingForceGrass,X \ There is grass under both sides of the car, so set A \ to the wingForceGrass value for this wing LDY #&FF \ Set Y = &FF (this has no effect as Y is already &FF, \ so this instruction is a bit of a mystery) .gras7 CLC \ Set A = A + G (front wing) or H (rear wing) ADC G,X \ \ This adds the effect of the brakes being applied STA wingForce,X \ Store A in wingForce for this wing JSR Multiply8x8 \ Set (A T) = A * U \ = A * 243 \ \ so A = A * 243 / 256 \ = A * 0.95 STA wingForce95,X \ Store A in wingForce95 for this wing DEX \ Decrement the loop counter in X to point to the next \ wing BPL gras5 \ Loop back until we have processed both wings RTS \ Return from the subroutine