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 |