| Chase H.Q. | Routines |
| Prev: A27A | Up: Map | Next: A4B8 |
|
Called every frame to see whether the hero car has left the road or hit something at the roadside.
If the fork is visible and the fork countdown has reached zero the whole job is handed to check_fork_scenery_collisions. Otherwise the last two entries of the centre x-position table say whether the car is on the road, half off it or fully off, and that becomes off_road and the crash spin. Inside a tunnel going off the road means hitting a wall, and the high byte of road_pos picks which one.
Last, the right and then the left object IDs are read from the road buffer, their collision widths looked up, and scenery_hit is called if the car's horizontal position falls inside the object's zone.
Used by the routines at main_loop and drive_attract_demo.
|
||||
| check_scenery_collisions | A399 | LD HL,$0048 | HL = $0048 | |
| A39C | LD DE,$01D8 | DE = $01D8 -- constant indicates road centre? | ||
| A39F | EXX | Bank | ||
| A3A0 | LD A,($A265) | Load fork_visible | ||
| A3A3 | AND A | Set flags | ||
| A3A4 | JR Z,csc_fork_not_visible_or_fork_in_progress | Jump to csc_fork_not_visible_or_fork_in_progress if zero | ||
|
The fork is visible.
|
||||
| A3A6 | LD A,($A266) | Load fork_countdown | ||
| A3A9 | AND A | Set flags | ||
| A3AA | JP Z,check_fork_scenery_collisions | Exit via check_fork_scenery_collisions if zero | ||
|
Currently forking.
|
||||
| A3AD | DEC A | Decrement the fork_countdown value | ||
| A3AE | RET Z | Return if zero -- can't collide immediately before fork? | ||
|
Check left hand side of car. $EAFE and $EAFC are the last two words of the page layout_objects fills: the left and right hand x-positions for the nearest road slice, pushed in that order from $EB00 downwards. They are rewritten every frame, which is why they vibrate in the debugger. They say where a roadside object on each side would stand, not that one is there.
|
||||
| csc_fork_not_visible_or_fork_in_progress | A3AF | LD HL,($EAFE) | Read signed word at $EAFE | |
|
When car off road left ~ 176 When car half off road left ~ 133 When car in lane 1 ~ 85 When car in lane 2 ~ 38 When car in lane 3 ~ -36 When car in lane 4 ~ -84 When car half off road right ~ -153 When car off road right ~ -186
|
||||
| A3B2 | LD A,H | Set flags from sign of word: 0 when hero car on left side, 255 if right | ||
| A3B3 | AND A | |||
| A3B4 | JR NZ,csc_clear_trigger_lane_change_sfx | Jump to csc_clear_trigger_lane_change_sfx if non-zero -- right side | ||
|
Otherwise left side.
|
||||
| A3B6 | PUSH HL | Jump to csc_clear_trigger_lane_change_sfx if HL < 64 | ||
| A3B7 | LD BC,$0040 | |||
| A3BA | SBC HL,BC | |||
| A3BC | POP HL | |||
| A3BD | JR C,csc_clear_trigger_lane_change_sfx | |||
| A3BF | PUSH HL | Jump to csc_check_right_hand if HL < 106 | ||
| A3C0 | LD C,$6A | |||
| A3C2 | SBC HL,BC | |||
| A3C4 | POP HL | |||
| A3C5 | JR C,csc_check_right_hand | |||
| A3C7 | LD C,$85 | HL -= 133 | ||
| A3C9 | SBC HL,BC | |||
| A3CB | INC A | A++ -- A == 1 => partially off-road (note: A is zero here) | ||
| A3CC | JR C,csc_store_off_road | Jump to csc_store_off_road if HL < 133 (note: INC A doesn't affect carry) | ||
| A3CE | INC A | A++ -- A == 2 => fully off-road | ||
| A3CF | JR csc_store_off_road | Jump to csc_store_off_road | ||
| csc_clear_trigger_lane_change_sfx | A3D1 | XOR A | trigger_left_hand_passed_object_sfx = 0. Reached only when the car is alongside the left hand object, which stops the passed-object sound effect from firing | |
| A3D2 | LD ($A23D),A | |||
|
Check right hand side of car. Car off road left ~ (not hit!) Car half off road left ~ 0x170 ish Car in lane 1 ~ 0x164 Car in lane 2 ~ 0x117 Car in lane 3 ~ 0xe0 Car in lane 4 ~ 0x98 Car half off road right ~ 0x4e Car off road right ~ 0x4b
|
||||
| csc_check_right_hand | A3D5 | LD HL,($EAFC) | Read signed word at $EAFC -- the right hand x-position for the nearest slice, where csc_fork_not_visible_or_fork_in_progress read the left | |
| A3D8 | LD A,H | Set flags from sign of word: 1 when hero car on left side, 0 if right | ||
| A3D9 | AND A | |||
| A3DA | LD A,$00 | Init value for trigger_right_hand_passed_object_sfx -- this must stop the passed object sfx from playing | ||
| A3DC | JR NZ,csc_store_sfx_trigger | Jump to csc_store_sfx_trigger if non-zero | ||
| A3DE | PUSH HL | Jump to csc_store_sfx_trigger if HL >= 190 | ||
| A3DF | LD BC,$00BE | |||
| A3E2 | SBC HL,BC | |||
| A3E4 | POP HL | |||
| A3E5 | JR NC,csc_store_sfx_trigger | |||
| A3E7 | PUSH HL | Jump to csc_store_off_road if HL >= 142 | ||
| A3E8 | LD BC,$008E | |||
| A3EB | SBC HL,BC | |||
| A3ED | POP HL | |||
| A3EE | JR NC,csc_store_off_road | |||
| A3F0 | LD C,$7C | HL -= 124 | ||
| A3F2 | SBC HL,BC | |||
| A3F4 | INC A | A++ -- A == 1 => partially off-road | ||
| A3F5 | JR NC,csc_store_off_road | Jump to csc_store_off_road if no carry | ||
| A3F7 | INC A | A++ -- A == 2 => fully off-road | ||
| A3F8 | JR csc_store_off_road | Jump to csc_store_off_road | ||
| csc_store_sfx_trigger | A3FA | LD ($A23C),A | trigger_right_hand_passed_object_sfx = A | |
| csc_store_off_road | A3FD | LD ($A23E),A | off_road = A -- 0/1/2 => on-road/one wheel off-road/both wheels off-road | |
| A400 | AND A | Set flags | ||
| A401 | LD C,$00 | C = 0 (not self modified) | ||
| A403 | JR Z,csc_store_crash_spin | Jump if not off road | ||
|
Otherwise we're off-road.
|
||||
| A405 | LD A,($A240) | Load road_buffer_offset.lo into A | ||
| A408 | ADD A,$40 | Add 64 so it's the lanes data offset | ||
| A40A | LD L,A | Point HL at road buffer lanes data | ||
| A40B | LD H,$EE | |||
| A40D | LD A,(HL) | Read lane data byte | ||
| A40E | BIT 6,A | Test bit 6 -- clear for plain road, set for a tunnel, | ||
| A410 | JR Z,csc_store_crash_spin | a fork or a dirt track. Jump if clear | ||
| A412 | RLA | Test bit 7 | ||
| A413 | JR C,csc_store_crash_spin | Jump if set | ||
|
We arrive here if we're far into the tunnel.
|
||||
| A415 | BIT 3,A | Test bit 3 (was bit 2 before RLA) | ||
| A417 | LD A,($A26D) | Load road_pos high byte | ||
| A41A | JR Z,csc_a426 | Jump if bit 3 clear | ||
| A41C | LD C,A | C = A | ||
| A41D | LD A,$14 | A = 20 | ||
| A41F | EX AF,AF' | Bank it | ||
| A420 | LD A,C | A = C & 1 | ||
| A421 | AND $01 | |||
| A423 | JP scenery_hit | Exit via scenery_hit | ||
| csc_a426 | A426 | LD HL,$00D1 | HL = 209 | |
| A429 | LD DE,$0195 | DE = 405 | ||
| A42C | EXX | Unbank from A39F | ||
| A42D | AND A | Set flags -- A is still road_pos high byte, loaded before the jump in; EXX doesn't touch AF | ||
| A42E | LD C,$01 | C = 1 | ||
| A430 | JR Z,csc_hit_tunnel_wall | |||
| A432 | INC C | C = 2 | ||
| csc_hit_tunnel_wall | A433 | PUSH BC | Preserve BC | |
| A434 | LD BC,$0604 | Effect 6 (tunnel wall hit), Priority 4 | ||
| A437 | CALL start_sfx | Call start_sfx | ||
| A43A | POP BC | Restore BC | ||
| csc_store_crash_spin | A43B | LD A,C | A = C | |
| A43C | LD ($B3DC),A | ($B3DC) = A | ||
| A43F | EXX | |||
| A440 | LD ($B396),HL | ($B396) = HL | ||
| A443 | LD ($B3A4),DE | ($B3A4) = DE | ||
| A447 | AND A | Set flags from A (was C) | ||
| A448 | RET NZ | Return if non-zero | ||
|
-- RIGHT SIDE OBJECT HIT CHECKING --
|
||||
| A449 | LD A,($A240) | Load road_buffer_offset.lo into A | ||
| A44C | ADD A,$60 | Add 96 so it's the right side objects data offset | ||
| A44E | LD L,A | Point HL at road buffer right side objects data | ||
| A44F | EX AF,AF' | Bank road buffer offset | ||
| A450 | LD H,$EE | (cont.) | ||
| A452 | LD A,($A240) | Load road_buffer_offset.lo into A | ||
| A455 | RLA | Top bit -> carry | ||
| A456 | LD A,(HL) | Read a right side object data byte | ||
| A457 | JR NC,csc_a45a | Jump if top bit was clear | ||
| A459 | INC L | L++ -- so if the top bit of the road buffer offset is set we take next byte? | ||
| csc_a45a | A45A | OR (HL) | OR in the (next) byte | |
| A45B | JR Z,csc_a480 | Jump if it's zero -- no object | ||
|
Build a graphics_defs address.
|
||||
| A45D | LD C,A | HL = (*addrof_right_hand_objects)[A * 7] | ||
| A45E | ADD A,A | |||
| A45F | ADD A,A | |||
| A460 | ADD A,A | |||
| A461 | SUB C | |||
| A462 | LD C,A | |||
| A463 | LD B,$00 | |||
| A465 | LD HL,($5CFA) | |||
| A468 | ADD HL,BC | |||
|
Read collision values.
|
||||
| A469 | LD C,(HL) | C = *HL++ -- e.g. $5E5B. a higher value | ||
| A46A | INC HL | |||
| A46B | LD E,(HL) | E = *HL++ -- e.g. $5E5C. a lower value | ||
| A46C | INC HL | |||
| A46D | LD A,(HL) | A = *HL -- e.g. $5E5D. a speed cap | ||
| A46E | LD D,B | DE = E, BC = C -- B is zero from A463 above | ||
|
Check for collisions with scenery (right hand side).
|
||||
| A46F | LD HL,($EAFC) | HL = *$EAFC -- near end of road drawing words (centre)... must be position of car | ||
| A472 | PUSH HL | Jump to csc_a480 if HL >= BC | ||
| A473 | SBC HL,BC | |||
| A475 | POP HL | |||
| A476 | JR NC,csc_a480 | |||
| A478 | SBC HL,DE | Jump to csc_a480 if HL < DE | ||
| A47A | JR C,csc_a480 | |||
| A47C | EX AF,AF' | Bank speed cap | ||
| A47D | XOR A | Set flip flag to 0 | ||
| A47E | JR csc_hit_scenery | Jump to csc_hit_scenery | ||
| csc_a480 | A480 | EX AF,AF' | Unbank road buffer offset or/and bank mystery value in A | |
|
-- LEFT SIDE OBJECT HIT CHECKING --
|
||||
| A481 | ADD A,$20 | Add 32 so it's the left side objects data offset | ||
| A483 | LD L,A | Point HL at road buffer left side objects data | ||
| A484 | LD H,$EE | |||
| A486 | LD A,($A240) | Load road_buffer_offset.lo into A | ||
| A489 | RLA | Top bit -> carry | ||
| A48A | LD A,(HL) | Read a left side object data byte | ||
| A48B | JR NC,csc_a48e | Jump if top bit of road_buffer_offset.lo was clear | ||
| A48D | INC L | Advance to next data byte | ||
| csc_a48e | A48E | OR (HL) | OR in the (next) byte | |
| A48F | RET Z | Return if combined value is zero -- no object | ||
| A490 | LD C,A | HL = (*addrof_left_hand_objects)[A * 7] -- indexing left hand objects | ||
| A491 | ADD A,A | |||
| A492 | ADD A,A | |||
| A493 | ADD A,A | |||
| A494 | SUB C | |||
| A495 | LD C,A | |||
| A496 | LD B,$00 | |||
| A498 | LD HL,($5D00) | |||
| A49B | ADD HL,BC | |||
|
Read collision values.
|
||||
| A49C | LD C,(HL) | C = *HL++ -- must be min/left hit coord | ||
| A49D | INC HL | |||
| A49E | LD E,(HL) | E = *HL++ -- must be max/right hit coord | ||
| A49F | INC HL | |||
| A4A0 | LD A,(HL) | A = *HL -- a speed cap | ||
| A4A1 | LD D,B | DE = E, BC = C -- B is zero from A496 above | ||
|
Check for collisions with scenery (left hand side).
|
||||
| A4A2 | LD HL,($EAFE) | HL = *$EAFE -- suspected position of car/road | ||
| A4A5 | PUSH HL | Return if HL < BC | ||
| A4A6 | SBC HL,BC | |||
| A4A8 | POP HL | |||
| A4A9 | RET C | |||
| A4AA | SBC HL,DE | Return if HL >= DE | ||
| A4AC | RET NC | |||
| A4AD | EX AF,AF' | Bank speed cap | ||
| A4AE | LD A,$01 | Set flip flag to 1 | ||
|
Arrive here if hit scenery, e.g. drove into a tree or a lamp post.
|
||||
| csc_hit_scenery | A4B0 | PUSH AF | Preserve AF -- suspected left hand flag | |
| A4B1 | LD BC,$0403 | Effect 4 (scenery crash), Priority 3 | ||
| A4B4 | CALL start_sfx | Call start_sfx | ||
| A4B7 | POP AF | Restore AF | ||
|
FALLTHROUGH
|
||||
| Prev: A27A | Up: Map | Next: A4B8 |