| Chase H.Q. | Routines | 
| Prev: 8A36 | Up: Map | Next: 8C3A | 
| 
This handles slowing cars down to a stop when the perp has been caught. It also calculates and displays the bonus score.
 | ||||
| handle_perp_caught | 8A57 | LD A,($A230) | Return if perp_caught_phase is zero | |
| 8A5A | AND A | |||
| 8A5B | RET Z | |||
| 8A5C | DEC A | Jump to hpc_move_perp if it's currently one | ||
| 8A5D | JP Z,hpc_move_perp | |||
| 8A60 | DEC A | Jump to hpc_phase2 if it's currently two | ||
| 8A61 | JR Z,hpc_phase2 | |||
| 8A63 | DEC A | Jump to hpc_phase3 if it's currently three | ||
| 8A64 | JR Z,hpc_phase3 | |||
| 8A66 | DEC A | Jump to hpc_phase4 if it's currently four | ||
| 8A67 | JR Z,hpc_phase4 | |||
| 
Otherwise it's five or six.
 | ||||
| 8A69 | EX AF,AF' | Bank | ||
| 8A6A | LD A,($A231) | Return if transition_control != 0 | ||
| 8A6D | AND A | |||
| 8A6E | RET NZ | |||
| 8A6F | EX AF,AF' | Unbank | ||
| 8A70 | DEC A | Jump to hpc_phase5 if perp_caught_phase is currently five | ||
| 8A71 | JR Z,hpc_phase5 | |||
| 
Otherwise all of the perp caught phases are complete and we can move on to the next stage.
 | ||||
| 8A73 | POP HL | Throw away the return address. This causes the remainder of main_loop to be bypassed | ||
| 8A74 | CALL silence_audio_hook | Call silence_audio_hook | ||
| 8A77 | LD HL,$8007 | Increment wanted_stage_number | ||
| 8A7A | INC (HL) | |||
| 8A7B | JP main_loop | Exit via main_loop | ||
| hpc_phase5 | 8A7E | LD A,$06 | perp_caught_phase = 6 | |
| 8A80 | LD ($A230),A | |||
| 8A83 | LD A,$08 | Forward transition | ||
| 8A85 | JP setup_transition | Exit via setup_transition | ||
| 
This phase moves the car upwards and makes it pull to the left so that it appears to pull in in front of the perp's car.
 | ||||
| hpc_phase2 | 8A88 | LD A,($A22A) | Fetch car_y | |
| 8A8B | CP $10 | Jump to hpc_start_phase_3 if car_y >= 16 | ||
| 8A8D | JR NC,hpc_start_phase_3 | |||
| 
Move the car up and left.
 | ||||
| 8A8F | ADD A,$04 | car_y += 4 | ||
| 8A91 | LD ($A22A),A | |||
| 8A94 | LD HL,($A26C) | HL = road_pos + 12 -- move the car left by 12 | ||
| 8A97 | LD DE,$000C | |||
| 8A9A | ADD HL,DE | |||
| 8A9B | PUSH HL | Preserve HL | ||
| 8A9C | LD DE,$0126 | HL -= $126 -- are we at $126 yet? | ||
| 8A9F | SBC HL,DE | |||
| 8AA1 | POP HL | Restore HL | ||
| 8AA2 | JR C,hpc_set_road_pos | Jump to hpc_set_road_pos if HL < $126 | ||
| 
Otherwise the car's in the correct position now.
 | ||||
| 8AA4 | EX DE,HL | Move $126 in DE to HL | ||
| hpc_set_road_pos | 8AA5 | LD ($A26C),HL | road_pos = HL | |
| 
Not sure why we're changing fast_counter here.
 | ||||
