Prev: 26152 Up: Map Next: 26679
26163: Handler: Car
Moves and draws one of the two cars (the entities at Entity_Car_1 and Entity_Car_2), which chase the player. The car is drawn at its position relative to the player, but only when it is closer than 88 map units in both directions. It is then steered towards the player, bounces off objects, and destroys the player if it hits.
Byte Contents
0 State (2), or the sprite ID while the car is being drawn
1 X position on the screen
2 Y position on the screen
3 Colour (0 or 2), or the attribute while the car is drawn
4-5 X position (twice the map position)
6-7 Y position (twice the map position)
8 X speed (bit 7: moving to lower X; bits 0-4: speed)
9 Y speed (bit 7: moving to lower Y; bits 0-4: speed)
10 Flags (bit 0: car is drawn; bit 7: faster car)
11 Sprite ID
Before After
handler-car-before handler-car-after
Input
IX Car entity
Draw the car using the sprite ID from the last frame.
HandlerCar 26163 LD A,(IX+11) Fetch the sprite ID of the car from the last frame.
26166 LD (IX+0),A Write A to the first byte of the entity, as this is the sprite ID that StoreEntity copies.
26169 CALL StoreEntity Call StoreEntity to copy the position and sprite ID of the entity.
Move the car in the X direction. The distance moved is the X speed divided by 4 or by 2 for the faster car.
26172 LD D,(IX+5) D=high byte of the X position.
26175 LD E,(IX+4) E=low byte of the X position.
26178 LD A,(IX+8) Fetch the X speed of the car.
26181 BIT 7,(IX+10) If the car is the faster car (bit 7 of the flags is set) then jump to HandlerCar_ScaleSpeedX.
26185 JR NZ,HandlerCar_ScaleSpeedX
26187 RRA Halve the speed again, as this is not the faster car.
HandlerCar_ScaleSpeedX 26188 RRA Halve the speed.
26189 AND %00001111 Keep only bits 0-3 to give the distance to move.
26191 LD L,A HL=the distance to move.
26192 LD H,0
26194 BIT 7,(IX+8) If the car is moving towards lower X then jump to ReduceCarX to subtract the distance.
26198 JR NZ,ReduceCarX
26200 ADD HL,DE Add the distance to the X position.
This entry point is used by the routine at ReduceCarX.
HandlerCar_StoreX 26201 LD (IX+5),H Store the high byte of the new X position.
26204 LD (IX+4),L Store the low byte of the new X position.
26207 SRL H Halve the X position (to match the scale of the player position).
26209 RR L
26211 PUSH HL Stash the X position on the stack.
Move the car in the Y direction in the same way.
26212 LD D,(IX+7) D=high byte of the Y position.
26215 LD E,(IX+6) E=low byte of the Y position.
26218 LD A,(IX+9) A=Y speed.
26221 BIT 7,(IX+10) If bit 7 of the flags is set then jump to HandlerCar_ScaleSpeedY.
26225 JR NZ,HandlerCar_ScaleSpeedY
26227 RRA Divide A by two.
HandlerCar_ScaleSpeedY 26228 RRA Divide A by two.
26229 AND %00001111 Keep only bits 0-3.
26231 LD L,A HL=the distance to move.
26232 LD H,0
26234 BIT 7,(IX+9) If the car is moving towards lower Y then jump to ReduceCarY to subtract the distance.
26238 JR NZ,ReduceCarY
26240 ADD HL,DE Add the distance to the Y position.
This entry point is used by the routine at ReduceCarY.
HandlerCar_StoreY 26241 LD (IX+7),H Store the high byte of the new Y position.
26244 LD (IX+6),L Store the low byte of the new Y position.
26247 SRL H Halve the Y position (to match the scale of the player position).
26249 RR L
Work out the distance between the car and the player, and which side of the player the car is on. This is kept in the shadow AF register: bit 0 is set if the car is below the player and bit 1 is set if the car is to the left of the player.
26251 LD DE,(24072) Fetch the player's Y position on the map (PlayerMapPositionY).
26255 XOR A Reset the shadow AF register.
26256 EX AF,AF'
26257 SBC HL,DE Take the player's Y position away from the Y position of the car.
26259 JR NC,HandlerCar_DistanceX If the car is not below the player then jump to HandlerCar_DistanceX.
26261 CALL NegateHL Call NegateHL to make the distance positive.
26264 EX AF,AF' Switch to the shadow AF register.
26265 LD A,1 Set bit 0 by making A 1 as the car is below the player.
26267 EX AF,AF' Switch back to the normal AF register.
Do the same for the X direction.
HandlerCar_DistanceX 26268 EX (SP),HL Swap the Y distance with the X position on the stack.
26269 LD DE,(24069) Fetch the player's X position on the map (PlayerMapPosition).
26273 AND A Reset the carry flag.
26274 SBC HL,DE Take the player's X position away from the X position of the car.
26276 JR NC,HandlerCar_CheckVisible If the car is not to the left of the player then jump to HandlerCar_CheckVisible.
26278 CALL NegateHL Call NegateHL to make the distance positive.
26281 EX AF,AF' Switch to the shadow AF register.
26282 OR %00000010 Set bit 1.
26284 EX AF,AF' Switch back to the normal AF register.
HandlerCar_CheckVisible 26285 POP DE Fetch the Y distance from the player.
26286 EX AF,AF' Switch to the shadow AF register.
26287 LD C,A Keep the direction flags in C.
The car is only drawn when both distances are less than 88.
26288 LD A,H Jump to HandlerCar_TooFar if either distance is more than 255.
26289 OR D
26290 JP NZ,HandlerCar_TooFar
26293 LD A,L Jump to HandlerCar_TooFar if the X distance is 88 or more.
26294 CP 88
26296 JP NC,HandlerCar_TooFar
26299 LD A,E Jump to HandlerCar_TooFar if the Y distance is 88 or more.
26300 CP 88
26302 JP NC,HandlerCar_TooFar
Work out the position of the car on the screen. The player is at 152 across and 104 down.
26305 BIT 0,C If the car is below the player then jump to HandlerCar_AddPlayerY.
26307 JR NZ,HandlerCar_AddPlayerY
26309 NEG Negate the Y distance, as the car is above the player.
HandlerCar_AddPlayerY 26311 ADD A,104 Add 104 (the Y position of the player).
26313 LD (IX+2),A Store the Y position of the car.
26316 BIT 1,C Check if the car is to the left of the player.
26318 LD A,L Fetch the X distance from the player.
26319 JR Z,HandlerCar_AddPlayerX If the car is not to the left of the player then jump to HandlerCar_AddPlayerX.
26321 NEG Negate the X distance, as the car is to the left of the player.
HandlerCar_AddPlayerX 26323 ADD A,152 Add 152 (the X position of the player).
26325 LD (IX+1),A Store the X position of the car.
Choose which of the 16 car sprites to use, so that the car points in the direction it is moving. The quadrant of travel comes from the direction bits (bit 7) of the two speeds, and the angle within it from CarDirectionTable using the top three bits of each speed.
26328 PUSH BC Stash the direction flags on the stack.
26329 LD A,(IX+9) Fetch the Y speed and keep it in E.
26332 LD E,A
26333 RLCA Rotate A left so that bit 0 is the direction bit of the Y speed.
26334 LD C,(IX+8) Fetch the X speed and keep it in B.
26337 LD B,C
26338 RLC C Rotate C left so that bit 0 is the direction bit of the X speed.
26340 XOR C Exclusive OR A with C.
26341 AND %00000001 Keep only bit 0.
26343 SLA C Shift C left so that bit 1 is the direction bit of the X speed.
26345 OR C Combine the bits.
26346 AND %00000011 Keep only bits 0-1 (the quadrant).
26348 SLA A Multiply the quadrant by 4.
26350 SLA A
26352 LD C,A Keep the quadrant in C.
26353 LD A,B Fetch the X speed.
26354 RRA Divide the X speed by four.
26355 RRA
26356 AND %00000111 Keep only bits 0-2.
26358 LD B,A Keep the X speed bits in B.
26359 LD A,E Fetch the Y speed.
26360 RLA Rotate A left.
26361 AND %00111000 Keep only bits 3-5.
26363 OR B Combine with the X speed bits.
26364 LD E,A E=the index into the table.
26365 LD D,0 D=0.
26367 LD HL,26683 Point HL at the table of angles (CarDirectionTable).
26370 ADD HL,DE Add the index to the start of the table.
26371 LD A,(HL) Fetch the angle from the table.
26372 CP 255 Compare the angle with 255.
26374 JR Z,HandlerCar_Colour If the car has no speed then keep the same sprite and jump to HandlerCar_Colour.
26376 BIT 2,C Jump to HandlerCar_SetSprite if the quadrant is not odd.
26378 JR Z,HandlerCar_SetSprite
26380 NEG Negate the angle.
26382 INC C Add 4 to C.
26383 INC C
26384 INC C
26385 INC C
HandlerCar_SetSprite 26386 ADD A,C Add the quadrant.
26387 AND %00001111 Keep only bits 0-3.
26389 ADD A,16 Add 16 to get the sprite ID.
26391 LD (IX+11),A Store the sprite ID.
26394 LD (IX+0),A Write the sprite ID to the first byte of the entity, as this is the sprite ID that DisplayEntity draws.
Set the colour of the car, which depends on whether it is day or night, then draw it.
HandlerCar_Colour 26397 LD C,(IX+3) Fetch the colour of the car.
26400 LD A,(24131) Fetch the day/night flag (Flag_DayNight).
26403 PUSH BC Stash BC on the stack.
26404 LD B,0 Clear the high byte of the table index.
26406 ADD A,C Add the colour to the day/night flag.
26407 LD C,A Keep the index into the table of car attributes in C.
26408 LD HL,26679 Point HL at the table of car attributes (CarAttributes).
26411 ADD HL,BC Add the index to the start of the table.
26412 LD A,(HL) Fetch the attribute of the car.
26413 LD (IX+3),A Write the attribute to the colour byte of the entity.
26416 CALL DisplayEntity Call DisplayEntity to erase the old car and draw the new one.
26419 CALL ColouriseSprite Call ColouriseSprite to set the attributes of the car.
26422 POP BC Restore BC from the stack.
26423 LD (IX+3),C Put the colour back in the entity.
26426 POP BC Restore the direction flags from the stack.
26427 SET 0,(IX+10) Set bit 0 of the flags (the car is drawn).
26431 JR HandlerCar_SteerX Jump to HandlerCar_SteerX.
The car is too far away to be seen. If it was drawn then erase it.
HandlerCar_TooFar 26433 BIT 0,(IX+10) If the car has not been drawn then jump to HandlerCar_SteerX.
26437 JR Z,HandlerCar_SteerX
26439 RES 0,(IX+10) Reset bit 0 of the flags (the car is no longer drawn).
26443 PUSH BC Stash the direction flags on the stack.
26444 CALL RemoveEntity Call RemoveEntity to erase the car.
26447 POP BC Restore the direction flags from the stack.
Steer the car towards the player, starting with the X speed.
HandlerCar_SteerX 26448 BIT 1,C Check if the car is to the left of the player.
26450 LD A,(IX+8) Fetch the X speed.
26453 JR NZ,HandlerCar_SteerLeft If the car is to the left of the player then jump to HandlerCar_SteerLeft.
The car is to the right of the player, so it wants to move towards lower X.
26455 BIT 7,A If the car is moving towards higher X then jump to HandlerCar_SlowDownX to slow it down.
26457 JR Z,HandlerCar_SlowDownX
26459 AND %00011111 Keep only bits 0-4 (the speed).
HandlerCar_SpeedUpX 26461 BIT 7,(IX+10) If it is the faster car then jump to HandlerCar_LimitX.
26465 JR NZ,HandlerCar_LimitX
26467 CP 31 Compare the speed with the limit of 31.
HandlerCar_CheckLimitX 26469 JR NC,HandlerCar_SteerY If the speed is at the limit then jump to HandlerCar_SteerY.
26471 INC (IX+8) Increase the X speed by one.
Do the same for the Y speed.
HandlerCar_SteerY 26474 BIT 0,C Check if the car is below the player.
26476 LD A,(IX+9) Fetch the Y speed.
26479 JR NZ,HandlerCar_SteerBelow If it is then jump to HandlerCar_SteerBelow.
The car is above the player, so it wants to move towards lower Y.
26481 BIT 7,A If the car is moving towards higher Y then jump to HandlerCar_SlowDownY to slow it down.
26483 JR Z,HandlerCar_SlowDownY
26485 AND %00011111 Keep only bits 0-4 (the speed).
HandlerCar_SpeedUpY 26487 BIT 7,(IX+10) If it is the faster car then jump to HandlerCar_LimitY.
26491 JR NZ,HandlerCar_LimitY
26493 CP 31 Compare the speed with the limit of 31.
HandlerCar_CheckLimitY 26495 JR NC,HandlerCar_Collisions If the speed is at the limit then jump to HandlerCar_Collisions.
26497 INC (IX+9) Increase the Y speed by one.
26500 JR HandlerCar_Collisions Jump to HandlerCar_Collisions.
Slow the car down. When it stops, the direction bit is set so that the car speeds up in the opposite direction.
HandlerCar_SlowDownX 26502 DEC (IX+8) Decrease the X speed by one.
26505 JR NZ,HandlerCar_SteerY If the speed is not zero then jump to HandlerCar_SteerY.
26507 SET 7,(IX+8) Set bit 7 of the X speed.
26511 JR HandlerCar_SteerY Jump to HandlerCar_SteerY.
The limit on the speed of the faster car is lower.
HandlerCar_LimitX 26513 CP 21 Compare the speed with the limit of 21.
26515 JR HandlerCar_CheckLimitX Jump to HandlerCar_CheckLimitX.
HandlerCar_LimitY 26517 CP 21 Compare the speed with the limit of 21.
26519 JR HandlerCar_CheckLimitY Jump to HandlerCar_CheckLimitY.
The car is to the left of the player, so it wants to move towards higher X.
HandlerCar_SteerLeft 26521 BIT 7,A If the car is moving towards higher X then jump to HandlerCar_SpeedUpX to speed it up.
26523 JR Z,HandlerCar_SpeedUpX
26525 AND %00011111 Keep only bits 0-4 (the speed).
26527 JR NZ,HandlerCar_SlowDownX If the car is still moving then jump to HandlerCar_SlowDownX to slow it down.
26529 LD (IX+8),0 Set the X speed to zero.
26533 JR HandlerCar_SteerY Jump to HandlerCar_SteerY.
HandlerCar_SlowDownY 26535 DEC (IX+9) Decrease the Y speed by one.
26538 JR NZ,HandlerCar_Collisions If the speed is not zero then jump to HandlerCar_Collisions.
26540 SET 7,(IX+9) Set bit 7 of the Y speed.
26544 JR HandlerCar_Collisions Jump to HandlerCar_Collisions.
The car is below the player, so it wants to move towards higher Y.
HandlerCar_SteerBelow 26546 BIT 7,A If the car is moving towards higher Y then jump to HandlerCar_SpeedUpY to speed it up.
26548 JR Z,HandlerCar_SpeedUpY
26550 AND %00011111 Keep only bits 0-4 (the speed).
26552 JR NZ,HandlerCar_SlowDownY If the car is still moving then jump to HandlerCar_SlowDownY to slow it down.
26554 LD (IX+9),0 Set the Y speed to zero.
Put the state back, then check whether the car has hit an object.
HandlerCar_Collisions 26558 LD (IX+0),2 Write 2 (the car state) to the first byte of the entity.
26562 BIT 0,(IX+10) Return if the car is not drawn.
26566 RET Z
26567 LD HL,24144 Point HL at the first object (Object_1_State).
26570 LD B,7 Set the object counter to 7.
HandlerCar_ObjectLoop 26572 BIT 6,(HL) If bit 6 of the object (a place name or collected cup) is set then jump to HandlerCar_NextObject to skip it.
26574 JR NZ,HandlerCar_NextObject
26576 INC HL Move on to the X position of the object.
26577 LD A,(HL) Fetch the X position of the object.
26578 SUB (IX+1) Take the X position of the car away to give the distance.
26581 JP P,HandlerCar_CheckDistanceX If the result is positive then jump to HandlerCar_CheckDistanceX.
26584 NEG Negate A.
HandlerCar_CheckDistanceX 26586 CP 10 If the object is 10 or more pixels away then jump to HandlerCar_NextObject_FromX.
26588 JR NC,HandlerCar_NextObject_FromX
26590 INC HL Move on to the Y position of the object.
26591 LD A,(HL) Fetch the Y position of the object.
26592 SUB (IX+2) Take the Y position of the car away to give the distance.
26595 JP P,HandlerCar_CheckDistanceY If the result is positive then jump to HandlerCar_CheckDistanceY.
26598 NEG Negate A.
HandlerCar_CheckDistanceY 26600 CP 10 If the object is 10 or more pixels away then jump to HandlerCar_NextObject_FromY.
26602 JR NC,HandlerCar_NextObject_FromY
The car has hit the object. Bounce off it, turning the car around in the X direction and changing the Y speed by a random amount.
26604 LD A,R Fetch a random number (from the Z80 refresh register).
26606 AND %00001111 Keep only bits 0-3.
26608 OR %10000000 Set bit 7.
26610 LD B,A Keep the random change in B.
26611 LD A,(IX+9) Fetch the Y speed.
26614 XOR B Change the Y speed by the random number.
26615 LD (IX+9),A Store the Y speed.
26618 LD A,(IX+8) Fetch the X speed.
26621 XOR %10000000 Flip bit 7 to turn the car around in the X direction.
26623 LD (IX+8),A Store the X speed.
26626 CALL PlayNoise Call PlayNoise to play a noise.
26629 JR HandlerCar_PlayerCollision Jump to HandlerCar_PlayerCollision.
Move on to the next object.
HandlerCar_NextObject 26631 INC HL Move on to the X position of the object.
HandlerCar_NextObject_FromX 26632 INC HL Move on to the Y position of the object.
HandlerCar_NextObject_FromY 26633 INC HL Move on to the next object.
26634 DJNZ HandlerCar_ObjectLoop Decrease the object counter by one and loop back to HandlerCar_ObjectLoop until all 7 objects have been checked.
The car has not hit anything. There is a small chance of the X speed being changed.
26636 LD A,R Fetch a random number (from the Z80 refresh register).
26638 AND %01111111 Keep only bits 0-6.
26640 JR NZ,HandlerCar_PlayerCollision If it is not zero (which is most of the time) then jump to HandlerCar_PlayerCollision.
26642 LD A,(IX+8) Fetch the X speed.
26645 XOR %00001111 Flip bits 0-3 to change the X speed.
26647 LD (IX+8),A Store the X speed.
Check if the car has hit the player, which is when the car is less than 12 pixels away in both directions.
HandlerCar_PlayerCollision 26650 LD A,(IX+1) Fetch the X position of the car.
26653 SUB 152 A=A - 152 (the X position of the player).
26655 JP P,HandlerCar_PlayerDistanceX If the result is positive then jump to HandlerCar_PlayerDistanceX.
26658 NEG Negate A.
HandlerCar_PlayerDistanceX 26660 CP 12 Compare the distance with 12.
26662 RET NC Return if the car is 12 or more pixels away.
26663 LD A,(IX+2) Fetch the Y position of the car.
26666 SUB 104 A=A - 104 (the Y position of the player).
26668 JP P,HandlerCar_PlayerDistanceY If the result is positive then jump to HandlerCar_PlayerDistanceY.
26671 NEG Negate A.
HandlerCar_PlayerDistanceY 26673 CP 12 Compare the distance with 12.
26675 RET NC Return if the car is 12 or more pixels away.
26676 JP HitObject_DestroyPlayer Jump to HitObject_DestroyPlayer to destroy the player.
Prev: 26152 Up: Map Next: 26679