Prev: CBC5 Up: Map Next: CD3A
CBCE: Builds road curvature tables
Builds the table for one section of road at a time; layout_road (layout_road) calls it multiple times per invocation, once for each section (main road, fork branches).
This gets hit during road forks (where the roads bend outwards).
build_curve_table_forked CBCE LD HL,$EEEC Load two table high-bytes: $EE, $EC
CBD1 LD DE,$44ED Load $ED $44 => Opcode of NEG instruction for CC21
CBD4 JR build_curve_table_self_modify Jump forward
This entry point is used by the routine at layout_road.
build_curve_table CBD6 LD HL,$EDE9 Load two table high-bytes: $ED, $E9
CBD9 LD DE,$0000 Load opcodes of two NOP instructions for CC21
build_curve_table_self_modify CBDC LD ($CC21),DE Write pair of instructions in DE to CC21
CBE0 LD A,H Self modify 'LD HL' @ CC70 to load ($<H>00) e.g. $ED00 or $EE00
CBE1 LD ($CC72),A
CBE4 LD A,L Self modify 'LD HL' @ CCA5 to load ($<L>00) e.g. $E900 or $EC00
CBE5 LD ($CCA7),A
Using road_buffer_offset as a full address here.
CBE8 LD HL,($A240) Load road_buffer_offset into HL
CBEB LD C,(HL) Read a curvature data byte
See similar code at CD47.
CBEC LD A,($A23F) Load fast_counter
CBEF AND $E0 Isolate top three bits
CBF1 LD B,A Move result to B
Map B (0,32,64,96,...,224) to (0,22,44,66,...,154)
CBF2 RRC B Divide by 4 and subtract
CBF4 RRC B
CBF6 SUB B
CBF7 RRC B Divide by 16 and subtract
CBF9 RRC B
CBFB SUB B
Index the road animation table persp_x_scale_right.
CBFC ADD A,$B0 IY = persp_x_scale_right + A
CBFE LD IYl,A
CC00 LD A,$E6
CC02 ADC A,$00
CC04 LD IYh,A
Multiply C by the top three bits of A then divide by 8 (with rounding) on return.
CC06 CALL scale_curvature_or_height Call multiply (result in A)
CC09 NEG A = (128 - A) & $FE
CC0B ADD A,$80
CC0D AND $FE
CC0F LD IXl,A IX = $E500 + A -- point into inward_bend_table
CC11 LD IXh,$E5
CC14 LD DE,$E320 -> table_e320
CC17 LD B,$16 20 iterations
CC19 EXX Bank
CC1A LD DE,($A26C) Read road position
SP is regular stack here.
CC1E PUSH DE Stack it
CC1F EXX Unbank
bct_loop CC20 LD A,(HL) Read road buffer byte
CC21 NOP Self modified above - Set to NOP (if non-forked) or NEG (if forked)
CC22 NOP
CC23 INC L Advance road buffer pointer (wrapping)
CC24 EXX Bank
CC25 ADD A,IXl IX.low += A -- point into bend table
CC27 LD IXl,A
CC29 LD HL,$0000 Initialise a multiplier result
Subtract road_pos in DE from table entry, result in BC.
CC2C LD A,(IX+$00) Reads low byte from the inward_bend_table table (inward_bend_table)
CC2F SUB E C = A - E
CC30 LD C,A
CC31 LD A,(IX+$01) Reads high byte
CC34 SBC A,D B = A - D (with carry)
CC35 LD B,A
Sampled IY = $E71E $E71F $E720 ..
CC36 LD A,(IY+$00) Load from somewhere in persp_x_scale_right[]
CC39 INC IY Advance
This is a multiplier of HL (distance shift value computed above) by A (value from $E600Vertical perspective weights — Y scale by speed and distance+).
CC3B ADD A,A Shift left
CC3C JR NC,bct_mult1 Top bit not set
CC3E LD H,B Copy distance shift value
CC3F LD L,C
CC40 ADD HL,HL Double it
bct_mult1 CC41 ADD A,A Shift topmost bit out
CC42 JR NC,bct_mult2 Jump if top bit not set
CC44 ADD HL,BC Otherwise HL += BC
bct_mult2 CC45 ADD HL,HL Repeat
CC46 ADD A,A
CC47 JR NC,bct_mult3
CC49 ADD HL,BC
bct_mult3 CC4A ADD HL,HL Repeat
CC4B ADD A,A
CC4C JR NC,bct_mult4
CC4E ADD HL,BC
bct_mult4 CC4F ADD HL,HL Repeat
CC50 ADD A,A
CC51 JR NC,bct_mult5
CC53 ADD HL,BC
bct_mult5 CC54 ADD HL,HL Repeat
CC55 ADD A,A
CC56 JR NC,bct_cc59
CC58 ADD HL,BC
bct_cc59 CC59 LD A,H A = H
CC5A RL L L <<= 1
CC5C LD H,$00 H = 0
CC5E ADC A,H L = A + H + carry
CC5F LD L,A
CC60 ADD A,A A <<= 1
CC61 JR NC,bct_topbitclear Jump if top bit not set
CC63 DEC H H = $FF - make negative
bct_topbitclear CC64 RRA A >>= 1
CC65 ADD HL,DE HL += DE
CC66 EX DE,HL Swap (DE is result)
CC67 EXX Unbank
CC68 LD (DE),A *DE++ = A
CC69 INC E
CC6A DJNZ bct_loop Loop back to bct_loop to read buffer byte bit
CC6C POP DE Pop road position
CC6D LD B,$00 B = 0 -- not self modified
CC6F EXX Bank
CC70 LD HL,$ED00 SELF MODIFIED output address $ED00 or $EE00
CC73 CALL build_curve_table_fill Call build_curve_table_fill
CC76 LD A,($A23F) Load fast_counter
CC79 AND $E0 Take top three bits
CC7B LD B,A Move result to B
Reduce B 0..31 => 0..21.
CC7C RRC B Divide by 4 and subtract
CC7E RRC B
CC80 SUB B
CC81 RRC B Divide by 16 and subtract
CC83 RRC B
CC85 SUB B
Index the road animation table persp_x_delta_left.
CC86 ADD A,$60 HL = $E700 + $60 + A
CC88 LD L,A
CC89 LD H,$E7
CC8B JR NC,bct_build_table_e320 Jump if A+$60 had no carry
CC8D INC H Add carry otherwise
Adds one of the entries somewhere in persp_x_delta_left to the 22 bytes at $E320.
bct_build_table_e320 CC8E LD DE,$E320 Address of table_e320 (written to)
CC91 LD B,$16 22 iterations
bct_build_table_e320_loop CC93 LD A,(DE) Load an entry from table_e320
This reads from (somewhere in) persp_x_delta_left in sequence.
CC94 ADD A,(HL) Increment it by (HL)
CC95 LD (DE),A Write back to (DE)
CC96 INC HL Increment entry address in persp_x_delta_left
CC97 INC E Increment entry address in table_e320
CC98 DJNZ bct_build_table_e320_loop Loop while B > 0
This controls the vanishing point. Decrease this value for wider roads - but the road might appear to bend left... Consider that this is $127 but $109 is the centre.
CC9A LD HL,($A26C) HL = road_pos - 295
CC9D LD DE,$FED9
CCA0 ADD HL,DE
CCA1 EX DE,HL Swap result to DE
CCA2 LD B,$00 Initialise total/counter
CCA4 EXX Unbank
CCA5 LD HL,$E900 SELF MODIFIED destination address $E900 or $EC00
Called as subroutine, also fallthrough.
build_curve_table_fill CCA8 LD IY,$E300 Address of height table (22 bytes long)
CCAC LD B,$15 21 iterations
CCAE LD ($CCF5),SP Save SP to restore on exit (self modify)
CCB2 LD SP,HL Put address in SP (so we can use PUSH for speed)
bct_loop_ccb3 CCB3 EXX Bank
CCB4 LD A,B A = B - 2 + IY[0] - IY[1]; IY++
CCB5 SUB $02
CCB7 ADD A,(IY+$00)
CCBA INC IYl
CCBC SUB (IY+$00)
CCBF JP M,bct_endbit_negative Jump to bct_endbit_negative if M
CCC2 ADD A,$02 A += 2
CCC4 LD (IY+$4E),A IY[$4E] = A -- in table_e320?
CCC7 SUB B A -= B
CCC8 LD C,A C = A
CCC9 LD B,A B = A
CCCA LD L,(IY+$1F) L = IY[$1F]
CCCD BIT 7,L Test bit 7 of L
CCCF JR Z,bct_increment_case Jump if clear
CCD1 LD A,L L = -L
CCD2 NEG
CCD4 LD L,A
CCD5 LD A,B A = B
CCD6 CP L A < L ?
CCD7 LD A,$1B Opcode for DEC DE
CCD9 JR C,bct_endbit_A Jump to bct_endbit_A if A < L
CCDB JP bct_do_self_modify Jump to bct_do_self_modify
bct_increment_case CCDE CP L A < L ?
CCDF LD A,$13 Opcode for INC DE
CCE1 JR C,bct_endbit_A Jump to bct_endbit_A if A < L
bct_do_self_modify CCE3 LD ($CCED),A Self modify instruction below
CCE6 LD A,B A = B >> 1
CCE7 RRA
bct_loop_cce8 CCE8 ADD A,L A += L
CCE9 CP C A < C ?
CCEA JR C,bct_ccee Jump if A < C
CCEC SUB C A -= C
CCED INC DE Self modified: could be INC DE or DEC DE
bct_ccee CCEE PUSH DE Store the current state of DE to table
CCEF DJNZ bct_loop_cce8 Loop to bct_loop_cce8 while B > 0
CCF1 EXX Unbank
CCF2 DJNZ bct_loop_ccb3 Loop to bct_loop_ccb3 while B > 0
bct_exit CCF4 LD SP,$0000 Restore original SP (self modified by CCAE)
CCF7 RET Return
A is opcode of instruction (INC DE/DEC DE) B is max iterations C is ? L is ? DE is ?
bct_endbit_A CCF8 LD ($CCFC),A Self modify instruction below
CCFB XOR A Initialise total to zero
bct_loop_ccfc CCFC INC DE Self modified: could be INC DE or DEC DE
CCFD ADD A,C Increment total by C
CCFE JR C,bct_carried_or_a_ge_l Jump if overflow
CD00 CP L Otherwise, loop if A < L
CD01 JR C,bct_loop_ccfc
bct_carried_or_a_ge_l CD03 SUB L Decrement A by L
CD04 PUSH DE Push the current state of DE to table
CD05 DJNZ bct_loop_ccfc Loop to bct_loop_ccfc while B > 0
CD07 EXX Unbank
CD08 DJNZ bct_loop_ccb3 Loop to bct_loop_ccb3 while B > 0
CD0A JR bct_exit Exit via bct_exit
bct_endbit_negative CD0C LD (IY+$4E),$01 IY[$4E] = 1
CD10 INC A A++
CD11 JR Z,bct_endbit_C Jump to bct_endbit_C if zero
CD13 INC A A++
CD14 LD B,A B = A
CD15 LD A,(IY+$1F) A = IY[$1F]
CD18 LD L,A L = A
CD19 ADD A,A A <<= 1
CD1A SBC A,A H = A - A - carry -- sign extend?
CD1B LD H,A
CD1C ADD HL,DE HL += DE
CD1D EX DE,HL swap
CD1E PUSH DE push result?
CD1F EXX Bank/Unbank?
CD20 DEC B Decrement loop counter -- Why not using DJNZ?
CD21 JP NZ,bct_loop_ccb3 Loop to bct_loop_ccb3 while B > 0
CD24 JP bct_exit Exit via bct_exit
This is identical to the preceding sequence starting at CD14, so could be removed if CD11 instead just jumped over CD13.
bct_endbit_C CD27 LD B,A
CD28 LD A,(IY+$1F)
CD2B LD L,A
CD2C ADD A,A
CD2D SBC A,A
CD2E LD H,A
CD2F ADD HL,DE
CD30 EX DE,HL
CD31 PUSH DE
CD32 EXX
CD33 DEC B
CD34 JP NZ,bct_loop_ccb3
CD37 JP bct_exit
Prev: CBC5 Up: Map Next: CD3A