| 8AA8 | LD A,($A23F) | A = fast_counter + 32 | ||
| 8AAB | ADD A,$20 | |||
| 8AAD | RET C | Return if result > 255 | ||
| 8AAE | LD ($A23F),A | fast_counter = A | ||
| 8AB1 | RET | Return | ||
| hpc_start_phase_3 | 8AB2 | LD A,$03 | perp_caught_phase = 3 | |
| 8AB4 | LD ($A230),A | |||
| 8AB7 | INC A | Self modify the 'LD A,x' at hpc_phase3 below to load 4 | ||
| 8AB8 | LD ($8ABF),A | |||
| 8ABB | JP fill_attributes | Exit via fill_attributes | ||
| hpc_phase3 | 8ABE | LD A,$00 | Self modified by 8AB8 above -- meaning? | |
| 8AC0 | DEC A | A-- | ||
| 8AC1 | LD ($8ABF),A | Self modify 'LD A' at hpc_phase3 to load A | ||
| 8AC4 | RET NZ | Return if A != 0 | ||
| 8AC5 | LD A,$04 | perp_caught_phase = 4 | ||
| 8AC7 | LD ($A230),A | |||
| 8ACA | LD HL,($5D06) | Point HL at addrof_arrest_messages | ||
| 8ACD | LD A,$01 | Set transition_control to 1 (draw mugshots) | ||
| 8ACF | JP setup_overlay_messages_with_A | Exit via setup_overlay_messages_with_A | ||
| hpc_phase4 | 8AD2 | LD A,($A139) | Call relocated handle_perp_caught_128k if in 128K mode | |
| 8AD5 | AND A | |||
| 8AD6 | CALL NZ,$8193 | |||
| 8AD9 | LD A,($A231) | Return if transition_control != 0 | ||
| 8ADC | AND A | |||
| 8ADD | RET NZ | |||
| 8ADE | LD A,($A139) | Call relocated handle_perp_caught_128k if in 128K mode | ||
| 8AE1 | AND A | |||
| 8AE2 | CALL NZ,$8193 | |||
| 8AE5 | LD A,$05 | perp_caught_phase = 5 | ||
| 8AE7 | LD ($A230),A | |||
| 
Calculate level clear bonus (<stage number> * 100,000 points for the first try, 10,000 on retries).
 | ||||
| 8AEA | LD H,$30 | '0' (second digit) | ||
| 8AEC | LD A,($8007) | D = wanted_stage_number | ||
| 8AEF | LD D,A | |||
| 8AF0 | ADD A,H | L = wanted_stage_number + '0' | ||
| 8AF1 | LD L,A | |||
| 
Completing the level on the first try awards <stage number> * 100,000 points.
 | ||||
| 8AF2 | LD A,($8006) | Jump to hpc_set_score if retry_count is zero | ||
| 8AF5 | AND A | |||
| 8AF6 | JR Z,hpc_set_score | |||
| 
Divide bonus by 10 if stage was retried.
 | ||||
| 8AF8 | RLC D | Neutralise the upcoming shift so bonus is divided by 10 | ||
| 8AFA | RLC D | |||
| 8AFC | RLC D | |||
| 8AFE | RLC D | |||
| 8B00 | LD H,L | H = L -- becomes second ASCII digit | ||
| 8B01 | LD L,$20 | L = ' ' -- first ASCII digit replaced with space | ||
| hpc_set_score | 8B03 | LD ($8C6F),HL | Set first two digits of the clear bonus to HL, "LH0,000" | |
| 
Set score increment to (<stage number> * 100,000).
 | ||||
| 8B06 | RLC D | Move wanted_stage_number to first digit | ||
| 8B08 | RLC D | |||
| 8B0A | RLC D | |||
| 8B0C | RLC D | |||
| 8B0E | XOR A | Zero other digits | ||
| 8B0F | LD E,A | |||
| 8B10 | CALL increment_score | Call increment_score (with D,E,A) | ||
| 
Calculate time remaining bonus.
 | ||||
| 8B13 | LD A,($A17E) | Get time remaining (BCD) | ||
| 8B16 | LD ($8C8A),A | Set A in "TIME BONUS Ax X 5000" as a temporary location | ||
| 8B19 | LD C,A | Copy time remaining (BCD) | ||
| 8B1A | RLCA | Extract high digit | ||
| 8B1B | RLCA | |||
| 8B1C | RLCA | |||
| 8B1D | RLCA | |||
| 8B1E | AND $0F | |||
| 8B20 | JR NZ,hpc_have_high_digit | Jump if it's non-zero | ||
| 
Otherwise write out a space character.
 | ||||
