Audio, save scores, allow quit

More audio, better tuned.  Allow Quit.  Save high scores.
This commit is contained in:
StewBC 2020-01-18 16:58:11 -08:00
parent 1307c2ae66
commit d9c2957b60
11 changed files with 316 additions and 114 deletions

View File

@ -8,6 +8,7 @@
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
.proc serviceAudio
lda audioMask ; get the active channels
@ -50,7 +51,7 @@ explosion:
rts
bombDrop:
ldy #$50
ldy #$30
ldx #$10
jmp playNote
@ -77,8 +78,8 @@ engine:
jmp playNote
ui:
ldy #$80
ldx #$10
ldy #$40
ldx #$08
jmp playNote
.endproc
@ -91,7 +92,7 @@ ui:
sty delay
loop:
lda speaker_toggle
lda SPEAKER
ldy delay
:
nop

View File

@ -7,19 +7,28 @@
;-----------------------------------------------------------------------------
; System locations
.include "apple2.inc"
PATHNAME = $0280
ram_layer0 = $2000 ; HGR Pages
ram_layer1 = $4000
ram_layer0 = $2000 ; HGR Pages
ram_layer1 = $4000
speaker_toggle = $C030
MLI = $BF00 ; ProDOS API
SPEAKER = $C030 ; Access to toggle the speaker
PADDL0 = $C064 ; Read to get POT
PTRIG = $C070 ; Reset PADDLE values
PADDL0 = $C064
PTRIG = $C070
;-----------------------------------------------------------------------------
; MLI call type bytes
QUIT_CALL = $65
OPEN_CALL = $C8
READ_CALL = $CA
WRITE_CALL = $CB
CLOSE_CALL = $CC
CREATE_CALL = $C0
;-----------------------------------------------------------------------------
; self-modifying address marker
PLACEHOLDER = $FFFF
PLACEHOLDER = $FFFF
;-----------------------------------------------------------------------------
; modes
@ -44,7 +53,7 @@ KEY_BOMB = %10000000
;-----------------------------------------------------------------------------
; game constants
XINSET = 4 ; By how many BYTE cols the display is offset into X
XSIZE = (80 - (4 * XINSET)) ; columns on screen (1 BYTE col = 2 game cols)
XSIZE = (80 - (4 * XINSET)) ; columns on screen (1 BYTE col = 2 game cols)
YSIZE = 192 ; lines on screen
WORLD_START = $08 ; top line where world is drawn

View File

@ -49,6 +49,11 @@ loop:
bcc notnum
sbc #'1' ; stages are 0 based
sta stage
lda #AUDIO_UI_TICK ; make a sound
sta audioFrame
jsr serviceAudio
lda #0 ; reset where the buffers will start
sta bufferInsert
jsr drawClearScreen
@ -58,6 +63,11 @@ loop:
notnum:
cmp #$1b ; ESC key
bne notQuit
lda #AUDIO_UI_TICK ; make a sound
sta audioFrame
jsr serviceAudio
lda #1
sta pause ; abuse pause to signal quit
rts
@ -69,6 +79,10 @@ notQuit:
bne notHelp
help:
lda #AUDIO_UI_TICK ; make a sound
sta audioFrame
jsr serviceAudio
jmp uiShowEditHelp
notHelp:
@ -78,6 +92,10 @@ notHelp:
bne notSave
save:
lda #AUDIO_UI_TICK ; make a sound
sta audioFrame
jsr serviceAudio
lda #0 ; a 0 is save
jsr uiFileLoadSave
jmp editLoop
@ -89,6 +107,10 @@ notSave:
bne done
load:
lda #AUDIO_UI_TICK ; make a sound
sta audioFrame
jsr serviceAudio
lda #1 ; a 1 is load
jsr uiFileLoadSave
jmp editLoop
@ -235,8 +257,8 @@ missile:
sta zCollision
sta stopScrolling
sta bufferInsert
sta dangerTickIdx
sta pause
sta terrainOrigin
tax ; start at 0 for the buffers
:
@ -257,6 +279,10 @@ missile:
lda #$ff
sta lastInput ; set no keys down - all 1's
sta nextStage
lda #DANGER_TICKS
sta dangerTickCount
lda #(XSIZE/2) ; middle of the screen in X
sta playerShipX ; is where the cursor is

View File

