********************************************************************************
* Stellar 7 for the Apple II, by Damon Slye *
* Copyright 1983 Dynamix *
* *
* Disassembly of "ROCK1". *
********************************************************************************
* This has various math and graphics routines and some data tables. There's a *
* lot of padding here to ensure page alignment. *
********************************************************************************
* Disassembly by Andy McFadden, using 6502bench SourceGen v1.6. *
* Last updated 2020/03/25 *
********************************************************************************
instr_DEC .eq $c6 {const}
instr_DEX .eq $ca {const}
instr_INC .eq $e6 {const}
instr_INX .eq $e8 {const}
hpage .eq $32
VIEW_X_ADJ .eq $50 {addr/2} ;translate viewport to screen coords
VIEW_Y_ADJ .eq $52 {addr/2} ;translate viewport to screen coords
VIEW_LEFT .eq $54 {addr/2} ;left edge of current viewport
VIEW_RIGHT .eq $56 {addr/2} ;right edge of current viewport
VIEW_TOP .eq $58 {addr/2} ;top edge of current viewport
VIEW_BOTTOM .eq $5a {addr/2} ;bottom edge of current viewport
UPDATE_DRAW_OBJECTS .eq $6010 ;updates and draws all active objects
RENDER_PAGE .eq $65f0 ;hi-res page to draw on (0=p1, 1=p2)
ERASE_VIEW_FLAG .eq $65f1 ;bool 00/80: erase viewport before rendering
BLOCK_MOVEMENT0 .eq $65f2 ;bool 00/80: don't move units when rendering page 0
BLOCK_MOVEMENT1 .eq $65f3 ;bool 00/80: don't move units when rendering page 1
MESH_DATA_PTR .eq $65f4 {addr/2} ;pointer to 3D mesh data
JMP_ADDR_CLEAR .eq $65f6 {addr/2} ;ClearScreen or ClearViewport
JUMP_ADDR2 .eq $65f8 {addr/2} ;(initialized but not used)
JUMP_ADDR3 .eq $65fa {addr/2} ;(initialized but not used)
SHOW_BKGND_FLAG .eq $65fc ;bool 00/80: show stars/mountains
HORIZON_BASELINE .eq $65fd ;adjusts star/mountain position
OBJ_ALIVE_FLAG .eq $6600 {addr/24} ;bool 00/80: is object alive?
OBJ_TYPE .eq $6618 {addr/24} ;object type, 0-63
OBJ_MAX_DIM .eq $6630 {addr/24} ;largest dimension in mesh
OBJ_XC_LO .eq $6648 {addr/24} ;object X coordinate, lo
OBJ_XC_HI .eq $6660 {addr/24} ;object X coordinate, hi
OBJ_ZC_LO .eq $6678 {addr/24} ;object Z coordinate, lo
OBJ_ZC_HI .eq $6690 {addr/24} ;object Z coordinate, hi
OBJ_YC_LO .eq $66a8 {addr/24} ;object Y coordinate, lo
OBJ_YC_HI .eq $66c0 {addr/24} ;object Y coordinate, hi
OBJ_FACING .eq $66d8 {addr/24} ;facing angle, 0-255
OBJ_XC_MOVE .eq $66f0 {addr/24} ;add to obj XC each frame
OBJ_ZC_MOVE .eq $6708 {addr/24} ;add to obj ZC each frame
OBJ_YC_MOVE .eq $6720 {addr/24} ;add to obj YC each frame
OBJ_SPEED .eq $6738 {addr/24} ;move fwd this much each frame
OBJ_FACING_ADJ .eq $6750 {addr/24} ;offset facing for movement calc
OBJ_ROT_SPEED .eq $6768 {addr/24} ;rotation speed, in angle256/frame
OBJ_IMMOB_FLAG .eq $6780 {addr/24} ;bool 00/80: object is immobile
OBJ_VIS_FLAG .eq $6798 {addr/24} ;bool 00/80: object is visible
VIEW_ACTV_FLAGS .eq $67c0 {addr/4} ;bool 00/80: is viewport N active
VIEW_SKIP_OBJS .eq $67c4 {addr/4} ;viewer object (0-23), never shown
VIEW_ANGLE_ADJS .eq $67c8 {addr/4} ;angle adjustment, for left/right/rear view
VIEW_ZOOMS .eq $67cc {addr/4} ;camera zoom, 7=normal, 9=telephoto
VIEW_NEAR_VERT .eq $67d0 {addr/4} ;near clip plane, applied to vertices
VIEW_NEAR_LO .eq $67d4 {addr/4} ;near clip plane, applied to obj (low)
VIEW_NEAR_HI .eq $67d8 {addr/4} ;near clip plane, applied to obj (hi)
VIEW_FAR_LO .eq $67dc {addr/4} ;far clip plane, applied to obj (low)
VIEW_FAR_HI .eq $67e0 {addr/4} ;far clip plane, applied to obj (high)
VIEW_X_ADJS .eq $67e4 {addr/4} ;viewport screen adjustments
VIEW_Y_ADJS .eq $67e8 {addr/4} ;viewport screen adjustments
VIEW_LEFT_VALS .eq $67ec {addr/4} ;viewport bounds, left edge
VIEW_RIGHT_VALS .eq $67f0 {addr/4} ;viewport bounds, right edge
VIEW_TOP_VALS .eq $67f4 {addr/4} ;viewport bounds, top edge
VIEW_BOTTOM_VALS .eq $67f8 {addr/4} ;viewport bounds, bottom edge
MESH_DATA .eq $6800 ;3D object mesh data
DRAW_MOUNTAINS .eq $7000 ;draw mountains (part of LEV#)
DRAW_STARS .eq $70b0 ;draw stars and horizon line (part of LEV#)
CLEAR_VIEWPORT .eq $7400 ;clear the viewport, page determined by A-reg
DRAW_HUD_ITEMS .eq $7e00 ;draw reticle, score, radar, shields/fuel
OBJ_MOVE_CLASS .eq $8418 {addr/24} ;movement classes
SHOTS_VIS_FLAG .eq $8581 ;if nonzero, shots are visible on radar
UPDATE_SOUND .eq $a040 ;update sound effects
MIXCLR .eq $c052 ;RW display full screen
.org $0800
0800: 00 00 00 0a+ .junk 16
********************************************************************************
* Computes (val0 * 2^mult) / val1. val0 may be signed. *
* *
* Used for perspective calculations. val0 is XC or YC, val1 is ZC, and the *
* multiplier is 7 (128) for normal view, 9 (512) for zoom. The result is the *
* projected clip-space coordinate Px or Py. *
* *
* (If you include the mid-function page padding, this is 695 bytes long.) *
* *
* On entry: *
* $00/01: val0 (16-bit dividend, XC/YC) *
* $02/03: val1 (16-bit divisor, ZC) *
* $06: multiplier 2^N (e.g. pass 7 to multiply by 128) *
* *
* On exit: *
* $00/01: quotient (16-bit) *
********************************************************************************
]dividend .var $00 {addr/2} ;numerator
]divisor .var $02 {addr/2} ;denominator
]val4 .var $04 {addr/2}
]mult2n .var $06 {addr/1}
]tmp .var $09 {addr/1}
0810: a5 01 Divide16 lda ]dividend+1 ;get high byte for sign flag
0812: 48 pha ;save for later
0813: 10 0d bpl :Pos ;positive, branch
0815: 38 sec ;negative, make it positive
0816: a9 00 lda #$00
0818: e5 00 sbc ]dividend
081a: 85 00 sta ]dividend
081c: a9 00 lda #$00
081e: e5 01 sbc ]dividend+1
0820: 85 01 sta ]dividend+1
0822: a6 06 :Pos ldx ]mult2n
0824: f0 12 beq :WasNeg
0826: a5 01 lda ]dividend+1 ;check sign flag again
0828: 30 0e bmi :WasNeg
082a: 06 00 :ShiftLoop asl ]dividend ;left-shift value until high bit set
082c: 2a rol A ; to reduce iterations in divide code
082d: 30 04 bmi :ShiftDone
082f: ca dex ;reduce iterations
0830: d0 f8 bne :ShiftLoop ;continue until we hit zero
0832: e8 inx ;balance the next DEX
0833: ca :ShiftDone dex
0834: 86 06 stx ]mult2n ;save updated multiplier
0836: 85 01 sta ]dividend+1 ; and numerator
0838: 20 00 09 :WasNeg jsr :DivideMain
083b: a6 06 ldx ]mult2n ;are we done?
083d: f0 03 beq :DivideDone ;yes
083f: 20 70 08 jsr :DivideFinish ;no, apply finishing touches
0842: 68 :DivideDone pla ;get original high byte
0843: 10 0d bpl :Done ;positive, we're done
0845: 38 sec ;negative, flip arg1 back
0846: a9 00 lda #$00
0848: e5 00 sbc ]dividend
084a: 85 00 sta ]dividend
084c: a9 00 lda #$00
084e: e5 01 sbc ]dividend+1
0850: 85 01 sta ]dividend+1
0852: 60 :Done rts
0853: 00 ff ff 00+ .junk 29
0870: a5 03 :DivideFinish lda ]divisor+1
0872: d0 14 bne L0888
0874: a5 04 lda ]val4
0876: 0a L0876 asl A
0877: b0 04 bcs L087D
0879: c5 02 cmp ]divisor
087b: 90 03 bcc L0880
087d: e5 02 L087D sbc ]divisor
087f: 38 sec
0880: 26 00 L0880 rol ]dividend
0882: 26 01 rol ]dividend+1
0884: ca dex
0885: d0 ef bne L0876
0887: 60 rts
0888: 06 04 L0888 asl ]val4
088a: 26 05 rol ]val4+1
088c: 90 0f bcc L089D
088e: a5 04 lda ]val4
0890: e5 02 sbc ]divisor
0892: 85 04 sta ]val4
0894: a5 05 lda ]val4+1
0896: e5 03 sbc ]divisor+1
0898: 85 05 sta ]val4+1
089a: 38 sec
089b: b0 10 bcs L08AD
089d: 38 L089D sec
089e: a5 04 lda ]val4
08a0: e5 02 sbc ]divisor
08a2: a8 tay
08a3: a5 05 lda ]val4+1
08a5: e5 03 sbc ]divisor+1
08a7: 90 04 bcc L08AD
08a9: 84 04 sty ]val4
08ab: 85 05 sta ]val4+1
08ad: 26 00 L08AD rol ]dividend
08af: 26 01 rol ]dividend+1
08b1: ca dex
08b2: d0 d4 bne L0888
08b4: 60 rts
08b5: ff 00 00 ff+ .align $0100 (75 bytes)
; Branch to a specific handler based on the input characteristics.
0900: a5 03 :DivideMain lda ]divisor+1 ;check high byte - denominator < 256?
0902: f0 17 beq :SmallDenom ;yes, branch
0904: a5 01 lda ]dividend+1 ;small numerator?
0906: f0 04 beq :SmallNumBigDenom ;yes, branch
0908: c5 03 cmp ]divisor+1 ;is numerator high byte >= denominator?
090a: b0 1b bcs :BigNumBigDen ;yes, branch
; The numerator is smaller than the denominator, so we know that the result will
; be < 256.
:SmallNumBigDenom
090c: a5 01 lda ]dividend+1
090e: 85 05 sta ]val4+1
0910: a5 00 lda ]dividend
0912: 85 04 sta ]val4
0914: a9 00 lda #$00
0916: 85 01 sta ]dividend+1
0918: 85 00 sta ]dividend
091a: 60 rts
; Denominator is < 256.
091b: a5 01 :SmallDenom lda ]dividend+1 ;divisor+1 is zero...
091d: c5 02 cmp ]divisor ;is numerator >= 256x divisor?
091f: 90 03 bcc :SmallDenom_jmp ;no
0921: 4c 00 0a jmp :HugeNumSmallDen ;yes
0924: 4c 5a 0a :SmallDenom_jmp jmp :SmallDenom
; Numerator is >= 256, denominator high byte is >= numerator high byte.
0927: a9 00 :BigNumBigDen lda #$00
0929: 85 09 sta ]tmp
092b: 06 00 asl ]dividend
092d: 26 01 rol ]dividend+1
092f: 26 09 rol ]tmp
0931: 38 sec
0932: a5 01 lda ]dividend+1
0934: e5 02 sbc ]divisor
0936: a8 tay
0937: a5 09 lda ]tmp
0939: e5 03 sbc ]divisor+1
093b: 90 04 bcc L0941
093d: 84 01 sty ]dividend+1
093f: 85 09 sta ]tmp
0941: 26 00 L0941 rol ]dividend
0943: 26 01 rol ]dividend+1
0945: 26 09 rol ]tmp
0947: 38 sec
0948: a5 01 lda ]dividend+1
094a: e5 02 sbc ]divisor
094c: a8 tay
094d: a5 09 lda ]tmp
094f: e5 03 sbc ]divisor+1
0951: 90 04 bcc L0957
0953: 84 01 sty ]dividend+1
0955: 85 09 sta ]tmp
0957: 26 00 L0957 rol ]dividend
0959: 26 01 rol ]dividend+1
095b: 26 09 rol ]tmp
095d: 38 sec
095e: a5 01 lda ]dividend+1
0960: e5 02 sbc ]divisor
0962: a8 tay
0963: a5 09 lda ]tmp
0965: e5 03 sbc ]divisor+1
0967: 90 04 bcc L096D
0969: 84 01 sty ]dividend+1
096b: 85 09 sta ]tmp
096d: 26 00 L096D rol ]dividend
096f: 26 01 rol ]dividend+1
0971: 26 09 rol ]tmp
0973: 38 sec
0974: a5 01 lda ]dividend+1
0976: e5 02 sbc ]divisor
0978: a8 tay
0979: a5 09 lda ]tmp
097b: e5 03 sbc ]divisor+1
097d: 90 04 bcc L0983
097f: 84 01 sty ]dividend+1
0981: 85 09 sta ]tmp
0983: 26 00 L0983 rol ]dividend
0985: 26 01 rol ]dividend+1
0987: 26 09 rol ]tmp
0989: 38 sec
098a: a5 01 lda ]dividend+1
098c: e5 02 sbc ]divisor
098e: a8 tay
098f: a5 09 lda ]tmp
0991: e5 03 sbc ]divisor+1
0993: 90 04 bcc L0999
0995: 84 01 sty ]dividend+1
0997: 85 09 sta ]tmp
0999: 26 00 L0999 rol ]dividend
099b: 26 01 rol ]dividend+1
099d: 26 09 rol ]tmp
099f: 38 sec
09a0: a5 01 lda ]dividend+1
09a2: e5 02 sbc ]divisor
09a4: a8 tay
09a5: a5 09 lda ]tmp
09a7: e5 03 sbc ]divisor+1
09a9: 90 04 bcc L09AF
09ab: 84 01 sty ]dividend+1
09ad: 85 09 sta ]tmp
09af: 26 00 L09AF rol ]dividend
09b1: 26 01 rol ]dividend+1
09b3: 26 09 rol ]tmp
09b5: 38 sec
09b6: a5 01 lda ]dividend+1
09b8: e5 02 sbc ]divisor
09ba: a8 tay
09bb: a5 09 lda ]tmp
09bd: e5 03 sbc ]divisor+1
09bf: 90 04 bcc L09C5
09c1: 84 01 sty ]dividend+1
09c3: 85 09 sta ]tmp
09c5: 26 00 L09C5 rol ]dividend
09c7: 26 01 rol ]dividend+1
09c9: 26 09 rol ]tmp
09cb: 38 sec
09cc: a5 01 lda ]dividend+1
09ce: e5 02 sbc ]divisor
09d0: a8 tay
09d1: a5 09 lda ]tmp
09d3: e5 03 sbc ]divisor+1
09d5: 90 04 bcc L09DB
09d7: 84 01 sty ]dividend+1
09d9: 85 09 sta ]tmp
09db: 26 00 L09DB rol ]dividend
09dd: a5 09 lda ]tmp
09df: 85 05 sta ]val4+1
09e1: a5 01 lda ]dividend+1
09e3: 85 04 sta ]val4
09e5: a9 00 lda #$00
09e7: 85 01 sta ]dividend+1
09e9: 60 rts
09ea: 00 00 ff ff+ .align $0100 (22 bytes)
; Numerator is >= 256x the denominator.
:HugeNumSmallDen
0a00: a9 00 lda #$00
0a02: 06 01 asl ]dividend+1
0a04: 2a rol A
0a05: c5 02 cmp ]divisor
0a07: 90 02 bcc L0A0B
0a09: e5 02 sbc ]divisor
0a0b: 26 01 L0A0B rol ]dividend+1
0a0d: 2a rol A
0a0e: c5 02 cmp ]divisor
0a10: 90 02 bcc L0A14
0a12: e5 02 sbc ]divisor
0a14: 26 01 L0A14 rol ]dividend+1
0a16: 2a rol A
0a17: c5 02 cmp ]divisor
0a19: 90 02 bcc L0A1D
0a1b: e5 02 sbc ]divisor
0a1d: 26 01 L0A1D rol ]dividend+1
0a1f: 2a rol A
0a20: c5 02 cmp ]divisor
0a22: 90 02 bcc L0A26
0a24: e5 02 sbc ]divisor
0a26: 26 01 L0A26 rol ]dividend+1
0a28: 2a rol A
0a29: c5 02 cmp ]divisor
0a2b: 90 02 bcc L0A2F
0a2d: e5 02 sbc ]divisor
0a2f: 26 01 L0A2F rol ]dividend+1
0a31: 2a rol A
0a32: c5 02 cmp ]divisor
0a34: 90 02 bcc L0A38
0a36: e5 02 sbc ]divisor
0a38: 26 01 L0A38 rol ]dividend+1
0a3a: 2a rol A
0a3b: c5 02 cmp ]divisor
0a3d: 90 02 bcc L0A41
0a3f: e5 02 sbc ]divisor
0a41: 26 01 L0A41 rol ]dividend+1
0a43: 2a rol A
0a44: c5 02 cmp ]divisor
0a46: 90 02 bcc L0A4A
0a48: e5 02 sbc ]divisor
0a4a: 26 01 L0A4A rol ]dividend+1
0a4c: a6 01 ldx ]dividend+1
0a4e: 86 08 stx $08
0a50: 85 01 sta ]dividend+1
0a52: 20 5a 0a jsr :SmallDenom
0a55: a5 08 lda $08
0a57: 85 01 sta ]dividend+1
0a59: 60 rts
; Numerator could be anything, denominator is < 256.
0a5a: a5 01 :SmallDenom lda ]dividend+1
0a5c: 06 00 asl ]dividend
0a5e: 2a rol A
0a5f: b0 04 bcs L0A65
0a61: c5 02 cmp ]divisor
0a63: 90 03 bcc L0A68
0a65: e5 02 L0A65 sbc ]divisor
0a67: 38 sec
0a68: 26 00 L0A68 rol ]dividend
0a6a: 2a rol A
0a6b: b0 04 bcs L0A71
0a6d: c5 02 cmp ]divisor
0a6f: 90 03 bcc L0A74
0a71: e5 02 L0A71 sbc ]divisor
0a73: 38 sec
0a74: 26 00 L0A74 rol ]dividend
0a76: 2a rol A
0a77: b0 04 bcs L0A7D
0a79: c5 02 cmp ]divisor
0a7b: 90 03 bcc L0A80
0a7d: e5 02 L0A7D sbc ]divisor
0a7f: 38 sec
0a80: 26 00 L0A80 rol ]dividend
0a82: 2a rol A
0a83: b0 04 bcs L0A89
0a85: c5 02 cmp ]divisor
0a87: 90 03 bcc L0A8C
0a89: e5 02 L0A89 sbc ]divisor
0a8b: 38 sec
0a8c: 26 00 L0A8C rol ]dividend
0a8e: 2a rol A
0a8f: b0 04 bcs L0A95
0a91: c5 02 cmp ]divisor
0a93: 90 03 bcc L0A98
0a95: e5 02 L0A95 sbc ]divisor
0a97: 38 sec
0a98: 26 00 L0A98 rol ]dividend
0a9a: 2a rol A
0a9b: b0 04 bcs L0AA1
0a9d: c5 02 cmp ]divisor
0a9f: 90 03 bcc L0AA4
0aa1: e5 02 L0AA1 sbc ]divisor
0aa3: 38 sec
0aa4: 26 00 L0AA4 rol ]dividend
0aa6: 2a rol A
0aa7: b0 04 bcs L0AAD
0aa9: c5 02 cmp ]divisor
0aab: 90 03 bcc L0AB0
0aad: e5 02 L0AAD sbc ]divisor
0aaf: 38 sec
0ab0: 26 00 L0AB0 rol ]dividend
0ab2: 2a rol A
0ab3: b0 04 bcs L0AB9
0ab5: c5 02 cmp ]divisor
0ab7: 90 03 bcc L0ABC
0ab9: e5 02 L0AB9 sbc ]divisor
0abb: 38 sec
0abc: 26 00 L0ABC rol ]dividend
0abe: 85 04 sta ]val4
0ac0: a9 00 lda #$00
0ac2: 85 05 sta ]val4+1
0ac4: 85 01 sta ]dividend+1
0ac6: 60 rts
0ac7: 00 ff ff 00+ .align $0100 (57 bytes)
********************************************************************************
* Rotates a pair of coordinates about a perpendicular axis (e.g. X,Z about Y). *
* *
* Computes newX = X * cos(theta) - Z * sin(theta) *
* newZ = X * sin(theta) + Z * cos(theta) *
* *
* The math uses a right-handed coordinate system. The angle expresses a full *
* circle in 256 units. An angle of 64 would rotate 90 degrees counter- *
* clockwise. *
* *
* Called from ROCK2. *
* *
* On entry: *
* $00/01: X coordinate (signed 16-bit) *
* $02/03: Z coordinate (signed 16-bit) *
* A-reg: angle (0-255) *
* *
* On exit: *
* $04/05: rotated X coordinate (signed 16-bit) *
* $06/07: rotated Z coordinate (signed 16-bit) *
********************************************************************************
• Clear variables
]xc .var $00 {addr/2}
]zc .var $02 {addr/2}
]rot_xc .var $04 {addr/2}
]rot_zc .var $06 {addr/2}
]sin_theta .var $08 {addr/1}
]cos_theta .var $09 {addr/1}
0b00: a8 RotateCoords tay ;preserve A-reg
0b01: 29 3f and #$3f ;check low 6 bits (test for 90-degree angles)
0b03: f0 56 beq :TrivialAngle ;zero, branch
0b05: b9 00 0f lda rotate_tab,y ;get cos(theta)
0b08: 85 09 sta ]cos_theta
0b0a: 18 clc
0b0b: 98 tya
0b0c: 69 c0 adc #$c0 ;sine is 1/4 out of phase
0b0e: a8 tay
0b0f: b9 00 0f lda rotate_tab,y ;get sin(theta)
0b12: 85 08 sta ]sin_theta
; compute rotated XC
0b14: a5 09 lda ]cos_theta
0b16: a6 00 ldx ]xc
0b18: a4 01 ldy ]xc+1
0b1a: 20 00 0c jsr Multiply16_8 ;compute XC * cos(theta)
0b1d: 85 05 sta ]rot_xc+1
0b1f: 84 04 sty ]rot_xc
0b21: a5 08 lda ]sin_theta ;flip the sign bit on the sine value
0b23: 49 80 eor #$80 ; (high bit is a signal to the multiplication
0b25: a6 02 ldx ]zc ; function; sign-extension not required)
0b27: a4 03 ldy ]zc+1
0b29: 20 00 0c jsr Multiply16_8 ;compute YC * sin(theta)
0b2c: aa tax ;rotXC = XC * cos(theta) - YC * sin(theta)
0b2d: 18 clc
0b2e: 98 tya
0b2f: 65 04 adc ]rot_xc
0b31: 85 04 sta ]rot_xc
0b33: 8a txa
0b34: 65 05 adc ]rot_xc+1
0b36: 85 05 sta ]rot_xc+1
; compute rotated YC
0b38: a5 08 lda ]sin_theta
0b3a: a6 00 ldx ]xc
0b3c: a4 01 ldy ]xc+1
0b3e: 20 00 0c jsr Multiply16_8 ;compute XC * sin(theta)
0b41: 85 07 sta ]rot_zc+1
0b43: 84 06 sty ]rot_zc
0b45: a5 09 lda ]cos_theta
0b47: a6 02 ldx ]zc
0b49: a4 03 ldy ]zc+1
0b4b: 20 00 0c jsr Multiply16_8 ;compute YC * cos(theta)
0b4e: aa tax ;rotYC = XC * sin(theta) + YC * cos(theta)
0b4f: 18 clc
0b50: 98 tya
0b51: 65 06 adc ]rot_zc
0b53: 85 06 sta ]rot_zc
0b55: 8a txa
0b56: 65 07 adc ]rot_zc+1
0b58: 85 07 sta ]rot_zc+1
0b5a: 60 rts
0b5b: 98 :TrivialAngle tya ;check full acc
0b5c: d0 11 bne :AngleNotZero ;not zero, branch
0b5e: a5 00 lda ]xc ;angle=0, just copy input args to output
0b60: 85 04 sta ]rot_xc
0b62: a5 01 lda ]xc+1
0b64: 85 05 sta ]rot_xc+1
0b66: a5 02 lda ]zc
0b68: 85 06 sta ]rot_zc
0b6a: a5 03 lda ]zc+1
0b6c: 85 07 sta ]rot_zc+1
0b6e: 60 rts
0b6f: 30 16 :AngleNotZero bmi :AngleNeg ;if negative, branch
0b71: 38 sec ;angle=64, ccw 90 degrees
0b72: a9 00 lda #$00 ;rotated XC = -YC
0b74: e5 02 sbc ]zc
0b76: 85 04 sta ]rot_xc
0b78: a9 00 lda #$00
0b7a: e5 03 sbc ]zc+1
0b7c: 85 05 sta ]rot_xc+1
0b7e: a5 00 lda ]xc ;rotated YC = XC
0b80: 85 06 sta ]rot_zc
0b82: a5 01 lda ]xc+1
0b84: 85 07 sta ]rot_zc+1
0b86: 60 rts
0b87: 29 40 :AngleNeg and #$40 ;check bit 6
0b89: d0 1b bne :Angle192
0b8b: 38 sec ;angle=128, ccw 180deg
0b8c: a9 00 lda #$00 ;rotated XC = -XC
0b8e: e5 00 sbc ]xc
0b90: 85 04 sta ]rot_xc
0b92: a9 00 lda #$00
0b94: e5 01 sbc ]xc+1
0b96: 85 05 sta ]rot_xc+1
0b98: 38 sec ;rotated YC = -YC
0b99: a9 00 lda #$00
0b9b: e5 02 sbc ]zc
0b9d: 85 06 sta ]rot_zc
0b9f: a9 00 lda #$00
0ba1: e5 03 sbc ]zc+1
0ba3: 85 07 sta ]rot_zc+1
0ba5: 60 rts
0ba6: a5 02 :Angle192 lda ]zc ;angle=192, ccw 270deg
0ba8: 85 04 sta ]rot_xc ;rotated XC = YC
0baa: a5 03 lda ]zc+1
0bac: 85 05 sta ]rot_xc+1
0bae: 38 sec ;rotated YC = -XC
0baf: a9 00 lda #$00
0bb1: e5 00 sbc ]xc
0bb3: 85 06 sta ]rot_zc
0bb5: a9 00 lda #$00
0bb7: e5 01 sbc ]xc+1
0bb9: 85 07 sta ]rot_zc+1
0bbb: 60 rts
; This looks like a couple of functions, one of which runs into $c00, but the
; code isn't referenced and it never tripped in a debugger.
0bbc: 03 a2 00 a5+ .align $0100 (68 bytes)
********************************************************************************
* Multiplies a signed 16-bit value by a an 8-bit value. *
* *
* Used for rotations. Only called within ROCK1. *
* *
* The caller handles 90-degree rotations, so A-reg will never be zero. *
* *
* On entry: *
* X-reg: low part of first value *
* Y-reg: high part of first value *
* A-reg: second value; set high bit for negative *
* flags must be set for Y-reg contents (so load that last) *
* *
* On exit: *
* Y-reg: low part of result *
* A-reg: high part of result *
********************************************************************************
• Clear variables
]tmp1 .var $0a {addr/1}
]tmp2 .var $0b {addr/1}
]tmp3 .var $0c {addr/1}
]result_lo .var $0d {addr/1}
0c00: 10 14 Multiply16_8 bpl :PosVal ;value is positive, branch
0c02: 49 80 eor #$80 ;value negative, clear high bit
0c04: 4a lsr A
0c05: 85 0c sta ]tmp3
0c07: 8a txa ;negate first value
0c08: 49 ff eor #$ff
0c0a: 85 0a sta ]tmp1
0c0c: 98 tya
0c0d: 49 ff eor #$ff
0c0f: 85 0b sta ]tmp2
0c11: 4c 27 0c jmp :Common ;branch skips DEX/DEY below
0c14: 98 :Zero tya ;set A-reg=0
0c15: 60 rts ; and bail
0c16: e0 00 :PosVal cpx #$00 ;is low part zero?
0c18: d0 05 bne L0C1F ;no
0c1a: c0 00 cpy #$00 ;is high part zero?
0c1c: f0 f6 beq :Zero ;yes, result is zero
0c1e: 88 dey
0c1f: ca L0C1F dex
0c20: 86 0a stx ]tmp1
0c22: 84 0b sty ]tmp2
0c24: 4a lsr A
0c25: 85 0c sta ]tmp3
0c27: a9 00 :Common lda #$00
0c29: 85 0d sta ]result_lo
0c2b: 90 0a bcc L0C37
0c2d: a8 tay
0c2e: a5 0d lda ]result_lo
0c30: 65 0a adc ]tmp1
0c32: 85 0d sta ]result_lo
0c34: 98 tya
0c35: 65 0b adc ]tmp2
0c37: 6a L0C37 ror A
0c38: 66 0d ror ]result_lo
0c3a: 66 0c ror ]tmp3
0c3c: 90 0a bcc L0C48
0c3e: a8 tay
0c3f: a5 0d lda ]result_lo
0c41: 65 0a adc ]tmp1
0c43: 85 0d sta ]result_lo
0c45: 98 tya
0c46: 65 0b adc ]tmp2
0c48: 6a L0C48 ror A
0c49: 66 0d ror ]result_lo
0c4b: 66 0c ror ]tmp3
0c4d: 90 0a bcc L0C59
0c4f: a8 tay
0c50: a5 0d lda ]result_lo
0c52: 65 0a adc ]tmp1
0c54: 85 0d sta ]result_lo
0c56: 98 tya
0c57: 65 0b adc ]tmp2
0c59: 6a L0C59 ror A
0c5a: 66 0d ror ]result_lo
0c5c: 66 0c ror ]tmp3
0c5e: 90 0a bcc L0C6A
0c60: a8 tay
0c61: a5 0d lda ]result_lo
0c63: 65 0a adc ]tmp1
0c65: 85 0d sta ]result_lo
0c67: 98 tya
0c68: 65 0b adc ]tmp2
0c6a: 6a L0C6A ror A
0c6b: 66 0d ror ]result_lo
0c6d: 66 0c ror ]tmp3
0c6f: 90 0a bcc L0C7B
0c71: a8 tay
0c72: a5 0d lda ]result_lo
0c74: 65 0a adc ]tmp1
0c76: 85 0d sta ]result_lo
0c78: 98 tya
0c79: 65 0b adc ]tmp2
0c7b: 6a L0C7B ror A
0c7c: 66 0d ror ]result_lo
0c7e: 66 0c ror ]tmp3
0c80: 90 0a bcc L0C8C
0c82: a8 tay
0c83: a5 0d lda ]result_lo
0c85: 65 0a adc ]tmp1
0c87: 85 0d sta ]result_lo
0c89: 98 tya
0c8a: 65 0b adc ]tmp2
0c8c: 6a L0C8C ror A
0c8d: 66 0d ror ]result_lo
0c8f: 66 0c ror ]tmp3
0c91: 90 0a bcc L0C9D
0c93: a8 tay
0c94: a5 0d lda ]result_lo
0c96: 65 0a adc ]tmp1
0c98: 85 0d sta ]result_lo
0c9a: 98 tya
0c9b: 65 0b adc ]tmp2
0c9d: 6a L0C9D ror A
0c9e: 66 0d ror ]result_lo
0ca0: 66 0c ror ]tmp3
0ca2: 90 0e bcc L0CB2
0ca4: aa tax
0ca5: a5 0d lda ]result_lo
0ca7: 49 ff eor #$ff
0ca9: 69 00 adc #$00
0cab: a8 tay
0cac: 8a txa
0cad: 49 ff eor #$ff
0caf: 69 00 adc #$00
0cb1: 60 rts
0cb2: a4 0d L0CB2 ldy ]result_lo
0cb4: 60 rts
0cb5: ff 00 00 ff+ .junk 27
;
; Scaled coordinates for radar display. Signed 8-bit values. Drawn by ROCK2 at
; $7e6c.
;
; The radar is 28x28. Objects may be outside that range, and won't be shown.
0cd0: ff ff 00 00+ radar_xcoords .junk 24
0ce8: ff ff 00 00+ radar_ycoords .junk 24
********************************************************************************
* Rotates the coordinate (X,0) about a perpendicular axis (let's say Y). Used *
* for object movement calculations and mesh transformation. *
* *
* On entry: *
* $00: X coordinate (8-bit value; seems to be 0-127) *
* A-reg: angle (0-255) *
* *
* On exit: *
* $22/23: rotated X coordinate (signed 16-bit) *
* $24/25: rotated Z coordinate (signed 16-bit) *
* *
* The return values seem to be -128 < val < 128, which makes sense given the *
* input value range, so the high byte is redundant. *
********************************************************************************
• Clear variables
]xc .var $00 {addr/1}
]val1 .var $01 {addr/1}
]val2 .var $02 {addr/1}
]rot_xc .var $22 {addr/2}
]rot_yc .var $24 {addr/2}
0d00: a6 00 RotateInt8 ldx ]xc ;is coordinate value zero?
0d02: d0 09 bne :NotZero ;no, do the work
0d04: 86 22 stx ]rot_xc ;yes, result is zero
0d06: 86 23 stx ]rot_xc+1
0d08: 86 24 stx ]rot_yc
0d0a: 86 25 stx ]rot_yc+1
0d0c: 60 rts
0d0d: a8 :NotZero tay ;preserve angle
0d0e: 29 3f and #$3f ;check for simple case
0d10: d0 03 bne :NotTrivial ;nonzero, do it the hard way
0d12: 4c b3 0d jmp :SimpleAngle ;yes
; Calculate the X coordinate.
0d15: b9 00 0f :NotTrivial lda rotate_tab,y ;get cos(theta)
0d18: ca dex ;X-reg = XC - 1
0d19: 86 01 stx ]val1 ;save as multiplier part
0d1b: 4a lsr A ;get low bit of cosine
0d1c: 85 02 sta ]val2 ;high byte of 8.8 result
0d1e: a9 00 lda #$00 ;low byte of 8.8 result
0d20: 90 02 bcc L0D24
0d22: 65 01 adc ]val1
0d24: 6a L0D24 ror A
0d25: 66 02 ror ]val2
0d27: 90 02 bcc L0D2B
0d29: 65 01 adc ]val1
0d2b: 6a L0D2B ror A
0d2c: 66 02 ror ]val2
0d2e: 90 02 bcc L0D32
0d30: 65 01 adc ]val1
0d32: 6a L0D32 ror A
0d33: 66 02 ror ]val2
0d35: 90 02 bcc L0D39
0d37: 65 01 adc ]val1
0d39: 6a L0D39 ror A
0d3a: 66 02 ror ]val2
0d3c: 90 02 bcc L0D40
0d3e: 65 01 adc ]val1
0d40: 6a L0D40 ror A
0d41: 66 02 ror ]val2
0d43: 90 02 bcc L0D47
0d45: 65 01 adc ]val1
0d47: 6a L0D47 ror A
0d48: 66 02 ror ]val2
0d4a: 90 02 bcc L0D4E
0d4c: 65 01 adc ]val1
0d4e: 6a L0D4E ror A
0d4f: 66 02 ror ]val2
0d51: a2 00 ldx #$00
0d53: 90 07 bcc L0D5C
0d55: 49 ff eor #$ff
0d57: 69 00 adc #$00
0d59: f0 01 beq L0D5C
0d5b: ca dex
0d5c: 85 22 L0D5C sta ]rot_xc ;rotated XC = X * cos(theta)
0d5e: 86 23 stx ]rot_xc+1
; Now calculate the Y coordinate.
0d60: a6 00 ldx ]xc
0d62: 98 tya
0d63: 18 clc
0d64: 69 c0 adc #$c0 ;sine is offset by 1/4 phase
0d66: a8 tay
0d67: b9 00 0f lda rotate_tab,y ;get sin(theta)
0d6a: ca dex ;X-reg = XC - 1
0d6b: 86 01 stx ]val1
0d6d: 4a lsr A
0d6e: 85 02 sta ]val2
0d70: a9 00 lda #$00
0d72: 90 02 bcc L0D76
0d74: 65 01 adc ]val1
0d76: 6a L0D76 ror A
0d77: 66 02 ror ]val2
0d79: 90 02 bcc L0D7D
0d7b: 65 01 adc ]val1
0d7d: 6a L0D7D ror A
0d7e: 66 02 ror ]val2
0d80: 90 02 bcc L0D84
0d82: 65 01 adc ]val1
0d84: 6a L0D84 ror A
0d85: 66 02 ror ]val2
0d87: 90 02 bcc L0D8B
0d89: 65 01 adc ]val1
0d8b: 6a L0D8B ror A
0d8c: 66 02 ror ]val2
0d8e: 90 02 bcc L0D92
0d90: 65 01 adc ]val1
0d92: 6a L0D92 ror A
0d93: 66 02 ror ]val2
0d95: 90 02 bcc L0D99
0d97: 65 01 adc ]val1
0d99: 6a L0D99 ror A
0d9a: 66 02 ror ]val2
0d9c: 90 02 bcc L0DA0
0d9e: 65 01 adc ]val1
0da0: 6a L0DA0 ror A
0da1: 66 02 ror ]val2
0da3: a2 00 ldx #$00
0da5: 90 07 bcc L0DAE ;last bit was clear, branch
0da7: 49 ff eor #$ff ;negate low byte
0da9: 69 00 adc #$00 ;note carry is set
0dab: f0 01 beq L0DAE
0dad: ca dex
0dae: 85 24 L0DAE sta ]rot_yc ;rotated YC = X * sin(theta)
0db0: 86 25 stx ]rot_yc+1
0db2: 60 rts
0db3: 98 :SimpleAngle tya ;check full angle
0db4: d0 0d bne :AngleNotZero
0db6: a2 00 ldx #$00 ;angle=0
0db8: 86 24 stx ]rot_yc ;rotated YC = 0
0dba: 86 25 stx ]rot_yc+1
0dbc: a5 00 lda ]xc ;rotated XC = XC
0dbe: 85 22 sta ]rot_xc
0dc0: 86 23 stx ]rot_xc+1
0dc2: 60 rts
0dc3: 30 0d :AngleNotZero bmi :AngleNeg
0dc5: a2 00 ldx #$00 ;rotated XC = 0
0dc7: 86 22 stx ]rot_xc
0dc9: 86 23 stx ]rot_xc+1
0dcb: a5 00 lda ]xc ;rotated YC = XC
0dcd: 85 24 sta ]rot_yc
0dcf: 86 25 stx ]rot_yc+1
0dd1: 60 rts
0dd2: 29 40 :AngleNeg and #$40 ;bit 6 set?
0dd4: d0 10 bne :Angle192 ;yes
0dd6: a2 00 ldx #$00 ;rotated YC = 0
0dd8: 86 24 stx ]rot_yc
0dda: 86 25 stx ]rot_yc+1
0ddc: 38 sec ;rotated XC = -XC
0ddd: 8a txa
0dde: e5 00 sbc ]xc
0de0: 85 22 sta ]rot_xc
0de2: ca dex
0de3: 86 23 stx ]rot_xc+1
0de5: 60 rts
0de6: a2 00 :Angle192 ldx #$00 ;rotated XC = 0
0de8: 86 22 stx ]rot_xc
0dea: 86 23 stx ]rot_xc+1
0dec: 38 sec ;rotated YC = -XC
0ded: 8a txa
0dee: e5 00 sbc ]xc
0df0: 85 24 sta ]rot_yc
0df2: ca dex
0df3: 86 25 stx ]rot_yc+1
0df5: 60 rts
0df6: 00 00 ff ff+ .junk 10
;
; This holds the result of projecting 3D vertices into 16-bit clip-space
; coordinates.
0e00: ff ff 00 00+ clip_coord_xlo .junk 64
0e40: ff ff 00 00+ clip_coord_xhi .junk 64
0e80: ff ff 00 00+ clip_coord_ylo .junk 64
0ec0: ff ff 00 00+ clip_coord_yhi .junk 64
;
; Sine/cosine values for rotation calculation (256 entries). cos(N) starts at
; offset 0, sin(N) is at +192. Angle represents a counter-clockwise rotation.
;
; Values are signed 8-bit.
;
; The entries at 0/64/128/192 aren't used, as the 90-degree angles are special-
; cased in the code.
0f00: ff 7f 7f 7f+ rotate_tab .bulk $ff,$7f,$7f,$7f,$7f,$7f,$7f,$7e,$7e,$7d,$7c,$7b,$7a,$7a,$79,$77
+ $76,$75,$74,$72,$71,$6f,$6e,$6c,$6a,$69,$67,$65,$63,$61,$5f,$5d
+ $5b,$58,$56,$54,$51,$4f,$4c,$4a,$47,$44,$42,$3f,$3c,$3a,$37,$34
+ $31,$2e,$2b,$28,$25,$22,$1f,$1c,$19,$16,$13,$10,$0d,$09,$06,$03
+ $ff,$83,$86,$89,$8d,$90,$93,$96,$99,$9c,$9f,$a2,$a5,$a8,$ab,$ae
+ $b1,$b4,$b7,$ba,$bc,$bf,$c2,$c4,$c7,$ca,$cc,$cf,$d1,$d4,$d6,$d8
+ $db,$dd,$df,$e1,$e3,$e5,$e7,$e9,$ea,$ec,$ee,$ef,$f1,$f2,$f4,$f5
+ $f6,$f7,$f9,$fa,$fa,$fb,$fc,$fd,$fe,$fe,$ff,$ff,$ff,$ff,$ff,$ff
+ $ff,$ff,$ff,$ff,$ff,$ff,$ff,$fe,$fe,$fd,$fc,$fb,$fa,$fa,$f9,$f7
+ $f6,$f5,$f4,$f2,$f1,$ef,$ee,$ec,$ea,$e9,$e7,$e5,$e3,$e1,$df,$dd
+ $db,$d8,$d6,$d4,$d1,$cf,$cc,$ca,$c7,$c4,$c2,$bf,$bc,$ba,$b7,$b4
+ $b1,$ae,$ab,$a8,$a5,$a2,$9f,$9c,$99,$96,$93,$90,$8d,$89,$86,$83
+ $ff,$03,$06,$09,$0d,$10,$13,$16,$19,$1c,$1f,$22,$25,$28,$2b,$2e
+ $31,$34,$37,$3a,$3c,$3f,$42,$44,$47,$4a,$4c,$4f,$51,$54,$56,$58
+ $5b,$5d,$5f,$61,$63,$65,$67,$69,$6a,$6c,$6e,$6f,$71,$72,$74,$75
+ $76,$77,$79,$7a,$7a,$7b,$7c,$7d,$7e,$7e,$7f,$7f,$7f,$7f,$7f,$7f
********************************************************************************
* Draws a line on the hi-res screen. *
* *
* Called internally (post clip) and from ROCK2. *
* *
* On entry: *
* $00/01: x0,y0 *
* $02/03: x1,y1 *
********************************************************************************
]x0 .var $00 {addr/1}
]y0 .var $01 {addr/1}
]x1 .var $02 {addr/1}
]y1 .var $03 {addr/1}
]pixel_index .var $04 {addr/1}
]end_pixel_index .var $05 {addr/1}
]delta_x .var $07 {addr/1}
]delta_y .var $08 {addr/1}
]div_result .var $09 {addr/2}
]y_direction .var $0f {addr/1}
1000: 38 DrawLine sec ;compute deltaX
1001: a5 02 lda ]x1
1003: e5 00 sbc ]x0
1005: d0 30 bne :NotVert ;nonzero, branch
1007: a5 03 lda ]y1 ;compute deltaY
1009: e5 01 sbc ]y0
100b: d0 0f bne :Vert ;nonzero, branch to vertical line handler
100d: a4 00 ldy ]x0 ;both zero, draw a point
100f: b9 00 17 lda div7_tab,y
1012: 85 00 sta ]x0 ;col
1014: b9 00 18 lda mod7_tab,y
1017: 85 04 sta ]pixel_index ;pixel index (0-7)
1019: 4c cd 14 jmp DrawPoint ;draw and bail
101c: b0 0a :Vert bcs :Y0OnTop ;branch if y1 > y0
101e: a5 01 lda ]y0 ;flip y0/y1 so y0 is on top
1020: 48 pha
1021: a5 03 lda ]y1
1023: 85 01 sta ]y0
1025: 68 pla
1026: 85 03 sta ]y1
1028: a4 00 :Y0OnTop ldy ]x0 ;prep for vertical line
102a: b9 00 17 lda div7_tab,y
102d: 85 00 sta ]x0 ;col
102f: b9 00 18 lda mod7_tab,y
1032: 85 04 sta ]pixel_index ;pixel index (0-7)
1034: 4c 9e 14 jmp DrawVerticalLine
1037: 85 07 :NotVert sta ]delta_x
1039: b0 1b bcs :X0OnLeft ;if x1 > x0, branch
103b: 49 ff eor #$ff ;deltaX = -deltaX
103d: 18 clc
103e: 69 01 adc #$01
1040: 85 07 sta ]delta_x
1042: a5 00 lda ]x0 ;flip x0/x1 and y0/y1 so x0 is on the left
1044: 48 pha
1045: a5 02 lda ]x1
1047: 85 00 sta ]x0
1049: 68 pla
104a: 85 02 sta ]x1
104c: a5 01 lda ]y0
104e: 48 pha
104f: a5 03 lda ]y1
1051: 85 01 sta ]y0
1053: 68 pla
1054: 85 03 sta ]y1
1056: 38 :X0OnLeft sec ;compute deltaY
1057: a5 03 lda ]y1
1059: e5 01 sbc ]y0
105b: d0 1b bne :NotHoriz ;branch if not horizontal
105d: a4 02 ldy ]x1 ;prep for horizontal line
105f: b9 00 17 lda div7_tab,y
1062: 85 02 sta ]x1 ;last byte
1064: b9 00 18 lda mod7_tab,y
1067: 85 05 sta ]end_pixel_index ;last pixel index
1069: a4 00 ldy ]x0
106b: b9 00 17 lda div7_tab,y
106e: 85 00 sta ]x0 ;first byte
1070: b9 00 18 lda mod7_tab,y
1073: 85 04 sta ]pixel_index ;first pixel index
1075: 4c 00 14 jmp DrawHorizontal
1078: a2 00 :NotHoriz ldx #$00 ;set Y direction to 0 (pos) or 1 (neg)
107a: b0 07 bcs :PosDeltaY ;if deltaY positive, branch
107c: a2 01 ldx #$01 ;set deltaY = -deltaY
107e: 49 ff eor #$ff
1080: 18 clc
1081: 69 01 adc #$01
1083: 85 08 :PosDeltaY sta ]delta_y
1085: 86 0f stx ]y_direction
1087: 20 40 a0 jsr UPDATE_SOUND
108a: a5 07 lda ]delta_x ;compare deltas
108c: c5 08 cmp ]delta_y
108e: 90 35 bcc :VertDom ;deltaX < deltaY, vertically dominant
1090: a5 07 lda ]delta_x ;handle horizontally-dominant line
1092: a6 08 ldx ]delta_y
1094: 20 00 11 jsr CalcLineSlope ;compute deltaX / (deltaY+1)
1097: a4 02 ldy ]x1
1099: b9 00 17 lda div7_tab,y
109c: 85 02 sta ]x1 ;replace end coord with end col
109e: b9 00 18 lda mod7_tab,y
10a1: 85 05 sta ]end_pixel_index ;and end pixel index
10a3: a4 00 ldy ]x0
10a5: b9 00 17 lda div7_tab,y
10a8: 85 00 sta ]x0 ;replace start coord with start col
10aa: b9 00 18 lda mod7_tab,y
10ad: 85 04 sta ]pixel_index ;and start pixel index
10af: 20 40 a0 jsr UPDATE_SOUND
10b2: a5 0a lda ]div_result+1 ;check integer part of quotient
10b4: c9 03 cmp #$03 ;>= 3?
10b6: b0 03 bcs :MedLong ;yes, branch
10b8: 4c 00 12 jmp DrawHorizShortRun
10bb: c9 07 :MedLong cmp #$07 ;>= 7?
10bd: b0 03 bcs :LongRun
10bf: 4c 00 13 jmp DrawHorizMedRun
10c2: 4c 7c 13 :LongRun jmp DrawHorizLongRun
10c5: a5 08 :VertDom lda ]delta_y ;compute deltaY / (deltaX+1)
10c7: a6 07 ldx ]delta_x
10c9: 20 00 11 jsr CalcLineSlope
10cc: a4 00 ldy ]x0
10ce: b9 00 17 lda div7_tab,y
10d1: 85 00 sta ]x0
10d3: b9 00 18 lda mod7_tab,y
10d6: 85 04 sta ]pixel_index
10d8: 20 40 a0 jsr UPDATE_SOUND
10db: 4c 41 14 jmp DrawVertDom
10de: 00 00 ff ff+ .align $0100 (34 bytes)
********************************************************************************
* Compute A/(B+1), generating an 8.8 fixed-point result. Both values must be *
* positive. *
* *
* This is used to compute the run-slice length and error term, dividing deltaX *
* by deltaY or vice-versa (larger value on top). *
* *
* Only used internally. Loops are unrolled for speed. Takes about 270 *
* cycles. *
* *
* This result is sometimes off by one, e.g. A=0D X=03 -> $0340 (correct), but *
* A=17 X=0C -> $01C5 (should be $01C4). *
* *
* When deltaX==deltaY (diagonal line), the integer part of the quotient will *
* be zero, but the fractional part will be large (e.g. 127/128 yields 00 FE). *
* Every iteration will start with a slice length of zero, but adding FE sets *
* the carry. Because the hi-res screen is less than 255 lines high we never *
* get to a point where updating the error term fails to set the carry flag, so *
* we always get a proper diagonal line. *
* *
* General line-drawing note: the canonical run-slice code uses A/B rather than *
* A/(B+1). For a shallow line like (0,0) to (32,1), the mid-line step is *
* created by the initial/final pixel count setup (which uses delta/2), but *
* this code doesn't seem to do that. (It might be instructive to do a pixel- *
* by-pixel comparison of this vs. classic Bresenham. If you watch the LEV1 *
* mountains while rotating, they look a bit off at the edges of the screen.) *
* *
* On entry: *
* A-reg: numerator *
* X-reg: denominator *
* *
* On exit: *
* $09/0a: 8.8 fixed-point result *
********************************************************************************
• Clear variables
]result .var $09 {addr/2}
]denom .var $0e {addr/1}
1100: e8 CalcLineSlope inx ;increment denominator
1101: 86 0e stx ]denom
1103: 0a asl A
1104: 85 0a sta ]result+1
1106: a9 00 lda #$00
1108: 2a rol A
1109: c5 0e cmp ]denom
110b: 90 02 bcc L110F
110d: e5 0e sbc ]denom
110f: 26 0a L110F rol ]result+1
1111: 2a rol A
1112: c5 0e cmp ]denom
1114: 90 02 bcc L1118
1116: e5 0e sbc ]denom
1118: 26 0a L1118 rol ]result+1
111a: 2a rol A
111b: c5 0e cmp ]denom
111d: 90 02 bcc L1121
111f: e5 0e sbc ]denom
1121: 26 0a L1121 rol ]result+1
1123: 2a rol A
1124: c5 0e cmp ]denom
1126: 90 02 bcc L112A
1128: e5 0e sbc ]denom
112a: 26 0a L112A rol ]result+1
112c: 2a rol A
112d: c5 0e cmp ]denom
112f: 90 02 bcc L1133
1131: e5 0e sbc ]denom
1133: 26 0a L1133 rol ]result+1
1135: 2a rol A
1136: c5 0e cmp ]denom
1138: 90 02 bcc L113C
113a: e5 0e sbc ]denom
113c: 26 0a L113C rol ]result+1
113e: 2a rol A
113f: c5 0e cmp ]denom
1141: 90 02 bcc L1145
1143: e5 0e sbc ]denom
1145: 26 0a L1145 rol ]result+1
1147: 2a rol A
1148: c5 0e cmp ]denom
114a: 90 02 bcc L114E
114c: e5 0e sbc ]denom
114e: 26 0a L114E rol ]result+1 ;9th iteration, need to worry about 2nd byte
1150: 0a asl A
1151: b0 04 bcs L1157
1153: c5 0e cmp ]denom
1155: 90 03 bcc L115A
1157: e5 0e L1157 sbc ]denom
1159: 38 sec
115a: 26 09 L115A rol ]result
115c: 0a asl A
115d: b0 04 bcs L1163
115f: c5 0e cmp ]denom
1161: 90 03 bcc L1166
1163: e5 0e L1163 sbc ]denom
1165: 38 sec
1166: 26 09 L1166 rol ]result
1168: 0a asl A
1169: b0 04 bcs L116F
116b: c5 0e cmp ]denom
116d: 90 03 bcc L1172
116f: e5 0e L116F sbc ]denom
1171: 38 sec
1172: 26 09 L1172 rol ]result
1174: 0a asl A
1175: b0 04 bcs L117B
1177: c5 0e cmp ]denom
1179: 90 03 bcc L117E
117b: e5 0e L117B sbc ]denom
117d: 38 sec
117e: 26 09 L117E rol ]result
1180: 0a asl A
1181: b0 04 bcs L1187
1183: c5 0e cmp ]denom
1185: 90 03 bcc L118A
1187: e5 0e L1187 sbc ]denom
1189: 38 sec
118a: 26 09 L118A rol ]result
118c: 0a asl A
118d: b0 04 bcs L1193
118f: c5 0e cmp ]denom
1191: 90 03 bcc L1196
1193: e5 0e L1193 sbc ]denom
1195: 38 sec
1196: 26 09 L1196 rol ]result
1198: 0a asl A
1199: b0 04 bcs L119F
119b: c5 0e cmp ]denom
119d: 90 03 bcc L11A2
119f: e5 0e L119F sbc ]denom
11a1: 38 sec
11a2: 26 09 L11A2 rol ]result
11a4: 0a asl A
11a5: b0 04 bcs L11AB
11a7: c5 0e cmp ]denom
11a9: 90 03 bcc L11AE
11ab: e5 0e L11AB sbc ]denom
11ad: 38 sec
11ae: 26 09 L11AE rol ]result ;low byte of result is zero?
11b0: c9 00 cmp #$00
11b2: f0 06 beq L11BA ;yes, bail
11b4: e6 09 inc ]result ;increment result (?)
11b6: d0 02 bne L11BA
11b8: e6 0a inc ]result+1
11ba: 60 L11BA rts
;
; Hi-res pixel table. Converts a pixel index (0-7) into a single pixel bit.
11bb: 01 02 04 08+ hires_pixel .bulk $01,$02,$04,$08,$10,$20,$40
;
; Hi-res pixel table. Converts a pixel index into a set of bits that includes
; the specified index, as well as all pixels to the right. Used when drawing
; horizontal or mostly-horizontal lines.
hires_right_pixels
11c2: 7f 7e 7c 78+ .bulk $7f,$7e,$7c,$78,$70,$60,$40
;
; Hi-res pixel table. Converts a pixel index into a set of bits that includes
; the specified index, as well as all pixels to the left. Used when drawing
; horizontal or mostly-horizontal lines.
hires_left_pixels
11c9: 01 03 07 0f+ .bulk $01,$03,$07,$0f,$1f,$3f,$7f
;
; Mask off bits while drawing multiple pixels in the line draw code.
hires_partial_mask
11d0: 00 01 03 07+ .bulk $00,$01,$03,$07,$0f,$1f,$3f
11d7: 00 ff ff 00+ .align $0100 (41 bytes)
;
; Draws a relatively steep horizontal line (1 <= deltaX/(deltaY+1) < 3), as well
; as diagonal lines (deltaX==deltaY).
;
; On entry:
; $00: start column (0-39)
; $01: start row (0-191)
; $02: end column (0-39)
; $04: start pixel index (0-6)
; $05: end pixel index (0-6)
; $09/0a: quotient from deltaX/(deltaY+1) (8.8)
; $0f: Y direction (0 or 1)
; $32: hpage ($20/$40)
;
• Clear variables
]start_col .var $00 {addr/1}
]start_row .var $01 {addr/1}
]end_col .var $02 {addr/1}
]start_pixel_index .var $04 {addr/1}
]end_pixel_index .var $05 {addr/1}
]quotient .var $09 {addr/2}
]pixel_mask .var $0c {addr/1}
]error_term .var $0d {addr/1}
]hptr .var $0e {addr/2}
DrawHorizShortRun
1200: a6 0f ldx ]hptr+1 ;get Y direction (0=pos, 1=neg)
1202: bd ae 12 lda inc_or_dec,x ;modify instructions
1205: 8d 4b 12 sta :_IncOrDec1
1208: 8d 89 12 sta :_IncOrDec2
120b: a5 32 lda hpage
120d: 8d 53 12 sta :_OrPage1+1
1210: 8d 91 12 sta :_OrPage2+1
1213: a6 01 ldx ]start_row ;get address of hi-res line
1215: 1d 00 16 ora hires_addr_hi,x
1218: 85 0f sta ]hptr+1
121a: bd 00 15 lda hires_addr_lo,x
121d: 85 0e sta ]hptr
121f: a6 04 ldx ]start_pixel_index ;get initial pixel mask
1221: bd bb 11 lda hires_pixel,x
1224: 85 0c sta ]pixel_mask
1226: a6 09 ldx ]quotient ;init error term with fractional part of quotient
1228: 86 0d stx ]error_term
122a: a6 0a ldx ]quotient+1 ;integer part is number of pixels
122c: e8 inx ;start with a "long" slice
122d: a4 00 ldy ]start_col
122f: b1 0e lda (]hptr),y
1231: c4 02 cpy ]end_col ;reached end column?
1233: 90 0f bcc :LoopEntry ;no, branch
1235: a5 05 lda ]end_pixel_index
1237: e5 04 sbc ]start_pixel_index
1239: 85 05 sta ]end_pixel_index
123b: b1 0e lda (]hptr),y ;get screen byte to blend with
123d: 4c 7e 12 jmp :LastByte
1240: 06 0c :Loop asl ]pixel_mask ;shift mask to next pixel
1242: 30 27 bmi :NextByte ;reached end of byte, branch
1244: 05 0c :LoopEntry ora ]pixel_mask ;set pixel
1246: ca dex ;more to do in this run?
1247: d0 f7 bne :Loop ;yes, loop
1249: 91 0e sta (]hptr),y ;store pixels
124b: e6 01 :_IncOrDec1 inc ]start_row ;advance to next row (up or down)
124d: a6 01 ldx ]start_row
124f: bd 00 16 lda hires_addr_hi,x ;update pointer
1252: 09 00 :_OrPage1 ora #$00
1254: 85 0f sta ]hptr+1
1256: bd 00 15 lda hires_addr_lo,x
1259: 85 0e sta ]hptr
125b: a5 0d lda ]error_term ;update error term
125d: 65 09 adc ]quotient
125f: 85 0d sta ]error_term
1261: b1 0e lda (]hptr),y
1263: a6 0a ldx ]quotient+1 ;reset slice counter
1265: 90 d9 bcc :Loop ;ADC didn't roll over, do short slice
1267: e8 inx ;make it a long slice
1268: 4c 40 12 jmp :Loop
126b: 91 0e :NextByte sta (]hptr),y ;store what we have
126d: a9 01 lda #$01 ;reset to leftmost pixel
126f: 85 0c sta ]pixel_mask
1271: c8 iny ;advance to next byte
1272: b1 0e lda (]hptr),y ;get screen byte
1274: c4 02 cpy ]end_col ;are we on the last column?
1276: 90 cc bcc :LoopEntry ;no, back to the loop
1278: 18 clc ;?
1279: 4c 7e 12 jmp :LastByte
127c: 06 0c :FinishLoop asl ]pixel_mask
127e: 05 0c :LastByte ora ]pixel_mask ;set pending bit
1280: c6 05 dec ]end_pixel_index ;done with pixels in this byte?
1282: 30 25 bmi :Done ;yes, store and exit
1284: ca dex ;more in this run?
1285: d0 f5 bne :FinishLoop ;yes, loop
1287: 91 0e sta (]hptr),y ;store it
1289: e6 01 :_IncOrDec2 inc ]start_row ;advance to next row
128b: a6 01 ldx ]start_row
128d: bd 00 16 lda hires_addr_hi,x
1290: 09 00 :_OrPage2 ora #$00
1292: 85 0f sta ]hptr+1
1294: bd 00 15 lda hires_addr_lo,x
1297: 85 0e sta ]hptr
1299: a5 0d lda ]error_term ;update error term
129b: 65 09 adc ]quotient
129d: 85 0d sta ]error_term
129f: b1 0e lda (]hptr),y ;get screen pixels
12a1: a6 0a ldx ]quotient+1 ;reset slice counter
12a3: 90 d7 bcc :FinishLoop ;ADC didn't roll over, do short slice
12a5: e8 inx ;do one extra iteration
12a6: 4c 7c 12 jmp :FinishLoop
12a9: 91 0e :Done sta (]hptr),y ;write pending bits
12ab: 4c 40 a0 jmp UPDATE_SOUND
12ae: e6 inc_or_dec .dd1 instr_INC
12af: c6 .dd1 instr_DEC
12b0: ff ff 00 00+ .align $0100 (80 bytes)
;
; Draws a moderately steep horizontal line (3 <= deltaX/(deltaY+1) < 6).
;
; On entry:
; $00: start column (0-39)
; $01: start row (0-191)
; $02: end column (0-39)
; $04: start pixel index (0-6)
; $05: end pixel index (0-6)
; $09/0a: quotient from deltaX/(deltaY+1) (8.8)
; $0f: Y direction (0 or 1)
; $32: hpage ($20/$40)
;
1300: a5 32 DrawHorizMedRun lda hpage ;set up self-modifying code
1302: 8d 23 13 sta :_OrPage+1
1305: a6 0f ldx ]hptr+1
1307: bd ae 12 lda inc_or_dec,x
130a: 8d 1b 13 sta :_IncOrDec
130d: a4 00 ldy ]start_col ;init
130f: a9 00 lda #$00
1311: 85 0d sta ]error_term
1313: 18 clc
1314: 4c 1d 13 jmp :LoopEntry
1317: 11 0e :Loop ora (]hptr),y ;blend pixels onto screen
1319: 91 0e sta (]hptr),y
131b: e6 01 :_IncOrDec inc ]start_row ;move to the next row
131d: a6 01 :LoopEntry ldx ]start_row ;set up hi-res row addr
131f: bd 00 16 lda hires_addr_hi,x
1322: 09 00 :_OrPage ora #$00
1324: 85 0f sta ]hptr+1
1326: bd 00 15 lda hires_addr_lo,x
1329: 85 0e sta ]hptr
132b: a5 0d lda ]error_term ;update the error term
132d: 65 09 adc ]quotient ;(carry is always clear before here)
132f: 85 0d sta ]error_term
1331: a5 0a lda ]quotient+1 ;get base run length
1333: 65 04 adc ]start_pixel_index ;add index of first pixel (+1 if error term rolled)
1335: c9 07 cmp #$07 ;does this fill or overflow the current byte?
1337: b0 1e bcs :AcrossBytes ;yes, branch
1339: a6 04 ldx ]start_pixel_index ;no; get original start in X-reg
133b: 85 04 sta ]start_pixel_index ;save next index
133d: bd c2 11 lda hires_right_pixels,x ;A-reg = pixels set from start to end of byte
1340: a6 04 ldx ]start_pixel_index ;get index of last pixel
1342: 3d d0 11 and hires_partial_mask,x ;mask off pixels past this slice
1345: c4 02 cpy ]end_col ;reached last column?
1347: 90 ce bcc :Loop ;not yet; blend pixels and continue
1349: e4 05 cpx ]end_pixel_index ;reached last pixel?
134b: 90 ca bcc :Loop ;not yet; blend pixels and continue
134d: 11 0e ora (]hptr),y ;blend what we have
134f: 1d bb 11 ora hires_pixel,x ;add in final pixel
1352: 91 0e sta (]hptr),y ;update display
1354: 4c 40 a0 jmp UPDATE_SOUND ;done drawing
1357: a6 04 :AcrossBytes ldx ]start_pixel_index ;X-reg = starting pixel index
1359: e9 07 sbc #$07 ;pixel index %= 7
135b: 85 04 sta ]start_pixel_index
135d: bd c2 11 lda hires_right_pixels,x ;get the pixels to set for the first byte
1360: 11 0e ora (]hptr),y ;blend with display
1362: 91 0e sta (]hptr),y
1364: a6 04 ldx ]start_pixel_index ;get pixel mask for second byte
1366: bd d0 11 lda hires_partial_mask,x ;(note this is zero if start_pixel_index is 0)
1369: c8 iny ;move to the next byte
136a: c4 02 cpy ]end_col ;reached last column?
136c: 90 a9 bcc :Loop ;not yet, blend pixels and continue
136e: e4 05 cpx ]end_pixel_index ;reached last pixel?
1370: 90 a5 bcc :Loop ;not yet, blend pixels and continue
1372: 11 0e ora (]hptr),y ;last byte, blend what we have
1374: 1d bb 11 ora hires_pixel,x ;add in the final pixel
1377: 91 0e sta (]hptr),y ;update display
1379: 4c 40 a0 jmp UPDATE_SOUND
;
; Draws a shallow horizontal line (7 <= deltaX/(deltaY+1)).
;
; On entry:
; $00: start column (0-39)
; $01: start row (0-191)
; $02: end column (0-39)
; $04: start pixel index (0-6)
; $05: end pixel index (0-6)
; $09/0a: quotient from deltaX/(deltaY+1) (8.8)
; $0f: Y direction (0 or 1)
; $32: hpage ($20/$40)
;
DrawHorizLongRun
137c: a5 32 lda hpage ;set up self-modifying code
137e: 8d 9b 13 sta :_OrPage+1
1381: a6 0f ldx ]hptr+1
1383: bd ae 12 lda inc_or_dec,x
1386: 8d 93 13 sta :_IncOrDec
1389: a4 00 ldy ]start_col ;init
138b: a9 00 lda #$00
138d: 85 0d sta ]error_term
138f: 18 clc
1390: 4c 95 13 jmp :LoopEntry
1393: e6 01 :_IncOrDec inc ]start_row ;move to next row
1395: a6 01 :LoopEntry ldx ]start_row ;set up hi-res row addr
1397: bd 00 16 lda hires_addr_hi,x
139a: 09 00 :_OrPage ora #$00
139c: 85 0f sta ]hptr+1
139e: bd 00 15 lda hires_addr_lo,x
13a1: 85 0e sta ]hptr
13a3: a5 0d lda ]error_term ;update error term
13a5: 65 09 adc ]quotient ;(carry is always clear to here)
13a7: 85 0d sta ]error_term
13a9: a5 0a lda ]quotient+1 ;get base run length (7+)
13ab: 65 04 adc ]start_pixel_index ;add index of first pixel (0-6)
13ad: aa tax ; (+1 if error term rolled)
13ae: bd 00 17 lda div7_tab,x ;divide by 7
13b1: 65 00 adc ]start_col ;add to start column
13b3: 85 00 sta ]start_col ;this is the column where the next slice starts
13b5: bd 00 18 lda mod7_tab,x ;compute mod 7 to get pixel index of next slice start
13b8: a6 04 ldx ]start_pixel_index ;grab the current start pixel index
13ba: 85 04 sta ]start_pixel_index ;save start index of next slice
13bc: bd c2 11 lda hires_right_pixels,x ;get the partial pixels for the first byte
13bf: 11 0e ora (]hptr),y ;we know it's 7+, so nothing to mask
13c1: 91 0e sta (]hptr),y ;blend with display and store
13c3: c8 iny ;move to next column
13c4: c4 00 cpy ]start_col ;reached start of next slice?
13c6: b0 09 bcs :SliceEnd ;yes, branch
13c8: a9 7f lda #$7f ;no, light up all 7 pixels
13ca: 91 0e :FastLoop sta (]hptr),y ;update display
13cc: c8 iny
13cd: c4 00 cpy ]start_col ;continue until we reach start of next slice
13cf: 90 f9 bcc :FastLoop
13d1: a6 04 :SliceEnd ldx ]start_pixel_index ;get the index of the next slice
13d3: bd c9 11 lda hires_left_pixels,x ;set the pixels to the left of it
13d6: 11 0e ora (]hptr),y ;blend with display
13d8: 91 0e sta (]hptr),y
13da: c4 02 cpy ]end_col ;done yet? (next slice is full byte, just check col)
13dc: 90 b5 bcc :_IncOrDec ;no, continue
13de: 4c 40 a0 jmp UPDATE_SOUND
13e1: ff 00 00 ff+ .align $0100 (31 bytes)
;
; Draws a horizontal line, from x0,yc to x1,yc (inclusive coordinates).
;
; On entry:
; $00: start column (0-39)
; $01: row (0-191)
; $02: end column (0-39)
; $04: start pixel index (0-6)
; $05: end pixel index (0-6)
; $32: hi-res page ($20/$40)
;
• Clear variables
]start_col .var $00 {addr/1}
]row .var $01 {addr/1}
]end_col .var $02 {addr/1}
]start_pixel_index .var $04 {addr/1}
]end_pixel_index .var $05 {addr/1}
]hptr .var $0e {addr/2}
1400: a6 01 DrawHorizontal ldx ]row ;set up hires addr
1402: bd 00 16 lda hires_addr_hi,x
1405: 05 32 ora hpage
1407: 85 0f sta ]hptr+1
1409: bd 00 15 lda hires_addr_lo,x
140c: 85 0e sta ]hptr
140e: a6 04 ldx ]start_pixel_index ;get start index
1410: bd c2 11 lda hires_right_pixels,x ;get set of bits for left edge
1413: a4 00 ldy ]start_col ;column for left edge
1415: c4 02 cpy ]end_col ;are we ending here?
1417: f0 1c beq :SingleByte ;yes, handle single-byte case
1419: 11 0e ora (]hptr),y ;no, blend with screen contents
141b: 91 0e sta (]hptr),y
141d: a9 7f lda #$7f ;write full bytes
141f: 4c 24 14 jmp :LoopEntry
1422: 91 0e :Loop sta (]hptr),y
1424: c8 :LoopEntry iny
1425: c4 02 cpy ]end_col ;reached end?
1427: 90 f9 bcc :Loop ;not yet
1429: a6 05 ldx ]end_pixel_index ;get last pixel index
142b: bd c9 11 lda hires_left_pixels,x ;get pixels
142e: 11 0e ora (]hptr),y ;blend with screen contents
1430: 91 0e sta (]hptr),y
1432: 4c 40 a0 jmp UPDATE_SOUND
1435: a6 05 :SingleByte ldx ]end_pixel_index ;mask with right-side bits
1437: 3d c9 11 and hires_left_pixels,x
143a: 11 0e ora (]hptr),y ;blend with screen contents
143c: 91 0e sta (]hptr),y
143e: 4c 40 a0 jmp UPDATE_SOUND
;
; Draws a vertically-dominant line.
;
; On entry:
; $00: start column (0-39)
; $01: start row (0-191)
; $03: end row (0-191)
; $04: start pixel index (0-6)
; $09: quotient from line slope calculation
; $0f: Y direction (0=down, 1=up)
; $32: hi-res page ($20/$40)
;
• Clear variables
]start_col .var $00 {addr/1}
]start_row .var $01 {addr/1}
]end_row .var $03 {addr/1}
]start_pixel_index .var $04 {addr/1}
]quotient .var $09 {addr/2}
]err_hi .var $0b {addr/1}
]pixel_mask .var $0c {addr/1}
]error_term .var $0d {addr/1}
]y_direction .var $0f {addr/1}
1441: a6 0f DrawVertDom ldx ]y_direction ;self-modify up vs. down
1443: bd 9c 14 lda :inx_dex,x
1446: 8d 65 14 sta :_InxDex
1449: a6 04 ldx ]start_pixel_index
144b: bd bb 11 lda hires_pixel,x ;get initial pixel mask
144e: 85 0c sta ]pixel_mask
1450: a5 32 lda hpage
1452: 8d 6a 14 sta :_Page+1
1455: a6 09 ldx ]quotient ;init error term
1457: 86 0d stx ]error_term
1459: a6 0a ldx ]quotient+1
145b: e8 inx
145c: 86 0b stx ]err_hi
145e: a4 00 ldy ]start_col ;init X-reg / Y-reg
1460: a6 01 ldx ]start_row
1462: 4c 66 14 jmp :Start ;jump into it
]hptr .var $0e {addr/2}
1465: e8 :_InxDex inx
1466: bd 00 16 :Start lda hires_addr_hi,x ;set hi-res row address
1469: 09 00 :_Page ora #$00
146b: 85 0f sta ]hptr+1
146d: bd 00 15 lda hires_addr_lo,x
1470: 85 0e sta ]hptr
1472: b1 0e lda (]hptr),y ;blend pixel
1474: 05 0c ora ]pixel_mask
1476: 91 0e sta (]hptr),y
1478: c6 0b dec ]err_hi ;update error term hi
147a: d0 e9 bne :_InxDex ;quick loop if we're in a run
147c: 06 0c asl ]pixel_mask ;move pixel right
147e: 30 14 bmi :NewByte ;branch if we reached end of byte
1480: 18 :UpdateErr clc ;update full error term
1481: a5 0d lda ]error_term
1483: 65 09 adc ]quotient
1485: 85 0d sta ]error_term
1487: a5 0a lda ]quotient+1
1489: 69 00 adc #$00
148b: 85 0b sta ]err_hi
148d: e4 03 cpx ]end_row
148f: d0 d4 bne :_InxDex
1491: 4c 40 a0 jmp UPDATE_SOUND
1494: a9 01 :NewByte lda #$01 ;restart with left pixel
1496: 85 0c sta ]pixel_mask
1498: c8 iny ;move right one byte
1499: 4c 80 14 jmp :UpdateErr
149c: e8 :inx_dex .dd1 instr_INX
149d: ca .dd1 instr_DEX
;
; Draws a vertical line, from xc,y0 to xc,y1 (exclusive end coord).
;
; The caller guarantees that y0 < y1.
;
; On entry:
; $00: start column (0-39)
; $01: start row (0-191)
; $03: end row (0-191)
; $04: pixel index
;
]start_col .var $00 {addr/1}
]start_row .var $01 {addr/1}
]end_row .var $03 {addr/1}
]pixel_index .var $04 {addr/1}
DrawVerticalLine
149e: 20 40 a0 jsr UPDATE_SOUND
14a1: a6 04 ldx ]pixel_index ;set up pixel mask
14a3: bd bb 11 lda hires_pixel,x
14a6: 8d c3 14 sta :_pixel_mask+1
14a9: a5 32 lda hpage
14ab: 8d b8 14 sta :_ora_page+1
14ae: a4 00 ldy ]start_col ;load byte offset into Y-reg
14b0: a6 01 ldx ]start_row
14b2: ca dex ;balance following INX
14b3: e8 :Loop inx
14b4: bd 00 16 lda hires_addr_hi,x ;get hi-res row address
14b7: 09 00 :_ora_page ora #$00
14b9: 85 0f sta ]hptr+1
14bb: bd 00 15 lda hires_addr_lo,x
14be: 85 0e sta ]hptr
14c0: b1 0e lda (]hptr),y
14c2: 09 00 :_pixel_mask ora #$00 ;blend with contents
14c4: 91 0e sta (]hptr),y ;update screen
14c6: e4 03 cpx ]end_row ;reached the end?
14c8: 90 e9 bcc :Loop ;not yet
14ca: 4c 40 a0 jmp UPDATE_SOUND
;
; Plots a single point on the hi-res screen. Called when x0==x1 and y0==y1.
;
; On entry:
; $00: column (0-39)
; $01: row (0-191)
; $04: pixel index (0-6)
; $32: hi-res page
;
• Clear variables
]col .var $00 {addr/1}
]row .var $01 {addr/1}
]bit .var $04 {addr/1}
]hptr .var $0e {addr/2}
14cd: a6 01 DrawPoint ldx ]row
14cf: bd 00 16 lda hires_addr_hi,x
14d2: 05 32 ora hpage
14d4: 85 0f sta ]hptr+1
14d6: bd 00 15 lda hires_addr_lo,x
14d9: 85 0e sta ]hptr
14db: a6 04 ldx ]bit
14dd: bd bb 11 lda hires_pixel,x
14e0: a4 00 ldy ]col
14e2: 11 0e ora (]hptr),y
14e4: 91 0e sta (]hptr),y
14e6: 4c 40 a0 jmp UPDATE_SOUND
14e9: ff 00 00 ff+ .align $0100 (23 bytes)
;
; Hi-res row address tables.
1500: 00 00 00 00+ hires_addr_lo .bulk $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80
+ $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80
+ $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80
+ $00,$00,$00,$00,$00,$00,$00,$00,$80,$80,$80,$80,$80,$80,$80,$80
+ $28,$28,$28,$28,$28,$28,$28,$28,$a8,$a8,$a8,$a8,$a8,$a8,$a8,$a8
+ $28,$28,$28,$28,$28,$28,$28,$28,$a8,$a8,$a8,$a8,$a8,$a8,$a8,$a8
+ $28,$28,$28,$28,$28,$28,$28,$28,$a8,$a8,$a8,$a8,$a8,$a8,$a8,$a8
+ $28,$28,$28,$28,$28,$28,$28,$28,$a8,$a8,$a8,$a8,$a8,$a8,$a8,$a8
+ $50,$50,$50,$50,$50,$50,$50,$50,$d0,$d0,$d0,$d0,$d0,$d0,$d0,$d0
+ $50,$50,$50,$50,$50,$50,$50,$50,$d0,$d0,$d0,$d0,$d0,$d0,$d0,$d0
+ $50,$50,$50,$50,$50,$50,$50,$50,$d0,$d0,$d0,$d0,$d0,$d0,$d0,$d0
+ $50,$50,$50,$50,$50,$50,$50,$50,$d0,$d0,$d0,$d0,$d0,$d0,$d0,$d0
15c0: 00 00 00 00+ .align $0100 (64 bytes)
1600: 00 04 08 0c+ hires_addr_hi .bulk $00,$04,$08,$0c,$10,$14,$18,$1c,$00,$04,$08,$0c,$10,$14,$18,$1c
+ $01,$05,$09,$0d,$11,$15,$19,$1d,$01,$05,$09,$0d,$11,$15,$19,$1d
+ $02,$06,$0a,$0e,$12,$16,$1a,$1e,$02,$06,$0a,$0e,$12,$16,$1a,$1e
+ $03,$07,$0b,$0f,$13,$17,$1b,$1f,$03,$07,$0b,$0f,$13,$17,$1b,$1f
+ $00,$04,$08,$0c,$10,$14,$18,$1c,$00,$04,$08,$0c,$10,$14,$18,$1c
+ $01,$05,$09,$0d,$11,$15,$19,$1d,$01,$05,$09,$0d,$11,$15,$19,$1d
+ $02,$06,$0a,$0e,$12,$16,$1a,$1e,$02,$06,$0a,$0e,$12,$16,$1a,$1e
+ $03,$07,$0b,$0f,$13,$17,$1b,$1f,$03,$07,$0b,$0f,$13,$17,$1b,$1f
+ $00,$04,$08,$0c,$10,$14,$18,$1c,$00,$04,$08,$0c,$10,$14,$18,$1c
+ $01,$05,$09,$0d,$11,$15,$19,$1d,$01,$05,$09,$0d,$11,$15,$19,$1d
+ $02,$06,$0a,$0e,$12,$16,$1a,$1e,$02,$06,$0a,$0e,$12,$16,$1a,$1e
+ $03,$07,$0b,$0f,$13,$17,$1b,$1f,$03,$07,$0b,$0f,$13,$17,$1b,$1f
16c0: 00 00 00 00+ .align $0100 (64 bytes)
;
; Division by 7.
1700: 00 00 00 00+ div7_tab .bulk $00,$00,$00,$00,$00,$00,$00,$01,$01,$01,$01,$01,$01,$01,$02,$02
+ $02,$02,$02,$02,$02,$03,$03,$03,$03,$03,$03,$03,$04,$04,$04,$04
+ $04,$04,$04,$05,$05,$05,$05,$05,$05,$05,$06,$06,$06,$06,$06,$06
+ $06,$07,$07,$07,$07,$07,$07,$07,$08,$08,$08,$08,$08,$08,$08,$09
+ $09,$09,$09,$09,$09,$09,$0a,$0a,$0a,$0a,$0a,$0a,$0a,$0b,$0b,$0b
+ $0b,$0b,$0b,$0b,$0c,$0c,$0c,$0c,$0c,$0c,$0c,$0d,$0d,$0d,$0d,$0d
+ $0d,$0d,$0e,$0e,$0e,$0e,$0e,$0e,$0e,$0f,$0f,$0f,$0f,$0f,$0f,$0f
+ $10,$10,$10,$10,$10,$10,$10,$11,$11,$11,$11,$11,$11,$11,$12,$12
+ $12,$12,$12,$12,$12,$13,$13,$13,$13,$13,$13,$13,$14,$14,$14,$14
+ $14,$14,$14,$15,$15,$15,$15,$15,$15,$15,$16,$16,$16,$16,$16,$16
+ $16,$17,$17,$17,$17,$17,$17,$17,$18,$18,$18,$18,$18,$18,$18,$19
+ $19,$19,$19,$19,$19,$19,$1a,$1a,$1a,$1a,$1a,$1a,$1a,$1b,$1b,$1b
+ $1b,$1b,$1b,$1b,$1c,$1c,$1c,$1c,$1c,$1c,$1c,$1d,$1d,$1d,$1d,$1d
+ $1d,$1d,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1f,$1f,$1f,$1f,$1f,$1f,$1f
+ $20,$20,$20,$20,$20,$20,$20,$21,$21,$21,$21,$21,$21,$21,$22,$22
+ $22,$22,$22,$22,$22,$23,$23,$23,$23,$23,$23,$23,$24,$24,$24,$24
;
; Modulo 7.
1800: 00 01 02 03+ mod7_tab .bulk $00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01
+ $02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03
+ $04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05
+ $06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00
+ $01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02
+ $03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04
+ $05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06
+ $00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01
+ $02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03
+ $04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05
+ $06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00
+ $01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02
+ $03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04
+ $05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06
+ $00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01
+ $02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03
********************************************************************************
* Clips a line to the viewport and draws it. Coordinates are signed clip- *
* space coordinates (0,0 is center of viewport, positive values are up and to *
* the right). *
* *
* Called from ROCK2. *
* *
* On entry: *
* $10/11: x0 (16-bit signed) *
* $12/13: y0 *
* $14/15: x1 *
* $16/17: y1 *
* *
* $50: viewport offset for X coord (8-bit device coords) *
* $52: viewport offset for Y coord *
* *
* $54/55: viewport left edge (16-bit signed device coords) *
* $56/57: viewport right edge *
* $58/59: viewport top edge *
* $5a/5b: viewport bottom edge *
* *
* During the mission briefing, the viewport is set to (-90,41),(91,-58) *
* (181x99). During the game, it's set to (-112,74),(111,-82) (224x157). Note *
* those are centered horizontally but not vertically -- there's more space *
* below the horizon line than above. *
* *
* The viewport-to-screen adjustment translates the coordinates so the top-left *
* corner is at 7,33. The adjustment is (132,54) in the mission briefing, and *
* 119/107 in-game. *
********************************************************************************
• Clear variables
]clip_x0 .var $00 {addr/1}
]clip_y0 .var $01 {addr/1}
]clip_x1 .var $02 {addr/1}
]clip_y1 .var $03 {addr/1}
]x0 .var $10 {addr/2}
]y0 .var $12 {addr/2}
]x1 .var $14 {addr/2}
]y1 .var $16 {addr/2}
]outcode0 .var $18 {addr/1}
]outcode1 .var $19 {addr/1}
]muldiv_val .var $1b {addr/1}
]delta2 .var $1c {addr/1}
]tmp .var $1d {addr/1}
1900: a6 14 ClipDrawLine ldx ]x1 ;see if abs(x1-x0) < 256
1902: e4 10 cpx ]x0 ;set carry as if we subtracted low part
1904: a5 15 lda ]x1+1 ;subtract high part
1906: e5 11 sbc ]x0+1
1908: f0 08 beq :CheckY ;0 <= x1-x0 < 256, continue
190a: c9 ff cmp #$ff ;is -256 < x1-x0 < 0?
190c: d0 16 bne :Bail ;no, bail
190e: e4 10 cpx ]x0 ;diff exactly 256?
1910: f0 12 beq :Bail ;yes, bail
1912: a6 16 :CheckY ldx ]y1 ;now see if abs(y1-y0) < 256
1914: e4 12 cpx ]y0
1916: a5 17 lda ]y1+1
1918: e5 13 sbc ]y0+1
191a: f0 09 beq :CoordsClose
191c: c9 ff cmp #$ff
191e: d0 04 bne :Bail
1920: e4 12 cpx ]y0
1922: d0 01 bne :CoordsClose
1924: 60 :Bail rts
; Compute Cohen-Sutherland outcodes. Each byte has the form LRTB0000, with a
; bit being set if the point is past the left, right, top, or bottom edges. If
; the point is entirely within the viewport, the outcode would be zero. This
; provides a fast path for trivial acceptance and trivial rejection.
;
; cf. https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
;
; The computations here initially set bits to 0 when the coord is out of bounds,
; rather than 1. The bits are inverted at the end.
;
; Start by checking x1,y1.
1925: a5 16 :CoordsClose lda ]y1 ;compute (y1 - bottom)
1927: c5 5a cmp VIEW_BOTTOM ;set carry as if we subtracted low bytes
1929: a5 17 lda ]y1+1 ;now do the high byte
192b: e5 5b sbc VIEW_BOTTOM+1 ;carry clear if we needed to borrow
192d: 6a ror A ;put the carry in the high bit
192e: 45 17 eor ]y1+1 ;flip it if y1 is negative
1930: 45 5b eor VIEW_BOTTOM+1 ;flip it if bottom is negative
1932: 0a asl A ;put hi bit in carry
1933: 66 19 ror ]outcode1 ;roll into outcode (this is "off bottom" flag)
1935: 38 sec ;set carry for "skip bottom" branch
1936: 10 0e bpl :SkipBottom1 ;if we're past bottom, no need to check top
1938: a5 58 lda VIEW_TOP ;compute (top - y1)
193a: c5 16 cmp ]y1
193c: a5 59 lda VIEW_TOP+1
193e: e5 17 sbc ]y1+1
1940: 6a ror A
1941: 45 59 eor VIEW_TOP+1
1943: 45 17 eor ]y1+1
1945: 0a asl A
1946: 66 19 :SkipBottom1 ror ]outcode1 ;roll "off top" flag into outcode
1948: a5 56 lda VIEW_RIGHT ;compute (right - x1)
194a: c5 14 cmp ]x1
194c: a5 57 lda VIEW_RIGHT+1
194e: e5 15 sbc ]x1+1
1950: 6a ror A
1951: 45 57 eor VIEW_RIGHT+1
1953: 45 15 eor ]x1+1
1955: 0a asl A
1956: 66 19 ror ]outcode1
1958: 38 sec
1959: 10 0e bpl :SkipLeft1 ;off right edge, don't need to check left
195b: a5 14 lda ]x1 ;compute (x1 - left)
195d: c5 54 cmp VIEW_LEFT
195f: a5 15 lda ]x1+1
1961: e5 55 sbc VIEW_LEFT+1
1963: 6a ror A
1964: 45 15 eor ]x1+1
1966: 45 55 eor VIEW_LEFT+1
1968: 0a asl A
1969: a5 19 :SkipLeft1 lda ]outcode1
196b: 6a ror A
196c: 29 f0 and #$f0 ;remove uninitialized bits
196e: 49 f0 eor #$f0 ;invert meaning of bits
1970: 85 19 sta ]outcode1 ;save
; Now check x0,y0.
;
; After we fix x0,y0 for one edge (e.g. left) we need to come back here to see
; if we need to fix it for another edge (e.g. top).
1972: a5 12 :ReCheck0 lda ]y0 ;compute (y0 - bottom)
1974: c5 5a cmp VIEW_BOTTOM
1976: a5 13 lda ]y0+1
1978: e5 5b sbc VIEW_BOTTOM+1
197a: 6a ror A
197b: 45 13 eor ]y0+1
197d: 45 5b eor VIEW_BOTTOM+1
197f: 0a asl A
1980: 66 18 ror ]outcode0
1982: 38 sec
1983: 10 0e bpl :SkipTop0
1985: a5 58 lda VIEW_TOP ;compute (top - y0)
1987: c5 12 cmp ]y0
1989: a5 59 lda VIEW_TOP+1
198b: e5 13 sbc ]y0+1
198d: 6a ror A
198e: 45 59 eor VIEW_TOP+1
1990: 45 13 eor ]y0+1
1992: 0a asl A
1993: 66 18 :SkipTop0 ror ]outcode0
1995: a5 56 lda VIEW_RIGHT ;compute (right - x0)
1997: c5 10 cmp ]x0
1999: a5 57 lda VIEW_RIGHT+1
199b: e5 11 sbc ]x0+1
199d: 6a ror A
199e: 45 57 eor VIEW_RIGHT+1
19a0: 45 11 eor ]x0+1
19a2: 0a asl A
19a3: 66 18 ror ]outcode0
19a5: 38 sec
19a6: 10 0e bpl :SkipLeft0
19a8: a5 10 lda ]x0 ;compute (x0 - left)
19aa: c5 54 cmp VIEW_LEFT
19ac: a5 11 lda ]x0+1
19ae: e5 55 sbc VIEW_LEFT+1
19b0: 6a ror A
19b1: 45 11 eor ]x0+1
19b3: 45 55 eor VIEW_LEFT+1
19b5: 0a asl A
19b6: a5 18 :SkipLeft0 lda ]outcode0
19b8: 6a ror A
19b9: 29 f0 and #$f0 ;remove uninitialized bits
19bb: 49 f0 eor #$f0 ;invert meaning of bits
19bd: 85 18 sta ]outcode0 ;save
; Trivial rejection: if both outcodes have the same bit set, then both
; coordinates are outside the same edge (e.g. they're both off the top).
19bf: 25 19 and ]outcode1 ;any bits in common?
19c1: f0 01 beq :CanClip ;no, it's clippable
19c3: 60 rts ;yes, reject
; Check to see if we have anything more to do.
19c4: a5 18 :CanClip lda ]outcode0 ;are any of the outcode bits set?
19c6: 05 19 ora ]outcode1
19c8: d0 1f bne :SwapMaybe ;yes, perform clip on x0,y0
19ca: 18 clc ;we're done; translate clip-space coordinates
19cb: a5 50 lda VIEW_X_ADJ ; to screen coords
19cd: 65 10 adc ]x0
19cf: 85 00 sta ]clip_x0
19d1: 38 sec
19d2: a5 52 lda VIEW_Y_ADJ
19d4: e5 12 sbc ]y0
19d6: 85 01 sta ]clip_y0
19d8: 18 clc
19d9: a5 50 lda VIEW_X_ADJ
19db: 65 14 adc ]x1
19dd: 85 02 sta ]clip_x1
19df: 38 sec
19e0: a5 52 lda VIEW_Y_ADJ
19e2: e5 16 sbc ]y1
19e4: 85 03 sta ]clip_y1
19e6: 4c 00 10 jmp DrawLine ;draw it
19e9: a5 18 :SwapMaybe lda ]outcode0 ;is x0 outside the viewport?
19eb: d0 2a bne :NoSwap ;yes, work on that
; We always update x0,y0, so when the initial x0,y0 is in the viewport we swap
; coordinates to work on the other pair.
19ed: a6 18 ldx ]outcode0
19ef: a5 19 lda ]outcode1
19f1: 85 18 sta ]outcode0
19f3: 86 19 stx ]outcode1
19f5: a6 10 ldx ]x0 ;swap x0 with x1
19f7: a5 14 lda ]x1
19f9: 85 10 sta ]x0
19fb: 86 14 stx ]x1
19fd: a6 11 ldx ]x0+1
19ff: a5 15 lda ]x1+1
1a01: 85 11 sta ]x0+1
1a03: 86 15 stx ]x1+1
1a05: a6 12 ldx ]y0 ;swap y0 with y1
1a07: a5 16 lda ]y1
1a09: 85 12 sta ]y0
1a0b: 86 16 stx ]y1
1a0d: a6 13 ldx ]y0+1
1a0f: a5 17 lda ]y1+1
1a11: 85 13 sta ]y0+1
1a13: 86 17 stx ]y1+1
1a15: a5 18 lda ]outcode0
1a17: 0a :NoSwap asl A ;x/LRTB0000 -> L/RTB00000
1a18: 90 49 bcc :LeftOkay
; Adjust x0,y0 so it's inside left edge.
;
; x = view_left
; y = y0 + (y1 - y0) * (view_left - x0) / (x1 - x0)
;
; At the start of the function we established that abs(x1-x0) is < 256, so we
; can ignore the high bytes when computing (x1-x0).
1a1a: 38 sec ;compute x1 - x0
1a1b: a5 14 lda ]x1 ;(treated as unsigned by muldiv?)
1a1d: e5 10 sbc ]x0
1a1f: 85 1c sta ]delta2
1a21: 38 sec ;compute view_left - x0
1a22: a5 54 lda VIEW_LEFT ;should be positive, since we know x0 < left
1a24: e5 10 sbc ]x0
1a26: aa tax
1a27: 38 sec ;compute y1 - y0, 16-bit
1a28: a5 16 lda ]y1 ;do the low part
1a2a: e5 12 sbc ]y0
1a2c: a8 tay ;tuck it into Y-reg
1a2d: a5 17 lda ]y1+1 ;do the high part
1a2f: e5 13 sbc ]y0+1
1a31: 85 1d sta ]tmp ;save it
1a33: 0a asl A ;check the high bit
1a34: 98 tya ;restore the low part
1a35: 90 04 bcc :IsPos ;high part positive, branch
1a37: 49 ff eor #$ff ;high negative, invert the low part
1a39: 69 00 adc #$00 ; so we're working with a positive value
1a3b: 20 43 1b :IsPos jsr ClipMulDiv ;compute A * B / C
1a3e: a2 00 ldx #$00
1a40: a5 1b lda ]muldiv_val ;get the result
1a42: 06 1d asl ]tmp ;was (y1-y0) negative?
1a44: 90 07 bcc :IsPosR ;no, keep going
1a46: 49 ff eor #$ff ;make result negative
1a48: 69 00 adc #$00
1a4a: f0 01 beq :IsPosR ;result was zero, don't DEX
1a4c: ca dex
1a4d: 18 :IsPosR clc ;set Y = y0 + [muldiv]
1a4e: 65 12 adc ]y0
1a50: a8 tay ;? why not STA y0?
1a51: 8a txa ;put $00 or $ff in X-reg based on result sign
1a52: 65 13 adc ]y0+1 ;add high byte
1a54: 84 12 sty ]y0 ;save new y0
1a56: 85 13 sta ]y0+1
1a58: a5 54 lda VIEW_LEFT ;x0 = viewport left edge
1a5a: 85 10 sta ]x0
1a5c: a5 55 lda VIEW_LEFT+1
1a5e: 85 11 sta ]x0+1
1a60: 4c 72 19 jmp :ReCheck0
1a63: 0a :LeftOkay asl A ;L/RTB00000 -> R/TB000000
1a64: 90 49 bcc :RightOkay
; Adjust x0,y0 so it's inside right edge.
;
; x = view_right
; standard: y = y0 + (y1 - y0) * (view_right - x0) / (x1 - x0)
; this: y = y1 + (y0 - y1) * (view_right - x1) / (x0 - x1)
1a66: 38 sec
1a67: a5 10 lda ]x0
1a69: e5 14 sbc ]x1
1a6b: 85 1c sta ]delta2
1a6d: 38 sec
1a6e: a5 56 lda VIEW_RIGHT
1a70: e5 14 sbc ]x1
1a72: aa tax
1a73: 38 sec
1a74: a5 12 lda ]y0
1a76: e5 16 sbc ]y1
1a78: a8 tay
1a79: a5 13 lda ]y0+1
1a7b: e5 17 sbc ]y1+1
1a7d: 85 1d sta ]tmp
1a7f: 0a asl A
1a80: 98 tya
1a81: 90 04 bcc L1A87
1a83: 49 ff eor #$ff
1a85: 69 00 adc #$00
1a87: 20 43 1b L1A87 jsr ClipMulDiv
1a8a: a2 00 ldx #$00
1a8c: a5 1b lda ]muldiv_val
1a8e: 06 1d asl ]tmp
1a90: 90 07 bcc L1A99
1a92: 49 ff eor #$ff
1a94: 69 00 adc #$00
1a96: f0 01 beq L1A99
1a98: ca dex
1a99: 18 L1A99 clc
1a9a: 65 16 adc ]y1
1a9c: a8 tay
1a9d: 8a txa
1a9e: 65 17 adc ]y1+1
1aa0: 84 12 sty ]y0
1aa2: 85 13 sta ]y0+1
1aa4: a5 56 lda VIEW_RIGHT
1aa6: 85 10 sta ]x0
1aa8: a5 57 lda VIEW_RIGHT+1
1aaa: 85 11 sta ]x0+1
1aac: 4c 72 19 jmp :ReCheck0
1aaf: 10 49 :RightOkay bpl :TopOkay ;R/TB000000 -> T/B0000000
; Adjust x0,y0 so it's inside top edge.
;
; standard: x = x0 + (x1 - x0) * (view_top - y0) / (y1 - y0)
; this: x = x1 + (x0 - x1) * (view_top - y1) / (y0 - y1)
; y = view_top
1ab1: 38 sec
1ab2: a5 12 lda ]y0
1ab4: e5 16 sbc ]y1
1ab6: 85 1c sta ]delta2
1ab8: 38 sec
1ab9: a5 58 lda VIEW_TOP
1abb: e5 16 sbc ]y1
1abd: aa tax
1abe: 38 sec
1abf: a5 10 lda ]x0
1ac1: e5 14 sbc ]x1
1ac3: a8 tay
1ac4: a5 11 lda ]x0+1
1ac6: e5 15 sbc ]x1+1
1ac8: 85 1d sta ]tmp
1aca: 0a asl A
1acb: 98 tya
1acc: 90 04 bcc L1AD2
1ace: 49 ff eor #$ff
1ad0: 69 00 adc #$00
1ad2: 20 43 1b L1AD2 jsr ClipMulDiv
1ad5: a2 00 ldx #$00
1ad7: a5 1b lda ]muldiv_val
1ad9: 06 1d asl ]tmp
1adb: 90 07 bcc L1AE4
1add: 49 ff eor #$ff
1adf: 69 00 adc #$00
1ae1: f0 01 beq L1AE4
1ae3: ca dex
1ae4: 18 L1AE4 clc
1ae5: 65 14 adc ]x1
1ae7: a8 tay
1ae8: 8a txa
1ae9: 65 15 adc ]x1+1
1aeb: 84 10 sty ]x0
1aed: 85 11 sta ]x0+1
1aef: a5 58 lda VIEW_TOP
1af1: 85 12 sta ]y0
1af3: a5 59 lda VIEW_TOP+1
1af5: 85 13 sta ]y0+1
1af7: 4c 72 19 jmp :ReCheck0
; Adjust x0,y0 so it's inside bottom edge.
;
; x = x0 + (x1 - x0) * (view_bottom - y0) / (y1 - y0)
; y = view_bottom
1afa: 38 :TopOkay sec ;must be off bottom (or we wouldn't be here)
1afb: a5 16 lda ]y1
1afd: e5 12 sbc ]y0
1aff: 85 1c sta ]delta2
1b01: 38 sec
1b02: a5 5a lda VIEW_BOTTOM
1b04: e5 12 sbc ]y0
1b06: aa tax
1b07: 38 sec
1b08: a5 14 lda ]x1
1b0a: e5 10 sbc ]x0
1b0c: a8 tay
1b0d: a5 15 lda ]x1+1
1b0f: e5 11 sbc ]x0+1
1b11: 85 1d sta ]tmp
1b13: 0a asl A
1b14: 98 tya
1b15: 90 04 bcc L1B1B
1b17: 49 ff eor #$ff
1b19: 69 00 adc #$00
1b1b: 20 43 1b L1B1B jsr ClipMulDiv
1b1e: a2 00 ldx #$00
1b20: a5 1b lda ]muldiv_val
1b22: 06 1d asl ]tmp
1b24: 90 07 bcc L1B2D
1b26: 49 ff eor #$ff
1b28: 69 00 adc #$00
1b2a: f0 01 beq L1B2D
1b2c: ca dex
1b2d: 18 L1B2D clc
1b2e: 65 10 adc ]x0
1b30: a8 tay
1b31: 8a txa
1b32: 65 11 adc ]x0+1
1b34: 84 10 sty ]x0
1b36: 85 11 sta ]x0+1
1b38: a5 5a lda VIEW_BOTTOM
1b3a: 85 12 sta ]y0
1b3c: a5 5b lda VIEW_BOTTOM+1
1b3e: 85 13 sta ]y0+1
1b40: 4c 72 19 jmp :ReCheck0
;
; Compute A * B / C.
;
; Only used internally, for line clipping. Takes about 240 cycles.
;
; On entry:
; A-reg: value A (signed)
; X-reg: value B
; $1c: value C (signed?)
;
; On exit:
; $1b: result
;
• Clear variables
]result_part .var $1a {addr/1}
]result .var $1b {addr/1}
]value_c .var $1c {addr/1}
1b43: e0 00 ClipMulDiv cpx #$00 ;check for multiply by zero
1b45: d0 03 bne :DoMult ;no, do the full thing
1b47: 86 1b stx ]result ;set result to zero
1b49: 60 rts
1b4a: ca :DoMult dex ;start with multiply A-reg * X-reg
1b4b: 86 1a stx ]result_part
1b4d: 4a lsr A
1b4e: 85 1b sta ]result
1b50: a9 00 lda #$00
1b52: 90 02 bcc L1B56
1b54: 65 1a adc ]result_part
1b56: 6a L1B56 ror A
1b57: 66 1b ror ]result
1b59: 90 02 bcc L1B5D
1b5b: 65 1a adc ]result_part
1b5d: 6a L1B5D ror A
1b5e: 66 1b ror ]result
1b60: 90 02 bcc L1B64
1b62: 65 1a adc ]result_part
1b64: 6a L1B64 ror A
1b65: 66 1b ror ]result
1b67: 90 02 bcc L1B6B
1b69: 65 1a adc ]result_part
1b6b: 6a L1B6B ror A
1b6c: 66 1b ror ]result
1b6e: 90 02 bcc L1B72
1b70: 65 1a adc ]result_part
1b72: 6a L1B72 ror A
1b73: 66 1b ror ]result
1b75: 90 02 bcc L1B79
1b77: 65 1a adc ]result_part
1b79: 6a L1B79 ror A
1b7a: 66 1b ror ]result
1b7c: 90 02 bcc L1B80
1b7e: 65 1a adc ]result_part
1b80: 6a L1B80 ror A
1b81: 66 1b ror ]result
1b83: 90 02 bcc L1B87
1b85: 65 1a adc ]result_part
1b87: 6a L1B87 ror A
1b88: 66 1b ror ]result
1b8a: 06 1b asl ]result
1b8c: 2a rol A ;now divide by $1c
1b8d: b0 04 bcs L1B93
1b8f: c5 1c cmp ]value_c
1b91: 90 03 bcc L1B96
1b93: e5 1c L1B93 sbc ]value_c
1b95: 38 sec
1b96: 26 1b L1B96 rol ]result
1b98: 2a rol A
1b99: b0 04 bcs L1B9F
1b9b: c5 1c cmp ]value_c
1b9d: 90 03 bcc L1BA2
1b9f: e5 1c L1B9F sbc ]value_c
1ba1: 38 sec
1ba2: 26 1b L1BA2 rol ]result
1ba4: 2a rol A
1ba5: b0 04 bcs L1BAB
1ba7: c5 1c cmp ]value_c
1ba9: 90 03 bcc L1BAE
1bab: e5 1c L1BAB sbc ]value_c
1bad: 38 sec
1bae: 26 1b L1BAE rol ]result
1bb0: 2a rol A
1bb1: b0 04 bcs L1BB7
1bb3: c5 1c cmp ]value_c
1bb5: 90 03 bcc L1BBA
1bb7: e5 1c L1BB7 sbc ]value_c
1bb9: 38 sec
1bba: 26 1b L1BBA rol ]result
1bbc: 2a rol A
1bbd: b0 04 bcs L1BC3
1bbf: c5 1c cmp ]value_c
1bc1: 90 03 bcc L1BC6
1bc3: e5 1c L1BC3 sbc ]value_c
1bc5: 38 sec
1bc6: 26 1b L1BC6 rol ]result
1bc8: 2a rol A
1bc9: b0 04 bcs L1BCF
1bcb: c5 1c cmp ]value_c
1bcd: 90 03 bcc L1BD2
1bcf: e5 1c L1BCF sbc ]value_c
1bd1: 38 sec
1bd2: 26 1b L1BD2 rol ]result
1bd4: 2a rol A
1bd5: b0 04 bcs L1BDB
1bd7: c5 1c cmp ]value_c
1bd9: 90 03 bcc L1BDE
1bdb: e5 1c L1BDB sbc ]value_c
1bdd: 38 sec
1bde: 26 1b L1BDE rol ]result
1be0: 2a rol A
1be1: b0 04 bcs L1BE7
1be3: c5 1c cmp ]value_c
1be5: 90 03 bcc L1BEA
1be7: e5 1c L1BE7 sbc ]value_c
1be9: 38 sec
1bea: 26 1b L1BEA rol ]result
1bec: 60 rts
1bed: ff 01 00 ff+ .align $0100 (19 bytes)
;
; Updates all objects, draws them, and draws the HUD items.
;
1c00: 20 10 60 UpdDrawObjHud jsr UPDATE_DRAW_OBJECTS
1c03: 20 32 1c jsr StripFromRadar
1c06: a9 80 lda #$80
1c08: 4c 00 7e jmp DRAW_HUD_ITEMS
1c0b: 00 ff ff 00+ .junk 5
********************************************************************************
* Copies hi-res page 2 to page 1. *
********************************************************************************
• Clear variables
]dst_ptr .var $fc {addr/2}
]src_ptr .var $fe {addr/2}
1c10: a9 00 CopyHires2to1 lda #$00
1c12: 85 fe sta ]src_ptr
1c14: 85 fc sta ]dst_ptr
1c16: a9 5f lda #$5f ;5fxx - 40xx
1c18: 85 ff sta ]src_ptr+1
1c1a: a9 3f lda #$3f ;3fxx - 20xx
1c1c: 85 fd sta ]dst_ptr+1
1c1e: a0 00 ldy #$00
1c20: b1 fe :Loop lda (]src_ptr),y
1c22: 91 fc sta (]dst_ptr),y
1c24: 88 dey
1c25: d0 f9 bne :Loop
1c27: c6 ff dec ]src_ptr+1
1c29: c6 fd dec ]dst_ptr+1
1c2b: a5 fd lda ]dst_ptr+1 ;(could use X-reg here)
1c2d: c9 20 cmp #$20
1c2f: b0 ef bcs :Loop
1c31: 60 rts
;
; Strips certain things out of the radar.
;
1c32: a9 00 StripFromRadar lda #$00
1c34: a0 17 ldy #23
1c36: be 18 84 :Loop ldx OBJ_MOVE_CLASS,y ;get movement class
1c39: e0 09 cpx #$09
1c3b: f0 0d beq :StripIt ;never on radar
1c3d: 2c 81 85 bit SHOTS_VIS_FLAG ;are shots visible?
1c40: 30 0e bmi :NoStrip ;yes, leave them
1c42: e0 08 cpx #$08 ;immovable (obstacle/fuelbay/warplink)?
1c44: f0 0a beq :NoStrip ;always visible
1c46: e0 05 cpx #$05 ;1-4 are visible
1c48: 90 06 bcc :NoStrip
1c4a: 99 d0 0c :StripIt sta radar_xcoords,y ;set coords to zero so we don't draw them
1c4d: 99 e8 0c sta radar_ycoords,y
1c50: 88 :NoStrip dey
1c51: d0 e3 bne :Loop
1c53: 60 rts
1c54: ff ff 00 00+ .junk 12
********************************************************************************
* Initializes zero-page locations with the game viewport parameters. This *
* uses the same values that InitViewport0 at ROCK2 $87da does. *
* *
* This is called when preparing for the warp-out animation. *
* *
* On exit: *
* $50-5b: initialized with game viewport parameters *
* $22-26: background render params initialized for player facing *
********************************************************************************
]bk_horiz_pos .var $22 {addr/2}
]bk_vert_pos .var $24 {addr/2}
]horizon_adj .var $26 {addr/1}
1c60: a9 77 InitWarpView lda #119 ;center of viewport on screen
1c62: 85 50 sta VIEW_X_ADJ
1c64: a9 6b lda #107
1c66: 85 52 sta VIEW_Y_ADJ
1c68: a9 90 lda #$90
1c6a: 85 54 sta VIEW_LEFT ;-112
1c6c: a9 6f lda #$6f
1c6e: 85 56 sta VIEW_RIGHT ;+111
1c70: a9 4a lda #$4a
1c72: 85 58 sta VIEW_TOP ;+74
1c74: a9 ae lda #$ae
1c76: 85 5a sta VIEW_BOTTOM ;-82
1c78: a9 00 lda #$00
1c7a: 85 51 sta VIEW_X_ADJ+1
1c7c: 85 53 sta VIEW_Y_ADJ+1
1c7e: 85 57 sta VIEW_RIGHT+1
1c80: 85 59 sta VIEW_TOP+1
1c82: a9 ff lda #$ff
1c84: 85 55 sta VIEW_LEFT+1
1c86: 85 5b sta VIEW_BOTTOM+1
; Configure star/mountain rendering values.
1c88: a9 ff lda #$ff ;horizon adjustment = -1
1c8a: 85 26 sta ]horizon_adj
1c8c: a9 00 lda #$00 ;vertical position to zero
1c8e: 85 24 sta ]bk_vert_pos
1c90: 85 25 sta ]bk_vert_pos+1
1c92: 38 sec
1c93: ed d8 66 sbc OBJ_FACING ;player facing; invert it
1c96: 0a asl A ;double it
1c97: 85 22 sta ]bk_horiz_pos ;save as horizontal position
1c99: 26 23 rol ]bk_horiz_pos+1
1c9b: 60 rts
1c9c: ff ff 01 00 .junk 4
********************************************************************************
* Updates the horizontal and vertical position for viewing the background. *
* Clears the viewport, then draws the background stuff (stars, horizon line, *
* mountains). Called during the warp-out animation. *
* *
* Called from ROCK2, at and around $89a4. *
* *
* On entry: *
* $22/23: background horizontal position (facing angle * 2) *
* $24/25: background vertical position *
* $c1: amount to rotate *
* $c3: amount to climb *
********************************************************************************
]rotate_amt .var $c1 {addr/1}
]climb_rate .var $c3 {addr/1}
1ca0: ae f0 65 DrawWarpBkgnd ldx RENDER_PAGE ;get page we're rendering on
1ca3: bd cd 1c lda hpage_addr_hi,x ;convert to high byte of address ($20/$40)
1ca6: 85 32 sta hpage
1ca8: 8a txa ;put 0/1 in A-reg
1ca9: 20 00 74 jsr CLEAR_VIEWPORT ;clear the viewport area on the hi-res screen
1cac: 18 clc
1cad: a5 22 lda ]bk_horiz_pos ;get current horizontal position
1caf: 65 c1 adc ]rotate_amt ;advance
1cb1: 85 22 sta ]bk_horiz_pos
1cb3: a9 00 lda #$00 ;repeat for high byte
1cb5: 65 23 adc ]bk_horiz_pos+1
1cb7: 48 pha
1cb8: a5 c1 lda ]rotate_amt ;get the rotation delta sign bit
1cba: 0a asl A
1cbb: 68 pla
1cbc: 69 00 adc #$00 ;add that in as well
1cbe: 85 23 sta ]bk_horiz_pos+1
1cc0: 18 clc
1cc1: a5 24 lda ]bk_vert_pos ;update the vertical position
1cc3: 65 c3 adc ]climb_rate
1cc5: 85 24 sta ]bk_vert_pos
1cc7: 20 00 70 jsr DRAW_MOUNTAINS ;draw mountains
1cca: 4c b0 70 jmp DRAW_STARS ;draw stars
1ccd: 20 40 hpage_addr_hi .bulk $20,$40
1ccf: 00 ff ff 00+ .align $0100 (49 bytes)
********************************************************************************
* Clears the hi-res screen to black. *
* *
* Theoretically called from ROCK2 by indirect jump ($60f9). I don't think *
* this is actually used in the game -- the vector gets replaced with *
* ClearViewport. *
* *
* On entry: *
* A-reg: hi-res page (0=page1, 1=page2) *
********************************************************************************
1d00: a2 00 ClearScreen ldx #$00
1d02: c9 00 cmp #$00
1d04: d0 64 bne :Page2
1d06: 9d 00 27 :Page1 sta $2700,x
1d09: 9d 00 26 sta $2600,x
1d0c: 9d 00 25 sta $2500,x
1d0f: 9d 00 24 sta $2400,x
1d12: 9d 00 23 sta $2300,x
1d15: 9d 00 22 sta $2200,x
1d18: 9d 00 21 sta $2100,x
1d1b: 9d 00 20 sta $2000,x
1d1e: 9d 00 2f sta $2f00,x
1d21: 9d 00 2e sta $2e00,x
1d24: 9d 00 2d sta $2d00,x
1d27: 9d 00 2c sta $2c00,x
1d2a: 9d 00 2b sta $2b00,x
1d2d: 9d 00 2a sta $2a00,x
1d30: 9d 00 29 sta $2900,x
1d33: 9d 00 28 sta $2800,x
1d36: 9d 00 37 sta $3700,x
1d39: 9d 00 36 sta $3600,x
1d3c: 9d 00 35 sta $3500,x
1d3f: 9d 00 34 sta $3400,x
1d42: 9d 00 33 sta $3300,x
1d45: 9d 00 32 sta $3200,x
1d48: 9d 00 31 sta $3100,x
1d4b: 9d 00 30 sta $3000,x
1d4e: 9d 00 3f sta $3f00,x
1d51: 9d 00 3e sta $3e00,x
1d54: 9d 00 3d sta $3d00,x
1d57: 9d 00 3c sta $3c00,x
1d5a: 9d 00 3b sta $3b00,x
1d5d: 9d 00 3a sta $3a00,x
1d60: 9d 00 39 sta $3900,x
1d63: 9d 00 38 sta $3800,x
1d66: e8 inx
1d67: d0 9d bne :Page1
1d69: 60 rts
1d6a: a9 00 :Page2 lda #$00
1d6c: 9d 00 47 :Loop2 sta $4700,x
1d6f: 9d 00 46 sta $4600,x
1d72: 9d 00 45 sta $4500,x
1d75: 9d 00 44 sta $4400,x
1d78: 9d 00 43 sta $4300,x
1d7b: 9d 00 42 sta $4200,x
1d7e: 9d 00 41 sta $4100,x
1d81: 9d 00 40 sta $4000,x
1d84: 9d 00 4f sta $4f00,x
1d87: 9d 00 4e sta $4e00,x
1d8a: 9d 00 4d sta $4d00,x
1d8d: 9d 00 4c sta $4c00,x
1d90: 9d 00 4b sta $4b00,x
1d93: 9d 00 4a sta $4a00,x
1d96: 9d 00 49 sta $4900,x
1d99: 9d 00 48 sta $4800,x
1d9c: 9d 00 57 sta $5700,x
1d9f: 9d 00 56 sta $5600,x
1da2: 9d 00 55 sta $5500,x
1da5: 9d 00 54 sta $5400,x
1da8: 9d 00 53 sta $5300,x
1dab: 9d 00 52 sta $5200,x
1dae: 9d 00 51 sta $5100,x
1db1: 9d 00 50 sta $5000,x
1db4: 9d 00 5f sta $5f00,x
1db7: 9d 00 5e sta $5e00,x
1dba: 9d 00 5d sta $5d00,x
1dbd: 9d 00 5c sta $5c00,x
1dc0: 9d 00 5b sta $5b00,x
1dc3: 9d 00 5a sta $5a00,x
1dc6: 9d 00 59 sta $5900,x
1dc9: 9d 00 58 sta $5800,x
1dcc: e8 inx
1dcd: d0 9d bne :Loop2
1dcf: 60 rts
********************************************************************************
* Initializes an object slot. *
* *
* Called from BRIEFING. *
* *
* On entry: *
* A-reg: object type *
* Y-reg: slot number *
********************************************************************************
1dd0: 99 18 66 InitObjSlot sta OBJ_TYPE,y ;set object type
1dd3: a9 00 lda #$00 ;zero in most of the rest
1dd5: 99 48 66 sta OBJ_XC_LO,y
1dd8: 99 60 66 sta OBJ_XC_HI,y
1ddb: 99 78 66 sta OBJ_ZC_LO,y
1dde: 99 90 66 sta OBJ_ZC_HI,y
1de1: 99 a8 66 sta OBJ_YC_LO,y
1de4: 99 c0 66 sta OBJ_YC_HI,y
1de7: 99 d8 66 sta OBJ_FACING,y
1dea: 99 f0 66 sta OBJ_XC_MOVE,y
1ded: 99 08 67 sta OBJ_ZC_MOVE,y
1df0: 99 20 67 sta OBJ_YC_MOVE,y
1df3: 99 38 67 sta OBJ_SPEED,y
1df6: 99 50 67 sta OBJ_FACING_ADJ,y
1df9: 99 68 67 sta OBJ_ROT_SPEED,y
1dfc: 99 80 67 sta OBJ_IMMOB_FLAG,y
1dff: a9 80 lda #$80 ;$80 in these three
1e01: 99 30 66 sta OBJ_MAX_DIM,y
1e04: 99 98 67 sta OBJ_VIS_FLAG,y
1e07: 99 00 66 sta OBJ_ALIVE_FLAG,y ;(this was zeroed earlier)
1e0a: 60 rts
;
; Zeroes all of the "object alive" flags.
;
1e0b: a0 17 MarkAllInactive ldy #23
1e0d: a9 00 lda #$00
1e0f: 99 00 66 :Loop sta OBJ_ALIVE_FLAG,y
1e12: 88 dey
1e13: 10 fa bpl :Loop
1e15: 60 rts
********************************************************************************
* Copies object state from one slot to another. *
* *
* Called from ROCK2. *
* *
* On entry: *
* X-reg: source slot *
* Y-reg: dest slot *
********************************************************************************
1e16: bd 00 66 CopyObjState lda OBJ_ALIVE_FLAG,x
1e19: 99 00 66 sta OBJ_ALIVE_FLAG,y
1e1c: bd 18 66 lda OBJ_TYPE,x
1e1f: 99 18 66 sta OBJ_TYPE,y
1e22: bd 30 66 lda OBJ_MAX_DIM,x
1e25: 99 30 66 sta OBJ_MAX_DIM,y
1e28: bd 48 66 lda OBJ_XC_LO,x
1e2b: 99 48 66 sta OBJ_XC_LO,y
1e2e: bd 60 66 lda OBJ_XC_HI,x
1e31: 99 60 66 sta OBJ_XC_HI,y
1e34: bd 78 66 lda OBJ_ZC_LO,x
1e37: 99 78 66 sta OBJ_ZC_LO,y
1e3a: bd 90 66 lda OBJ_ZC_HI,x
1e3d: 99 90 66 sta OBJ_ZC_HI,y
1e40: bd a8 66 lda OBJ_YC_LO,x
1e43: 99 a8 66 sta OBJ_YC_LO,y
1e46: bd c0 66 lda OBJ_YC_HI,x
1e49: 99 c0 66 sta OBJ_YC_HI,y
1e4c: bd d8 66 lda OBJ_FACING,x
1e4f: 99 d8 66 sta OBJ_FACING,y
1e52: bd f0 66 lda OBJ_XC_MOVE,x
1e55: 99 f0 66 sta OBJ_XC_MOVE,y
1e58: bd 08 67 lda OBJ_ZC_MOVE,x
1e5b: 99 08 67 sta OBJ_ZC_MOVE,y
1e5e: bd 20 67 lda OBJ_YC_MOVE,x
1e61: 99 20 67 sta OBJ_YC_MOVE,y
1e64: bd 38 67 lda OBJ_SPEED,x
1e67: 99 38 67 sta OBJ_SPEED,y
1e6a: bd 50 67 lda OBJ_FACING_ADJ,x
1e6d: 99 50 67 sta OBJ_FACING_ADJ,y
1e70: bd 68 67 lda OBJ_ROT_SPEED,x
1e73: 99 68 67 sta OBJ_ROT_SPEED,y
1e76: bd 80 67 lda OBJ_IMMOB_FLAG,x
1e79: 99 80 67 sta OBJ_IMMOB_FLAG,y
1e7c: bd 98 67 lda OBJ_VIS_FLAG,x
1e7f: 99 98 67 sta OBJ_VIS_FLAG,y
1e82: 60 rts
********************************************************************************
* Check to see if two objects collide. Only tests X/Z. Does a simple axis- *
* aligned bounding box overlap test. *
* *
* The arena wraps around at the edges, so we need to use modulo arithmetic *
* when checking the distance. *
* *
* Called from ROCK2. *
* *
* On entry: *
* X-reg: index of first object (0-23) *
* Y-reg: index of second object (0-23) *
* *
* On exit: *
* Carry flag set if the objects overlap *
********************************************************************************
• Clear variables
]diff .var $00 {addr/2}
]combined_dim .var $02 {addr/2}
1e83: 18 DetectCollision clc
1e84: bd 30 66 lda OBJ_MAX_DIM,x ;compute the sum of their maximum dimensions
1e87: 79 30 66 adc OBJ_MAX_DIM,y
1e8a: 85 02 sta ]combined_dim
1e8c: a9 00 lda #$00
1e8e: 69 00 adc #$00
1e90: 85 03 sta ]combined_dim+1
1e92: 38 sec
1e93: b9 48 66 lda OBJ_XC_LO,y ;compute the distance between object centers
1e96: fd 48 66 sbc OBJ_XC_LO,x ; along the X axis
1e99: 85 00 sta ]diff ;values are +/- 4K, so [0000,0fff] or [f000,ffff]
1e9b: b9 60 66 lda OBJ_XC_HI,y ;combined will be [0000,1ffe] or [e001,ffff]
1e9e: fd 60 66 sbc OBJ_XC_HI,x
1ea1: 29 1f and #$1f ;now [0000,1ffe] or [0001,1fff]
1ea3: 85 01 sta ]diff+1 ;save high part
1ea5: 29 10 and #$10 ;check bit 4
1ea7: f0 0e beq :XPos ;treat as positive
1ea9: 18 clc ;treat as negative
1eaa: a5 00 lda ]diff ;the value is flipped, not negated, so un-flip
1eac: 65 02 adc ]combined_dim
1eae: a5 01 lda ]diff+1
1eb0: 09 e0 ora #$e0 ;put the sign bits back
1eb2: 65 03 adc ]combined_dim+1
1eb4: b0 09 bcs :XClose ;close, go check Z
1eb6: 60 rts ;far, return
1eb7: a5 02 :XPos lda ]combined_dim ;compare the distance to the object dimensions
1eb9: c5 00 cmp ]diff
1ebb: a5 03 lda ]combined_dim+1
1ebd: e5 01 sbc ]diff+1
1ebf: 90 2c :XClose bcc :Return ;bail if they're far apart
; Repeat the process for the Z coordinate.
1ec1: b9 78 66 lda OBJ_ZC_LO,y
1ec4: fd 78 66 sbc OBJ_ZC_LO,x
1ec7: 85 00 sta ]diff
1ec9: b9 90 66 lda OBJ_ZC_HI,y
1ecc: fd 90 66 sbc OBJ_ZC_HI,x
1ecf: 29 1f and #$1f
1ed1: 85 01 sta ]diff+1
1ed3: 29 10 and #$10
1ed5: f0 0e beq :ZPos
1ed7: 18 clc
1ed8: a5 00 lda ]diff
1eda: 65 02 adc ]combined_dim
1edc: a5 01 lda ]diff+1
1ede: 09 e0 ora #$e0
1ee0: 65 03 adc ]combined_dim+1
1ee2: b0 09 bcs :Return ;close in X as well, collide
1ee4: 60 rts
1ee5: a5 02 :ZPos lda ]combined_dim
1ee7: c5 00 cmp ]diff
1ee9: a5 03 lda ]combined_dim+1
1eeb: e5 01 sbc ]diff+1
1eed: 60 :Return rts
1eee: 00 00 ff ff+ .junk 15
********************************************************************************
* Clears the object movement fields. *
* *
* Called from ROCK2 ($94ec,9789). *
* *
* On entry: *
* Y-reg: index ($00-17) *
* *
* On exit: *
* A-reg: $00 *
* X-reg and Y-reg preserved *
********************************************************************************
1efd: a9 00 ClearObjMove lda #$00
1eff: 99 f0 66 sta OBJ_XC_MOVE,y
1f02: 99 08 67 sta OBJ_ZC_MOVE,y
1f05: 99 20 67 sta OBJ_YC_MOVE,y
1f08: 99 38 67 sta OBJ_SPEED,y
1f0b: 99 50 67 sta OBJ_FACING_ADJ,y
1f0e: 99 68 67 sta OBJ_ROT_SPEED,y
1f11: 60 rts
********************************************************************************
* Initializes one viewport slot. *
* *
* Called from ROCK2. *
* *
* On entry: *
* Y-reg: index (0-3) *
********************************************************************************
InitViewportSlot
1f12: a9 80 lda #$80
1f14: 99 c0 67 sta VIEW_ACTV_FLAGS,y ;mark as active
1f17: a9 00 lda #$00
1f19: 99 c4 67 sta VIEW_SKIP_OBJS,y ;ignore player object
1f1c: a9 00 lda #$00
1f1e: 99 c8 67 sta VIEW_ANGLE_ADJS,y ;look straight ahead
1f21: a9 07 lda #$07
1f23: 99 cc 67 sta VIEW_ZOOMS,y ;default zoom
1f26: a9 80 lda #$80
1f28: 99 d0 67 sta VIEW_NEAR_VERT,y
1f2b: a9 80 lda #$80
1f2d: 99 d4 67 sta VIEW_NEAR_LO,y
1f30: a9 00 lda #$00
1f32: 99 d8 67 sta VIEW_NEAR_HI,y
1f35: a9 00 lda #$00
1f37: 99 dc 67 sta VIEW_FAR_LO,y
1f3a: a9 10 lda #$10
1f3c: 99 e0 67 sta VIEW_FAR_HI,y
1f3f: a9 80 lda #128 ;default viewport center (256/2)
1f41: 99 e4 67 sta VIEW_X_ADJS,y
1f44: a9 60 lda #96 ;(192/2)
1f46: 99 e8 67 sta VIEW_Y_ADJS,y
1f49: a9 80 lda #$80 ;-128
1f4b: 99 ec 67 sta VIEW_LEFT_VALS,y
1f4e: a9 7f lda #$7f ;+127
1f50: 99 f0 67 sta VIEW_RIGHT_VALS,y
1f53: a9 60 lda #$60 ;+96
1f55: 99 f4 67 sta VIEW_TOP_VALS,y
1f58: a9 a1 lda #$a1 ;-95
1f5a: 99 f8 67 sta VIEW_BOTTOM_VALS,y
1f5d: 60 rts
;
; Zeroes out $67C0-67C3, marking all viewports as inactive.
;
DisableViewports
1f5e: a0 03 ldy #$03
1f60: a9 00 lda #$00
1f62: 99 c0 67 :Loop sta VIEW_ACTV_FLAGS,y
1f65: 88 dey
1f66: 10 fa bpl :Loop
1f68: 60 rts
********************************************************************************
* Initializes graphics engine state. Clears viewports and object state slots. *
* *
* Called from ROCK2 during initialization. *
********************************************************************************
1f69: a9 00 InitGfxEngine lda #$00 ;draw on page 1
1f6b: 8d f0 65 sta RENDER_PAGE
1f6e: a9 80 lda #$80 ;erase the viewport
1f70: 8d f1 65 sta ERASE_VIEW_FLAG
1f73: a9 00 lda #$00 ;clear the "nobody move" flags
1f75: 8d f2 65 sta BLOCK_MOVEMENT0
1f78: a9 00 lda #$00
1f7a: 8d f3 65 sta BLOCK_MOVEMENT1
1f7d: a9 00 lda #<MESH_DATA ;set the pointer to the 3D mesh data
1f7f: 8d f4 65 sta MESH_DATA_PTR
1f82: a9 68 lda #>MESH_DATA
1f84: 8d f5 65 sta MESH_DATA_PTR+1
1f87: a9 00 lda #<ClearScreen ;default viewport clear to full screen
1f89: 8d f6 65 sta JMP_ADDR_CLEAR
1f8c: a9 1d lda #>ClearScreen
1f8e: 8d f7 65 sta JMP_ADDR_CLEAR+1
1f91: a9 c4 lda #<InitStateDone ;default these to known RTS
1f93: 8d f8 65 sta JUMP_ADDR2
1f96: a9 1f lda #>InitStateDone
1f98: 8d f9 65 sta JUMP_ADDR2+1
1f9b: a9 c4 lda #<InitStateDone
1f9d: 8d fa 65 sta JUMP_ADDR3
1fa0: a9 1f lda #>InitStateDone
1fa2: 8d fb 65 sta JUMP_ADDR3+1
1fa5: a9 00 lda #$00
1fa7: 8d fc 65 sta SHOW_BKGND_FLAG ;disable stars/mountains
1faa: a9 ff lda #$ff ;set horizon baseline to -1 (for mnts/stars)
1fac: 8d fd 65 sta HORIZON_BASELINE
1faf: 20 0b 1e jsr MarkAllInactive ;clear all of the "object is alive" flags
1fb2: a0 00 ldy #$00 ;zero out slot 0
1fb4: a9 00 lda #$00
1fb6: 20 d0 1d jsr InitObjSlot
1fb9: 20 5e 1f jsr DisableViewports ;disable all viewport slots
1fbc: a0 00 ldy #$00
1fbe: 20 12 1f jsr InitViewportSlot ;init viewport slot 0
1fc1: 2c 52 c0 bit MIXCLR ;make sure we're in full-screen mode
1fc4: 60 InitStateDone rts
1fc5: ff 00 00 ff+ .align $0100 (59 bytes)