| hpc_no_high_digit | 8B22 | LD A,$20 | Put a space character in A' | |
| 8B24 | EX AF,AF' | |||
| 8B25 | JR hpc_store_time_bonus_high | Jump to store | ||
| hpc_have_high_digit | 8B27 | LD B,A | Multiplier (high digit) | |
| 8B28 | ADD A,$30 | Make it ASCII | ||
| 8B2A | EX AF,AF' | Bank it | ||
| 8B2B | LD DE,$0500 | DE = $0500 (this is 50,000 here because we're doing the tens) | ||
| hpc_increment_score_loop_1 | 8B2E | XOR A | Clear A since increment_score will corrupt it | |
| 8B2F | CALL increment_score | Call increment_score (with D,E,A) | ||
| 8B32 | DJNZ hpc_increment_score_loop_1 | Loop while B > 0 | ||
| hpc_store_time_bonus_high | 8B34 | EX AF,AF' | Unbank ASCII of high digit | |
| 8B35 | LD ($8C8A),A | Store as x in "TIME BONUS xy X 5000" | ||
| 8B38 | LD A,C | Copy time remaining (BCD) | ||
| 8B39 | AND $0F | Extract low digit | ||
| 8B3B | JR Z,hpc_store_time_bonus_low | Jump if zero | ||
| 
Bug: This banks the low digit in A which the LD B,A then expects to be able to use. To fix this transpose the next two instructions. (Credit: Russell Marks)
 | ||||
| hpc_have_low_digit | 8B3D | EX AF,AF' | Bank low digit | |
| 8B3E | LD B,A | Multiplier (should be low digit but bugged) | ||
| 8B3F | LD DE,$0050 | DE = $0050 (this is 5,000 here because we're doing the ones) | ||
| hpc_increment_score_loop_2 | 8B42 | XOR A | Clear A since increment_score will corrupt it | |
| 8B43 | CALL increment_score | Call increment_score (with D,E,A) | ||
| 8B46 | DJNZ hpc_increment_score_loop_2 | Loop while B > 0 | ||
| hpc_store_time_bonus_low | 8B48 | EX AF,AF' | Unbank low digit | |
| 8B49 | ADD A,$30 | Make it ASCII | ||
| 8B4B | LD ($8C8B),A | Store as y in "TIME BONUS xy X 5000" | ||
| 
Display score.
 | ||||
| 8B4E | LD BC,$0400 | Iterations = 4; Clear C flag byte (set if seen a digit?) | ||
| 8B51 | LD DE,$8005 | Point DE at last digit of score_bcd (big end) | ||
| 8B54 | LD HL,$8CA8 | Point HL at x in "SCORE x " - the ten millions? | ||
| hpc_score_loop | 8B57 | LD A,(DE) | Fetch a pair of digits from score_bcd | |
| 8B58 | RLCA | Extract the high digit | ||
| 8B59 | RLCA | |||
| 8B5A | RLCA | |||
| 8B5B | RLCA | |||
| 8B5C | AND $0F | |||
| 8B5E | JR NZ,hpc_score_have_high_digit | Jump if it's non-zero | ||
| hpc_score_zero_high_digit | 8B60 | RLC C | Seen a digit yet? | |
| 8B62 | JR C,hpc_score_have_high_digit | Jump if so | ||
| 8B64 | LD A,$20 | Space | ||
| 8B66 | JR hpc_score_store_high | Jump to store | ||
| hpc_score_have_high_digit | 8B68 | LD C,$FF | Set "saw a digit" flag | |
| 8B6A | ADD A,$30 | Make it ASCII | ||
| hpc_score_store_high | 8B6C | LD (HL),A | Store ASCII high digit | |
| 8B6D | INC HL | |||
| 8B6E | LD A,(DE) | Extract the low digit | ||
| 8B6F | AND $0F | |||
| 8B71 | JR NZ,hpc_score_have_low_digit | Jump if it's non-zero | ||
| hpc_score_zero_low_digit | 8B73 | RLC C | Seen a digit yet? | |
| 8B75 | JR C,hpc_score_have_low_digit | Jump if so | ||
| 8B77 | LD A,$20 | Space | ||
| 8B79 | JR hpc_score_store_low | Jump to store | ||
| hpc_score_have_low_digit | 8B7B | LD C,$FF | Set "saw a digit" flag | |
| 8B7D | ADD A,$30 | Make it ASCII | ||
| hpc_score_store_low | 8B7F | LD (HL),A | Store ASCII low digit | |
| 8B80 | INC HL | |||
| 8B81 | DEC DE | Advance (backwards) to next digits of score_bcd | ||
| 8B82 | DJNZ hpc_score_loop | Loop hpc_score_loop while B > 0 | ||
| 8B84 | DEC HL | Terminate the string | ||
| 8B85 | SET 7,(HL) | |||
| 8B87 | LD HL,$8C58 | Point at "CLEAR BONUS ..." "TIME BONUS ..." "SCORE ..." messages | ||
| 8B8A | JP setup_overlay_messages | Call setup_overlay_messages | ||
| 
This is phase 1 of the caught process. Set the perp's horizontal position.
 | ||||
| hpc_move_perp | 8B8D | LD A,($A18D) | Load the perp car's horizontal position (as byte) | |
| 8B90 | LD C,$23 | Compare it to 35 (left hand side of road) | ||
| 8B92 | CP C | |||
| 8B93 | LD B,$05 | Change by 5 | ||
| 8B95 | JR Z,hpc_assign_perp_pos | Jump if no change required | ||
| 8B97 | JR C,hpc_change_perp_pos | Jump to increase by 5 if pos < 35 | ||
| 8B99 | LD B,$FB | Otherwise decrease by 5 | ||
| hpc_change_perp_pos | 8B9B | ADD A,B | new pos = old pos + delta | |
| 8B9C | LD C,A | |||
| hpc_assign_perp_pos | 8B9D | LD A,C | Set the perp car's horizontal position (as byte) | |
| 8B9E | LD ($A18D),A | |||
| 
Now move the hero car. This section is similar to code in cpu_driver.
 | ||||
| 8BA1 | LD HL,($A26C) | Get road position | ||
| 
If we're on the left, go right.
 | ||||
| 8BA4 | PUSH HL | Subtract centre-left edge. Carry flag will be set if we're on the right hand side of it | ||
| 8BA5 | LD DE,$0105 | |||
| 8BA8 | SBC HL,DE | |||
| 8BAA | POP HL | |||
| 8BAB | LD A,$09 | Set input ACCELERATE + RIGHT | ||
| 8BAD | JR NC,hpc_assign_hero_pos | Jump to hpc_assign_hero_pos if we're on the left | ||
| 
If we're on the right, go left.
 | ||||
| 8BAF | LD DE,$00F5 | Subtract centre-right edge. Carry flag will be set if we're on the right hand side of it | ||
| 8BB2 | SBC HL,DE | |||
| 8BB4 | LD A,$0A | Set input ACCELERATE + LEFT | ||
| 8BB6 | JR C,hpc_assign_hero_pos | Jump to hpc_assign_hero_pos if we're on the right | ||
| 
Otherwise we're in the centre zone.
 | ||||
| 8BB8 | LD A,$08 | Set input ACCELERATE | ||
| hpc_assign_hero_pos | 8BBA | LD C,A | Move input into C for the moment | |
| 8BBB | AND $03 | Mask off LEFT and RIGHT flags | ||
| 8BBD | JR NZ,hpc_perp_too_far_away | Jump to hpc_perp_too_far_away if either is set | ||
| 
Not turning. Are we within distance?
 | ||||
| hpc_check_distance | 8BBF | LD A,($A189) | Load perp's distance (low byte) | |
| 8BC2 | CP $03 | Jump if distance >= 3 | ||
| 8BC4 | JR NC,hpc_perp_too_far_away | |||
| 
Count down while we're within distance of the perp.
 | ||||
| 8BC6 | LD HL,$A173 | Decrement perp_halt_counter | ||
| 8BC9 | DEC (HL) | |||
| 8BCA | JR NZ,hpc_perp_too_far_away | Jump if countdown is non-zero | ||
| 
Countdown hit zero: stop.
 | ||||
| 8BCC | XOR A | speed = 0 | ||
| 8BCD | LD D,A | |||
| 8BCE | LD E,A | |||
| 8BCF | LD ($A24A),DE | |||
| 8BD3 | LD ($A18C),A | *$A18C = 0 -- distance related? [reset by set_up_stage] | ||
| 8BD6 | INC A | Set perp's distance to 1 | ||
| 8BD7 | LD ($A189),A | |||
| 8BDA | INC A | Set perp_caught_phase to 2 | ||
| 8BDB | LD ($A230),A | |||
| 8BDE | INC A | Set smoke to 3 | ||
| 8BDF | LD ($A24F),A | |||
| 8BE2 | JP hpc_set_perp_pos_or_accel | Jump to hpc_set_perp_pos_or_accel (with DE = 0) | ||
| 
HL = 350 - (16 - <distance related>) * 20  -- compared to speed later Arrive here if we're turning or the perp is too far away.
 | ||||
| hpc_perp_too_far_away | 8BE5 | LD A,($A189) | Load perp's distance | |
| 8BE8 | LD HL,$015E | HL = 350 -- compared to speed later | ||
| 8BEB | CP $0F | Jump if distance >= 15 | ||
| 8BED | JR NC,hpc_perp_far | |||
| 8BEF | CPL | A = 16 - distance | ||
| 8BF0 | ADD A,$0F | |||
| 
Calculate 350 - A * 20.
 | ||||
| 8BF2 | LD DE,$0014 | DE = 20 | ||
| 8BF5 | LD B,A | B = A -- iterations | ||
| hpc_subtract_loop | 8BF6 | SBC HL,DE | HL -= DE | |
| 8BF8 | DJNZ hpc_subtract_loop | Loop while B > 0 | ||
| hpc_perp_far | 8BFA | EX DE,HL | Put result in DE | |
| 8BFB | LD HL,($A24A) | Load speed | ||
| 8BFE | PUSH HL | Preserve speed | ||
| 8BFF | SBC HL,DE | Jump if speed < DE -- DE is e.g. 350 | ||
| 8C01 | JR C,hpc_set_gear | |||
| 
Slow down to match the perp. C is a user input here.
 | ||||
| 8C03 | RES 3,C | Clear input ACCELERATE | ||
| 8C05 | LD DE,$0032 | Jump if HL < 50 | ||
| 8C08 | SBC HL,DE | |||
| 8C0A | JR C,hpc_set_gear | |||
| 8C0C | SET 2,C | Set input BRAKE | ||
| hpc_set_gear | 8C0E | POP HL | Restore speed | |
| 8C0F | LD DE,$0096 | Calculate speed - 150 | ||
| 8C12 | SBC HL,DE | |||
| 8C14 | LD A,($A253) | Load gear | ||
| 8C17 | SBC A,$00 | Set gear to low if speed < 150, otherwise high | ||
| 8C19 | JR NZ,hpc_assign_user_input | |||
| 8C1B | SET 4,C | Set input GEAR | ||
| hpc_assign_user_input | 8C1D | LD A,C | Set user input | |
| 8C1E | LD ($A0D5),A | |||
| hpc_check_perp_accel | 8C21 | LD HL,($A195) | Load the (accel?) of the perp's car into HL | |
| 8C24 | PUSH HL | Compare it to 70 | ||
| 8C25 | LD DE,$0046 | |||
| 8C28 | SBC HL,DE | |||
| 8C2A | POP HL | |||
| 8C2B | JR Z,hpc_set_perp_pos_or_accel | Jump to hpc_set_perp_pos_or_accel if result <= 70, with DE = 70 | ||
| 8C2D | JR C,hpc_set_perp_pos_or_accel | |||
| 8C2F | LD DE,$0005 | Otherwise reduce it by 5 with result in DE | ||
| 8C32 | SBC HL,DE | |||
| 8C34 | EX DE,HL | |||
| 
This entry point is used by the routine at fully_smashed.
 | ||||
| hpc_set_perp_pos_or_accel | 8C35 | LD ($A195),DE | Set the horizontal position (or accel?) of the perp's car to DE -- and it's writing A196 too is that the high byte? | |
| 8C39 | RET | Return | ||
| Prev: 8A36 | Up: Map | Next: 8C3A |