| Chase H.Q. | Routines |
| Prev: C2E7 | Up: Map | Next: C8BE |
|
The main entry point for road drawing. It clears the on-dirt-track, tunnel visible and in-tunnel flags, sets the edge thickness to 3 and computes the initial horizon counter as 96 minus the second height table entry. The stripe phase comes from the lane data buffer offset: bit 0 gives the XOR base and bit 1 the initial stripe state. With the stripe parameters set it falls into dr_read_lanes to render the road row by row.
|
||||
| draw_road | C452 | LD ($C8A4),SP | Self modify SP restore instruction | |
| C456 | XOR A | Zero on_dirt_track | ||
| C457 | LD ($A248),A | |||
| C45A | LD ($C161),A | Self modify 'LD A,x' @ C160 to load zero (in draw_tunnel, "tunnel visible") | ||
| C45D | LD ($C890),A | Self modify 'LD A,x' @ C88F to load zero (below, "in tunnel") | ||
|
This affects the thickness of the road edges and lane markings with increasing distance. A larger value means lines remain thick into distance.
|
||||
| C460 | LD A,$03 | Self modify 'LD A,x' @ dr_edge_thickness to load 3 (below) | ||
| C462 | LD ($C6D9),A | |||
| C465 | LD IY,$E301 | Load address of height table[1] | ||
| C469 | LD A,$60 | C = $60 - IY[0] | ||
| C46B | SUB (IY+$00) | |||
| C46E | LD C,A | |||
|
Set initial road stripe state.
|
||||
| C46F | LD A,($A240) | Load road_buffer_offset.lo | ||
| C472 | ADD A,$40 | Add 64 so it's the lanes data offset | ||
| C474 | LD IXl,A | Load address of $EE00[A] | ||
| C476 | LD IXh,$EE | |||
| C479 | LD B,A | Copy lanes data offset to B | ||
| C47A | AND $01 | Self modify 'LD A,x' @ dr_set_stripes (below) to load <lanes data offset> & 1 | ||
| C47C | LD ($C6B3),A | |||
| C47F | RR B | Shift bit 1 of <lanes data offset> into carry | ||
| C481 | RR B | |||
| C483 | LD HL,$D010 | Set H to $D0 (table offset?); Set L to 16 (stripe height?) | ||
| C486 | LD A,H | Copy $D0 to A (XOR base) | ||
|
Alter this and the landscape uses that fill pattern, but only half the time.
|
||||
| C487 | LD B,$55 | Set B to $55 -- "on" fill pattern? | ||
| C489 | JR C,dr_stripe_state_set | If B carried out (earlier) then jump | ||
| C48B | LD HL,$0030 | Set H to $00 (table offset?); Set L to 48 | ||
| C48E | LD B,H | Copy $00 to B -- "off" fill pattern | ||
| dr_stripe_state_set | C48F | LD ($C6D4),A | Self modify 'XOR x' @ C6D3 to be x = $D0 | |
| C492 | LD A,H | Self modify 'ADD A,x' @ C677 to be x = $D0 or $00 | ||
| C493 | LD ($C678),A | |||
| C496 | LD A,L | Self modify 'ADD A,x' @ C651 to be x = $10 or $30 | ||
| C497 | LD ($C652),A | |||
| C49A | INC A | Self modify 'ADD A,x' @ C698 to be x = $11 or $31 | ||
| C49B | LD ($C699),A | |||
| C49E | LD HL,$C534 | Self modify 'JP Z,x' @ C4B2 to be dr_four_lane_highway/dr_four_lane_highway | ||
| C4A1 | LD ($C4B3),HL | |||
| C4A4 | LD L,$FF | Set L to $FF | ||
| C4A6 | LD DE,$0100 | Set DE to $0100 | ||
| C4A9 | LD A,B | Self modify 'LD A,x' @ dr_flip_stripe_patterns to load on/off stripe fill pattern | ||
| C4AA | LD ($C6BD),A | |||
|
This entry point is used by the routine at dr_dispatch_filled.
|
||||
| dr_read_lanes | C4AD | LD A,(IX+$00) | Load a lanes byte | |
| C4B0 | AND $03 | Isolate bottom two bits (left hand position) | ||
| C4B2 | JP Z,dr_four_lane_highway | Jump to <self modified> if zero (e.g. dr_four_lane_highway) | ||
|
Otherwise it's anything other than the zero case.
|
||||
| C4B5 | EXX | Bank | ||
|
Sampled IX=$EEFD $EEFE $EEFF $EE00 .. etc.
|
||||
| C4B6 | LD L,(IX+$00) | Reload the lanes byte | ||
| C4B9 | ADD A,$E7 | Turn left hand road position (1..3) into table high byte ($E8..$EA) | ||
| C4BB | LD ($C643),A | Self modify 'LD H,x' @ C642 | ||
| C4BE | LD ($C5B4),A | Self modify 'LD H,x' @ C5B3 | ||
| C4C1 | LD H,A | Copy | ||
| C4C2 | SLA L | Shift bit 7 of lanes byte into carry. With bit 6 clear it means a 3-lane or 3/4-lane-change section; with bit 6 set it separates dirt track and forked road (bit 7 set) from tunnel (clear) | ||
| C4C4 | BIT 7,L | Test former bit 6; is set for tunnel or for dirt track (carry preserved) | ||
| C4C6 | JR NZ,dr_special_road | Jump to dr_special_road if set | ||
|
If bit 6 was clear then it's a normal road (not tunnel, dirt track or forked road).
|
||||
| C4C8 | JR NC,dr_two_lane | Jump to dr_two_lane if bit 7 was clear (any of the two-lane roads or 2-to-3 narrowing/widening lane types) | ||
|
If bit 7 was set then it's a 3-lane, 3-to-4 lane or 4-to-3 lane section.
|
||||
| C4CA | ADD A,$03 | $E8..$EA becomes $EB..$ED | ||
| C4CC | LD C,$FD | Set C to -3 | ||
| C4CE | JP dr_setup_scene_change | Jump to dr_setup_scene_change | ||
|
If bit 7 was clear then it's a 2-lane, 2-to-3 lane or 3-to-2 lane section.
|
||||
| dr_two_lane | C4D1 | ADD A,$02 | $E8..$EA becomes $EA..$EC | |
| C4D3 | LD C,$FE | Set C to -2 | ||
| dr_setup_scene_change | C4D5 | LD ($C5DA),A | Self modify 'LD H,x' @ C5D9 | |
| C4D8 | LD ($C68B),A | Self modify 'LD H,x' @ dr_c68a | ||
| C4DB | LD A,C | Set A to $FD or $FE (from C) | ||
| C4DC | LD ($C5AD),A | Self modify 'LD B,x' @ C5AC | ||
| C4DF | JP draw_road_lanes_change | Exit via draw_road_lanes_change/draw_road_lanes_change [this is its only caller] | ||
|
If bit 6 was clear then it's a special road (tunnel, dirt track or forked road).
|
||||
| dr_special_road | C4E2 | JR C,dr_dirt_track | Jump to dr_dirt_track if carry set (bit 7 of lanes byte - dirt track flag) | |
|
If bit 7 was clear then it's a tunnel section.
|
||||
| C4E4 | LD C,$FF | Set C to $FF | ||
| C4E6 | LD H,$01 | Set H to 1 | ||
| C4E8 | BIT 4,L | Jump if former bit 3 of lanes byte set (tunnel exit) | ||
| C4EA | JR NZ,dr_tunnel_transition | |||
| C4EC | BIT 3,L | Jump if former bit 2 of lanes byte clear (also tunnel exit... so that can't be right) | ||
| C4EE | JR Z,dr_set_inside_flag | |||
|
If bits 2 or 3 are set then it's a tunnel transition section.
|
||||
| dr_tunnel_transition | C4F0 | LD A,IYl | Load IY.low (distance) | |
| C4F2 | LD ($C15E),A | Self modify 'CP x' @ C15D (in draw_tunnel) - tunnel distance | ||
| C4F5 | LD A,$01 | Set A to 1 - tunnel visible | ||
| C4F7 | INC C | Set C to 0 - fill pattern | ||
| C4F8 | BIT 5,L | Jump if former bit 4 of lanes byte clear (tunnel entrance) | ||
| C4FA | JR Z,dr_set_visible_flag | |||
|
If bit 4 is set then it's a tunnel exit.
|
||||
| C4FC | DEC C | Set C to $FF -- fill pattern | ||
| C4FD | INC A | Set A to 2 -- tunnel visible | ||
| C4FE | DEC H | Set H to 0 -- in-tunnel flag | ||
| dr_set_visible_flag | C4FF | LD ($C161),A | Self modify 'LD A,x' @ C160 (in draw_tunnel) | |
| dr_set_inside_flag | C502 | LD A,H | Set A to 0 (from H) | |
| C503 | LD ($C890),A | Self modify 'LD A,x' @ C88F (inside tunnel flag) | ||
| C506 | LD A,$EB | Set A to $EB -- top byte of table? | ||
| C508 | LD ($C5DA),A | Self modify 'LD H,x' @ C5D9 | ||
| C50B | LD ($C68B),A | Self modify 'LD H,x' @ dr_c68a | ||
| C50E | LD A,$FF | Set A to -1 | ||
| C510 | LD ($C5AD),A | Self modify 'LD B,x' @ C5AC (-ve lane count) | ||
| C513 | LD A,C | A = C (fill pattern) | ||
| C514 | EXX | Bank/unbank | ||
| C515 | LD B,A | B = A (fill pattern) | ||
| C516 | JP dr_dispatch_fill | Jump | ||
|
If bit 7 was set then it's a dirt track or forked road.
|
||||
| dr_dirt_track | C519 | BIT 6,L | Jump to draw_forked_road if former bit 5 (not 6 | |
|
If bit 5 was set then it's a forked road.
|
||||
| C51B | JP NZ,draw_forked_road | because shifted) of lanes byte is set} | ||
|
If bit 5 was clear then it's a dirt track section.
|
||||
| C51E | LD A,L | Set flags of (L & 24) | ||
| C51F | AND $18 | |||
| C521 | LD A,$00 | Set new on_dirt_track value to 0 -- not self modified (why not XOR A?) | ||
| C523 | JR NZ,dr_c526 | Jump if flags non-zero | ||
| C525 | INC A | Set new on_dirt_track value to 1 | ||
| dr_c526 | C526 | LD ($A248),A | Set on_dirt_track to new value | |
| C529 | LD A,$FF | Set A to -1 | ||
| C52B | LD ($C5AD),A | Self modify 'LD B,x' @ C5AC (-ve lane count) | ||
| C52E | LD HL,$C534 | -> dr_four_lane_highway | ||
| C531 | JP dr_set_lane_callback | Jump forward | ||
| dr_four_lane_highway | C534 | EXX | Bank | |
| C535 | LD A,$E8 | Set A to $E8 -- set left hand road position to leftmost | ||
| C537 | LD ($C643),A | Self modify 'LD H,x' @ C642 | ||
| C53A | LD ($C5B4),A | Self modify 'LD H,x' @ C5B3 | ||
| C53D | ADD A,$04 | Set A to $EC -- set right hand road position to rightmost | ||
| C53F | LD ($C68B),A | Self modify 'LD H,x' @ dr_c68a | ||
| C542 | LD ($C5DA),A | Self modify 'LD H,x' @ C5D9 | ||
| C545 | LD A,$FC | Set A to -4 | ||
| C547 | LD ($C5AD),A | Self modify 'LD B,x' @ C5AC | ||
| C54A | LD HL,$C551 | -> dr_c551 | ||
|
This entry point is used by the routine at draw_road_lanes_change. Called for regular roads incl dirt track, but not tunnels or splits.
|
||||
| dr_set_lane_callback | C54D | LD ($C4B3),HL | Self modify 'JP Z,x' @ C4B2 | |
| C550 | EXX | Bank/unbank | ||
| dr_dispatch_fill | C551 | LD A,B | Copy fill pattern from B | |
| C552 | AND A | |||
| C553 | JP NZ,dr_dispatch_filled | Jump if non-zero | ||
| C556 | EXX | Bank | ||
| C557 | LD HL,$C55F | Self modify 'JP NZ,x' @ C6AD to be dr_advance_unfilled | ||
| C55A | LD ($C6AE),HL | |||
| C55D | EXX | Unbank | ||
| C55E | EX AF,AF' | |||
|
Move to next scanline.
|
||||
| dr_advance_unfilled | C55F | LD A,D | Save for checking in a moment | |
| C560 | DEC D | Move to next scanline (visually upwards) | ||
| C561 | AND $0F | Would it have rolled over into the top nibble? | ||
| C563 | JR Z,dr_rollover_unfilled | Jump if zero | ||
|
This entry point is used by the routine at dr_rollover_unfilled.
|
||||
| dr_write_scanline_unfilled | C565 | LD ($C56D),DE | Self modify 'LD DE,x' @ C56C (below) | |
| C569 | LD B,$FF | Set B to $FF | ||
| C56B | EXX | Bank/unbank | ||
|
Calculate address of next bitmap scanline ??
|
||||
| C56C | LD DE,$0000 | DE = <self modified> | ||
| C56F | LD A,E | L = E + 31 | ||
| C570 | ADD A,$1F | |||
| C572 | LD L,A | |||
| C573 | LD H,D | H = D | ||
| C574 | LD SP,HL | Put it in SP (so we can use PUSH for speed) | ||
| C575 | LD HL,$0000 | HL = 0 [not self modified apparently] -- fill value | ||
| C578 | LD C,L | C = 0 | ||
| C579 | JP dr_fill_left_stripe | Jump into a sequence of 15 PUSH HLs | ||
|
This is scanline/buffer pointer movement
|
||||
| dr_rollover_filled | C57C | LD A,E | Move to next chunk of 16 scanlines | |
| C57D | SUB $20 | |||
| C57F | LD E,A | |||
| C580 | JP C,dr_fill | Carry set if CCC field was zero - don't compensate 1111 field and continue | ||
| C583 | LD A,D | Put back the bit stolen since BAAA field was zero | ||
| C584 | ADD A,$10 | |||
| C586 | LD D,A | |||
| C587 | JP dr_fill | jump | ||
|
This is scanline/buffer pointer movement
|
||||
| dr_rollover_unfilled | C58A | LD A,E | Move to next chunk of 16 scanlines | |
| C58B | SUB $20 | |||
| C58D | LD E,A | |||
| C58E | JP C,dr_write_scanline_unfilled | Carry set if CCC field was zero - don't compensate 1111 field and continue | ||
| C591 | LD A,D | Put back the bit stolen since BAAA field was zero | ||
| C592 | ADD A,$10 | |||
| C594 | LD D,A | |||
| C595 | JP dr_write_scanline_unfilled | jump | ||
|
Road and backdrop plotting
|
||||
| dr_dispatch_filled | C598 | EXX | Bank | |
| C599 | LD HL,$C5A1 | Self modify 'JP NZ,x' @ C6AD to be dr_advance_filled | ||
| C59C | LD ($C6AE),HL | |||
| C59F | EXX | Unbank | ||
| C5A0 | EX AF,AF' | |||
|
Move to next scanline.
|
||||
| dr_advance_filled | C5A1 | LD A,D | Save for checking in a moment | |
| C5A2 | DEC D | Move to next scanline (visually upwards) | ||
| C5A3 | AND $0F | Would it have rolled over into the top nibble? | ||
| C5A5 | JR Z,dr_rollover_filled | Jump if rolled over | ||
|
This entry point is used by the routine at dr_rollover_filled.
|
||||
| dr_fill | C5A7 | LD ($C5FA),DE | Self modify 'LD DE,x' @ C5F9 | |
| C5AB | LD A,L | A = L | ||
| C5AC | LD B,$00 | B = <self modified> e.g. $FC or $FD -- -ve lane count | ||
| C5AE | EXX | Bank | ||
| C5AF | LD L,A | L = A | ||
| C5B0 | LD BC,$10F8 | B = 16, C = $F8 (mask) | ||
| C5B3 | LD H,$E8 | Load <self modified> top byte of table left hand position | ||
| C5B5 | LD A,(HL) | Load from table | ||
| C5B6 | AND A | Set flags | ||
| C5B7 | JP Z,dr_c5c4 | Jump if zero | ||
| C5BA | LD A,$00 | A = 0 (not self modified) | ||
| C5BC | JP M,dr_c5d3 | Jump if negative | ||
| C5BF | LD A,$0F | A = 15 | ||
| C5C1 | JP dr_c5d3 | Jump | ||
|
Pattern
|
||||
| dr_c5c4 | C5C4 | DEC L | Load HL[-1] | |
| C5C5 | LD A,(HL) | |||
| C5C6 | INC L | |||
| C5C7 | AND C | A &= $F8 -- C is the mask $F8 here | ||
| C5C8 | RRCA | A >>= 3 | ||
| C5C9 | RRCA | |||
| C5CA | RRCA | |||
| C5CB | RRA | A >>= 1 | ||
| C5CC | ADC A,$00 | Add carry | ||
| C5CE | CP B | Jump if A < B | ||
| C5CF | JP C,dr_c5d3 | |||
| C5D2 | DEC A | A-- | ||
| dr_c5d3 | C5D3 | LD E,A | E = A | |
| C5D4 | CPL | A = ~E + B -- B is 16 | ||
| C5D5 | ADD A,B | |||
| C5D6 | LD ($C62D),A | Self modify 'JR x' @ dr_lefthand_jumptable -- jump table target | ||
| C5D9 | LD H,$EC | Set high byte of table address to <self modified> e.g. $EC | ||
| C5DB | LD A,(HL) | Read from table -- is this 8-bit or a partial 16-bit value? | ||
| C5DC | AND A | Set flags | ||
| C5DD | JP Z,dr_calc_righthand_width | Jump if zero -- jump to calc bit | ||
| C5E0 | LD A,$0F | Set righthand jump table target to 15 (just plots 16 pixels?) | ||
| C5E2 | JP P,dr_set_righthand_jump_table_target | Jump if positive | ||
| C5E5 | XOR A | Otherwise set it to zero (plots 15*16 pixels?) | ||
| C5E6 | JP dr_set_righthand_jump_table_target | Jump | ||
|
Same pattern again
|
||||
| dr_calc_righthand_width | C5E9 | DEC L | L-- | |
| C5EA | LD A,(HL) | Read from table | ||
| C5EB | AND C | Mask with $F8 (C is the mask $F8 here) | ||
| C5EC | RRCA | A >>= 3 | ||
| C5ED | RRCA | |||
| C5EE | RRCA | |||
| C5EF | RRA | A >>= 1 | ||
| dr_set_righthand_jump_table_target | C5F0 | LD ($C60B),A | Self modify 'JR x' @ dr_righthand_jumptable -- righthand jump table target | |
|
Calculate road jump table target.
|
||||
| C5F3 | CPL | A = ~A + B + E (== 15 - A + E) | ||
| C5F4 | ADD A,B | |||
| C5F5 | ADD A,E | |||
| C5F6 | LD ($C61C),A | Self modify 'JR x' @ dr_road_jumptable -- road jump table target | ||
| C5F9 | LD DE,$0000 | DE = <self modified by #$C5A7> | ||
| C5FC | LD A,E | L = E + 31 | ||
| C5FD | ADD A,$1F | |||
| C5FF | LD L,A | |||
| C600 | LD H,D | H = D | ||
| C601 | LD SP,HL | Put it in SP (so we can use PUSH for speed) | ||
| C602 | EX AF,AF' | Unbank fill byte | ||
| C603 | RLCA | Rotate fill pattern so we checkerboard | ||
| C604 | LD H,A | Widen stripe fill byte to whole word | ||
| C605 | LD L,A | |||
| C606 | EX AF,AF' | Bank fill byte | ||
| C607 | LD BC,$0000 | Set road fill to zero (but only when drawing stripes) | ||
|
Fill right hand road stripes - starting from right hand side.
|
||||
| dr_righthand_jumptable | C60A | JR dr_righthand_jumptable | Jump table (self modified) | |
| C60C | PUSH HL | |||
| C60D | PUSH HL | |||
| C60E | PUSH HL | |||
| C60F | PUSH HL | |||
| C610 | PUSH HL | |||
| C611 | PUSH HL | |||
| C612 | PUSH HL | |||
| C613 | PUSH HL | |||
| C614 | PUSH HL | |||
| C615 | PUSH HL | |||
| C616 | PUSH HL | |||
| C617 | PUSH HL | |||
| C618 | PUSH HL | |||
| C619 | PUSH HL | |||
| C61A | PUSH HL | |||
|
Fill blank road surface - continuing from the right hand side.
|
||||
| dr_road_jumptable | C61B | JR dr_road_jumptable | Jump table (self modified) | |
| C61D | PUSH BC | |||
| C61E | PUSH BC | |||
| C61F | PUSH BC | |||
| C620 | PUSH BC | |||
| C621 | PUSH BC | |||
| C622 | PUSH BC | |||
| C623 | PUSH BC | |||
| C624 | PUSH BC | |||
| C625 | PUSH BC | |||
| C626 | PUSH BC | |||
| C627 | PUSH BC | |||
| C628 | PUSH BC | |||
| C629 | PUSH BC | |||
| C62A | PUSH BC | |||
| C62B | PUSH BC | |||
|
Fill left hand road stripes - continuing from the right hand side.
|
||||
| dr_lefthand_jumptable | C62C | JR dr_lefthand_jumptable | Jump table (self modified) | |
|
This entry point is used by the routine at draw_road.
|
||||
| dr_fill_left_stripe | C62E | PUSH HL | ||
| C62F | PUSH HL | |||
| C630 | PUSH HL | |||
| C631 | PUSH HL | |||
| C632 | PUSH HL | |||
| C633 | PUSH HL | |||
| C634 | PUSH HL | |||
| C635 | PUSH HL | |||
| C636 | PUSH HL | |||
| C637 | PUSH HL | |||
| C638 | PUSH HL | |||
| C639 | PUSH HL | |||
| C63A | PUSH HL | |||
| C63B | PUSH HL | |||
| C63C | PUSH HL | |||
|
...
|
||||
| C63D | LD B,E | B = E | ||
| C63E | DEC C | 0 -> 255 | ||
| C63F | LD H,$E4 | Point HL at road edge/markings table at $E4xx | ||
| C641 | EXX | Bank/unbank | ||
| C642 | LD H,$E8 | Load <self modified> top byte of road left hand edge table ($E8/$E9/$EA for left/centre-left/centre) | ||
| C644 | LD A,(HL) | Read from left/centre-left/centre hand edge table at $E8xx/$E9xx/$EAxx | ||
| C645 | AND A | Jump if non-zero | ||
| C646 | JR NZ,dr_road_lane_marking_loop | |||
|
Otherwise zero.
|
||||
| C648 | DEC L | index = HL[-1] -- Load the byte prior | ||
| C649 | LD A,(HL) | |||
| C64A | INC L | |||
| C64B | EXX | Bank | ||
|
Build address of road edge marking graphic.
|
||||
| C64C | LD E,A | Save index | ||
| C64D | AND $07 | Bottom three bits select the row number 0..7 | ||
| C64F | RLCA | Turn into a scanline offset (4 bytes per row) | ||
| C650 | RLCA | |||
| C651 | ADD A,$00 | Add offset of current edge marking graphic ($10,$30,$50,$70,$90,$B0) | ||
| C653 | LD L,A | Set HL to road edge marking address | ||
|
The top five bits of the x position give the byte column within the 32-byte back buffer row, which is why breaking this only moves the left hand edge.
|
||||
| C654 | LD A,E | E = ((index >> 3) & 31) + B | ||
| C655 | RRA | |||
| C656 | RRA | |||
| C657 | RRA | |||
| C658 | AND $1F | |||
| C65A | ADD A,B | |||
| C65B | LD E,A | |||
|
AND-OR masking here. DE is address of screen buffer byte. HL is address of mask byte, followed by bitmap byte [then again since the edges are 16x8]
|
||||
| C65C | LD A,(DE) | Read a screen buffer byte | ||
| C65D | AND (HL) | Apply the mask | ||
| C65E | INC L | Advance to bitmap byte | ||
| C65F | OR (HL) | Apply the bitmap | ||
| C660 | LD (DE),A | Write the new screen buffer byte | ||
| C661 | INC L | L += 2 | ||
| C662 | INC L | |||
| C663 | INC E | E++ | ||
| C664 | LDI | *DE++ = *HL++, BC-- | ||
| C666 | EXX | Unbank | ||
|
Draw road lane markings.
|
||||
| dr_road_lane_marking_loop | C667 | INC B | Increment counter | |
| C668 | JR Z,dr_c68a | Exit loop if zero | ||
| C66A | INC H | H++ | ||
| C66B | LD A,(HL) | Read from road left drawing table e.g $E89F | ||
| C66C | AND A | Set flags | ||
| C66D | JR NZ,dr_road_lane_marking_loop | Loop if non-zero | ||
| C66F | DEC L | A = HL[-1] (with wraparound?) | ||
| C670 | LD A,(HL) | |||
| C671 | INC L | |||
| C672 | EXX | Bank | ||
| C673 | LD E,A | E = A -- save A | ||
| C674 | AND $07 | L = ((A & 7) << 1) + <self modified> | ||
| C676 | RLCA | |||
| C677 | ADD A,$00 | |||
| C679 | LD L,A | |||
| C67A | LD A,E | E = ((E >> 3) & 31) + B | ||
| C67B | RRA | |||
| C67C | RRA | |||
| C67D | RRA | |||
| C67E | AND $1F | |||
| C680 | ADD A,B | |||
| C681 | LD E,A | |||
| C682 | LDI | *DE++ = *HL++, BC-- | ||
|
This reads an (unmasked) road lane marker bitmap byte from $E4D0+.
|
||||
| C684 | LD A,(HL) | Copy a byte from $E4D0+ to the buffer | ||
| C685 | LD (DE),A | |||
| C686 | EXX | Unbank | ||
| C687 | JP dr_road_lane_marking_loop | Loop | ||
| dr_c68a | C68A | LD H,$00 | Set high byte of table address to <self modified> e.g. $EC | |
| C68C | LD A,(HL) | A = *HL | ||
| C68D | DEC L | L-- | ||
| C68E | AND A | Set flags | ||
| C68F | JR NZ,dr_c6ab | Jump if non-zero | ||
| C691 | LD A,(HL) | A = *HL | ||
| C692 | EXX | Bank | ||
| C693 | LD E,A | E = A -- save A | ||
|
Must be the right hand edge handling.
|
||||
| C694 | AND $07 | L = ((A & 7) << 2) + <self modified> -- as above but * 4 | ||
| C696 | RLCA | |||
| C697 | RLCA | |||
| C698 | ADD A,$11 | |||
| C69A | LD L,A | |||
| C69B | LD A,E | E = ((E >> 3) & 31) + B | ||
| C69C | RRA | |||
| C69D | RRA | |||
| C69E | RRA | |||
| C69F | AND $1F | |||
| C6A1 | ADD A,B | |||
| C6A2 | LD E,A | |||
| C6A3 | LDI | *DE++ = *HL++, BC-- | ||
|
AND-OR masking here. This affects road lines when altered.
|
||||
| C6A5 | LD A,(DE) | A = *DE & *HL | ||
| C6A6 | AND (HL) | |||
| C6A7 | INC L | L++ | ||
| C6A8 | OR (HL) | *DE = A | *HL | ||
| C6A9 | LD (DE),A | |||
| C6AA | EXX | Unbank | ||
| dr_c6ab | C6AB | DEC L | L-- | |
| C6AC | DEC C | C-- -- road row counter | ||
| C6AD | JP NZ,$0000 | Jump to <self modified> if non-zero | ||
| C6B0 | EX AF,AF' | Swap | ||
| C6B1 | LD B,A | B = A | ||
|
This causes the alternating road stripes.
|
||||
| dr_set_stripes | C6B2 | LD A,$00 | Load <self modified> -- loads (<lanes data offset> & 1) | |
| C6B4 | XOR $01 | Toggle the road stripe state | ||
| C6B6 | LD ($C6B3),A | Write it back | ||
| C6B9 | JP NZ,dr_edge_thickness | Jump if non-zero | ||
| dr_flip_stripe_patterns | C6BC | LD A,$00 | Load <self modified> fill pattern | |
| C6BE | XOR $55 | Exclusive or with $55 -- flips the chequerboard fill pattern to its opposite phase | ||
| C6C0 | LD ($C6BD),A | Self modify above | ||
| C6C3 | LD B,A | Keep a copy of the stripe fill pattern for the rows drawn below | ||
|
This causes the road edge stripes.
|
||||
| C6C4 | LD A,($C652) | Toggle bit 5 of x in 'ADD A,x' @ C651 -- switch between adjacent edge graphics (that are 32 bytes each) | ||
| C6C7 | XOR $20 | |||
| C6C9 | LD ($C652),A | |||
| C6CC | INC A | The right hand edge reads the same 4-byte record one byte along: its solid byte comes first and its masked pair second, mirroring the left hand edge | ||
| C6CD | LD ($C699),A | Self modify 'ADD A,x' @ C698 | ||
| C6D0 | LD A,($C678) | Toggle <self modified> bits of 'ADD A,x' @ C677 | ||
| C6D3 | XOR $00 | |||
| C6D5 | LD ($C678),A | |||
| dr_edge_thickness | C6D8 | LD A,$00 | Load <self modified> edge width value | |
| C6DA | DEC A | Decrement it | ||
| C6DB | LD ($C6D9),A | Self modify 'LD A' above @ dr_edge_thickness to be new A | ||
| C6DE | JP NZ,dr_edge_width_handled | Jump if non-zero | ||
|
Otherwise edge width value was zero.
|
||||
| C6E1 | LD A,($C6D4) | Read 'XOR x' @ C6D3 | ||
| C6E4 | ADD A,$10 | A += 16 | ||
| C6E6 | JR C,dr_edge_width_handled | Jump if carried | ||
| C6E8 | LD ($C6D4),A | Self modify 'XOR x' @ C6D3 to be new A | ||
| C6EB | LD C,A | C = A | ||
| C6EC | LD A,($C678) | Read 'ADD A,x' @ C677 | ||
| C6EF | AND A | Set flags | ||
| C6F0 | JR Z,dr_c6f6 | Jump if zero | ||
| C6F2 | LD A,C | A = C | ||
| C6F3 | LD ($C678),A | Self modify 'ADD A,x' @ C677 | ||
| dr_c6f6 | C6F6 | LD A,($C652) | Increment x in 'ADD A,x' @ C651 by 64 -- steps on to the next pair of edge variants, since C6C7 toggles between the two members of a pair | |
| C6F9 | ADD A,$40 | |||
| C6FB | LD ($C652),A | |||
| C6FE | LD A,$05 | Self modify 'LD A,x' @ dr_edge_thickness to be 5 | ||
| C700 | LD ($C6D9),A | |||
|
Sampled IY = $E301..$E315
|
||||
| dr_edge_width_handled | C703 | LD A,(IY+$00) | Load IY[0] | |
| C706 | INC IY | Increment IY | ||
|
Sampled IX = $EEC5..$EED9
|
||||
| C708 | INC IXl | IX.low++ -- wrapping around | ||
| C70A | SUB (IY+$00) | A -= IY[0] | ||
| C70D | JR Z,dr_level_road | Jump if zero | ||
| C70F | JP P,dr_c794 | Jump if positive | ||
| C712 | JP dr_c746 | Jump | ||
| dr_level_road | C715 | DEC L | L -= 2 | |
| C716 | DEC L | |||
|
Sampled IX = $EE2C ... EE39 EE45
|
||||
| C717 | LD C,(IX+$00) | Load the lanes flags byte | ||
| C71A | BIT 6,C | Bit 6 indicates tunnel or dirt track | ||
| C71C | JP Z,dr_set_stripes | Jump (loop?) if clear (neither tunnel nor dirt track) | ||
|
Tunnel or dirt track.
|
||||
| C71F | BIT 7,C | Bit 7 indicates dirt track | ||
| C721 | JP NZ,dr_set_stripes | Jump (loop?) if set (dirt track only) | ||
|
Tunnel.
|
||||
| C724 | LD B,$FF | Load 255 | ||
| C726 | BIT 2,C | Bit 2 indicates tunnel start | ||
| C728 | LD A,$01 | Load 1 -- value for (tunnel related) | ||
| C72A | JR Z,dr_c740 | Jump if clear (tunnel cont/end?) | ||
| C72C | LD A,IYl | Load IY.low (distance) | ||
| C72E | LD ($C15E),A | Self modify 'CP x' @ C15D [15 when tunnel is small, 6 when fills screen] | ||
| C731 | LD A,$01 | A = 1 | ||
| C733 | INC B | 255 -> 0 | ||
| C734 | BIT 4,C | Bit 4 of C set? | ||
| C736 | LD C,A | C = A | ||
| C737 | JR Z,dr_c73c | Jump if clear | ||
| C739 | DEC B | B-- | ||
| C73A | INC A | A++ | ||
| C73B | DEC C | C-- | ||
| dr_c73c | C73C | LD ($C161),A | Self modify 'LD A,x' @ C160 (in draw_tunnel) | |
| C73F | LD A,C | A = C | ||
| dr_c740 | C740 | LD ($C890),A | Self modify 'LD A,x' @ C88F (tunnel related) | |
| C743 | JP dr_set_stripes | Jump | ||
|
Variation:
|
||||
| dr_c746 | C746 | LD C,(IX+$00) | C = IX[0] | |
| C749 | BIT 6,C | Bit 6 of C set? | ||
| C74B | JP Z,dr_c774 | Jump if clear | ||
| C74E | BIT 7,C | Bit 7 of C set? | ||
| C750 | JP NZ,dr_c774 | Jump if set | ||
| C753 | EX AF,AF' | Swap | ||
| C754 | LD B,$FF | B = 255 | ||
| C756 | BIT 2,C | Bit 2 of C set? | ||
| C758 | LD A,$01 | A = 1 | ||
| C75A | JR Z,dr_c770 | Jump if clear | ||
| C75C | LD A,IYl | Load IY.low (distance) | ||
| C75E | LD ($C15E),A | Self modify 'CP x' @ C15D [15 when tunnel is small, 6 when fills screen] | ||
| C761 | LD A,$01 | A = 1 | ||
| C763 | INC B | B++ | ||
| C764 | BIT 4,C | Bit 4 of C set? | ||
| C766 | LD C,A | C = A | ||
| C767 | JR Z,dr_c76c | Jump if clear | ||
| C769 | DEC B | B-- | ||
| C76A | INC A | A++ | ||
| C76B | DEC C | C-- | ||
| dr_c76c | C76C | LD ($C161),A | Self modify 'LD A,x' @ C160 (in draw_tunnel) | |
| C76F | LD A,C | A = C | ||
| dr_c770 | C770 | LD ($C890),A | Self modify 'LD A,x' @ C88F (tunnel related) | |
| C773 | EX AF,AF' | Swap | ||
| dr_c774 | C774 | LD C,A | C = A | |
| C775 | LD A,(IY+$00) | A = IY[0] | ||
| C778 | INC IY | IY++ | ||
| C77A | INC IXl | IX.low++ | ||
| C77C | SUB (IY+$00) | A -= IY[0] | ||
| C77F | CP $E0 | Compare to $E0 | ||
| C781 | JP NC,dr_c788 | Jump if A >= $E0 | ||
| C784 | CP $50 | Compare to $50 | ||
| C786 | JR NC,dr_start_backdrop_fill | Jump if A >= $50 | ||
| dr_c788 | C788 | DEC L | L -= 2 | |
| C789 | DEC L | |||
| C78A | ADD A,C | A += C | ||
| C78B | JR Z,dr_c746 | Jump if zero or negative | ||
| C78D | JP M,dr_c746 | |||
| C790 | LD C,A | C = A | ||
| C791 | JP dr_read_lanes | Jump | ||
| dr_c794 | C794 | LD C,A | C = A | |
| C795 | CP $50 | Compare to $50 | ||
| C797 | JP C,dr_read_lanes | Jump if A < $50 | ||
|
This entry point is used by the routines at mystery_cba4 and backdrop_fill_dispatch.
|
||||
| dr_start_backdrop_fill | C79A | INC E | E++ | |
| C79B | LD HL,$C161 | Load address of x in 'LD A,x' @ C160 (in draw_tunnel) | ||
| C79E | LD A,($C890) | Read 'LD A,x' @ C88F (tunnel related) | ||
| C7A1 | OR (HL) | A |= *HL | ||
| C7A2 | RRA | A >>= 1 | ||
| C7A3 | JP C,dr_start_sky_fill | Jump if carry (bottom bit set) | ||
| C7A6 | LD A,D | C = D & 15 | ||
| C7A7 | AND $0F | |||
| C7A9 | LD C,A | |||
| C7AA | LD A,E | B = ~((E >> 1) + C) + $80 | ||
| C7AB | SRL A | |||
| C7AD | ADD A,C | |||
| C7AE | CPL | |||
| C7AF | ADD A,$80 | |||
| C7B1 | LD B,A | |||
| C7B2 | LD HL,($A171) | Load horizon_level | ||
| C7B5 | LD C,$18 | C = 24 | ||
| C7B7 | LD A,H | A = H | ||
| C7B8 | AND A | Set flags | ||
| C7B9 | JP M,dr_start_sky_fill | Jump if negative | ||
| C7BC | JR NZ,dr_c7ca | Jump if non-zero | ||
| C7BE | LD A,L | A = L - B | ||
| C7BF | SUB B | |||
| C7C0 | JR NC,dr_c7ca | Jump if A was >= B | ||
| C7C2 | ADD A,C | A += C | ||
| C7C3 | JP NC,dr_start_sky_fill | Jump if no carry | ||
| C7C6 | JP Z,dr_start_sky_fill | Jump if zero | ||
| C7C9 | LD C,A | C = A | ||
| dr_c7ca | C7CA | LD A,C | A = C | |
| C7CB | LD ($C80C),A | Self modify xx in 'LD BC,$xxyy' @ C80A | ||
| C7CE | ADD A,B | A += B | ||
| C7CF | JP P,dr_c7db | Jump if positive | ||
| C7D2 | SUB $7F | A = -(A - 127) + C | ||
| C7D4 | NEG | |||
| C7D6 | ADD A,C | |||
| C7D7 | LD ($C80C),A | Self modify xx in 'LD BC,$xxyy' @ C80A | ||
| C7DA | LD C,A | C = A | ||
| dr_c7db | C7DB | LD A,C | BC = (24 - C) * 3 -- assuming no overflow from calc of C | |
| C7DC | CPL | |||
| C7DD | ADD A,$19 | |||
| C7DF | RLCA | |||
| C7E0 | LD C,A | |||
| C7E1 | RLCA | |||
| C7E2 | RLCA | |||
| C7E3 | ADD A,C | |||
| C7E4 | LD C,A | |||
| C7E5 | LD B,$00 | |||
| C7E7 | LD A,$00 | Load <self modified> horizon's horizontal shift value (ranges 0..19) | ||
|
Decide whether to use the pre-shifted or the non-shifted version of the backdrop bitmap.
|
||||
| C7E9 | RRA | Shift bottom bit out to carry | ||
| C7EA | LD HL,$5B00 | Point at hill backdrop (pre-shifted version) | ||
| C7ED | JR NC,dr_c7f2 | Jump if no carry | ||
| C7EF | LD HL,$5C00 | Point at hill backdrop (non-shifted version) | ||
| dr_c7f2 | C7F2 | ADD HL,BC | HL += BC | |
| C7F3 | EXX | Bank/unbank | ||
|
A is 0..9 here, turn it back to 0..18 and invert to make jump table target.
|
||||
| C7F4 | ADD A,A | A = 18 - A * 2 | ||
| C7F5 | CPL | |||
| C7F6 | ADD A,$13 | |||
| C7F8 | LD ($C86D),A | Self modify 'JR x' @ dr_c86c -- jump table target | ||
| C7FB | LD E,A | Set source address to backdrop_shifting_instrs[A] | ||
| C7FC | LD D,$00 | |||
| C7FE | LD HL,$86F6 | |||
| C801 | ADD HL,DE | |||
| C802 | LD BC,$0012 | Copy 18 bytes | ||
| C805 | LD DE,$C82D | Set destination address to instruction stream | ||
| C808 | LDIR | Copy | ||
| C80A | LD BC,$180A | BC = $<self modified>0A | ||
| C80D | EXX | Bank/unbank | ||
| C80E | LD A,L | A = L | ||
| C80F | EX AF,AF' | Swap | ||
| C810 | JP dr_c824 | Jump | ||
|
Scanline advance pattern.
|
||||
| dr_c813 | C813 | LD A,E | E -= 32 | |
| C814 | SUB $20 | |||
| C816 | LD E,A | |||
| C817 | JP C,dr_c82a | Jump if E < 32 | ||
| C81A | LD A,D | D -= 16 | ||
| C81B | ADD A,$10 | |||
| C81D | LD D,A | |||
| C81E | JP dr_c82a | |||
| dr_c821_apparent_loop_start | C821 | EXX | Bank/unbank | |
| C822 | EX AF,AF' | Swap | ||
| C823 | LD E,A | E = A | ||
| dr_c824 | C824 | LD A,D | A = D | |
| C825 | DEC D | D-- | ||
| C826 | AND $0F | A &= 15 | ||
| C828 | JR Z,dr_c813 | Jump if zero | ||
|
This entry point is used by the routine at dr_c813.
|
||||
| dr_c82a | C82A | LD A,E | A = E | |
| C82B | EX AF,AF' | Swap | ||
| C82C | LD L,A | L = A | ||
| dr_c82d | C82D | NOP | 18 instructions/lines filled in by earlier code | |
| C82E | NOP | |||
| C82F | NOP | |||
| C830 | NOP | |||
| C831 | NOP | |||
| C832 | NOP | |||
| C833 | NOP | |||
| C834 | NOP | |||
| C835 | NOP | |||
| C836 | NOP | |||
| C837 | NOP | |||
| C838 | NOP | |||
| C839 | NOP | |||
| C83A | NOP | |||
| C83B | NOP | |||
| C83C | NOP | |||
| C83D | NOP | |||
| C83E | NOP | |||
| C83F | LDI | |||
| C841 | LD L,A | |||
| C842 | LDI | |||
| C844 | LDI | |||
| C846 | LDI | |||
| C848 | LDI | |||
| C84A | LDI | |||
| C84C | LDI | |||
| C84E | LDI | |||
| C850 | LDI | |||
| C852 | LDI | |||
| C854 | LDI | |||
| C856 | LD L,A | |||
| C857 | LDI | |||
| C859 | LDI | |||
| C85B | LDI | |||
| C85D | LDI | |||
| C85F | LDI | |||
| C861 | LDI | |||
| C863 | LDI | |||
| C865 | LDI | |||
| C867 | LDI | |||
| C869 | LDI | |||
| C86B | LD L,A | |||
| dr_c86c | C86C | JR dr_c86c | Self modified - jump table | |
| C86E | LDI | |||
| C870 | LDI | |||
| C872 | LDI | |||
| C874 | LDI | |||
| C876 | LDI | |||
| C878 | LDI | |||
| C87A | LDI | |||
| C87C | LDI | |||
| C87E | LDI | |||
| C880 | EXX | |||
| C881 | ADD A,C | A += C | ||
| C882 | DJNZ dr_c821_apparent_loop_start | Loop? | ||
| C884 | EXX | Bank/unbank | ||
| C885 | EX AF,AF' | Swap | ||
| C886 | LD E,A | E = A | ||
|
This entry point is used by the routine at dr_dispatch_filled.
|
||||
| dr_start_sky_fill | C887 | EX DE,HL | Swap | |
| C888 | LD A,L | L += 30 | ||
| C889 | ADD A,$1E | |||
| C88B | LD L,A | |||
| C88C | LD DE,$0000 | Fill value for blank sky | ||
|
The following value is tunnel related: 1 if in tunnel, 0 if not.
It alternates fast when there is a partial tunnel on screen.
|
||||
| C88F | LD A,$00 | A = <self modified> | ||
| C891 | AND A | Set flags | ||
| C892 | JP Z,dr_chose_colour | Jump if zero | ||
|
In tunnel. Draw black scanlines for the sky instead of coloured.
|
||||
| C895 | DEC DE | $0000 -> $FFFF | ||
| dr_chose_colour | C896 | LD C,$0F | Mask for later | |
|
Decrement the screen address.
|
||||
| dr_sky_fill_loop | C898 | LD A,H | Save H in A | |
| C899 | DEC H | Decrement row address | ||
| C89A | AND C | Extract low four bits of row address | ||
| C89B | JR NZ,dr_sky_fill_scanline | Jump to dr_sky_fill_scanline if non-zero (easy case) | ||
|
Otherwise it was zero so will need extra work.
|
||||
| C89D | LD A,L | Decrement high three bits of the row address | ||
| C89E | SUB $20 | |||
| C8A0 | LD L,A | |||
| C8A1 | JR NC,dr_sky_fill_fix_address | No carry, so ... | ||
|
Exit.
|
||||
| C8A3 | LD SP,$0000 | Restore original SP (self modified) | ||
| C8A6 | RET | Return | ||
| dr_sky_fill_fix_address | C8A7 | LD A,H | Didn't carry so fix H from earlier DEC H (1110xxxx -> 1111xxxx) | |
| C8A8 | ADD A,$10 | |||
| C8AA | LD H,A | |||
|
Writes DE to HL 15 times filling the scanline. Draws the blank upper part of the sky. DE must always be zero? or what about tunnels?
|
||||
| dr_sky_fill_scanline | C8AB | LD SP,HL | Put it in SP (so we can use PUSH for speed) | |
| C8AC | PUSH DE | Write 30 bytes of sky pixels | ||
| C8AD | PUSH DE | |||
| C8AE | PUSH DE | |||
| C8AF | PUSH DE | |||
| C8B0 | PUSH DE | |||
| C8B1 | PUSH DE | |||
| C8B2 | PUSH DE | |||
| C8B3 | PUSH DE | |||
| C8B4 | PUSH DE | |||
| C8B5 | PUSH DE | |||
| C8B6 | PUSH DE | |||
| C8B7 | PUSH DE | |||
| C8B8 | PUSH DE | |||
| C8B9 | PUSH DE | |||
| C8BA | PUSH DE | |||
| C8BB | JP dr_sky_fill_loop | Loop | ||
| Prev: C2E7 | Up: Map | Next: C8BE |