@ -5,71 +5,180 @@
; Stefan Wessels, 2019
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
PATHNAME = $0280
MLI = $BF00
QUIT_CALL = $65
OPEN_CALL = $C8
READ_CALL = $CA
WRITE_CALL = $CB
CLOSE_CALL = $CC
CREATE_CALL = $C0
;-----------------------------------------------------------------------------
.segment "DATA"
createParam:
.byte $07 ;PARAM_COUNT
.addr PATHNAME ;PATHNAME
.byte $C3 ;ACCESS
.byte $06 ;FILE_TYPE (6 is binay)
.word $0000 ;AUX_TYPE
.byte $01 ;STORAGE_TYPE
.word $0000 ;CREATE_DATE
.word $0000 ;CREATE_TIME
.byte $07 ; param_count
createName:
.addr PATHNAME ; pathname
.byte $C3 ; access
.byte $06 ; file_type (6 is binay)
.word $0000 ; aux_type
.byte $01 ; storage_type
.word $0000 ; create_date
.word $0000 ; create_time
openParam:
.byte $03 ;PARAM_COUNT
.addr PATHNAME ;PATHNAME
.addr $2000-$400 ;IO_BUFFER
.byte $03 ; param_count
openName:
.addr PATHNAME ; pathname
.addr $2000-$400 ; io_buffer
openRef:
.byte $00 ;REF_NUM
.byte $00 ; ref_num
readParam:
.byte $04 ;PARAM_COUNT
.byte $04 ; param_count
readRef:
.byte $00 ;REF_NUM
.addr worldDataStart ;DATA_BUFFER
.word $FFFF ;REQUEST_COUNT
.word $0000 ;TRANS_COUNT
.byte $00 ; ref_num
readAddress:
.addr worldDataStart ; data_buffer
readLength:
.word $FFFF ; request_count
.word $0000 ; trans_count
writeParam:
.byte $04 ;PARAM_COUNT
.byte $04 ; param_count
writeRef:
.byte $00 ;REF_NUM
.addr worldDataStart ;DATA_BUFFER
.word worldDataEnd-worldDataStart ;REQUEST_COUNT
.word $0000 ;TRANS_COUNT
.byte $00 ; ref_num
writeAddress:
.addr worldDataStart ; data_buffer
writeLength:
.word worldDataEnd-worldDataStart ; request_count
.word $0000 ; trans_count
closeParam:
.byte $01 ;PARAM_COUNT
.byte $01 ; param_count
closeRef:
.byte $00 ;REF_NUM
.byte $00 ; ref_num
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
.proc fileSave
.proc saveWorld
jsr MLI ; create the file
.byte CREATE_CALL
.word createParam
bcc :+
jmp error
lda #<worldDataStart ; set the location
sta writeAddress
lda #>worldDataStart
sta writeAddress + 1
lda #<(worldDataEnd-worldDataStart) ; set the size
sta writeLength
lda #>(worldDataEnd-worldDataStart)
sta writeLength + 1
jmp saveFile ; save
.endproc
;-----------------------------------------------------------------------------
.proc loadWorld
lda #<worldDataStart ; set the location
sta readAddress
lda #>worldDataStart
sta readAddress + 1
lda #<(worldDataEnd-worldDataStart) ; set the length (size)
sta readLength
lda #>(worldDataEnd-worldDataStart)
sta readLength + 1
jmp loadFile ; load
.endproc
;-----------------------------------------------------------------------------
.proc saveHighScores
jsr setHighScoreFileNames ; set the name
lda #<scoresTable ; set the location
sta writeAddress
lda #>scoresTable
sta writeAddress + 1
lda #<(scoresTableEnd-scoresTable) ; set the size
sta writeLength
lda #>(scoresTableEnd-scoresTable)
sta writeLength + 1
jmp saveFile ; save
.endproc
;-----------------------------------------------------------------------------
.proc loadHighScores
jsr setHighScoreFileNames ; set the name
lda #<scoresTable ; set the location
sta readAddress
lda #>scoresTable
sta readAddress + 1
lda #<(scoresTableEnd-scoresTable) ; set the size
sta readLength
lda #>(scoresTableEnd-scoresTable)
sta readLength + 1
jmp loadFile ; load
.endproc
;-----------------------------------------------------------------------------
.proc setHighScoreFileNames
ldx pathPos ; append to the end of the path
ldy #0 ; from the 1st char pf the name
:
lda hihgScoreFileName, y ; copy name to path
sta PATHNAME, x
beq :+
iny
inx
bne :-
:
jsr MLI
stx PATHNAME
dec PATHNAME ; don't count the trailing null
rts
.endproc
;-----------------------------------------------------------------------------
.proc setWorldFileName
zaEntryL = zWorldPtr ; internal - ptr to a string being entered (abusing world ptr)
tya ; add the file length to the path length
clc
adc pathPos
tax
stx PATHNAME
dec PATHNAME ; don't count the trailing null
:
lda (zaEntryL), y ; copy the file name to the end of the path
sta PATHNAME, x
dex
dey
bpl :-
rts
.endproc
;-----------------------------------------------------------------------------
.proc saveFile
jsr MLI ; create the file, ignoring errors
.byte CREATE_CALL
.word createParam
jsr MLI ; open the (now hopefully existing) file
.byte OPEN_CALL
.word openParam
bcc :+
@ -96,7 +205,7 @@ error:
.endproc
;-----------------------------------------------------------------------------
.proc fileLoad
.proc loadFile
jsr MLI
.byte OPEN_CALL

