LIST OFF ; *** W O R D Z A P P E R *** ; Copyright 1982 US Games Corporation ; Designer: Henry Will IV ; ; Analyzed, labeled and commented ; by Dennis Debro ; Last Update: November 17, 2020 ; ; *** 116 BYTES OF RAM USED 12 BYTES FREE ; *** 0 BYTES OF ROM FREE ; ; ============================================================================== ; = THIS REVERSE-ENGINEERING PROJECT IS BEING SUPPLIED TO THE PUBLIC DOMAIN = ; = FOR EDUCATIONAL PURPOSES ONLY. THOUGH THE CODE WILL ASSEMBLE INTO THE = ; = EXACT GAME ROM, THE LABELS AND COMMENTS ARE THE INTERPRETATION OF MY OWN = ; = AND MAY NOT REPRESENT THE ORIGINAL VISION OF THE AUTHOR. = ; = = ; = THE ASSEMBLED CODE IS © 1982, US GAMES CORPORATION = ; = = ; ============================================================================== ; ; - PAL50 version only adjusted frame times to produce 314 scan lines ; - Colors not adjusted for PAL50 ; - ROM contains 32 "garbage" or used bytes ; - You can read Henry's notebook he kept while developing this game and others ; from the Wayback Machine...https://tinyurl.com/y6aya4k5 processor 6502 ; ; NOTE: You must compile this with vcs.h version 105 or greater. ; TIA_BASE_READ_ADDRESS = $30 ; set the read address base so this runs on ; the real VCS and compiles to the exact ; ROM image ; ; NOTE: You must compile this with vcs.h version 105 or greater. ; include "tia_constants.h" include "vcs.h" include "macro.h" ; ; Make sure we are using vcs.h version 1.05 or greater. ; IF VERSION_VCS < 105 echo "" echo "*** ERROR: vcs.h file *must* be version 1.05 or higher!" echo "*** Updates to this file, DASM, and associated tools are" echo "*** available at https://dasm-assembler.github.io/" echo "" err ENDIF ; ; Make sure we are using macro.h version 1.01 or greater. ; IF VERSION_MACRO < 101 echo "" echo "*** ERROR: macro.h file *must* be version 1.01 or higher!" echo "*** Updates to this file, DASM, and associated tools are" echo "*** available at https://dasm-assembler.github.io/" echo "" err ENDIF LIST ON ;=============================================================================== ; A S S E M B L E R - S W I T C H E S ;=============================================================================== NTSC = 0 PAL50 = 1 TRUE = 1 FALSE = 0 IFNCONST COMPILE_REGION COMPILE_REGION = NTSC ; change to compile for different regions ENDIF IF !(COMPILE_REGION = NTSC || COMPILE_REGION = PAL50) echo "" echo "*** ERROR: Invalid COMPILE_REGION value" echo "*** Valid values: NTSC = 0, PAL50 = 1" echo "" err ENDIF ;=============================================================================== ; F R A M E - T I M I N G S ;=============================================================================== VSYNC_TIME = 19 IF COMPILE_REGION = PAL50 FPS = 50 ; ~50 frames per second VBLANK_TIME = 65 OVERSCAN_TIME = 65 ELSE FPS = 60 ; ~60 frames per second VBLANK_TIME = 34 OVERSCAN_TIME = 34 ENDIF ;=============================================================================== ; C O L O R - C O N S T A N T S ;=============================================================================== BLACK = $00 WHITE = $0E YELLOW = $10 RED_ORANGE = $20 BRICK_RED = $30 RED = $40 PURPLE = $50 COBALT_BLUE = $60 ULTRAMARINE_BLUE = $70 BLUE = $80 LT_BLUE = $90 CYAN = $A0 OLIVE_GREEN = $B0 GREEN = $C0 DK_GREEN = $D0 LT_BROWN = $E0 BROWN = $F0 CHARACTER_COLORS_TIMER_AREA = GREEN + 10 CHARACTER_COLORS_SCROLL_AREA = WHITE CHARACTER_COLORS_WORD_AREA = LT_BROWN + 10 ;=============================================================================== ; U S E R - C O N S T A N T S ;=============================================================================== ROM_BASE = $F000 H_FONT = 13 H_WORD_ZAPPER = 7 W_WORD_ZAPPER = 8 * 2 ; DOUBLE_SIZE H_OBSTACLE = 6 H_MOUNTAINS = 10 H_KERNEL = 190 ; ; Frame horizontal constants ; XMIN = 8 XMAX = 148 ; ; Message Area horizontal constants ; HORIZ_POS_TIMER_AREA = 37 HORIZ_POS_WORD_AREA = 36 INIT_HORIZ_POS_SCROLL_AREA = 45 ; ; Word Zapper horizontal constants ; XMIN_WORD_ZAPPER = XMIN + 2 XMAX_WORD_ZAPPER = XMAX - 13 WORD_ZAPPER_LANDING_HORIZ_POS = XMIN_WORD_ZAPPER + 27 ; ; Word Zapper vertical constants ; YMAX_WORD_ZAPPER = 136 YMIN_WORD_ZAPPER = 57 WORD_ZAPPER_LANDING_VERT_POS = YMIN_WORD_ZAPPER KERNEL_SECTIONS = 4 MISSILE_SPEED_VALUE = 4 MAX_GAME_SELECTION = 24 INIT_GAME_TIMER_VALUE = $99 ; BCD INIT_LETTER_LASER_TIME = 30 OBSTACLE_ANIMATIONS = 4 INIT_SHOTS_FOR_FREEBIE = 5 INIT_SCROLLER_ALPHABET_SCRAMBLE_TIME = 5 ; ; Game Round constants ; MAX_ROUNDS = 2 GAME_ROUNDS_DONE = 9 ; ; Game Selection masks ; METEOR_DENSITY_MASK = %00000001 METEOR_SPEED_MASK = %00000010 ; ; Obstacle Spawn Times ; SPAWN_TIME_ZONKER = 90 SPAWN_TIME_SCROLLER = 180 SPAWN_TIME_DOOMSDAY = 240 ; ; Game State values ; GS_OBSTACLE_ENTRY_MARCH = 1 GS_WORD_ZAPPER_ENTRANCE = 3 GS_SET_GAME_SELECTION_LITERALS = 5 GS_START_NEW_GAME = 6 GS_NEW_ROUND = 7 GS_GAME_IN_PROGRESS = 10 GS_WORD_ZAPPER_LANDING = 17 GS_DISPLAY_SCORE_RANKING = 20 GS_SET_TO_DISPLAY_SCORE_RANKING = 22 ; ; Sound Index Values ; WORD_ZAPPER_ENTRANCE_AUDIO_IDX = 0 LAUNCH_LETTER_LASER_AUDIO_IDX = 4 LAUNCH_MISSILE_AUDIO_IDX = 8 COMPLETED_WORD_AUDIO_IDX = 12 EXPLOSION_AUDIO_IDX = 16 ZONKER_COLLISION_AUDIO_IDX = 20 SCROLLER_COLLISION_AUDIO_IDX = 24 TIMER_EXPIRED_AUDIO_IDX = 28 GAME_WON_AUDIO_IDX = 32 BONKER_COLLISION_AUDIO_IDX = 36 OBSTACLE_ENTRANCE_AUDIO_IDX = 40 DOOMSDAY_SPAWN_AUDIO_IDX = 40 STARTING_ROUND_AUDIO_IDX = 44 START_NEW_GAME_AUDIO_IDX = 48 INCREMENT_GAME_SELECTION_AUDIO_IDX = 52 WORD_ZAPPER_LANDED_AUDIO_IDX = 56 SHOT_TARGET_LETTER_AUDIO_IDX = 60 ;=============================================================================== ; M A C R O S ;=============================================================================== MAC CHAR_SET_OFFSET .byte <[({1} / 2) + 42] ENDM MAC COMPRESS_SIX_LETTER_WORD .byte <[({6} - CommonEnglishLetters) << 4] | ({5} - CommonEnglishLetters) .byte <[({4} - CommonEnglishLetters) << 4] | ({3} - CommonEnglishLetters) .byte <[({2} - CommonEnglishLetters) << 4] | ({1} - CommonEnglishLetters) ENDM MAC COMPRESS_FOUR_LETTER_WORD .byte <[({4} - CommonEnglishLetters) << 4] | ({3} - CommonEnglishLetters) .byte <[({2} - CommonEnglishLetters) << 4] | ({1} - CommonEnglishLetters) ENDM MAC COMPRESS_FIVE_LETTER_WORD .byte <({5} - CommonEnglishLetters) .byte <[({4} - CommonEnglishLetters) << 4] | ({3} - CommonEnglishLetters) .byte <[({2} - CommonEnglishLetters) << 4] | ({1} - CommonEnglishLetters) ENDM MAC BYTE_STRING CHAR_SET_OFFSET {1} CHAR_SET_OFFSET {2} CHAR_SET_OFFSET {3} CHAR_SET_OFFSET {4} CHAR_SET_OFFSET {5} CHAR_SET_OFFSET {6} ENDM ;=============================================================================== ; Z P - V A R I A B L E S ;=============================================================================== SEG.U variables .org $80 characterGraphicPtrs ds 12 ;-------------------------------------- tmpWordZapperGraphicIdx = characterGraphicPtrs ;-------------------------------------- tmpObstacleVertPos = tmpWordZapperGraphicIdx + 1 ;-------------------------------------- obstacleGraphicPtrs = tmpObstacleVertPos + 1 ;-------------------------------------- obstacleColorPtrs = obstacleGraphicPtrs + 2 ;-------------------------------------- tmpEndKernelZone = obstacleColorPtrs + 2 tmpFourthCharacter ds 1 ;-------------------------------------- tmpKernelSection = tmpFourthCharacter tmpFifthCharacter ds 1 ;-------------------------------------- tmpObstacleGraphicIdx = tmpFifthCharacter ;-------------------------------------- tmpRamDataPointerIdx ds 1 ;-------------------------------------- tmpActionButtonValues = tmpRamDataPointerIdx ;-------------------------------------- tmpObstacleColorValue = tmpActionButtonValues zpUnused_00 ds 1 messageAreaDataValues ds 19 ;-------------------------------------- timerAreaDataValues = messageAreaDataValues scrollAreaDataValues = timerAreaDataValues + 6 wordAreaDataValues = scrollAreaDataValues + 6 tmpMessageAreaHorizPos ds 1 ;-------------------------------------- tmpWordCountMulti2 = tmpMessageAreaHorizPos ;-------------------------------------- tmpLetterLaserActiveTimer = tmpWordCountMulti2 ;-------------------------------------- tmpLetterIndex = tmpLetterLaserActiveTimer ;-------------------------------------- tmpEnglishWordOffset = tmpLetterIndex randomMod16 ds 1 ramDataPointer ds 2 previousJoystickValues ds 1 joystickDebounceValues ds 1 ; never referenced scrollAreaHorizPos ds 1 gameScrollingSpeed ds 1 selectedScrollSpeedValue ds 1 scrollerAlphabetScrambleTimer ds 1 wordZapperGraphicPtrs ds 2 actionButtonValues ds 1 wordZapperColorPtrs ds 2 wordZapperAnimationIdx ds 1 obstacleAnimationOffset ds 1 gameState ds 1 wordZapperHorizPos ds 1 wordZapperVertPos ds 1 random ds 3 wordZapperMissileHorizPos ds 1 wordZapperMissileVertPos ds 1 wordZapperColorValue ds 1 wordZapperGraphicValue ds 1 obstacleHorizPos ds 4 obstacleVertPos ds 4 obstacleGraphicLSBValues ds 4 obstacleVelocityValues ds 4 frameSecondsCount ds 1 currentGameTimer ds 1 ;-------------------------------------- tmpSelectDebounceRate = currentGameTimer targetLetters ds 7 letterLaserActiveTimer ds 1 targetLetterIndex ds 1 letterLaserLetterIndex ds 1 gameIdleTimer ds 1 gameSelection ds 1 currentRound ds 1 consoleSwitchDebounceValues ds 1 playerGamerTimerValues ds 2 ;-------------------------------------- player1GameTimerValue = playerGamerTimerValues player2GameTimerValue = player1GameTimerValue + 1 shotTallyForFreebie ds 1 activePlayerNumber ds 1 playerCorrectWordCount ds 2 ;-------------------------------------- player1CorrectWordCount = playerCorrectWordCount player2CorrectWordCount = player1CorrectWordCount + 1 tvTypeSwitchValue ds 1 obstacleSpawningTimer ds 1 destroyedWordZapperGraphicLSB ds 1 zpUnused_01 ds 1 audioChannelIndex ds 1 audioFrequencyAdjustmentValues ds 2 ;-------------------------------------- leftChannelFreqAdjustment = audioFrequencyAdjustmentValues rightChannelFreqAdjustment = leftChannelFreqAdjustment + 1 audioFrequencyValues ds 2 ;-------------------------------------- leftChannelFrequencyValue = audioFrequencyValues rightChannelFrequencyValue = leftChannelFrequencyValue + 1 audioDurationValues ds 2 ;-------------------------------------- leftChannelAudioDuration = audioDurationValues rightChannelAudioDuration = leftChannelAudioDuration + 1 initAudioVolumeDurationValues ds 2 ;-------------------------------------- leftChannelInitVolumeDuration = initAudioVolumeDurationValues rightChannelInitVolumeDuration = leftChannelInitVolumeDuration + 1 audioVolumeDurationValues ds 2 ;-------------------------------------- leftChannelVolumeDuration = audioVolumeDurationValues rightChannelVolumeDuration = leftChannelVolumeDuration + 1 audioVolumeValues ds 2 ;-------------------------------------- leftChannelVolumeValue = audioVolumeValues rightChannelVolumeValue = leftChannelVolumeValue + 1 frameCount ds 1 echo "***",(* - $80 - 2)d, "BYTES OF RAM USED", ($100 - * + 2)d, "BYTES FREE" ;=============================================================================== ; R O M - C O D E ;=============================================================================== SEG Bank0 .org ROM_BASE .byte "COPYRIGHT 1982 US GAMES CORP." Start ; ; Set up everything so the power up state is known. ; cld ; clear decimal mode ldx #$FF txs ; set stack to the beginning lda #0 .clearLoop sta VSYNC,x dex bne .clearLoop ldy #START_NEW_GAME_AUDIO_IDX jsr SetGameAudioValues ; set audio values for starting new game ldx #17 .initGameTitleMessage lda GameTitleLiterals,x ; get game title literal values sta messageAreaDataValues,x ; set message area character values dex bpl .initGameTitleMessage lda #HORIZ_POS_TIMER_AREA sta scrollAreaHorizPos ; set horizontal position for scroll area dec wordZapperHorizPos dec wordZapperVertPos dec random dec random + 1 dec random + 2 dec gameIdleTimer ; init game idle timer to 255 lda #3 sta actionButtonValues ; set to disable game start lda #Blank sta wordZapperGraphicPtrs + 1 lda #2 sta currentGameTimer lda #ULTRAMARINE_BLUE + 2 sta COLUBK VerticalBlank sta WSYNC ; wait for next scan line sta VSYNC lda #VBLANK_TIME sta TIM64T ; set timer for vertical blank time rol random + 2 rol random rol random + 1 ror ror ror eor random + 1 asl asl sta random + 2 lda INPT4 ; read left player action button value and #$80 beq .resetGameIdleTimerValue ; branch if action button pressed lda INPT5 ; read right player action button value and #$80 ; branch if action button pressed beq .resetGameIdleTimerValue lda SWCHA ; read joystick values eor #$FF ; flip joystick values bne .resetGameIdleTimerValue ; branch if joystick moved lda SWCHB ; read console switches eor #$FF ; flip console switch bits and #SELECT_MASK | RESET_MASK beq .checkForGameIdleTimeout ; branch if neither SELECT or RESET pressed .resetGameIdleTimerValue inc random ; increment current random value lda #255 sta gameIdleTimer ; set game idle timer value .checkForGameIdleTimeout lda gameIdleTimer ; get game idle timer value bne SetWordZapperGraphicValues jmp VerticalBlank ; perform vertical blanking if timer expired SetWordZapperGraphicValues lda destroyedWordZapperGraphicLSB; get destroyed Word Zapper graphic LSB bne .animateWordZapperExplosion ; branch if performing Word Zapper explosion ldx wordZapperAnimationIdx ; get Word Zapper animation index lda WordZapperAnimationSprites,x ; get LSB value for Word Zapper graphic sta wordZapperGraphicPtrs ; set Word Zapper graphic pointer LSB value lda WordZapperAnimationSprites + 1,x;get MSB value for Word Zapper graphic sta wordZapperGraphicPtrs + 1 ; set Word Zapper graphic pointer MSB value lda WordZapperAnimationColors,x ; get LSB value for Word Zapper colors sta wordZapperColorPtrs ; set Word Zapper color pointer LSB value lda WordZapperAnimationColors + 1,x;get MSB value for Word Zapper colors sta wordZapperColorPtrs + 1 ; set Word Zapper color pointer MSB value jmp SetupMessageAndTimerAreasForDisplay .animateWordZapperExplosion cmp #<[DestroyedObstacle_03 + 32] beq .doneWordZapperExplosionRoutine cmp #1 beq SetupMessageAndTimerAreasForDisplay;branch if not showing Word Zapper sta wordZapperGraphicPtrs ; set exploding Word Zapper graphic LSB eor #$80 sta wordZapperColorPtrs ; set exploding Word Zapper color LSB ldx #>DestroyedObstacleColor_00 stx wordZapperGraphicPtrs + 1 stx wordZapperColorPtrs + 1 tax ; move explosion color LSB to x register lda frameSecondsCount ; get frame seconds count and #3 bne SetupMessageAndTimerAreasForDisplay;branch if not time to animate txa ; restore explosion color LSB to accumulator clc adc #160 sta destroyedWordZapperGraphicLSB bne SetupMessageAndTimerAreasForDisplay .doneWordZapperExplosionRoutine ldx #0 stx currentGameTimer ; reset current game timer inx ; x = 1 stx destroyedWordZapperGraphicLSB; set to not show Word Zapper lda #Blank sta wordZapperGraphicPtrs + 1 SetupMessageAndTimerAreasForDisplay lda #HORIZ_POS_TIMER_AREA jsr PositionObjectsForMessageArea; position sprites for timer area lda #THREE_MED_COPIES sta NUSIZ0 sta NUSIZ1 lda #ObstacleSprites ; 2 sta obstacleGraphicPtrs + 1; 3 set obstacle graphic pointer MSB value lda #>ObstacleColors ; 2 sta obstacleColorPtrs + 1 ; 3 set obstacle color pointer MSB value dex ; 2 decrement scan line count sta WSYNC ;-------------------------------------- sta HMCLR ; 3 dex ; 2 decrement scan line count jmp BeginKernelSectionKernel;3 .doneGameKernel jmp DrawMountainsKernel ; 3 BeginKernelSectionKernel lda #KERNEL_SECTIONS ; 2 sta tmpKernelSection ; 3 .nextKernelSection dec tmpKernelSection ; 5 bmi .doneGameKernel ; 2³ dex ; 2 decrement scan line count cpx wordZapperMissileVertPos;3 compare missile vertical position php ; 3 push compare to stack cpx wordZapperVertPos ; 3 compare Word Zapper vertical position bcs PositionObstacleHorizontally;2³ branch if not time to draw Word Zapper ldy tmpWordZapperGraphicIdx; 3 get Word Zapper graphic index value lda (wordZapperColorPtrs),y; 5 get Word Zapper color value sta wordZapperColorValue ; 3 lda (wordZapperGraphicPtrs),y;5 get Word Zapper graphic data beq .setWordZapperGraphicValue;2³ iny ; 2 increment Word Zapper graphic index .setWordZapperGraphicValue sta wordZapperGraphicValue ; 3 sty tmpWordZapperGraphicIdx; 3 PositionObstacleHorizontally ldy tmpKernelSection ; 3 lda obstacleHorizPos,y ; 4 get obstacle horizontal position sta WSYNC ;-------------------------------------- sec ; 2 .coarsePositionObstacle sbc #15 ; 2 divide position by 15 bcs .coarsePositionObstacle; 2³ eor #15 ; 2 4-bit 1's complement for fine motion asl ; 2 shift remainder to upper nybbles asl ; 2 asl ; 2 asl ; 2 adc #(8 + 1) << 4 ; 2 increment by 8 for full range SLEEP 2 ; 2 sta RESP1 ; 3 set coarse position value sta WSYNC ;-------------------------------------- sta HMP1 ; 3 = @03 lda wordZapperGraphicValue ; 3 sta GRP0 ; 3 = @09 lda wordZapperColorValue ; 3 sta COLUP0 ; 3 = @15 pla ; 4 pull status to enable/disable missile sta ENAM0 ; 3 = @22 lda obstacleGraphicLSBValues,y;4 get obstacle graphic LSB value cmp #$80 ; 2 bcs .setObstacleGraphicLSBValue;2³ branch if explosion sprite clc ; 2 adc obstacleAnimationOffset; 3 increment for obstacle animation .setObstacleGraphicLSBValue sta obstacleGraphicPtrs ; 3 get obstacle graphic pointer LSB value eor #$80 ; 2 sta obstacleColorPtrs ; 3 set obstacle color pointer LSB value lda KernelZoneValues,y ; 4 sta tmpEndKernelZone ; 3 set end of kernel zone value sta WSYNC ;-------------------------------------- sta HMOVE ; 3 dex ; 2 decrement scan line count dex ; 2 decrement scan line count lda obstacleVertPos,y ; 4 sta tmpObstacleVertPos ; 3 lda #0 ; 2 sta tmpObstacleGraphicIdx ; 3 bpl .checkToDrawWordZapperMissile;3 unconditional branch .drawKernelSection sta WSYNC ;-------------------------------------- .nextKernelSectionScanLine dex ; 2 decrement scan line count cpx tmpEndKernelZone ; 3 bcc .nextKernelSection ; 2³ txa ; 2 move scan line to accumulator lsr ; 2 shift D0 to carry bcc .checkToDrawObstacle ; 2³ + 1 branch on an even scan line .checkToDrawWordZapperMissile cpx wordZapperMissileVertPos;3 compare missile vertical position php ; 3 push status to stack pla ; 4 pull status to enable/disable missile sta ENAM0 ; 3 cpx wordZapperVertPos ; 3 compare Word Zapper vertical position bcs .drawKernelSection ; 2³ + 1 branch if not time to draw Word Zapper ldy tmpWordZapperGraphicIdx; 3 get Word Zapper graphic index value lda (wordZapperColorPtrs),y; 5 get Word Zapper color value sta wordZapperColorValue ; 3 lda (wordZapperGraphicPtrs),y;5 get Word Zapper graphic data beq .setWordZapperGraphicIndex;2³ branch if done drawing Word Zapper iny ; 2 increment Word Zapper graphic index .setWordZapperGraphicIndex sty tmpWordZapperGraphicIdx; 3 sta WSYNC ;-------------------------------------- sta GRP0 ; 3 = @03 lda wordZapperColorValue ; 3 sta COLUP0 ; 3 = @09 jmp .nextKernelSectionScanLine;3 .byte $B1 ; unused byte .checkToDrawObstacle cpx tmpObstacleVertPos ; 3 compare obstacle vertical position bcs .skipObstacleDraw ; 2³ branch if not time to draw obstacle ldy tmpObstacleGraphicIdx ; 3 get obstacle graphic index value lda (obstacleColorPtrs),y ; 5 get obstacle color value sta tmpObstacleColorValue ; 3 lda (obstacleGraphicPtrs),y; 5 get obstacle graphic data beq .setObstacleGraphicIndex;2³ branch if done drawing obstacle iny ; 2 increment obstacle graphic index .setObstacleGraphicIndex sty tmpObstacleGraphicIdx ; 3 sta WSYNC ;-------------------------------------- sta GRP1 ; 3 = @03 lda tmpObstacleColorValue ; 3 sta COLUP1 ; 3 = @09 dex ; 2 decrement scan line count jmp .checkToDrawWordZapperMissile;3 .skipObstacleDraw sta WSYNC ;-------------------------------------- dex ; 2 decrement scan line count jmp .checkToDrawWordZapperMissile;3 .byte $85 ; unused byte DrawMountainsKernel ldy #(H_MOUNTAINS * 6) - 1 ; 2 .drawMountainsKernel lda #<~(PF_SCORE | PF_REFLECT);2 sta WSYNC ;-------------------------------------- sta CTRLPF ; 3 = @03 set playfield to PF_NO_REFLECT dex ; 2 decrement scan line count lda MountainGraphics,y ; 4 sta PF0 ; 3 = @12 dey ; 2 lda MountainGraphics,y ; 4 sta PF1 ; 3 = @21 dey ; 2 lda MountainGraphics,y ; 4 sta PF2 ; 3 = @30 dey ; 2 lda MountainGraphics,y ; 4 sta PF0 ; 3 = @39 dey ; 2 lda MountainGraphics,y ; 4 sta PF1 ; 3 = @48 dey ; 2 lda MountainGraphics,y ; 4 sta PF2 ; 3 = @57 dey ; 2 bpl .drawMountainsKernel ; 2³ sta WSYNC ;-------------------------------------- dex ; 2 decrement scan line count ldy #136 + (MSBL_SIZE8 | PF_REFLECT);2 sty CTRLPF ; 3 = @07 lda #THREE_MED_COPIES ; 2 sta NUSIZ0 ; 3 = @12 sta NUSIZ1 ; 3 = @15 lda #HORIZ_POS_WORD_AREA ; 2 jsr PositionObjectsForMessageArea;6 ;-------------------------------------- lda #NO_REFLECT ; 2 sta REFP0 ; 3 = @14 lda #> 5 beq .setBumpedWordZapperAudioIndex;branch to play Bonker collision sounds lda #ZONKER_COLLISION_AUDIO_IDX ; set to play Zonker collision sounds .setBumpedWordZapperAudioIndex tay ; move audio index to y register jsr SetGameAudioValues ; set audio values for collision jmp .decrementLetterLaserTimer PlayerCollidedWithDoomsday ldy #EXPLOSION_AUDIO_IDX jsr SetGameAudioValues ; set audio values for explosion jsr SetGameAudioValues lda #> 5 rts BOUNDARY 0 Sprite_D .byte $FE ; |XXXXXXX.| .byte $FE ; |XXXXXXX.| .byte $FF ; |XXXXXXXX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $FF ; |XXXXXXXX| .byte $FE ; |XXXXXXX.| .byte $FE ; |XXXXXXX.| Sprite_W .byte $7E ; |.XXXXXX.| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $DB ; |XX.XX.XX| .byte $DB ; |XX.XX.XX| .byte $DB ; |XX.XX.XX| .byte $DB ; |XX.XX.XX| .byte $DB ; |XX.XX.XX| .byte $DB ; |XX.XX.XX| .byte $DB ; |XX.XX.XX| ; ; last 3 bytes shared with table below ; Sprite_M .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $DB ; |XX.XX.XX| .byte $DB ; |XX.XX.XX| .byte $DB ; |XX.XX.XX| .byte $DB ; |XX.XX.XX| .byte $DB ; |XX.XX.XX| .byte $DB ; |XX.XX.XX| .byte $DB ; |XX.XX.XX| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| ; ; last byte shared with table below ; Sprite_U .byte $7E ; |.XXXXXX.| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| ; ; last 5 bytes shared with table below ; Sprite_H .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $C3 ; |XX....XX| ; ; last 4 bytes shared with table below ; Sprite_A .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| ; ; last byte shared with table below ; Sprite_O .byte $7E ; |.XXXXXX.| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| ; ; last byte shared with table below ; Sprite_G .byte $7E ; |.XXXXXX.| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $CF ; |XX..XXXX| .byte $CF ; |XX..XXXX| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| ; ; last byte shared with table below ; Sprite_C .byte $7F ; |.XXXXXXX| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $7F ; |.XXXXXXX| QuestionMarkCharacter .byte $30 ; |..XX....| .byte $30 ; |..XX....| .byte $00 ; |........| .byte $30 ; |..XX....| .byte $30 ; |..XX....| .byte $3E ; |..XXXXX.| .byte $3F ; |..XXXXXX| .byte $1F ; |...XXXXX| .byte $03 ; |......XX| .byte $03 ; |......XX| .byte $7F ; |.XXXXXXX| .byte $7F ; |.XXXXXXX| ; ; last byte shared with table below ; Sprite_I .byte $7E ; |.XXXXXX.| .byte $7E ; |.XXXXXX.| .byte $7E ; |.XXXXXX.| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $7E ; |.XXXXXX.| .byte $7E ; |.XXXXXX.| ; ; last byte shared with table below ; Sprite_J .byte $7E ; |.XXXXXX.| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $03 ; |......XX| .byte $03 ; |......XX| .byte $03 ; |......XX| .byte $03 ; |......XX| .byte $03 ; |......XX| .byte $03 ; |......XX| .byte $03 ; |......XX| .byte $03 ; |......XX| Sprite_N .byte $C7 ; |XX...XXX| .byte $C7 ; |XX...XXX| .byte $C7 ; |XX...XXX| .byte $CF ; |XX..XXXX| .byte $CF ; |XX..XXXX| .byte $DF ; |XX.XXXXX| .byte $DF ; |XX.XXXXX| .byte $DB ; |XX.XX.XX| .byte $FB ; |XXXXX.XX| .byte $F3 ; |XXXX..XX| .byte $F3 ; |XXXX..XX| .byte $E3 ; |XXX...XX| .byte $E3 ; |XXX...XX| Sprite_Q .byte $79 ; |.XXXX..X| .byte $FB ; |XXXXX.XX| .byte $F6 ; |XXXX.XX.| .byte $CC ; |XX..XX..| .byte $DA ; |XX.XX.X.| .byte $C6 ; |XX...XX.| .byte $C6 ; |XX...XX.| .byte $C6 ; |XX...XX.| .byte $C6 ; |XX...XX.| .byte $C6 ; |XX...XX.| .byte $FE ; |XXXXXXX.| .byte $FE ; |XXXXXXX.| .byte $7C ; |.XXXXX..| Sprite_T .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| ; ; last 3 bytes shared with table below ; Sprite_L .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $C0 ; |XX......| ; ; last 5 bytes shared with table below ; Sprite_F .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $FC ; |XXXXXX..| .byte $FC ; |XXXXXX..| .byte $FC ; |XXXXXX..| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| ; ; last byte shared with table below ; Sprite_E .byte $7F ; |.XXXXXXX| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $FC ; |XXXXXX..| .byte $FC ; |XXXXXX..| .byte $FC ; |XXXXXX..| .byte $C0 ; |XX......| .byte $C0 ; |XX......| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $7F ; |.XXXXXXX| Sprite_V .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $3C ; |..XXXX..| .byte $3C ; |..XXXX..| .byte $7E ; |.XXXXXX.| .byte $66 ; |.XX..XX.| .byte $E7 ; |XXX..XXX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| Sprite_1 .byte $7E ; |.XXXXXX.| .byte $7E ; |.XXXXXX.| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $78 ; |.XXXX...| .byte $38 ; |..XXX...| ; ; last byte shared with table below ; Sprite_7 .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $08 ; |....X...| .byte $0C ; |....XX..| .byte $04 ; |.....X..| .byte $06 ; |.....XX.| .byte $02 ; |......X.| .byte $43 ; |.X....XX| .byte $7F ; |.XXXXXXX| .byte $7F ; |.XXXXXXX| DetermineCollisionObstacle lda obstacleGraphicLSBValues,x ; get obstacle graphic LSB value rol ; shift D6 and D5 to D1 and D0 rol rol rol and #3 jmp .continueDetermineCollisionObstacle BOUNDARY 0 Sprite_9 .byte $60 ; |.XX.....| .byte $70 ; |.XXX....| .byte $18 ; |...XX...| .byte $0C ; |....XX..| .byte $06 ; |.....XX.| .byte $3E ; |..XXXXX.| .byte $7F ; |.XXXXXXX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $7E ; |.XXXXXX.| ; ; last byte shared with table below ; Sprite_0 .byte $3C ; |..XXXX..| .byte $7E ; |.XXXXXX.| .byte $E7 ; |XXX..XXX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $E7 ; |XXX..XXX| .byte $7E ; |.XXXXXX.| ; ; last byte shared with table below ; Sprite_8 .byte $3C ; |..XXXX..| .byte $7E ; |.XXXXXX.| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $7E ; |.XXXXXX.| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $7E ; |.XXXXXX.| ; ; last byte shared with table below ; Sprite_3 .byte $3C ; |..XXXX..| .byte $7E ; |.XXXXXX.| .byte $E7 ; |XXX..XXX| .byte $C3 ; |XX....XX| .byte $03 ; |......XX| .byte $03 ; |......XX| .byte $1E ; |...XXXX.| .byte $03 ; |......XX| .byte $03 ; |......XX| .byte $C3 ; |XX....XX| .byte $E7 ; |XXX..XXX| .byte $7E ; |.XXXXXX.| ; ; last byte shared with table below ; Sprite_5 .byte $3C ; |..XXXX..| .byte $7E ; |.XXXXXX.| .byte $E7 ; |XXX..XXX| .byte $C3 ; |XX....XX| .byte $03 ; |......XX| .byte $03 ; |......XX| .byte $03 ; |......XX| .byte $FE ; |XXXXXXX.| .byte $FC ; |XXXXXX..| .byte $C0 ; |XX......| .byte $C0 ; |XX......| ; ; last 2 bytes shared with table below ; Sprite_2 .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $C0 ; |XX......| .byte $E0 ; |XXX.....| .byte $70 ; |.XXX....| .byte $3C ; |..XXXX..| .byte $1E ; |...XXXX.| .byte $07 ; |.....XXX| .byte $03 ; |......XX| .byte $C3 ; |XX....XX| .byte $E7 ; |XXX..XXX| .byte $7E ; |.XXXXXX.| ; ; last byte shared with table below ; Sprite_6 .byte $3C ; |..XXXX..| .byte $7E ; |.XXXXXX.| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $C3 ; |XX....XX| .byte $FE ; |XXXXXXX.| .byte $7C ; |.XXXXX..| .byte $60 ; |.XX.....| .byte $30 ; |..XX....| .byte $18 ; |...XX...| .byte $0E ; |....XXX.| ; ; last byte shared with table below ; Sprite_4 .byte $06 ; |.....XX.| .byte $06 ; |.....XX.| .byte $06 ; |.....XX.| .byte $06 ; |.....XX.| .byte $FF ; |XXXXXXXX| .byte $FF ; |XXXXXXXX| .byte $C6 ; |XX...XX.| .byte $C6 ; |XX...XX.| .byte $66 ; |.XX..XX.| .byte $36 ; |..XX.XX.| .byte $1E ; |...XXXX.| .byte $0E ; |....XXX.| .byte $06 ; |.....XX.| Blank .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| PlayGameAudioSounds ldx #1 .playGameAudioSounds lda audioDurationValues,x ; get audio duration value bne .determineAudioVolumeAndFrequency sta AUDC0,x ; set channel audio tone beq .nextAudioChannel ; unconditional branch .determineAudioVolumeAndFrequency dec audioDurationValues,x ; decrement audio duration value dec audioVolumeDurationValues,x ; decrement audio volume duration value bne .setAudioVolumeAndFrequency dec audioVolumeValues,x ; decrement volume value lda initAudioVolumeDurationValues,x sta audioVolumeDurationValues,x ; reseed audio volume duration .setAudioVolumeAndFrequency lda audioVolumeValues,x ; get channel volume value sta AUDV0,x ; set sound volume lda audioFrequencyValues,x ; get channel audio frequency value clc adc audioFrequencyAdjustmentValues,x;increment by frequency adjustment value sta audioFrequencyValues,x ; set channel audio frequency value sta AUDF0,x .nextAudioChannel dex bpl .playGameAudioSounds rts AudioValues ; ; Each audio value configuration uses 4 bytes arranged as... ; |------------|-----------|----------|--------|----------| ; | Frequency | Audio | Audio | | Volume | ; | Adjustment | Frequency | Duration | Tone | Duration | ; |------------|-----------|----------|--------|----------| .byte 253, 1, 159, 10 << 4 | 1 .byte 8, 0, 64, 5 << 4 | 1 .byte 1, 0, 31, 0 << 4 | 4 .byte 228, 255, 111, 1 << 4 | 4 .byte 254, 20, 79, 5 << 4 | 3 .byte 252, 255, 7, 3 << 4 | 4 .byte 252, 253, 5, 3 << 4 | 12 .byte 4, 20, 66, 0 << 4 | 12 .byte 0, 3, 255, 1 << 4 | 12 .byte 0, 1, 15, 1 << 4 | 1 .byte 0, 31, 144, 0 << 4 | 3 .byte 255, 0, 31, 0 << 4 | 15 .byte 255, 255, 8, 1 << 4 | 12 .byte 0, 2, 15, 1 << 4 | 7 .byte 1, 31, 31, 0 << 4 | 8 .byte 16, 1, 63, 4 << 4 | 4 StartObstacleEntranceMarch ldx #KERNEL_SECTIONS - 1 stx currentGameTimer .setPositionAndVelocityForObstacleEntrance lda #1 sta obstacleVelocityValues,x ; set obstacle velocity to move right lda KernelZoneValues,x clc adc #15 sta obstacleVertPos,x ; set obstacle vertical position lda #XMIN sta obstacleHorizPos,x ; set obstacle horizontal position dex bpl .setPositionAndVelocityForObstacleEntrance ldy #OBSTACLE_ENTRANCE_AUDIO_IDX jsr SetGameAudioValues ; set audio values for obstacle entrance jmp StepToNextGameState PlayWordZapperEntranceSounds ldy #0 sty destroyedWordZapperGraphicLSB jsr SetGameAudioValues ; set audio values for Word Zapper entrance jmp StepToNextGameState .byte $A0,$E0,$A0 ; unused bytes BOUNDARY 0 SixDigitDisplayKernel txa ; 2 move scan line to accumulator pha ; 3 ldy #H_FONT - 1 ; 2 lda (characterGraphicPtrs + 10),y;5 ldx VSYNC ; 3 tax ; 2 lda (characterGraphicPtrs + 6),y;5 sta tmpFourthCharacter ; 3 lda (characterGraphicPtrs + 8),y;5 sta tmpFifthCharacter ; 3 sta WSYNC ;-------------------------------------- SLEEP 2 ; 2 SLEEP 2 ; 2 SLEEP 2 ; 2 SLEEP 2 ; 2 SLEEP 2 ; 2 jmp .jmpIntoSixDigitDisplayKernelLoop;3 .sixDigitDisplayKernelLoop lda (characterGraphicPtrs + 10),y;5 ldx VSYNC ; 3 tax ; 2 ;-------------------------------------- lda (characterGraphicPtrs + 8),y;5 = @02 sta tmpFifthCharacter ; 3 lda (characterGraphicPtrs + 6),y;5 sta tmpFourthCharacter ; 3 .jmpIntoSixDigitDisplayKernelLoop lda (characterGraphicPtrs),y;5 cmp VSYNC ; 3 sta GRP0 ; 3 = @24 lda (characterGraphicPtrs + 2),y;5 sta GRP1 ; 3 = @32 lda (characterGraphicPtrs + 4),y;5 sta GRP0 ; 3 = @40 lda tmpFourthCharacter ; 3 sta GRP1 ; 3 = @46 lda tmpFifthCharacter ; 3 sta GRP0 ; 3 = @52 lda tmpFifthCharacter ; 3 stx GRP1 ; 3 = @58 dey ; 2 bpl .sixDigitDisplayKernelLoop;2³ sta WSYNC ;-------------------------------------- lda #0 ; 2 sta GRP0 ; 3 = @05 sta GRP1 ; 3 = @08 pla ; 4 clc ; 2 adc #<~H_FONT ; 2 tax ; 2 rts ; 6 SetupMessageAreaForDisplay sta ramDataPointer ; 3 set ramDataPointer LSB value txa ; 2 move scan line to accumulator pha ; 3 push scan line to stack ldy #5 ; 2 ldx #11 ; 2 .setupMessageAreaForDisplay lda (ramDataPointer),y ; 5 get character data in message area sec ; 2 sbc #42 ; 2 asl ; 2 sty tmpRamDataPointerIdx ; 3 tay ; 2 iny ; 2 lda CharacterSet,y ; 4 get character MSB value sta characterGraphicPtrs,x ; 4 set graphic pointer MSB value dey ; 2 dex ; 2 lda CharacterSet,y ; 4 get character LSB value sta characterGraphicPtrs,x ; 4 set graphic pointer LSB value dex ; 2 ldy tmpRamDataPointerIdx ; 3 dey ; 2 bpl .setupMessageAreaForDisplay;2³ pla ; 4 pull scan line from stack tax ; 2 restore scan line count rts ; 6 PositionGRP0Horizontally ldy #<[RESP0 - RESP0] ; 2 PositionObjectHorizontally sec ; 2 sta WSYNC ;-------------------------------------- dex ; 2 .coarsePositionObject sbc #15 ; 2 divide position by 15 bcs .coarsePositionObject ; 2³ eor #15 ; 2 4-bit 1's complement for fine motion asl ; 2 shift remainder to upper nybbles asl ; 2 asl ; 2 asl ; 2 adc #(8 + 1) << 4 ; 2 increment by 8 for full range sta RESP0,y ; 5 set coarse position value sta WSYNC ;-------------------------------------- dex ; 2 sta HMP0,y ; 5 iny ; 2 rts ; 6 PositionObjectsForMessageArea sta tmpMessageAreaHorizPos ; 3 save current message area position jsr PositionGRP0Horizontally;6 lda tmpMessageAreaHorizPos ; 3 get current message area position clc ; 2 adc #16 ; 2 increment for next character jsr PositionObjectHorizontally;6 position GRP1 horizontally dex ; 2 sta WSYNC ;-------------------------------------- sta HMOVE ; 3 rts ; 6 PlaceTimerInDisplayArea ldx #2 ; timer offset position for ONE_PLAYER game lda tvTypeSwitchValue ; get TV Type switch value bne .placeTimerInDisplayArea ; branch if set to ONE_PLAYER game ldx #0 ; timer offset position for player 1 lda activePlayerNumber ; get active player number beq .placeTimerInDisplayArea ; branch if player 1 is active ldx #4 ; timer offset position for player 2 .placeTimerInDisplayArea lda currentGameTimer ; get current game timer value tay ; move game timer to y register and #15 ; keep ones value ora #<[(_0 / 2) + 42] sta timerAreaDataValues + 1,x ; place ones value to timer area tya ; move game timer value to accumulator lsr ; shift upper nybbles to lower nybbles lsr lsr lsr ora #<[(_0 / 2) + 42] sta timerAreaDataValues,x ; place tens value to timer area rts SetGameAudioValues inc audioChannelIndex ; increment audio channel index value lda #1 and audioChannelIndex ; 0 <= a <= 1 tax lda AudioValues,y ; get audio frequency adjustment value sta audioFrequencyAdjustmentValues,x lda AudioValues + 1,y ; get audio frequency value sta audioFrequencyValues,x lda AudioValues + 2,y ; get audio duration value sta audioDurationValues,x lda AudioValues + 3,y ; get audio tone and volume duration sta AUDC0,x ; set audio tone lsr ; shift volume duration to lower nybbles lsr lsr lsr sta initAudioVolumeDurationValues,x sta audioVolumeDurationValues,x lda #$FF sta audioVolumeValues,x rts .byte $F0,$C6,$A0,$C6,$D3,$C8,$A0,$A4,$A0;unused bytes BOUNDARY 252 .word Start ; RESET vector .byte $E0,$88 ; BRK vector