******************************************************************************** * Caverns of Freitag, by David Shapiro * * Copyright 1982 * * * * Disassembly of "SB2". * ******************************************************************************** * Fireworks display, shown when the game is won. Uses GRAPHIX II to draw * * particles. * * * * (This is one of the best hi-res fireworks displays I've seen.) * ******************************************************************************** * Disassembly by Andy McFadden, using 6502bench SourceGen v1.5. * * Last updated 2020/01/26 * ******************************************************************************** ptr .eq $08 {addr/2} ARG_DRAW_MODE .eq $1c ;0=draw, 1=erase, 2=invert ARG_COLOR .eq $1f ;0=green, 1=orange, 2=purple, 3=blue ptr_x0 .eq $40 {addr/2} ptr_y0 .eq $42 {addr/2} ptr_deltax .eq $44 {addr/2} ptr_deltay .eq $46 {addr/2} state_ptr48 .eq $48 {addr/2} ptr_color .eq $4a {addr/2} ARG_X0 .eq $f9 {addr/2} ;X coord #0 (0-255 or 0-139) ARG_Y0 .eq $fb ;Y coord #0 (0-191) ARG_FF .eq $ff ;shape fill flag -or- CLR color center_x .eq $035c center_y .eq $035d saved_xreg .eq $035e particle_index .eq $035f counter_24bit .eq $0360 {addr/3} update_cadence .eq $0363 {addr/5} max_particle_count .eq $0368 next_particle_index .eq $0369 {addr/5} next_explosion_ctr .eq $036e always_one .eq $036f CLR .eq $080f ;clear the screen CDOT .eq $082a ;plot a colored pixel (140 mode) storage .eq $9000 {addr/2304} KBD .eq $c000 ;R last key pressed + 128 KBDSTRB .eq $c010 ;RW keyboard strobe SPKR .eq $c030 ;RW toggle speaker TXTCLR .eq $c050 ;RW display graphics MIXSET .eq $c053 ;RW display split screen HIRES .eq $c057 ;RW display hi-res graphics .org $7a00 7a00: a9 00 lda #$00 7a02: aa tax 7a03: 2c 50 c0 bit TXTCLR ;enable hi-res graphics, mixed-mode 7a06: 2c 57 c0 bit HIRES 7a09: 2c 53 c0 bit MIXSET 7a0c: a9 00 lda #$00 7a0e: 85 ff sta ARG_FF 7a10: 20 0f 08 jsr CLR ;clear screen to black ; Init data area ($9000-99ff) to zeroes. 7a13: a9 00 lda #<storage 7a15: 85 08 sta ptr 7a17: a9 90 lda #>storage 7a19: 85 09 sta ptr+1 7a1b: a2 0a ldx #$0a 7a1d: a0 00 :ClrLoop1 ldy #$00 7a1f: 98 tya 7a20: 91 08 :ClrLoop2 sta (ptr),y 7a22: c8 iny 7a23: d0 fb bne :ClrLoop2 7a25: e6 09 inc ptr+1 7a27: ca dex 7a28: d0 f3 bne :ClrLoop1 ; Zero out $360-364 and $369-36D. (This erases part of LBOLT.) 7a2a: a9 00 :ClrLoop3 lda #$00 ;note X=0 7a2c: 9d 69 03 sta next_particle_index,x 7a2f: 9d 60 03 sta counter_24bit,x 7a32: e8 inx 7a33: e0 05 cpx #$05 7a35: d0 f3 bne :ClrLoop3 ; Copy data from 7E4C-7E51 to $363-367. 7a37: a2 00 ldx #$00 7a39: bd 4c 7e :CopyLoop lda move_cadences,x 7a3c: 9d 63 03 sta update_cadence,x 7a3f: e8 inx 7a40: e0 05 cpx #$05 7a42: d0 f5 bne :CopyLoop ; Save $40-4e so we can use it for variable storage. 7a44: a2 0e ldx #$0e 7a46: b5 40 :PreserveLoop lda ptr_x0,x 7a48: 9d 45 7d sta saved_dp_40,x 7a4b: ca dex 7a4c: 10 f8 bpl :PreserveLoop 7a4e: 8d 10 c0 sta KBDSTRB ;clear pending key ; ; It works like this: ; - Pick a random center point and a color for the explosion. ; - Start generating particles from that center point. ; - Every M cycles, move particles (M varies by particle set). ; - After N cycles, start a new firework. ; ; Existing particles continue to move until the explosion gets overwritten by a ; new one. They disappear when something else occupies their slot. The CDOT ; code performs clipping at screen boundaries. ; ; There are five particle sets. New particles pick a number from 0-23, then get ; a movement vector and a set number from a 24-entry table. ; 7a51: a9 01 OuterLoop lda #$01 7a53: 8d 6f 03 sta always_one ; Pick random values for firework position and inter-explosion delay. 7a56: a9 60 lda #96 7a58: 20 c5 7c jsr GetRandomLtN ;get 0-95 7a5b: 09 23 ora #$23 ;provide minimum duration 7a5d: 8d 6e 03 sta next_explosion_ctr 7a60: a9 64 lda #100 7a62: 20 c5 7c jsr GetRandomLtN ;get 0-99 7a65: 18 clc 7a66: 69 14 adc #20 ;now 20-119 (out of 0-139) 7a68: 8d 5c 03 sta center_x 7a6b: a9 78 lda #120 7a6d: 20 c5 7c jsr GetRandomLtN ;get 0-119 7a70: 18 clc 7a71: 69 14 adc #20 ;now 20-139 (out of 0-159) 7a73: 8d 5d 03 sta center_y 7a76: ce c4 7c dec next_color ;change color 7a79: 10 05 bpl :InnerLoop ;did it go negative? 7a7b: a9 03 lda #$03 ;yes, reset to 3 7a7d: 8d c4 7c sta next_color ; Fun fact: if you change $7A81 to $00, particles shoot out straight ; horizontally or vertically. 7a80: a2 04 :InnerLoop ldx #$04 ;for each of the 5 sets 7a82: de 63 03 :FworkLoop dec update_cadence,x ;time to move particles? 7a85: d0 0f bne :NoMove ;not yet 7a87: 8e 5e 03 stx saved_xreg ;preserve this 7a8a: 20 ce 7a jsr UpdateParticles ;move particles in the set 7a8d: ae 5e 03 ldx saved_xreg 7a90: bd 4c 7e lda move_cadences,x ;reset state 7a93: 9d 63 03 sta update_cadence,x 7a96: ca :NoMove dex 7a97: 10 e9 bpl :FworkLoop 7a99: ee 60 03 inc counter_24bit ;increment 24-bit counter 7a9c: d0 08 bne :NoInc24 ;(not actually used for anything?) 7a9e: ee 61 03 inc counter_24bit+1 7aa1: d0 03 bne :NoInc24 7aa3: ee 62 03 inc counter_24bit+2 7aa6: ce 6e 03 :NoInc24 dec next_explosion_ctr ;update explosion countdown 7aa9: ad 6e 03 lda next_explosion_ctr 7aac: c9 ff cmp #$ff ;time for a new explosion? 7aae: d0 08 bne :CheckKbd ;not yet 7ab0: ce 6f 03 dec always_one ;looks like this is always one 7ab3: d0 03 bne :CheckKbd ; so this branch is never taken 7ab5: 4c 51 7a jmp OuterLoop ;go make new explosion 7ab8: 20 6f 7b :CheckKbd jsr CreateParticle 7abb: ad 00 c0 lda KBD ;key hit? 7abe: 10 0b bpl :NoKeyHit ;no, branch ; Restore $40-4e. 7ac0: a2 0e ldx #$0e 7ac2: bd 45 7d :RestoreLoop lda saved_dp_40,x 7ac5: 95 40 sta ptr_x0,x 7ac7: ca dex 7ac8: 10 f8 bpl :RestoreLoop 7aca: 60 rts 7acb: 4c 80 7a :NoKeyHit jmp :InnerLoop ; Moves particles in one firework set. ; ; On entry: ; X-reg: firework set (0-4) 7ace: bd 40 7c UpdateParticles lda addr0_lo,x ;extract pointers into DP 7ad1: 85 40 sta ptr_x0 7ad3: bd 45 7c lda addr0_hi,x 7ad6: 85 41 sta ptr_x0+1 7ad8: bd 4a 7c lda addr1_lo,x 7adb: 85 42 sta ptr_y0 7add: bd 4f 7c lda addr1_hi,x 7ae0: 85 43 sta ptr_y0+1 7ae2: bd 54 7c lda addr2_lo,x 7ae5: 85 44 sta ptr_deltax 7ae7: bd 59 7c lda addr2_hi,x 7aea: 85 45 sta ptr_deltax+1 7aec: bd 5e 7c lda addr3_lo,x 7aef: 85 46 sta ptr_deltay 7af1: bd 63 7c lda addr3_hi,x 7af4: 85 47 sta ptr_deltay+1 7af6: bd 68 7c lda addr4_lo,x ;unused? 7af9: 85 48 sta state_ptr48 7afb: bd 6d 7c lda addr4_hi,x 7afe: 85 49 sta state_ptr48+1 7b00: bd 72 7c lda addr5_lo,x 7b03: 85 4a sta ptr_color 7b05: bd 77 7c lda addr5_hi,x 7b08: 85 4b sta ptr_color+1 7b0a: bd 45 7e lda max_particle_counts,x 7b0d: 8d 68 03 sta max_particle_count 7b10: bd 69 03 lda next_particle_index,x 7b13: 18 clc 7b14: 69 01 adc #$01 7b16: cd 68 03 cmp max_particle_count ;reached limit? 7b19: d0 02 bne :NotLimit ;not yet 7b1b: a9 00 lda #$00 ;reset to zero 7b1d: 8d 5f 03 :NotLimit sta particle_index 7b20: a8 tay 7b21: b1 40 :DrawLoop lda (ptr_x0),y ;get current X0/Y0 7b23: 85 f9 sta ARG_X0 7b25: b1 42 lda (ptr_y0),y 7b27: 85 fb sta ARG_Y0 7b29: a9 01 lda #$01 7b2b: 85 1c sta ARG_DRAW_MODE ;mode=erase 7b2d: b1 4a lda (ptr_color),y 7b2f: 85 1f sta ARG_COLOR 7b31: 20 2a 08 jsr CDOT ;erase dot 7b34: ac 5f 03 ldy particle_index 7b37: b1 40 lda (ptr_x0),y ;update X0 position 7b39: 18 clc 7b3a: 71 44 adc (ptr_deltax),y 7b3c: 91 40 sta (ptr_x0),y 7b3e: 85 f9 sta ARG_X0 7b40: b1 42 lda (ptr_y0),y ;update Y0 position 7b42: 18 clc 7b43: 71 46 adc (ptr_deltay),y 7b45: 91 42 sta (ptr_y0),y 7b47: 85 fb sta ARG_Y0 7b49: a9 00 lda #$00 7b4b: 85 1c sta ARG_DRAW_MODE ;mode=draw 7b4d: b1 4a lda (ptr_color),y 7b4f: 20 2a 08 jsr CDOT ;draw dot 7b52: ac 5f 03 ldy particle_index ;increment counter 7b55: c8 iny 7b56: cc 68 03 cpy max_particle_count ;reached end? 7b59: d0 02 bne :NotDone ;not yet 7b5b: a0 00 ldy #$00 ;reset to zero 7b5d: 8c 5f 03 :NotDone sty particle_index 7b60: ae 5e 03 ldx saved_xreg 7b63: bd 69 03 lda next_particle_index,x 7b66: cd 5f 03 cmp particle_index 7b69: f0 03 beq :Done 7b6b: 4c 21 7b jmp :DrawLoop 7b6e: 60 :Done rts ; Creates a new particle, with random velocity, from the current explosion ; center. 7b6f: 20 db 7c CreateParticle jsr GetRandom ;get random value 0-255 7b72: 29 1f and #$1f ;clamp to 0-31 7b74: c9 18 cmp #24 ;is it 0-23? 7b76: b0 f7 bcs CreateParticle ;no, retry ; Get randomly selected deltaX/deltaY and particle sets. ; ; Particle movement is not purely random. The possible movements are defined in ; tables, but the table entry is chosen at random. ; ; One consequence is that particles in certain sets move in certain ways. For ; example, particles in set 0 move vertically or horizontally. This is why ; setting 7A81:00 limits particle movement: we're only moving the particles in ; set 0. 7b78: aa tax 7b79: bd 7c 7c lda delta_x_24,x ;fe/ff/00/01/02 7b7c: 8d 51 7e sta cur_delta_x 7b7f: bd 94 7c lda delta_y_24,x ;fe/ff/00/01/02 7b82: 8d 52 7e sta cur_delta_y 7b85: bd ac 7c lda setindex_24,x ;particle set (0-4) 7b88: aa tax 7b89: 8e 5e 03 stx saved_xreg ; set up pointers based on state index (0-4) 7b8c: bd 40 7c lda addr0_lo,x 7b8f: 85 40 sta ptr_x0 7b91: bd 45 7c lda addr0_hi,x 7b94: 85 41 sta ptr_x0+1 7b96: bd 4a 7c lda addr1_lo,x 7b99: 85 42 sta ptr_y0 7b9b: bd 4f 7c lda addr1_hi,x 7b9e: 85 43 sta ptr_y0+1 7ba0: bd 54 7c lda addr2_lo,x 7ba3: 85 44 sta ptr_deltax 7ba5: bd 59 7c lda addr2_hi,x 7ba8: 85 45 sta ptr_deltax+1 7baa: bd 5e 7c lda addr3_lo,x 7bad: 85 46 sta ptr_deltay 7baf: bd 63 7c lda addr3_hi,x 7bb2: 85 47 sta ptr_deltay+1 7bb4: bd 68 7c lda addr4_lo,x ;unused? 7bb7: 85 48 sta state_ptr48 7bb9: bd 6d 7c lda addr4_hi,x 7bbc: 85 49 sta state_ptr48+1 7bbe: bd 72 7c lda addr5_lo,x 7bc1: 85 4a sta ptr_color 7bc3: bd 77 7c lda addr5_hi,x 7bc6: 85 4b sta ptr_color+1 7bc8: bd 45 7e lda max_particle_counts,x 7bcb: 8d 68 03 sta max_particle_count 7bce: bd 69 03 lda next_particle_index,x 7bd1: 8d 5f 03 sta particle_index ; erase the dot we're replacing 7bd4: a8 tay 7bd5: b1 40 lda (ptr_x0),y 7bd7: 85 f9 sta ARG_X0 7bd9: b1 42 lda (ptr_y0),y 7bdb: 85 fb sta ARG_Y0 7bdd: b1 4a lda (ptr_color),y 7bdf: 85 1f sta ARG_COLOR 7be1: a9 01 lda #$01 7be3: 85 1c sta ARG_DRAW_MODE ;mode=erase 7be5: 20 2a 08 jsr CDOT 7be8: ae 5e 03 ldx saved_xreg ;(not used?) 7beb: ac 5f 03 ldy particle_index 7bee: ad 51 7e lda cur_delta_x ;set up deltaX/deltaY 7bf1: 91 44 sta (ptr_deltax),y ; with values generated randomly earlier 7bf3: ad 52 7e lda cur_delta_y 7bf6: 91 46 sta (ptr_deltay),y 7bf8: ad c4 7c lda next_color ;set color 7bfb: 91 4a sta (ptr_color),y 7bfd: 85 1f sta ARG_COLOR 7bff: 2c 30 c0 bit SPKR ;click 7c02: ce 65 7e dec nine_count 7c05: 10 05 bpl :NotNeg 7c07: a9 08 lda #$08 ;reset counter 7c09: 8d 65 7e sta nine_count ; Set X0/Y0 to center + value from delta_x_tab/delta_y_tab. The initial ; positions are offset in a 9-point diamond pattern. 7c0c: ae 65 7e :NotNeg ldx nine_count ;rotate through 0-8 7c0f: ad 5c 03 lda center_x 7c12: 18 clc 7c13: 7d 53 7e adc delta_x_tab,x 7c16: 91 40 sta (ptr_x0),y 7c18: 85 f9 sta ARG_X0 7c1a: ad 5d 03 lda center_y 7c1d: 18 clc 7c1e: 7d 5c 7e adc delta_y_tab,x 7c21: 91 42 sta (ptr_y0),y 7c23: 85 fb sta ARG_Y0 7c25: a9 00 lda #$00 7c27: 85 1c sta ARG_DRAW_MODE ;mode=draw 7c29: 20 2a 08 jsr CDOT 7c2c: ae 5e 03 ldx saved_xreg ;firework index 7c2f: bd 69 03 lda next_particle_index,x ;update particle index 7c32: 18 clc 7c33: 69 01 adc #$01 7c35: cd 68 03 cmp max_particle_count ;reached limit? 7c38: d0 02 bne :MoreToGo ;not yet 7c3a: a9 00 lda #$00 ;wrap back to zero 7c3c: 9d 69 03 :MoreToGo sta next_particle_index,x 7c3f: 60 rts ; Five sets of 6 addresses, all pointing into $9xxx. These hold x0, y0, deltaX, ; deltaY, color, and something that isn't used. ; ; Each address is +62 or +124 bytes from the previous, suggesting 5 sets with up ; to 62 particles per set. 7c40: 00 74 e8 5c+ addr0_lo .bulk 0074e85cd0 7c45: 90 91 92 94+ addr0_hi .bulk 9091929495 7c4a: 3e b2 26 9a+ addr1_lo .bulk 3eb2269a4c 7c4f: 90 91 93 94+ addr1_hi .bulk 9091939496 7c54: 7c f0 64 d8+ addr2_lo .bulk 7cf064d8c8 7c59: 90 91 93 94+ addr2_hi .bulk 9091939496 7c5e: ba 2e a2 16+ addr3_lo .bulk ba2ea21644 7c63: 90 92 93 95+ addr3_hi .bulk 9092939597 7c68: f8 6c e0 54+ addr4_lo .bulk f86ce054c0 7c6d: 90 92 93 95+ addr4_hi .bulk 9092939597 7c72: 36 aa 1e 92+ addr5_lo .bulk 36aa1e923c 7c77: 91 92 94 95+ addr5_hi .bulk 9192949598 ; 24 sets of stuff 7c7c: fe ff 00 01+ delta_x_24 .bulk feff000102feff000102feff0102feff000102feff000102 7c94: fe fe fe fe+ delta_y_24 .bulk fefefefefeffffffffff0000000001010101010202020202 7cac: 03 04 02 04+ setindex_24 .bulk 030402040304010001040200000204010001040304020403 7cc4: 00 next_color .dd1 $00 ;(0-3) ; Gets a random number in the range 0 <= value < max. ; ; (If you pass $10 as the limit, it will quickly lock up. $20 seems fine. ; Apparently the RNG could use some work.) ; ; On entry: ; A-reg: max value ; ; On exit: ; A-reg: value 7cc5: 8d 40 7d GetRandomLtN sta tmp_arg ;store arg 7cc8: 20 db 7c :Loop jsr GetRandom 7ccb: 8d 41 7d sta tmp_result ;store result 7cce: ad 41 7d lda tmp_result ;get result (redundant) 7cd1: 38 sec 7cd2: ed 40 7d sbc tmp_arg ;is arg >= result? 7cd5: b0 f1 bcs :Loop ;yes, try again 7cd7: ad 41 7d lda tmp_result ;load result 7cda: 60 rts ; Generate a random number. ; ; On exit: ; A-reg: random value (0-255) 7cdb: ad 3e 7d GetRandom lda rand4 7cde: 29 05 and #$05 7ce0: a8 tay 7ce1: a9 34 lda #52 7ce3: f9 3a 7d sbc rand0,y 7ce6: 8d 3a 7d sta rand0 7ce9: ad 3c 7d lda rand2 7cec: 4d 3f 7d eor rand5 7cef: 8d 3f 7d sta rand5 7cf2: 4e 3a 7d lsr rand0 7cf5: 6e 3b 7d ror rand1 7cf8: 6e 3c 7d ror rand2 7cfb: 6e 3d 7d ror rand3 7cfe: 6e 3e 7d ror rand4 7d01: 4e 3f 7d lsr rand5 7d04: 90 30 bcc L7D36 7d06: ad 3a 7d lda rand0 7d09: 49 ff eor #$ff 7d0b: 8d 3a 7d sta rand0 7d0e: ad 3b 7d lda rand1 7d11: 49 ff eor #$ff 7d13: 8d 3b 7d sta rand1 7d16: ad 3c 7d lda rand2 7d19: 49 ff eor #$ff 7d1b: 8d 3c 7d sta rand2 7d1e: ad 3d 7d lda rand3 7d21: 49 ff eor #$ff 7d23: 8d 3d 7d sta rand3 7d26: ad 3e 7d lda rand4 7d29: 49 ff eor #$ff 7d2b: 8d 3e 7d sta rand4 7d2e: ad 3f 7d lda rand5 7d31: 49 ff eor #$ff 7d33: 8d 3f 7d sta rand5 7d36: ad 3d 7d L7D36 lda rand3 7d39: 60 rts ; 48-bit RNG state 7d3a: 0c rand0 .dd1 $0c 7d3b: 62 rand1 .dd1 $62 7d3c: 49 rand2 .dd1 $49 7d3d: ff rand3 .dd1 $ff 7d3e: 11 rand4 .dd1 $11 7d3f: 00 rand5 .dd1 $00 ; temp storage 7d40: 00 tmp_arg .dd1 $00 7d41: 00 tmp_result .dd1 $00 7d42: 00 00 00 .junk 3 7d45: 00 00 00 00+ saved_dp_40 .fill 15,$00 7d54: 00 00 00 00+ .junk 237 7e41: 1e 1e 1e 1e .junk 4 max_particle_counts 7e45: 1e 1e 1e 1e+ .bulk 1e1e1e1e3c 7e4a: 1e 0a .junk 2 ; Every M iterations we move the particles in set N (0-4). This determines how ; often they move. 7e4c: 05 07 0a 0b+ move_cadences .bulk 05070a0b0e 7e51: 01 cur_delta_x .dd1 $01 7e52: fe cur_delta_y .dd1 $fe ; This yields 9 dots in a diamond pattern: ; * ; * * ; * * * ; * * ; * 7e53: 00 ff 01 fe+ delta_x_tab .bulk 00ff01fe0002ff0100 7e5c: fe ff ff 00+ delta_y_tab .bulk feffff000000010102 7e65: 04 nine_count .dd1 $04 ;0-9
No exported symbols found.