View File

@ -41,16 +41,6 @@ preamble: ; bring terrain on-screen with n
wait #$40 ; give the user a moment to get ready
loop:
lda runAudio ; alternate between game and audio
eor #1
sta runAudio
beq :+ ; run the game when runAudio eq 0
jsr serviceAudio ; run the audio
jmp loop ; go back and flip to the game
:
lda playerDead ; check if the input should run
bne skip ; and skip if not
jsr inputGame ; read joystick and move player, check for pause key
cmp #$9b ; check for ESC
bne skip ; if not, check for pause
@ -90,12 +80,13 @@ delay:
lda victory ; when set, either a nuke or back home
bne win
jsr serviceAudio ; run the audio
lda playerDead
beq loop ; playerDead = 0 means alive so keep going
died:
dec playerDead ; the counter holds the explosion state
bne loop ; don't get user input
bne skip ; don't get user input
jsr gameNextPlayer ; switch players if a 2p game
jmp outerloop
@ -153,7 +144,6 @@ win:
sta dangerTickIdx
sta moveHorz
sta moveVert
sta runAudio
sta flipFlop
sta pause
sta fireCoolDown

View File

@ -288,8 +288,11 @@ joyDone:
sta rawEor ; and save this state as the key state
Button_B:
bit Bit7Mask ; Button_B
bit Bit7Mask ; Button_B
beq Button_A
lda #AUDIO_UI_TICK ; make a sound
sta audioFrame
jsr serviceAudio
lda brushType
bne radar
ora #KEY_RIGHT ; when pressed, move right as well
@ -305,6 +308,9 @@ radar:
Button_A:
bit Bit8Mask ; Button_A
beq up
lda #AUDIO_UI_TICK ; make a sound
sta audioFrame
jsr serviceAudio
lda brushType
bne missile
ora #KEY_RIGHT
@ -356,6 +362,9 @@ Button_Start:
and lastInput ; and debounce
bit Bit5Mask ; test if Start button down
beq joyDone
lda #AUDIO_UI_TICK ; make a sound
sta audioFrame
jsr serviceAudio
lda brushType ; if down, toggle the brush type between terrain and enemies
eor #1
sta brushType

View File

