Prev: B8D2 Up: Map Next: BB69
B9F4: Lays out the road
Called once a frame from read_map. It scans up to 20 lane data entries looking for a fork marker, a byte where (byte & $E1) == $E1, and takes one of two paths.
No fork: build the curve table for a straight road, then fill 104 entries each of the centre, centre right and centre left x-position tables by interpolating between the left and right tables that are already populated.
Fork: record which fork the player is taking, start the chatter, advance the spawn accumulator and the fork distance, then build the curve table twice, once per half of the road, moving road_pos temporarily for each. The fork loop runs as many iterations as the height at the fork calls for and the remaining entries are filled by falling into the non-fork path.
Used by the routines at main_loop, drive_attract_demo and escape_scene.
layout_road B9F4 LD A,($A240) Load road_buffer_offset.lo into A [as byte]
B9F7 ADD A,$40 Add 64 so it's the lanes data offset (wrapping around)
B9F9 LD E,A Point DE at road buffer lanes data
B9FA LD D,$EE
Count the distance to the forked road.
B9FC LD BC,$16E1 B = 22 iterations, C = $E1 (a mask) [forked road is $ED]
B9FF LD L,$00 Counter
lr_loop1 BA01 LD A,(DE) Load a lanes byte
BA02 AND C Jump to lr_forked_road if (lanes byte & $E1) == $E1
BA03 CP C
BA04 JP Z,lr_forked_road
BA07 INC E Advance to next lanes byte (wrapping around)
BA08 INC L Increment counter
BA09 DJNZ lr_loop1 Loop while B
No forked road found.
The road is still rendered if the following call is nopped out, but it's in the wrong position.
lr_no_fork BA0B CALL build_curve_table Call build_curve_table
BA0E LD ($BA4E),SP Self modify 'LD SP' @ lr_exit to restore SP on exit
BA12 LD SP,$EC30 Put $EC30 (road right) in SP (so we can use POP for speed)
BA15 LD A,$30 Iterate from $30 to $00 in steps of 2 = 104 iterations
Note that the fork case branches back here.
lr_calc_single_lane BA17 LD HL,$BA36 Self modify BA35 to load $EA30 upwards (road centre)
BA1A LD DE,$BA40 Self modify BA3F to load $EB30 upwards (road centre right)
BA1D LD BC,$BA45 Self modify BA44 to load $E930 upwards (road centre left)
lr_ba20 BA20 LD (HL),A Self modify the locations setup above
BA21 LD (DE),A
BA22 LD (BC),A
BA23 LD ($BA29),A Self modify BA27 (below) to load ($E800 | A) (road left)
BA26 EXX Bank
Centre = Left + (Right - Left) / 2
BA27 LD DE,($E800) DE = *$E8xx (xx = self modified) (road left)
BA2B POP HL Read from $ECxx
BA2C SBC HL,DE HL = *$ECxx - *$E8xx [total width]
BA2E SRA H Divide HL by 2 [halve total width]
BA30 RR L
BA32 LD B,H BC = HL [keep a copy]
BA33 LD C,L
BA34 ADD HL,DE HL += DE == (*$ECxx - *$E8xx) / 2 + *$E8xx [calc centre from left]
BA35 LD ($EA00),HL *$EAxx = HL (xx = self modified) (road centre) [store centre pos]
BA38 LD D,B DE = BC [copy halved width again]
BA39 LD E,C
BA3A SRA B Divide BC by 2 again for quarter width
BA3C RR C
BA3E ADD HL,BC == [centre] + [quarter width]
BA3F LD ($EB00),HL *$EBxx = HL (xx = self modified) (road centre right) [store centre-right pos]
BA42 SBC HL,DE == [[centre] + [quarter width]] - [half total width]
BA44 LD ($E900),HL *$E9xx = HL (xx = self modified) (road centre left) [store centre-left pos]
BA47 INC A A += 2 [remember A's not banked by EXX]
BA48 INC A
BA49 EXX Unbank
BA4A JP NZ,lr_ba20 Loop while A
lr_exit BA4D LD SP,$0000 Restore original SP (self modified)
BA50 RET Return
Handle a forked road.
lr_forked_road BA51 LD A,L
BA52 LD ($A266),A fork_countdown = A
BA55 LD H,$E3 HL = $E3xx
BA57 LD A,$60 Set fork_visible
BA59 LD ($A265),A
BA5C SUB (HL) A = 106 - (A - *HL) -- HL is $E3xx
BA5D CPL
BA5E ADD A,$69
BA60 PUSH AF Preserve A
BA61 LD HL,($A267) Load fork_distance
BA64 LD A,(DE) A = *DE & 4 -- DE is the lanes byte ptr
BA65 AND $04
BA67 JR NZ,lr_badf Jump if non-zero
Lanes byte & 4 is zero. Hit when the road forks (during the fork itself).
BA69 LD A,($A269) A = fork_in_progress - 1
BA6C DEC A
BA6D JR Z,lr_check_spawning Jump to lr_check_spawning if zero
BA6F NEG fork_in_progress = -A
BA71 LD ($A269),A
BA74 LD DE,($A26C) Get road position
BA78 LD A,$01 A = 1
BA7A DEC D D--
BA7B JP M,lr_check_correct_fork_taken jump with A==1 => right fork
BA7E JP NZ,lr_left_fork jump with A==1 => left fork
BA81 LD A,E A = E -- E is bottom of road position
BA82 CP $0C Jump with A==1 if E < 12
BA84 LD A,$01
BA86 JR C,lr_check_correct_fork_taken
lr_left_fork BA88 DEC A A should be 1, will become zero
lr_check_correct_fork_taken BA89 LD ($A249),A Set fork_taken to A
BA8C INC A 0/1 -> 1/2
BA8D PUSH HL Preserve HL (holds fork_distance)
BA8E LD HL,$A226 Load address of correct_fork
BA91 CP (HL) Match?
BA92 LD HL,$9941 -> Tony: "LET'S GO. MR. DRIVER." <STOP>
BA95 JR Z,lr_chatter Jump to lr_chatter if correct fork was taken
Incorrect fork was taken.
BA97 LD A,$5F Set the speed of the perp's car to 95 (normally 60)
BA99 LD ($A195),A
Add a bonus of (40,000 + 10,000 * level number) for going the wrong way (eh?)
BA9C LD A,($8007) A = wanted_stage_number + 4
BA9F ADD A,$04
BAA1 LD D,A Set top digits
BAA2 XOR A Clear low digit
BAA3 LD E,A Clear middle digits
BAA4 CALL add_bonus Call add_bonus
BAA7 LD HL,$98D0 -> Raymond: "WHAT ARE YOU DOING MAN!" / "THE BAD GUYS ARE GOING THE OTHER WAY." <STOP>
lr_chatter BAAA LD A,$14 Call start_chatter (with priority 20)
BAAC CALL start_chatter
BAAF POP HL Restore HL (holds fork_distance)
lr_check_spawning BAB0 LD A,($A254) Load allow_spawning (0/1/2)
BAB3 AND A Jump to lr_no_car_spawning if zero
BAB4 JR Z,lr_no_car_spawning
allow_spawning is non-zero.
BAB6 LD C,A A = allow_spawning + spawn_accumulator
BAB7 LD A,($A16D)
BABA ADD A,C
BABB LD C,A C = A -- copy so we can destroy A
BABC SUB $02 A -= 2
BABE JR C,lr_set_var_a16d_from_c Jump if A < 2
Otherwise clamp it to 2.
BAC0 LD C,A C = A
Adjusting this delta will cause the forked road effect to proceed faster (higher values) or slower (lower values).
BAC1 LD DE,$0010 Increase fork_distance by 16
BAC4 ADD HL,DE
BAC5 LD ($A267),HL
lr_set_var_a16d_from_c BAC8 LD A,C spawn_accumulator = C
BAC9 LD ($A16D),A
lr_no_car_spawning BACC LD A,($A16D) A = spawn_accumulator
BACF RRA this must extract the bottom bit to carry
BAD0 LD A,($A23F) A = fast_counter
BAD3 RLA A = (A << 1) | carry
BAD4 RLA A = (...)
BAD5 RLA
BAD6 RLA
BAD7 AND $0F
BAD9 SUB $10 A -= 16 -- sets top nibble to $F
BADB LD E,A DE = $FF00 | A -- ($FFF0..$FFFF)
BADC LD D,$FF
BADE ADD HL,DE HL += DE -- fork_distance + DE
Lanes byte & 4 is non-zero. Hit when the road forks (as it becomes visible).
lr_badf BADF PUSH HL Preserve HL
BAE0 LD A,($A249) Jump if fork_taken was 1 (right fork taken)
BAE3 DEC A
BAE4 JR Z,lr_right_fork_taken
Left fork was taken.
lr_left_fork_taken BAE6 CALL build_curve_table Call build_curve_table
BAE9 POP DE Restore HL from earlier
BAEA LD HL,($A26C) Get road position
BAED PUSH HL Stack it
BAEE ADD HL,DE DE must be a road position delta?
BAEF LD ($A26C),HL Set road position
BAF2 CALL build_curve_table_forked Call build_curve_table_forked
BAF5 JR lr_bb07
Right fork was taken.
lr_right_fork_taken BAF7 CALL build_curve_table_forked Call build_curve_table_forked
BAFA POP DE Pop result?
BAFB LD HL,($A26C) Get road position
BAFE PUSH HL Stack it
BAFF SBC HL,DE DE must be a road position delta?
BB01 LD ($A26C),HL Set road position
BB04 CALL build_curve_table Call build_curve_table
lr_bb07 BB07 POP HL Unstack road position
BB08 LD ($A26C),HL Set road position
BB0B POP BC B used as a counter in a moment
BB0C LD ($BA4E),SP Self modify 'LD SP' @ lr_exit to restore SP
BB10 LD SP,$EC30 Put $EC30 (road right) in SP (so we can use POP for speed)
BB13 LD A,$30 Iterate from $30 to $00 in steps of 2 = 104 iterations [CHECK]
BB15 LD HL,$BB38 Self modify 'LD ($EAxx),HL' @ BB37 to be $EA30 (road centre)
BB18 LD DE,$BB40 Self modify 'LD ($E9xx),HL' @ BB3F to be $E930 (road centre left)
lr_loop BB1B LD (HL),A Self modify the locations setup above
BB1C LD (DE),A
BB1D LD ($BB2F),A Self modify 'LD DE,($E8xx)' @ BB2D to be $E830 (road left)
BB20 LD ($BB44),A Self modify 'LD DE,($EDxx)' @ BB42 to be $ED30
BB23 LD ($BB47),A Self modify 'LD HL,($EB00)' @ BB46 to be $EB30 (road centre right)
BB26 LD ($BB4F),A Self modify 'LD ($EB00),HL' @ BB4E to be $EB30 (road centre right)
BB29 LD ($BB57),A Self modify 'LD ($EC00),HL' @ BB56 to be $EC30 (road right)
BB2C EXX Bank during inner loop
BB2D LD DE,($E800) DE = *$E8xx (xx = self modified) (road left)
BB31 POP HL Read from $ECxx
BB32 ADD HL,DE (Right + Left) / 2 == new road centre
BB33 SRA H
BB35 RR L
BB37 LD ($EA00),HL *$EAxx = HL (xx = self modified) (store road centre)
BB3A ADD HL,DE (Centre + Left) / 2 == new road centre left
BB3B SRA H
BB3D RR L
BB3F LD ($E900),HL *$E9xx = HL (xx = self modified) store (road centre left)
BB42 LD DE,($ED00) DE = *$EDxx (xx = self modified) (?)
BB46 LD HL,($EB00) HL = *$EBxx (xx = self modified) (road centre right)
BB49 ADD HL,DE (Centre-right + ?) / 2 == new road centre right
BB4A SRA H
BB4C RR L
BB4E LD ($EB00),HL *$EBxx = HL (xx = self modified) store (road centre right)
BB51 ADD HL,DE (Centre-right) + ?) / 2 == new road right
BB52 SRA H
BB54 RR L
BB56 LD ($EC00),HL *$ECxx = HL (xx = self modified) (road right)
BB59 INC A A += 2
BB5A INC A
BB5B EXX Unbank
BB5C DJNZ lr_loop Loop while B > 0
BB5E AND A Jump to lr_exit if A is zero
BB5F JP Z,lr_exit
BB62 LD H,$EC Point SP at $EC00 | A (road right)
BB64 LD L,A
BB65 LD SP,HL
BB66 JP lr_calc_single_lane Jump back to lr_calc_single_lane
Prev: B8D2 Up: Map Next: BB69