wudsn-ide/com.wudsn.ide.ref/ASM/Atari2600/DASM/minidig/disassembly/kaboom.asm
2018-12-30 16:52:33 +01:00

1702 lines
55 KiB
NASM
Raw Blame History

LIST OFF
; *** K A B O O M ! ***
; Copyright 1981 Activision, Inc.
; Programmer: Larry Kaplan
; Graphics: David Crane
; Analyzed, labeled and commented
; by Dennis Debro
; Last Update: August 20, 2004
processor 6502
include vcs.h
LIST ON
;===============================================================================
; A S S E M B L E R - S W I T C H E S
;===============================================================================
NTSC = 0
PAL = 1
COMPILE_VERSION = NTSC ; change this to compile for different
; regions
;Mad Bomber movement switches
ORIGINAL = 0
SMOOTH = 1 ; smooth movement vs. back and forth
MAD_BOMBER_MOVEMENT = ORIGINAL
;============================================================================
; T I A - C O N S T A N T S
;============================================================================
HMOVE_L7 = $70
HMOVE_L6 = $60
HMOVE_L5 = $50
HMOVE_L4 = $40
HMOVE_L3 = $30
HMOVE_L2 = $20
HMOVE_L1 = $10
HMOVE_0 = $00
HMOVE_R1 = $F0
HMOVE_R2 = $E0
HMOVE_R3 = $D0
HMOVE_R4 = $C0
HMOVE_R5 = $B0
HMOVE_R6 = $A0
HMOVE_R7 = $90
HMOVE_R8 = $80
; values for NUSIZx:
ONE_COPY = %000
TWO_COPIES = %001
TWO_WIDE_COPIES = %010
THREE_COPIES = %011
DOUBLE_SIZE = %101
THREE_MED_COPIES = %110
QUAD_SIZE = %111
; values for REFPx:
NO_REFLECT = %0000
REFLECT = %1000
; mask for SWCHB
P1_DIFF_MASK = %10000000
BW_MASK = %00001000 ; black and white bit
SELECT_MASK = %00000010
RESET_MASK = %00000001
;============================================================================
; U S E R - C O N S T A N T S
;============================================================================
ROM_BASE_ADDRESS = $F000
; color constants
BLACK = $00
WHITE = $0F
IF COMPILE_VERSION = NTSC
; NTSC frame time values
VBLANK_TIME = $30
OVERSCAN_TIME = $21
; NTSC color constants
BRICK_RED = $30
YELLOW = $10
GREEN = $D0
RED = $40
BLUE = $80
WATER_COLOR = BLUE+8
LOGO_COLOR = WATER_COLOR
ELSE
; PAL frame time values
VBLANK_TIME = $4F
OVERSCAN_TIME = $3D
;PAL color constants
BRICK_RED = $40
YELLOW = $20
GREEN = $50
RED = $60
BLUE = $B0
WATER_COLOR = BLUE+6
LOGO_COLOR = WATER_COLOR
ENDIF
SELECT_DELAY = 30
PADDLE_MIN = 2
PADDLE_MAX = 254
; kernel boundaries
H_KERNEL = 85
XMIN = 5
XMAX = 118
MAX_BOMBS = 8
MAX_BUCKETS = 3
H_MAD_BOMBER = 32
H_BOMB = 16
H_BUCKETS = 16
H_SPLASH = 8
H_ACTIVISION_LOGO = 8
SCORE_HEIGHT = 8
STARTING_EXPLODING_TIMER = 43
EXPLODING_FLASH_TIME = STARTING_EXPLODING_TIMER - 11
; bomb group constants
BOMB_GROUP_MAX = 8
MAX_BOMBS_GROUP1 = 10
MAX_BOMBS_GROUP2 = 20
MAX_BOMBS_GROUP3 = 30
MAX_BOMBS_GROUP4 = 40
MAX_BOMBS_GROUP5 = 50
MAX_BOMBS_GROUP6 = 75
MAX_BOMBS_GROUP7 = 100
MAX_BOMBS_GROUP8 = 150
DROPPING_FREQ = 18
BOMB_DROP_RATE = 1
; Mad Bomber traveling values
MAD_BOMBER_TRAVELING_LEFT = $FF
MAD_BOMBER_TRAVELING_RIGHT = $00
; game state constances
LEVEL_DONE = $7F
WAIT_LEVEL_START = $FF
BONUS_BUCKET_FREQ = 63
CATCHING_BOMB_FREQ = 16
;============================================================================
; M A C R O S
;============================================================================
MAC FILL_NOP
REPEAT {1}
NOP
REPEND
ENDM
;============================================================================
; Z P - V A R I A B L E S
;============================================================================
SEG.U variables
org $80
gameSelection ds 1
frameCount ds 1
randomSeed ds 1
colorEOR ds 1
hueMask ds 1
bomberKernelBGColor ds 1
backgroundColor ds 1
loopCount ds 1
;--------------------------------------
scanline = loopCount
tempCharHolder ds 1
;--------------------------------------
tempXHolder = tempCharHolder
;--------------------------------------
temp = tempXHolder
;--------------------------------------
scoreColor = loopCount
player1ScoreColor = scoreColor
player2ScoreColor = scoreColor+1
;--------------------------------------
bomberExpressionState = tempCharHolder ; only D7 is used for this
bombColors ds H_BOMB-1
bucketsFineCoarse ds 1
madBomberFineCoarse ds 1
madBomberHorizPosition ds 1
madBomberDirection ds 1
catchingBucketNumber ds 1
bucketHorizPosition ds 1
attractMode ds 1
selectDebounce ds 1
playerNumber ds 1 ; ranges from 0 - 1
currentPlayerVariables ds 5
;--------------------------------------
remainingBuckets = currentPlayerVariables
bombGroup = remainingBuckets+1
playerScore = bombGroup+1
reservedPlayerVariables ds 5
;--------------------------------------
reservedRemainingBuckets = reservedPlayerVariables
numberBombsCaught ds 1
explodingBombNumber ds 1
gameState ds 1
bombExplodingTimer ds 1
catchingBombSoundFreq ds 1
bonusBucketSoundFreq ds 1
bombDropVelocity ds 1
bombFineCoarse ds 9
bombLSB ds 9
bucketGraphics ds H_BUCKETS*MAX_BUCKETS
thirdRowBucketGraphics = bucketGraphics
secondRowBucketGraphics = thirdRowBucketGraphics + H_BUCKETS
firstRowBucketGraphics = secondRowBucketGraphics + H_BUCKETS
digitPointer ds 12
;--------------------------------------
paddleRangeMax = digitPointer+1
bombNumber = digitPointer+2
paddleValue = digitPointer+3
bombIndexCaught = digitPointer+4
tempBombGraphic = digitPointer+5
;--------------------------------------
tempCoarseValue = tempBombGraphic
;--------------------------------------
splashGraphicLoopCount = tempCoarseValue
bombGraphicPointer = digitPointer+6
;============================================================================
; R O M - C O D E
;============================================================================
SEG Bank0
org ROM_BASE_ADDRESS
Start
;
; Set up everything so the power up state is known.
;
sei ; disable interrupts
cld ; clear decimal mode
ldx #0
txa
.clearLoop
sta VSYNC,x
txs
inx
bne .clearLoop
jmp JumpIntoConsoleSwitchCheck
MainLoop
ldx #18
.loadColorsLoop
lda GameColors,x ; read the game colors from ROM
ldy bombExplodingTimer
cpy #EXPLODING_FLASH_TIME
bcc .doExplodingFlash
ldy explodingBombNumber ; get the current exploding bomb
bne .maskColorValues ; branch if no bomb exploding
cpx #4
bcc .maskColorValues
lda randomSeed
.doExplodingFlash
eor bombExplodingTimer
.maskColorValues
eor colorEOR
and hueMask
sta bomberKernelBGColor,x
dex
bpl .loadColorsLoop
sta COLUBK ; color the Mad Bomber are background
ldx playerNumber ; get the current player number
lda scoreColor,x ; get the score color for the player
sta COLUP0 ; color the player's score
sta COLUP1
DisplayKernel SUBROUTINE
.waitTime
lda INTIM
bne .waitTime
sta WSYNC
;--------------------------------------
sta VBLANK ; 3 = @03 enable TIA
sta COLUPF ; 3 = @06 color playfield black
lda #%00110101 ; 2 set ball size to 8 clocks wide,
sta CTRLPF ; 3 = @11 reflect PF, and PF has priority
; over players (ball not used)
sta PF0 ; 3 = @14 used to black out HMOVE lines
ldy #THREE_COPIES ; 2
sty NUSIZ0 ; 3 = @19
sty NUSIZ1 ; 3 = @22
ldy #SCORE_HEIGHT-1 ; 2
sty VDELP0 ; 3 = @27 VDEL player0 and player 1 (D0 = 1)
sty VDELP1 ; 3 = @30
.scoreLoop
sty loopCount ; 3
lda (digitPointer+10),y ; 5
sta tempCharHolder ; 3
sta WSYNC ; 3
;--------------------------------------
lda (digitPointer),y ; 5
sta GRP0 ; 3 = @08
lda (digitPointer+2),y ; 5
sta GRP1 ; 3 = @16
lda (digitPointer+4),y ; 5
sta GRP0 ; 3 = @24
lda (digitPointer+8),y ; 5
tax ; 2
lda (digitPointer+6),y ; 5
ldy tempCharHolder ; 3
sta GRP1 ; 3 = @42
stx GRP0 ; 3 = @45
sty GRP1 ; 3 = @48
sta GRP0 ; 3 = @48
ldy loopCount ; 3
dey ; 2
bpl .scoreLoop ; 2<>
iny ; 2 = @57 y = 0
lda bombLSB ; 3 get the bomb LSB to store in
sta bombGraphicPointer ; 3 the graphic pointer for animation
lda bombFineCoarse ; 3 get the bomb's fine/coarse value
sta WSYNC ; 3 = @69
;--------------------------------------
sty VDELP0 ; 3 = @03 turn off the verical delay of the
sty VDELP1 ; 3 = @06 players (D1 = 0)
sty GRP0 ; 3 = @09 clear the player graphics
sty GRP1 ; 3 = @12
sta REFP0 ; 3 = @15 set reflect state
sta HMP0 ; 3 = @18 set the bomb's fine horiz position
and #$07 ; 2 mask to get the coarse horiz value
tax ; 2
.coarseMoveBomb
dex ; 2
bpl .coarseMoveBomb ; 2<>
sta RESP0 ; 3 set bomb's coarse position
sta WSYNC
;--------------------------------------
sty NUSIZ1 ; 3 = @03 single copy of player 1 (y = 0)
sty tempBombGraphic ; 3 clear the temp bomb graphic
sty NUSIZ0 ; 3 = @09 single copy of player 0 (y = 0)
lda madBomberFineCoarse ; 3 get bomber's fine/coarse value
sta HMP1 ; 3 = @15 set bomber's fine horiz position
and #$07 ; 2 mask to get the coarse horiz value
tax ; 2
lda bombDropVelocity ; 3 subtraction must start @ cycle 22
.coarseMoveMadBomber
dex ; 2
bpl .coarseMoveMadBomber ; 2<>
sta RESP1 ; 3 set bomber's coarse position
sta WSYNC
;--------------------------------------
sta HMOVE ; 3 = @03
ldx #H_MAD_BOMBER-1 ; 2
ora #H_BOMB*2 ; 2
tay ; 2
lda playerScore ; 3 get the player's score (MSB)
cmp #1 ; 2 see if the player scored >= 100,000
ror bomberExpressionState ; 5 rotate carry into D7
bmi DrawMadBomber ; 2<>
lda bombExplodingTimer ; 3
bne .colorMadBomberLoop ; 2<>
lda remainingBuckets ; 3
beq .colorMadBomberLoop ; 2<>
DrawMadBomber
lda MadBomberColors,x ; 4
eor colorEOR ; 3
and hueMask ; 3
sta WSYNC ; 3
;--------------------------------------
sta COLUP1 ; 3 = @03
lda MadBomber,x ; 4
cpx #22 ; 2 are we drawing Bomber's upper mouth
bne .checkForLowerMouth ; 2<> if not check lower mouth
lda #%01101100 ; 2 Mad Bomber frown graphic
.checkForLowerMouth
bcs .drawMadBomber ; 2<>
lda #%01101100 ; 2 Mad Bomber surprise graphic
bit bomberExpressionState ; 3
bmi .drawMadBomber ; 2<>
lda #%01010100 ; 2 Mad Bomber smile graphic
.drawMadBomber
sta GRP1 ; 3
dey ; 2
dex ; 2
cpx #21 ; 2
bcs DrawMadBomber ; 2<>
.colorMadBomberLoop
lda MadBomberColors,x ; 4
eor colorEOR ; 3
and hueMask ; 3
cpx #3 ; 2
bne .colorMadBomber ; 2<>+1
lda backgroundColor ; 3
sta WSYNC ; 3
;--------------------------------------
sta COLUBK ; 3 = @03
jmp .drawBombHeldByBomber ; 3
.colorMadBomber
sta WSYNC ; 3
;--------------------------------------
sta COLUP1 ; 3 = @03
lda MadBomber,x ; 4
sta GRP1 ; 3 = @10
.drawBombHeldByBomber
lda bombColors-1,y ; 4
sta COLUP0 ; 3 = @17
lda tempBombGraphic ; 3
sta GRP0 ; 3 = @23
dey ; 2
cpy #H_BOMB ; 2
bcs .skipDrawHeldBomb ; 2<>
lda (bombGraphicPointer),y ; 5
sta tempBombGraphic ; 3
.skipDrawHeldBomb
dex ; 2
bpl .colorMadBomberLoop ; 2<>+1
lda SWCHB ; 4 read the console switches
ldx playerNumber ; 3 get the current player number
bne .onePlayerGame ; 2<> get player 1 difficulty value
asl ; 2 shift to get difficulty in carry
.onePlayerGame
asl ; 2
lda #ONE_COPY ; 2
sta bombNumber ; 3 reset bomb number at kernel start
bcs .skipDoubleSizeBuckets ; 2<>
lda #DOUBLE_SIZE ; 2
.skipDoubleSizeBuckets
sta WSYNC ; 3
;--------------------------------------
sta NUSIZ1 ; 3 set size of player buckets
lda bombColors-1,y ; 4
sta COLUP0 ; 3 = @10
lda tempBombGraphic ; 3
sta GRP0 ; 3 = @16
lda #0 ; 2
sta GRP1 ; 3 = @21 clear the Mad Bomber graphic
sta CXCLR ; 3 = @24 clear all previous collisions
bcc .calibratePaddle ; 2<>
lda #10 ; 2
.calibratePaddle
clc ; 2
adc #108 ; 2
sta paddleRangeMax ; 3
adc #6 ; 2
sta paddleValue ; 3
lda #H_KERNEL ; 2 get the kernel height
sta scanline ; 3 store it (decremented in kernel)
dey ; 2
bmi StartBombKernel ; 2<>
LF159:
cpy #H_BOMB ; 2
bcc .drawBomb ; 2<>
sta WSYNC ; 3
;--------------------------------------
dec scanline ; 5
dey ; 2
bne LF159 ; 2<>
.drawBomb
lda (bombGraphicPointer),y ; 5
sta WSYNC ; 3
;--------------------------------------
sta GRP0 ; 3 = @03 draw the bomb graphic
lda bombColors-1,y ; 4 get the bomb colors to
sta COLUP0 ; 3 = @10 color the bomb
dec scanline ; 5 reduce the scanline count
lda INPT0,x ; 4 read the paddle controller
bmi .skipReducePaddleValue ; 2<> check if capacitor charged
dec paddleValue ; 5
.skipReducePaddleValue
dey ; 2
bpl .drawBomb ; 2<>
StartBombKernel SUBROUTINE
sta WSYNC ; 3
;--------------------------------------
inc bombNumber ; 5 increment bomb number
ldy bombNumber ; 3 load y with bomb number for index
lda bombFineCoarse,y ; 4 get the fine/coarse value for bomb
sta HMP0 ; 3 = @15 set bomb's fine motion value
sta REFP0 ; 3 = @18 set reflect state
and #$07 ; 2 mask the fine motion value
tay ; 2 move to y for coarse movement
.coarseMoveBomb
dey ; 2
bpl .coarseMoveBomb ; 2<>
sta RESP0 ; 3 set bomb's coarse position
sta WSYNC ; 3
;--------------------------------------
ldy bombNumber ; 3 load y with bomb number for index
lda bombLSB,y ; 4 get the bomb's sprite LSB
sta bombGraphicPointer ; 3 store it in graphic pointer
nop ; 2 waste 2 cycles so coarse
; subtraction happens @ cycle 22
lda bucketsFineCoarse ; 3 get bucket's fine/coarse value
sta HMP1 ; 3 = @18 set bucket's fine motion
and #$07 ; 2 mask the fine motion value
tay ; 2 move to y for coarse movement
.coarseMoveBuckets
dey ; 2
bpl .coarseMoveBuckets ; 2<>
sta RESP1 ; 3 set bucket's coarse position
sta WSYNC ; 3
;--------------------------------------
sta HMOVE ; 3 = @03
ldy #H_BOMB-1 ; 2
lda (bombGraphicPointer),y ; 5
sta GRP0 ; 3 = @13 draw the bomb graphic
lda bombColors-1,y ; 4 get the bomb colors to
sta COLUP0 ; 3 color the bomb
lda INPT0,x ; 4 read the paddle controller
bmi .skipReducePaddleValue ; 2<> check if capacitor charged
dec paddleValue ; 5 reduce paddle value if not charged
.skipReducePaddleValue
dey ; 2
sta HMCLR ; 3 = @36 clear horizontal movements
DroppingBombKernel SUBROUTINE
.drawBomb
lda bombNumber ; 3 get the current bomb number
cmp explodingBombNumber ; 3 skip the explosion random colors
bne .skipExplosionColor ; 2<> if this is not an exploding bomb
lda randomSeed ; 3 get the random number
sta bombColors-1,y ; 5 set the color of the bomb explosion
.skipExplosionColor
lda (bombGraphicPointer),y ; 5
sta WSYNC
;--------------------------------------
sta GRP0 ; 3 = @03 draw the bomb
lda bombColors-1,y ; 4 get the color for the bomb
sta COLUP0 ; 3 = @10 color the bomb
.bombKernelLoop
dec scanline ; 5
beq DrawBucketKernel ; 2<>+1
lda INPT0,x ; 4 read the paddle controller
bmi .skipReducePaddleValue ; 2<> check if capacitor charged
dec paddleValue ; 5 reduce paddle value if not charged
.skipReducePaddleValue
dey ; 2
bpl .drawBomb ; 2<>
inc bombNumber ; 5 increment bomb number
ldy bombNumber ; 3 load y with bomb number for index
lda bombLSB,y ; 4 get the bomb's sprite LSB
sta WSYNC
;--------------------------------------
nop ; 2 waste 2 cycles for coarse move
sta bombGraphicPointer ; 3 store it in graphic pointer
sty bombIndexCaught ; 3 assume bomb will be caught by bucket
lda bombFineCoarse,y ; 4 get the fine/coarse value for bomb
sta HMP0 ; 3 = @15 set bomb's fine motion value
sta REFP0 ; 3 = @18 set reflect state
and #$07 ; 2 mask the fine motion value
tay ; 2 move to y for coarse movement
.coarseMoveBomb
dey ; 2
bpl .coarseMoveBomb ; 2<>
sta RESP0 ; 3 set bomb's coarse position
sta WSYNC
;--------------------------------------
sta HMOVE ; 3
ldy #H_BOMB ; 2
dec scanline ; 5
beq JumpIntoBucketKernel ; 2<>+1
bne .bombKernelLoop ; 3 unconditional branch
DrawBucketKernel SUBROUTINE
ldx #H_BUCKETS*MAX_BUCKETS ; 2
dey ; 2
bmi .doNextBomb ; 2<>
bpl .determineBombColor ; 3
JumpIntoBucketKernel
dey ; 2
ldx #H_BUCKETS*MAX_BUCKETS-1; 2
.drawBucketKernelLoop
stx tempXHolder ; 3
ldx playerNumber ; 3 get the current player number
lda INPT0,x ; 4 read the paddle controller
bmi .resetKernelScanline ; 2<> check if capacitor charged
dec paddleValue ; 5 reduce paddle value if not charged
.resetKernelScanline
ldx tempXHolder ; 3
.determineBombColor
lda bombNumber ; 3 get the current bomb number
cmp explodingBombNumber ; 3 skip the explosion random colors
bne .skipExplosionColor ; 2<> if this is not an exploding bomb
lda BucketColors-1,x ; 4 get the bucket colors
and hueMask ; 3
sta WSYNC
;--------------------------------------
sta COLUP1 ; 3 = @03
lda.w randomSeed ; 4 get the random number
sta COLUP0 ; 3 = @10 set the color of the bomb explosion
jmp .drawBucket ; 3
.skipExplosionColor
lda BucketColors-1,x ; 4
eor colorEOR ; 3
and hueMask ; 3
sta WSYNC
;--------------------------------------
sta COLUP1 ; 3 = @03
lda bombColors-1,y ; 4
sta COLUP0 ; 3 = @10
.drawBucket
lda bucketGraphics-1,x ; 4
sta GRP1 ; 3 = @20
lda (bombGraphicPointer),y ; 5
sta GRP0 ; 3 = @28
dex ; 2
beq CopyrightKernel ; 2<>
dey ; 2
.nextBucket
bpl .drawBucketKernelLoop ; 2<>
.doNextBomb
inc bombNumber ; 5 increment bomb number
ldy bombNumber ; 3 load y with bomb number for index
bit CXPPMM ; 3 check player to player collisions
bmi .bombCaught ; 2<> branch if P0 and P1 collide
sty bombIndexCaught ; 3
.bombCaught
lda bombLSB,y ; 4 get the bomb's sprite LSB
sta bombGraphicPointer ; 3 store it in graphic pointer
lda bombFineCoarse,y ; 4 get the fine/coarse value for bomb
sta HMP0 ; 3 = @66 set bomb's fine motion value
sta REFP0 ; 3 = @69 set reflect state (wiggle wick)
and #$07 ; 2 mask the fine motion value
sta WSYNC
;--------------------------------------
tay ; 2 move to y for coarse movement
lda BucketColors-1,x ; 4
eor colorEOR ; 3
and hueMask ; 3
sta COLUP1 ; 3 = @15
lda bucketGraphics-1,x ; 4
sta GRP1 ; 3 = @22
.coarseMoveBomb_b
dey ; 2
bpl .coarseMoveBomb_b ; 2<>
sta RESP0 ; 3
lda BombColors+13,x ; 4
eor colorEOR ; 3
sta WSYNC
;--------------------------------------
sta HMOVE ; 3
dex ; 2
beq .jmpIntoCopyrightKernel; 2<>
and hueMask ; 3
sta COLUP1 ; 3 = @13
lda bucketGraphics-1,x ; 4
sta GRP1 ; 3 = @20
ldy #H_BOMB-1 ; 2
dex ; 2
bne .nextBucket ; 2<>
CopyrightKernel
sta WSYNC
;--------------------------------------
.jmpIntoCopyrightKernel
stx GRP0 ; 3 clear the player graphics (x = 0)
stx GRP1 ; 3
lda colorEOR ; 3
and hueMask ; 3
sta WSYNC
;--------------------------------------
sta.w COLUBK ; 4 = @04
eor #LOGO_COLOR ; 2
and hueMask ; 3
sta COLUP0 ; 3 = @12
sta COLUP1 ; 3 = @15
stx HMCLR ; 3 = @18 clear horizontal movements
stx REFP0 ; 3 = @21
stx REFP1 ; 3 = @24
lda #HMOVE_L1 | TWO_COPIES ; 2
sta NUSIZ0 ; 3 = @29
sta NUSIZ1 ; 3 = @32
sta HMP1 ; 3 = @35 move player 1 left 1 pixel
sta RESP0 ; 3 = @38 player 0 @ pixel 114
sta RESP1 ; 3 = @41 player 1 @ pixel 122
ldx #H_ACTIVISION_LOGO-1 ; 2
.activisionLogoLoop
sta WSYNC
;--------------------------------------
sta HMOVE ; 3
lda Copyright0,x ; 4
sta GRP0 ; 3 = @10
lda Copyright1,x ; 4
sta GRP1 ; 3 = @17
jsr Waste12Cycles ; 12
lda Copyright3,x ; 4
tay ; 2
lda Copyright2,x ; 4
sta GRP0 ; 3 = @42
sty GRP1 ; 3 = @45
sta HMCLR ; 3 = @48
dex ; 2
bpl .activisionLogoLoop ; 2<>
Overscan SUBROUTINE
lda #OVERSCAN_TIME
sta TIM64T ; set timer for overscan
ldx SWCHA ; read the paddle fire buttons
inx
beq CalculateBucketPosition ; branch if fire buttons not pressed
sty attractMode ; y = 0 from above copyright loop
CalculateBucketPosition
sec ; set carry for subtraction
lda paddleValue ; get the paddle value
sbc #5 ; subtract by 5
bpl .calcPaddleBucketPosDelta ; keep the value if not negative
tya ; set accumulator to 0
.calcPaddleBucketPosDelta
sec ; set carry for subtraction
sbc bucketHorizPosition
clc ; clear carry for rotation below
bpl .compareToPaddleRange ; branch if subtraction is positive
sec ; set carry for rotation
.compareToPaddleRange
ror ; rotate a right (carry now in D7)
cmp #PADDLE_MIN
bcc .skipAttractModeReset ; branch if less than 2
cmp #PADDLE_MAX
bcs .skipAttractModeReset ; branch if greater than 254
sty attractMode ; set to 0
.skipAttractModeReset
clc ; clear carry for addition
adc bucketHorizPosition ; 2 <= a <= 254
cmp paddleRangeMax ; if less than the maz range then
bcc .setBucketHorizontalPosition ; set bucket horizontal position
lda paddleRangeMax ; set bucket position to max paddle range
.setBucketHorizontalPosition
sta bucketHorizPosition ; save for the bucket's horiz position
jsr CalcPosX ; calculate fine/coarse value
sta bucketsFineCoarse
ldx #H_BUCKETS-1
.storeBucketGraphicsLoop
lda BucketGraphics,x
sta thirdRowBucketGraphics,x
sta secondRowBucketGraphics,x
sta firstRowBucketGraphics,x
ldy remainingBuckets
beq .clearFirstRowBucket
dey
beq .clearSecondRowBucket
dey
beq .clearThirdRowBucket
bne .nextBucketGraphicLine ; unconditional branch
.clearFirstRowBucket
sty firstRowBucketGraphics,x
.clearSecondRowBucket
sty secondRowBucketGraphics,x
.clearThirdRowBucket
sty thirdRowBucketGraphics,x
.nextBucketGraphicLine
dex
bpl .storeBucketGraphicsLoop
StoreSplashGraphics
ldy catchingBucketNumber ; get number of bucket that caught bomb
ldx WaterSplashOffset,y ; set x to it's RAM offset
lda catchingBombSoundFreq ; get the cathing bomb sound frequency
asl ; multiply the value by 2
and #%00011000 ; make sure value is less than 24 (i.e.
; 4 animations * H_SPLASH)
tay
lda #H_SPLASH-1
sta splashGraphicLoopCount
.storeBucketSplashGraphics
lda SplashAnimations,y
sta bucketGraphics+8,x
iny
inx
dec splashGraphicLoopCount
bpl .storeBucketSplashGraphics
VerticalSync SUBROUTINE
.waitTime
lda INTIM ; wait until overscan is done
bne .waitTime
ldy #%10000010
sty WSYNC ; wait for next scan line
sty VBLANK ; disable TIA and discharge paddles
sty VSYNC ; start vertical sync
sty WSYNC
sty WSYNC
sty WSYNC
sta VSYNC ; end vertical sync (D1 = 0)
inc frameCount ; increment frame count each new frame
bne ReadConsoleSwitches
inc attractMode ; increment attractMode when frameCount
; rolls over (i.e. every 256 frames)
bne ReadConsoleSwitches
sec ; set carry bit
ror attractMode ; rotate carry into D7 to enable color
; cycling
ReadConsoleSwitches
ldy #$FF ; assume color mode
lda SWCHB ; read the console switches
and #BW_MASK ; get the B/W switch value
bne .colorMode ; branch if set to color
ldy #$0F
.colorMode
tya
ldy #0
bit attractMode ; check if in attract mode (color cycling)
bpl .noColorCycling
and #%11110111
ldy attractMode
.noColorCycling
sty colorEOR
asl colorEOR
sta hueMask
lda #VBLANK_TIME
sta WSYNC
sta TIM64T ; set timer for vertical blank time
ldy #0
sty temp
lda SWCHB ; read the console switches
lsr ; RESET now in carry
bcs .skipGameReset
jsr ClearGameRAM
stx gameState ; x = #$ff
asl gameSelection ; shift the game selection left
sec
ror gameSelection ; set D7 of gameSelection high
lda #MAX_BUCKETS ; set the number of remaining buckets
sta remainingBuckets ; also ready so we'll branch to
sta reservedRemainingBuckets ; .resetSelectDebounce below :-)
.skipGameReset
lsr ; SELECT now in carry
bcs .resetSelectDebounce
lda selectDebounce ; get the select debounce delay
beq .incrementGameSelection ; if it's zero -- increase game selection
dec selectDebounce ; decrement select debounce
bpl .skipGameSelect ; unconditional branch
.incrementGameSelection
inc gameSelection
JumpIntoConsoleSwitchCheck
jsr ClearGameRAM
lda gameSelection ; get the game selection value
and #$01 ; alternate the value between 0 and 1 and
sta gameSelection ; set D7 low to show RESET not pressed
tay ; move game selection to y
iny ; increment the value so it shows as
sty playerScore+2 ; 1 and/or 2 to the user :-)
ldy #SELECT_DELAY
.resetSelectDebounce
sty selectDebounce ; reset select debounce rate
.skipGameSelect
bit gameSelection ; see if game was RESET this frame
bpl .jumpToPlayGameSounds ; if not then play the game sounds
lda remainingBuckets
bne CheckForExplodingBombs
lda frameCount
and #$7F
bne .jumpToPlayGameSounds
beq SwitchToOtherPlayer
CheckForExplodingBombs
lda bombExplodingTimer ; get the exploding bomb timer
beq DoneExplodingBombs
cmp #EXPLODING_FLASH_TIME
bcc CheckToReduceNumberOfBuckets
beq DetermineNextExplodingBomb
.setExplodingBombSprite
lda bombExplodingTimer ; get the exploding bomb timer
and #$0C
asl ; multiply by 4 (i.e. 12 * 4 =
asl ; NUM_EXPLODE_ANIM * H_BOMB = 48)
adc #<ExplodingBombs
ldx explodingBombNumber
sta bombLSB,x
dec bombExplodingTimer
.jumpToPlayGameSounds
jmp PlayGameSounds
DetermineNextExplodingBomb
ldx explodingBombNumber
lda #<Blank
sta bombLSB,x
.bombLoop
lda #STARTING_EXPLODING_TIMER
sta bombExplodingTimer
ldx #MAX_BOMBS
lda numberBombsCaught
beq .determineExplodingBombSprite
dec numberBombsCaught
.determineExplodingBombSprite
stx explodingBombNumber
lda bombLSB,x ; get the bomb's LSB
bne .setExplodingBombSprite ; set explosion pointer if not clear
dex
bpl .determineExplodingBombSprite
lda #EXPLODING_FLASH_TIME
sta bombExplodingTimer
CheckToReduceNumberOfBuckets
dec bombExplodingTimer
bne .jumpToPlayGameSounds
lda bonusBucketSoundFreq ; get the bonus bucket sound timer
bne .skipBucketReduction ; don't reduce buckets until sound done
dec remainingBuckets ; reduce number of player's buckets
.skipBucketReduction
lda reservedRemainingBuckets
beq .skipPlayerDataSwap
SwitchToOtherPlayer
lda gameSelection ; get the game selection
lsr ; shift right
bcc .skipPlayerDataSwap ; branch if not a two player game
ldx #4
.playerDataSwapLoop
ldy currentPlayerVariables,x
lda reservedPlayerVariables,x
sta currentPlayerVariables,x
sty reservedPlayerVariables,x
dex
bpl .playerDataSwapLoop
lda playerNumber ; alternate player number
eor #1
sta playerNumber
.skipPlayerDataSwap
ldx bombGroup ; get the bomb group (game level)
txa ; move it to the accumulator
beq .skipBombGroupReduction ; skip if 0 or lowest possible
dex ; reduce the bomb group
stx bombGroup
lda MaxBombsPerGroup,x ; get maximum bombs for bomb group
lsr ; when bomb group reduction happens the
clc ; player is only obligated to catch half
adc #1 ; as many bombs for the level
.skipBombGroupReduction
sta numberBombsCaught
ldx #WAIT_LEVEL_START
stx gameState
bne .jumpToPlayGameSounds
DoneExplodingBombs
bit gameState
bpl DetermineMadBomberMovement
lda SWCHA ; read the paddle buttons
ldx playerNumber ; get the current player number
beq .checkPlayerFireButton
asl ; move player 0 fire button value to D7
.checkPlayerFireButton
asl ; player fire button value in carry
lda #0
bcs .fireButtonNotPressed ; branch if fire button not pressed
sta gameState ; show that game is in progress
.fireButtonNotPressed
sta bombDropVelocity
jmp .setBombHorizPos
DetermineMadBomberMovement
lda frameCount ; get the current frame number
and #$0F ; mask the upper nybble
bne .skipMadBomberDirectionChange
jsr NextRandom ; get a new random number
bcs .skipMadBomberDirectionChange
lda madBomberDirection ; get the Mad Bomber's direction
IF MAD_BOMBER_MOVEMENT = SMOOTH
FILL_NOP 4 ; fill with 4 nops so ROM stays same size
ELSE
eor #$FF ; flip the bits so he moves in opposite
sta madBomberDirection ; direction
ENDIF
.skipMadBomberDirectionChange
bit gameState
bvs CheckPlayerCollisions
lda bombDropVelocity
cmp #DROPPING_FREQ-1
bcs CheckPlayerCollisions
cmp #2
bcc CheckPlayerCollisions
lda bombGroup ; get the current bomb group
bit madBomberDirection ; check direction Mad Bomber is moving
bpl .addWithHorizPosition
eor #$FF ; make the value positive
clc
.addWithHorizPosition
adc madBomberHorizPosition
cmp #240
bcc .moveMadBomberLeft
ldx #MAD_BOMBER_TRAVELING_RIGHT ; show bomber is traveling right
lda #XMIN
bne .setMadBomberDirection ; unconditional branch
.moveMadBomberLeft
cmp #XMAX
bcc .setMadBomberPosition
ldx #MAD_BOMBER_TRAVELING_LEFT ; show bomber is traveling left
lda #XMAX
.setMadBomberDirection
stx madBomberDirection
.setMadBomberPosition
sta madBomberHorizPosition
jsr CalcPosX
sta madBomberFineCoarse
CheckPlayerCollisions
bit CXPPMM ; read the player collision register
bpl SetFallingBombs ; branch if no collision
ldx bombIndexCaught
lda #<Blank
sta bombLSB,x ; clear the caught bomb sprite
ldy #MAX_BUCKETS-1
cpx #6
bcc .catchingBucketDetermined
beq .determineCatchingBucket
dey
.determineCatchingBucket
dey
.catchingBucketDetermined
ldx remainingBuckets
cpx #MAX_BUCKETS-1
beq .determineCatchingBucketOffset
bcs .setCatchingBucketOffset
ldy #MAX_BUCKETS-1
.determineCatchingBucketOffset
tya
bne .setCatchingBucketOffset
iny
.setCatchingBucketOffset
sty catchingBucketNumber ; set index of bucket that caught bomb
lda #CATCHING_BOMB_FREQ
sta catchingBombSoundFreq
IncrementScore
sed ; set to decimal mode
clc
lda bombGroup ; get the current bomb group
adc #1 ; increment by 1
ldx #2
ldy playerScore+1 ; save to compare for bonus bucket
.incrementScoreLoop
adc playerScore,x
sta playerScore,x
lda #0
dex
bpl .incrementScoreLoop
cld ; clear decimal mode
bcc .skipScoreMaxOut
sta remainingBuckets ; player has maxed out the game
lda #$99 ; make the score 999,999
sta playerScore
sta playerScore+1
sta playerScore+2
.skipScoreMaxOut
tya ; get the player's score MSB
eor playerScore+1 ; to see if they reached 1,000 and are
and #$F0 ; awarded a new bucket
beq SetFallingBombs
ldx remainingBuckets
inx
cpx #MAX_BUCKETS+1
bcs .initBonusBucketSoundFreq
stx remainingBuckets
.initBonusBucketSoundFreq
lda #BONUS_BUCKET_FREQ
sta bonusBucketSoundFreq
SetFallingBombs
ldx bombNumber
lda bombLSB,x
beq BombAnimation
ldx #MAX_BOMBS
.setFallingBombsLoop
lda bombLSB,x
beq .nextBomb
lda #<FallingBombs
sta bombLSB,x
.nextBomb
dex
bpl .setFallingBombsLoop
jmp .bombLoop
BombAnimation
ldx #MAX_BOMBS
.bombAnimationLoop
lda bombLSB,x ; get the LSB for the bomb sprite
beq .nextBombAnimation ; if zero then check the next sprite
dec temp
jsr NextRandom
eor frameCount
and #$03 ; 4 frames of animation
asl ; multiply the value by 16 (the height
asl ; of the bomb sprite)
asl
asl
adc #<FallingBombs ; add with starting frame animation LSB
sta bombLSB,x
.nextBombAnimation
dex
bpl .bombAnimationLoop
lda bombGroup ; get the current bomb group
lsr ; divide the value by 2
clc
adc #BOMB_DROP_RATE
adc bombDropVelocity
sta bombDropVelocity
sec
sbc #DROPPING_FREQ
bcc PlayGameSounds
sta bombDropVelocity
ldx #MAX_BOMBS-1
.dropBombLoop
lda bombFineCoarse,x
sta bombFineCoarse+1,x
lda bombLSB,x
sta bombLSB+1,x
dex
bpl .dropBombLoop
lda #<Blank
sta bombLSB
ldx bombGroup
bit gameState
bvc .skipIncrementingBombGroup
lda temp
ora catchingBombSoundFreq
bne PlayGameSounds
asl gameState
cpx #BOMB_GROUP_MAX-1
bcs .skipIncrementingBombGroup
inx ; increment bomb group for next round
stx bombGroup
.skipIncrementingBombGroup
txa
lsr
bcs LF581
lda bombLSB+1
bne PlayGameSounds
LF581:
inc numberBombsCaught ; increase the number of bombs caught
lda numberBombsCaught ; compare with the max bombs for bomb
cmp MaxBombsPerGroup,x ; group...don't reset if level not done
bcc DetermineBombHorizPos
lda #0
sta numberBombsCaught
lda #LEVEL_DONE
sta gameState ; show the level is done
DetermineBombHorizPos
lda randomSeed
and #$08
.setBombHorizPos
ora madBomberFineCoarse ; add in the bomber's fine/coarse value
sta bombFineCoarse ; set the fine/coarse position of bomb
lda #<FallingBombs
sta bombLSB ; set the Bomb sprite LSB
PlayGameSounds
jsr NextRandom ; get a new random number
and #$03 ; make sure 3 <= a <= 0
tax ; save for later
ldy #0
lda temp
beq DetermineCatchingBombSound
txa
lsr
adc #1
sta AUDV0
ldy #8
DetermineCatchingBombSound SUBROUTINE
lda catchingBombSoundFreq
beq DetermineBombExplosionSound
ldy #8
dec catchingBombSoundFreq
cmp #15
bcc .setVolume
ldy #12
sbc bombGroup
.setVolume
tax
sty AUDV0
DetermineBombExplosionSound SUBROUTINE
lda bombExplodingTimer
beq DetermineSoundFrequency
ldy #8
ldx #8
adc explodingBombNumber
cmp #EXPLODING_FLASH_TIME
bcs .setVolume
lsr
ldx #31
.setVolume
sta AUDV0
DetermineSoundFrequency SUBROUTINE
lda bonusBucketSoundFreq ; get the sound frequency for new bucket
beq .setFrequencyAndChannel ; set frequency if no new bucket rewarded
dec bonusBucketSoundFreq ; reduce frequency for next frame
tax ; x now holds new bucket frequency
lsr ; move D1 to carry
lsr
bcc .setVolume
tax ; keep shifted value for sound frequency
.setVolume
ldy #12
sty AUDV0 ; set volume for rewarded bucket
.setFrequencyAndChannel
stx AUDF0
sty AUDC0
BCD2DigitPtrs
ldy #2
.bcd2DigitLoop
tya ; move y to accumulator
asl ; multiply the value by 4 so it can
asl ; be used for the digitPointer indexes
tax
lda playerScore,y ; get the player's score
and #$F0 ; mask the lower nybble
lsr ; divide the value by 2
adc #<NumberFonts ; add in number font LSB
sta digitPointer,x ; set LSB pointer to digit
lda playerScore,y ; get the player's score
and #$0F ; mask the upper nybble
asl ; muliply the value by 8
asl
asl
adc #<NumberFonts ; add in number font LSB
sta digitPointer+2,x ; set LSB pointer to digit
lda #>NumberFonts ; set MSB pointer to digits
sta digitPointer+1,x
sta digitPointer+3,x
dey
bpl .bcd2DigitLoop
ldx #0
.suppressZeroLoop
lda digitPointer,x ; get LSB pointer to digit
eor #<NumberFonts ; end suppress loop if value not zero
bne .doneBCD2Digits
sta digitPointer,x ; set LSB to point to Space character
inx
inx
cpx #10
bcc .suppressZeroLoop
.doneBCD2Digits
jmp MainLoop
ClearGameRAM SUBROUTINE
lda #0
ldx #37
.clearLoop
sta attractMode,x
dex
bpl .clearLoop
rts
NextRandom
lsr randomSeed
rol
eor randomSeed
lsr
lda randomSeed
bcs .leaveNextRandom
ora #%01000000
sta randomSeed
.leaveNextRandom
rts
CalcPosX
ldy #-1
sec
.divideBy15
iny
sbc #15
bcs .divideBy15
sty tempCoarseValue
eor #$FF
adc #9
asl
asl
asl
asl
ora tempCoarseValue
Waste12Cycles
rts
MadBomberColors
.byte BLACK+2,BLACK+2,BRICK_RED+10,BRICK_RED+10,BRICK_RED+10,BLACK+12
.byte BLACK+2,BLACK+12,BLACK+2,BLACK+12,BLACK+2,BLACK+12,BLACK+2
.byte BLACK+12,BLACK+2,BLACK+12,BLACK+2,BLACK+12,BLACK+2,BRICK_RED+8
.byte BRICK_RED+10,BRICK_RED+10,BRICK_RED+10,BRICK_RED+10,BRICK_RED+10
.byte BRICK_RED+8,BLACK+2,BLACK+2,BLACK+2,YELLOW+4,YELLOW+2,YELLOW
GameColors
.byte BLACK+6 ; Bomber area background color
.byte GREEN+4 ; player area background color
.byte YELLOW+10 ; player1 score color
.byte RED+2 ; player2 score color
BombColors
.byte BLACK,BLACK+2,BLACK+4,BLACK+6,BLACK+6,BLACK+4,BLACK+2,BLACK
.byte BLACK+8,BLACK+8,BLACK+8,BLACK+8,RED+14,RED+14,RED+14
BucketColors
REPEAT 3
.byte YELLOW+2,YELLOW+2,YELLOW+4,YELLOW+4,YELLOW+6,YELLOW+6
.byte WATER_COLOR,YELLOW+6
;
; splash color
;
.byte BLUE+8,BLUE+8,BLUE+8,BLUE+8,BLUE+8,BLUE+8,BLUE+8,BLUE+8
REPEND
Copyright0
.byte $00 ; |........|
.byte $AD ; |X.X.XX.X|
.byte $A9 ; |X.X.X..X|
.byte $E9 ; |XXX.X..X|
.byte $A9 ; |X.X.X..X|
.byte $ED ; |XXX.XX.X|
.byte $41 ; |.X.....X|
.byte $0F ; |....XXXX|
Copyright1
.byte $00 ; |........|
.byte $50 ; |.X.X....|
.byte $58 ; |.X.XX...|
.byte $5C ; |.X.XXX..|
.byte $56 ; |.X.X.XX.|
.byte $53 ; |.X.X..XX|
.byte $11 ; |...X...X|
.byte $F0 ; |XXXX....|
Copyright2
.byte $00 ; |........|
.byte $BA ; |X.XXX.X.|
.byte $8A ; |X...X.X.|
.byte $BA ; |X.XXX.X.|
.byte $A2 ; |X.X...X.|
.byte $3A ; |..XXX.X.|
.byte $80 ; |X.......|
.byte $FE ; |XXXXXXX.|
Copyright3
.byte $00 ; |........|
.byte $E9 ; |XXX.X..X|
.byte $AB ; |X.X.X.XX|
.byte $AF ; |X.X.XXXX|
.byte $AD ; |X.X.XX.X|
.byte $E9 ; |XXX.X..X|
MadBomber
.byte $00 ; |........|
.byte $00 ; |........|
.byte $44 ; |.X...X..|
.byte $82 ; |X.....X.|
.byte $82 ; |X.....X.|
.byte $BA ; |X.XXX.X.|
.byte $D6 ; |XX.X.XX.|
.byte $BA ; |X.XXX.X.|
.byte $D6 ; |XX.X.XX.|
.byte $BA ; |X.XXX.X.|
.byte $D6 ; |XX.X.XX.|
.byte $BA ; |X.XXX.X.|
.byte $FE ; |XXXXXXX.|
.byte $FE ; |XXXXXXX.|
.byte $FE ; |XXXXXXX.|
.byte $FE ; |XXXXXXX.|
.byte $FE ; |XXXXXXX.|
.byte $7C ; |.XXXXX..|
.byte $38 ; |..XXX...|
.byte $38 ; |..XXX...|
.byte $38 ; |..XXX...|
.byte $6C ; |.XX.XX..|
.byte $54 ; |.X.X.X..|
.byte $7C ; |.XXXXX..|
.byte $6C ; |.XX.XX..|
.byte $EE ; |XXX.XXX.|
.byte $FE ; |XXXXXXX.|
.byte $D6 ; |XX.X.XX.|
.byte $7C ; |.XXXXX..|
.byte $7C ; |.XXXXX..|
.byte $7C ; |.XXXXX..|
.byte $38 ; |..XXX...|
MaxBombsPerGroup
.byte MAX_BOMBS_GROUP1-1,MAX_BOMBS_GROUP2,MAX_BOMBS_GROUP3,MAX_BOMBS_GROUP4
.byte MAX_BOMBS_GROUP5,MAX_BOMBS_GROUP6,MAX_BOMBS_GROUP7,MAX_BOMBS_GROUP8
;
; The following are never read. The bomb group maxes out at 7. It looks as if
; they had intended the bomb groups to go to 10.
;
.byte 255,255,240
align 256, 0
Blank
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
SplashAnimations
Splash0
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
Splash1
.byte $92 ; |X..X..X.|
.byte $00 ; |........|
.byte $38 ; |..XXX...|
.byte $10 ; |...X....|
.byte $82 ; |X.....X.|
.byte $28 ; |..X.X...|
.byte $00 ; |........|
.byte $00 ; |........|
Splash2
.byte $10 ; |...X....|
.byte $10 ; |...X....|
.byte $44 ; |.X...X..|
.byte $92 ; |X..X..X.|
.byte $10 ; |...X....|
.byte $00 ; |........|
.byte $44 ; |.X...X..|
.byte $00 ; |........|
Splash3
.byte $00 ; |........|
.byte $92 ; |X..X..X.|
.byte $10 ; |...X....|
.byte $00 ; |........|
.byte $10 ; |...X....|
.byte $82 ; |X.....X.|
.byte $00 ; |........|
.byte $00 ; |........|
NumberFonts
zero
.byte $3C ; |..XXXX..|
.byte $66 ; |.XX..XX.|
.byte $66 ; |.XX..XX.|
.byte $66 ; |.XX..XX.|
.byte $66 ; |.XX..XX.|
.byte $66 ; |.XX..XX.|
.byte $66 ; |.XX..XX.|
.byte $3C ; |..XXXX..|
one
.byte $3C ; |..XXXX..|
.byte $18 ; |...XX...|
.byte $18 ; |...XX...|
.byte $18 ; |...XX...|
.byte $18 ; |...XX...|
.byte $18 ; |...XX...|
.byte $38 ; |..XXX...|
.byte $18 ; |...XX...|
two
.byte $7E ; |.XXXXXX |
.byte $60 ; |.XX.....|
.byte $60 ; |.XX.....|
.byte $3C ; |..XXXX..|
.byte $06 ; |.....XX.|
.byte $06 ; |.....XX.|
.byte $46 ; |.X...XX.|
.byte $3C ; |..XXXX..|
three
.byte $3C ; |..XXXX..|
.byte $46 ; |.X...XX.|
.byte $06 ; |.....XX.|
.byte $0C ; |....XX..|
.byte $0C ; |....XX..|
.byte $06 ; |.....XX.|
.byte $46 ; |.X...XX.|
.byte $3C ; |..XXXX..|
four
.byte $0C ; |....XX..|
.byte $0C ; |....XX..|
.byte $0C ; |....XX..|
.byte $7E ; |.XXXXXX.|
.byte $4C ; |.X..XX..|
.byte $2C ; |..X.XX..|
.byte $1C ; |...XXX..|
.byte $0C ; |....XX..|
five
.byte $7C ; |.XXXXX..|
.byte $46 ; |.X...XX.|
.byte $06 ; |.....XX.|
.byte $06 ; |.....XX.|
.byte $7C ; |.XXXXX..|
.byte $60 ; |.XX.....|
.byte $60 ; |.XX.....|
.byte $7E ; |.XXXXXX.|
six
.byte $3C ; |..XXXX..|
.byte $66 ; |.XX..XX.|
.byte $66 ; |.XX..XX.|
.byte $66 ; |.XX..XX.|
.byte $7C ; |.XXXXX..|
.byte $60 ; |.XX.....|
.byte $62 ; |.XX...X.|
.byte $3C ; |..XXXX..|
seven
.byte $18 ; |...XX...|
.byte $18 ; |...XX...|
.byte $18 ; |...XX...|
.byte $18 ; |...XX...|
.byte $0C ; |....XX..|
.byte $06 ; |.....XX.|
.byte $42 ; |.X....X.|
.byte $7E ; |.XXXXXX.|
eight
.byte $3C ; |..XXXX..|
.byte $66 ; |.XX..XX.|
.byte $66 ; |.XX..XX.|
.byte $3C ; |..XXXX..|
.byte $3C ; |..XXXX..|
.byte $66 ; |.XX..XX.|
.byte $66 ; |.XX..XX.|
.byte $3C ; |..XXXX..|
nine
.byte $3C ; |..XXXX..|
.byte $46 ; |.X...XX.|
.byte $06 ; |.....XX.|
.byte $3E ; |..XXXXX.|
.byte $66 ; |.XX..XX.|
.byte $66 ; |.XX..XX.|
.byte $66 ; |.XX..XX.|
.byte $3C ; |..XXXX..|
FallingBombs
FallingBomb0
.byte $00 ; |........|
.byte $10 ; |...X....|
.byte $38 ; |..XXX...|
.byte $38 ; |..XXX...|
.byte $7C ; |.XXXXX..|
.byte $7C ; |.XXXXX..|
.byte $38 ; |..XXX...|
.byte $38 ; |..XXX...|
.byte $10 ; |...X....|
.byte $08 ; |....X...|
.byte $08 ; |....X...|
.byte $10 ; |...X....|
.byte $20 ; |..X.....|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
FallingBomb1
.byte $00 ; |........|
.byte $10 ; |...X....|
.byte $38 ; |..XXX...|
.byte $38 ; |..XXX...|
.byte $7C ; |.XXXXX..|
.byte $7C ; |.XXXXX..|
.byte $38 ; |..XXX...|
.byte $38 ; |..XXX...|
.byte $10 ; |...X....|
.byte $08 ; |....X...|
.byte $08 ; |....X...|
.byte $10 ; |...X....|
.byte $20 ; |..X.....|
.byte $20 ; |..X.....|
.byte $00 ; |........|
.byte $00 ; |........|
FallingBomb2
.byte $00 ; |........|
.byte $10 ; |...X....|
.byte $38 ; |..XXX...|
.byte $38 ; |..XXX...|
.byte $7C ; |.XXXXX..|
.byte $7C ; |.XXXXX..|
.byte $38 ; |..XXX...|
.byte $38 ; |..XXX...|
.byte $10 ; |...X....|
.byte $08 ; |....X...|
.byte $08 ; |....X...|
.byte $10 ; |...X....|
.byte $20 ; |..X.....|
.byte $20 ; |..X.....|
.byte $30 ; |..XX....|
.byte $10 ; |...X....|
FallingBomb3
.byte $00 ; |........|
.byte $10 ; |...X....|
.byte $38 ; |..XXX...|
.byte $38 ; |..XXX...|
.byte $7C ; |.XXXXX..|
.byte $7C ; |.XXXXX..|
.byte $38 ; |..XXX...|
.byte $38 ; |..XXX...|
.byte $10 ; |...X....|
.byte $08 ; |....X...|
.byte $08 ; |....X...|
.byte $10 ; |...X....|
.byte $20 ; |..X.....|
.byte $20 ; |..X.....|
.byte $60 ; |.XX.....|
.byte $20 ; |..X.....|
ExplodingBombs
ExplodingBomb0
.byte $00 ; |........|
.byte $14 ; |...X.X..|
.byte $91 ; |X..X...X|
.byte $5A ; |.X.XX.X.|
.byte $7E ; |.XXXXXX.|
.byte $3C ; |..XXXX..|
.byte $1D ; |...XXX.X|
.byte $B8 ; |X.XXX...|
.byte $3C ; |..XXXX..|
.byte $7E ; |.XXXXXX.|
.byte $59 ; |.X.XX..X|
.byte $9C ; |X..XXX..|
.byte $14 ; |...X.X..|
.byte $12 ; |...X..X.|
.byte $A0 ; |X.X.....|
.byte $04 ; |.....X..|
ExplodingBomb1
.byte $00 ; |........|
.byte $00 ; |........|
.byte $52 ; |.X.X..X.|
.byte $18 ; |...XX...|
.byte $3C ; |..XXXX..|
.byte $3C ; |..XXXX..|
.byte $1C ; |...XXX..|
.byte $38 ; |..XXX...|
.byte $7C ; |.XXXXX..|
.byte $7E ; |.XXXXXX.|
.byte $58 ; |.X.XX...|
.byte $1C ; |...XXX..|
.byte $54 ; |.X.X.X..|
.byte $00 ; |........|
.byte $02 ; |......X.|
.byte $00 ; |........|
ExplodingBomb2
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $18 ; |...XX...|
.byte $3C ; |..XXXX..|
.byte $3C ; |..XXXX..|
.byte $18 ; |...XX...|
.byte $3C ; |..XXXX..|
.byte $3C ; |..XXXX..|
.byte $18 ; |...XX...|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
WaterSplashOffset
.byte H_SPLASH*0,H_SPLASH*2,H_SPLASH*4,H_SPLASH*6
BucketGraphics
.byte $FE ; |XXXXXXX.|
.byte $AA ; |X.X.X.X.|
.byte $AA ; |X.X.X.X.|
.byte $AA ; |X.X.X.X.|
.byte $AA ; |X.X.X.X.|
.byte $AA ; |X.X.X.X.|
.byte $78 ; |.XXXX...|
.byte $7C ; |.XXXXX..|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
.byte $00 ; |........|
org ROM_BASE_ADDRESS+2048-4, 0 ; 2K ROM
.word Start ; RESET vector
.word 0 ; BRK vector