@ -18,6 +18,7 @@
jmp main ; This ends up at $080d (sys 2061's target)
;-----------------------------------------------------------------------------
.include "apple2.inc" ; Apple II locations from cc65
.include "defs.inc" ; constants
.include "macros.inc" ; vpoke, vpeek, print* & wait.
.include "zpvars.inc" ; Zero Page usage (variables)
@ -39,12 +40,15 @@ jmp main ; This ends up at $080d (sys 206
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
.proc main
jsr mainGameSetup
:
jsr inputCheckForInput ; wait for user interaction
beq :-
jsr drawClearScreen
jsr drawPresent
:
jsr uiTitleScreen
@ -56,6 +60,27 @@ jmp main ; This ends up at $080d (sys 206
;-----------------------------------------------------------------------------
.proc mainGameSetup
lda #$0
sta backLayer ; set back layer to 0
sta audioFrame ; set all audio channels to off (0)
sta numPlayers ; Init initially to 0 (not set for training)
lda PATHNAME ; length of file path
tax ; put in index
:
lda PATHNAME, x ; get character
cmp #'/' ; look backwards for directory seperator
beq :+
dex
bne :-
:
inx ; 1 or 1 past / is where the file name starts
stx pathPos ; save that location
jsr loadHighScores ; load high scores from disc
bcc cont ; on success, skip the init
ldx #((textHSEnd-textHS) - 1) ; empty the high score names to spaces
store:
lda textHS, x
@ -66,19 +91,16 @@ store:
dex
bpl store
ldx #((highScoresEnd-highScores) - 1) ; set high score table scores to 0
lda #$0
sta backLayer ; set back layer to 0
sta audioFrame ; set all audio channels to off (0)
sta numPlayers ; Init initially to 0 (not set for training)
ldx #((highScoresEnd-highScores) - 1) ; set high score table scores to 0
:
sta highScores, x
dex
bpl :-
ldx #(AUDIO_EXPLOSION | AUDIO_BOMB_DROP | AUDIO_FIRE | AUDIO_UI_TICK)
stx audioMask ; set the mask to all channels on ($ff)
cont:
lda #(AUDIO_EXPLOSION | AUDIO_BOMB_DROP | AUDIO_FIRE | AUDIO_UI_TICK)
sta audioMask ; set the mask for default ON channels
ldx #((BitMasksEnd - BitMasks) - 1)
:

View File

@ -38,6 +38,7 @@ textTrain: .asciiz "\"T\" FOR TRAINING CONTROL CENTER"
textEdit: .asciiz "\"E\" FOR THE LANDSCAPE EDITOR"
textLoad: .asciiz "\"L\" TO LOAD ANOTHER LANDSCAPE"
textSirens: .asciiz "\"S\" SET AUDIO: "
textQuit: .asciiz "\"Q\" QUIT"
; main menu audio options
textAudio1: .asciiz "ENGINE, SFX"
@ -102,28 +103,7 @@ textFileSuccess: .asciiz "SUCCESS."
textFileThe: .asciiz "The"
textFileFailed: .asciiz "Failed. Error Code"
;-----------------------------------------------------------------------------
.segment "DATA"
textHS:
textHighScore1: .asciiz "123456"
textHighScore2: .asciiz "123456"
textHighScore3: .asciiz "123456"
textHighScore4: .asciiz "123456"
textHighScore5: .asciiz "123456"
textHSEnd:
textStage: .asciiz "1"
textPlayerNum: .asciiz "1"
textNumber: .asciiz "1234567" ; score display 10x score - extra digit needed
textDangerBar: .asciiz "123"
textEnd:
textFileName: .asciiz "PENEWORLD01" ; default file name
textFilePad: .asciiz "" ; This makes the null terminator on textFileName viable and a 12 char filename
textFileNameEnd:
szHex: .asciiz " "
hihgScoreFileName:.asciiz "PENSCORES"
;-----------------------------------------------------------------------------
.segment "CODE"

View File

@ -199,6 +199,9 @@ show: ; a high-score was set, so show
width = tempBlock + 14
height = tempBlock + 15
lda #0
sta audioExplFrame ; use this as a delay counter for logo sound
lda #((dataLogoLinesEnd - dataLogoLines) / 4)
sta remain
@ -215,6 +218,8 @@ show: ; a high-score was set, so show
loop:
dec remain ; iterate over all lines
bpl :+
lda #0
sta audioExplFrame
rts
:
ldx index
@ -285,6 +290,18 @@ plot:
lda skip ; if key/button pressed - fast draw logo
bne :+
lda audioMask
beq nosnd
snd:
ldy audioExplFrame
ldx #4
jsr playNote ; play the note
dec audioExplFrame ; alter the note
dec audioExplFrame
bmi nosnd ; variable decay so that the duration
dec audioExplFrame ; is a close match to when the logo ends
dec audioExplFrame
nosnd:
jsr inputCheckForInput ; check for user interaction
sta skip
bne :+
@ -357,6 +374,7 @@ redraw:
print textEdit , #(02), #(8*13)
print textLoad , #(01), #(8*14)
print textSirens , #(05), #(8*15)
print textQuit , #(12), #(8*16)
lda audioMask
beq none
@ -416,7 +434,10 @@ load:
jsr uiFileLoadSave ; call the code to do file name and load
jmp uiMainMenu
sirens:
sirens: ; For Apple II this is the "set sound type"
cpx #5
bne quit
lda audioMask
beq audioSetAll
bit Bit8432Mask
@ -431,10 +452,23 @@ audioSetAll:
lda #%01111111
:
sta audioMask
jmp redraw ; siren code instead of this
jmp redraw
quit:
inc PWREDUP ; Make sure this isn't a power vector
options: .byte "12TELS"
jsr MLI ; call the prodos mli ($bf00) - never returns here
.byte QUIT_CALL ; call type = quit
.addr quitParam ; pointer to parameter table
quitParam:
.byte 4 ; number of parameters is 4
.byte 0 ; quit type
.word 0000 ; reserved
.byte 0 ; reserved
.word 0000 ; reserved
options: .byte "12TELSQ"
optionsEnd:
.endproc
@ -778,7 +812,8 @@ copyScore:
dey
bpl :-
jmp uiGetHighScoreName ; now get the new name
jsr uiGetHighScoreName ; now get the new name
jmp saveHighScores
.endproc
@ -981,13 +1016,7 @@ enter:
lda #0 ; and null terminate the string
sta (zaEntryL), y
setPathName:
sty PATHNAME
:
lda (zaEntryL), y
sta PATHNAME+1,y
dey
bpl :-
jsr setWorldFileName
lda #1 ; enter has been pressed - it's all over
sta allOver ; time to attempt a disc action, but just redraw once more
@ -996,13 +1025,13 @@ setPathName:
disc:
lda forLoad ; load or save
beq save
jsr fileLoad ; load the file by the name
jsr loadWorld ; load the file by the name
bcs fail ; if carry set then there's an error
jmp success ; no error - all good
save:
jsr fileSave ; save the file
jsr saveWorld ; save the file
bcs fail ; if carry set then there's an error
success:

View File

@ -20,6 +20,9 @@ rsEnd:
playerStats: .res ((rsEnd-rsStart) * 2) ; 2 copies of stats, for p1 and p2 is 2p game
;-----------------------------------------------------------------------------
; High scores table saved to disc
scoresTable:
highScores:
highScore1: .res 3
highScore2: .res 3
@ -28,6 +31,29 @@ highScore4: .res 3
highScore5: .res 3
highScoresEnd:
textHS:
textHighScore1: .asciiz "123456"
textHighScore2: .asciiz "123456"
textHighScore3: .asciiz "123456"
textHighScore4: .asciiz "123456"
textHighScore5: .asciiz "123456"
textHSEnd:
scoresTableEnd:
;-----------------------------------------------------------------------------
; user facing text area
textStage: .asciiz "1"
textPlayerNum: .asciiz "1"
textNumber: .asciiz "1234567" ; score display 10x score - extra digit needed
textDangerBar: .asciiz "123"
textEnd:
textFileName: .asciiz "PENEWORLD01" ; default file name
textFilePad: .asciiz "" ; This makes the null terminator on textFileName viable and a 12 char filename
textFileNameEnd:
szHex: .asciiz " "
;-----------------------------------------------------------------------------
; per "run" buffers
bombX: .res NUM_BOMBS ; 2 bombs allowed, their x values
bombY: .res NUM_BOMBS ; Y values for 2 bombs (0=available)

View File

@ -57,7 +57,6 @@ dangerTickCount: .res 1 ; how often a dot is added to th
dangerTickIdx: .res 1 ; the index into the text that holds the danger line of dots
moveHorz: .res 1 ; keeps track of horizontal movement - only moves every 2nd frame
moveVert: .res 1 ; keeps track of vertical movement - moves 4 rows but over 2 frames
runAudio: .res 1 ; flip-flop for service audio or run a game frame
; helper variables
updateHUD: .res 1 ; 0 - don't draw, 1+ - clean and redraw
@ -67,7 +66,9 @@ enemyHit: .res 1 ; the flags of the enemy destroy
enemyHitType: .res 1 ; 0 = nuke, 1 = missile, 2 = monster, 3 = radar, $ff - nothing
lastInput: .res 1 ; holds the value of the prev joystick frame
pause: .res 1 ; <> 0 when the game is paused
fireCoolDown: .res 1
fireCoolDown: .res 1 ; decay to zero before fire allowed
pathPos: .res 1 ; index to start of file name in path
; audio variables
audioMask: .res 1 ; which audio "channels" are active (and with audioFrame)