Rework the game logic to support one and two player games.

This commit is contained in:
Jeremy Rand 2021-01-20 00:06:32 -05:00
parent 3a77ba1367
commit 815758f3ff
9 changed files with 269 additions and 120 deletions

View File

@ -5,6 +5,7 @@ This is a list of the software bugs (as opposed to the bugs in the game that you
* The sound is muddy at times on real HW. Especially when lots of stuff is going on, the sound ends up coming out garbled. This isn't happening on emulators where everything is always quite clear. Perhaps I am reaching some limit of the Ensoniq. Do I need to reduce some sampling frequencies perhaps?
* I tried reducing the sampling frequency from 11025 for most of the samples to 5513 and I didn't notice any improvement in the quality of the sound on real HW. Nor did I notice any real degredation on real HW or on an emulator.
* The flea appears before the second level actually begins, in the time before the level starts if you have too few mushrooms at the bottom. This is due to the way that levels are incremented now in the game state machine.
FIXED

View File

@ -26,11 +26,19 @@ game start
using tileData
using playerData
jsl setupScreen
PLAYER_DEATH_FRAME_COUNT equ 30
NEXT_LEVEL_FRAME_COUNT equ 60
NEXT_PLAYER_FRAME_COUNT equ 180
GAME_OVER_FRAME_COUNT equ 180
RESTART_LEVEL_FRAME_COUNT equ 20
jsl setupScreen
lda #0
jsl setColour
jsl gameOver
jsl setGameNotRunning
jsl updateHighScore
gameLoop anop
@ -71,11 +79,11 @@ gameLoop anop
jsl updatePlayer
jsl updateShot
jsl updateGameState
jsl updateScorpion
jsl updateSpider
jsl updateFlea
jsl updateSegments
jsl updateLevel
jsl updateSounds
jsl checkKeyboard
@ -183,12 +191,13 @@ nextWord anop
; The accumulator has a 0 in it when starting a one player game, 1 when
; starting a two player game.
startGame entry
ldx gameRunning
bne startGame_notRunning
ldx gameState
beq startGame_notRunning
rtl
startGame_notRunning anop
sta isSinglePlayer
stz gameRunning
lda #GAME_STATE_LEVEL
sta gameState
jsl initPlayer
jsl scoreStartGame
lda isSinglePlayer
@ -213,12 +222,209 @@ startLevel entry
jsl shotInitLevel
jsl playerLevelStart
jmp levelStart
updateGameState entry
lda gameState
beq updateGameState_none
cmp #GAME_STATE_LEVEL
beq updateGameState_level
cmp #GAME_STATE_NEXT_LEVEL
beq updateGameState_nextLevel
cmp #GAME_STATE_PLAYER_DYING
beq updateGameState_playerDying
cmp #GAME_STATE_BONUS
beq updateGameState_bonus
jmp updateGameState_moreStates
updateGameState_none anop
stz frameCount
rtl
updateGameState_level anop
lda numSegments
bne updateGameState_levelNotDone
jsl levelNext
lda #GAME_STATE_NEXT_LEVEL
sta gameState
lda #NEXT_LEVEL_FRAME_COUNT
sta frameCount
jsl stopSegmentSound
updateGameState_levelNotDone anop
lda playerState
cmp #PLAYER_STATE_EXPLODING
bne updateGameState_levelPlayerNotDying
lda #GAME_STATE_PLAYER_DYING
sta gameState
lda #PLAYER_DEATH_FRAME_COUNT
sta frameCount
updateGameState_levelPlayerNotDying anop
rtl
updateGameState_nextLevel anop
lda playerState
cmp #PLAYER_STATE_EXPLODING
bne updateGameState_nextLevelPlayerNotDying
lda #GAME_STATE_PLAYER_DYING
sta gameState
lda #PLAYER_DEATH_FRAME_COUNT
sta frameCount
rtl
updateGameState_nextLevelPlayerNotDying anop
lda frameCount
beq updateGameState_startLevel
dec a
sta frameCount
rtl
updateGameState_startLevel anop
lda #GAME_STATE_LEVEL
sta gameState
jmp levelStart
updateGameState_playerDying anop
lda frameCount
beq updateGameState_playerDead
dec a
sta frameCount
rtl
updateGameState_playerDead anop
lda #GAME_STATE_BONUS
sta gameState
jsl segmentsInitLevel
jsl scorpionInitLevel
jsl spiderInitLevel
jsl fleaInitLevel
rtl
updateGameState_bonus anop
jsl resetMushrooms
bcc updateGameState_doneBonus
rtl
updateGameState_doneBonus anop
ldx playerNum
lda numLives,x
bne updateGameState_gameNotOver
jsl checkHighScore
bcc updateGameState_notHighScore
lda isSinglePlayer
beq updateGameState_isSinglePlayer
stz isSinglePlayer
bra updateGameState_twoPlayer
updateGameState_isSinglePlayer anop
jmp setGameNotRunning
updateGameState_notHighScore anop
lda isSinglePlayer
beq updateGameState_isSinglePlayer
lda #GAME_STATE_GAME_OVER
sta gameState
lda #GAME_OVER_FRAME_COUNT
rtl
updateGameState_gameNotOver anop
jsl segmentsInitLevel
jsl scorpionInitLevel
jsl spiderInitLevel
jsl fleaInitLevel
lda isSinglePlayer
bne updateGameState_twoPlayer
lda #GAME_STATE_NEXT_LIFE
sta gameState
lda #RESTART_LEVEL_FRAME_COUNT
sta frameCount
rtl
updateGameState_twoPlayer anop
lda #GAME_STATE_NEXT_PLAYER
sta gameState
lda #NEXT_PLAYER_FRAME_COUNT
sta frameCount
lda playerNum
eor #PLAYER_TWO
sta playerNum
jsl scoreSwitchPlayer
ldx playerNum
lda colourLevelNum,x
jsl setColour
lda playerNum
beq updateGameState_toPlayer1
jsl copyToPlayer1Tiles
jmp copyFromPlayer2Tiles
updateGameState_toPlayer1 anop
jsl copyToPlayer2Tiles
jmp copyFromPlayer1Tiles
updateGameState_moreStates anop
cmp #GAME_STATE_NEXT_LIFE
beq updateGameState_nextLife
cmp #GAME_STATE_NEXT_PLAYER
beq updateGameState_nextPlayer
cmp #GAME_STATE_GAME_OVER
beq updateGameState_gameOver
rtl
updateGameState_nextLife anop
lda frameCount
bne updateGameState_nextLifeWait
lda #GAME_STATE_LEVEL
sta gameState
jmp startLevel
updateGameState_nextLifeWait anop
dec a
sta frameCount
rtl
updateGameState_nextPlayer anop
lda frameCount
bne updateGameState_nextPlayerWait
lda #GAME_STATE_LEVEL
sta gameState
jmp startLevel
updateGameState_nextPlayerWait anop
dec a
sta frameCount
updateGameState_printPlayerNumber anop
ldx #GAME_NUM_TILES_WIDE*12+16
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_LETTER_P
_overwriteGameTile TILE_LETTER_L
_overwriteGameTile TILE_LETTER_A
_overwriteGameTile TILE_LETTER_Y
_overwriteGameTile TILE_LETTER_E
_overwriteGameTile TILE_LETTER_R
_overwriteGameTile TILE_EMPTY
lda playerNum
beq updateGameState_displayPlayer1
_overwriteGameTile TILE_NUMBER_2
rtl
updateGameState_displayPlayer1 anop
_overwriteGameTile TILE_NUMBER_1
rtl
updateGameState_gameOver anop
lda frameCount
bne updateGameState_gameOverWait
stz isSinglePlayer
jmp updateGameState_twoPlayer
updateGameState_gameOverWait anop
dec a
sta frameCount
ldx #GAME_NUM_TILES_WIDE*11+12
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_LETTER_G
_overwriteGameTile TILE_LETTER_A
_overwriteGameTile TILE_LETTER_M
_overwriteGameTile TILE_LETTER_E
_overwriteGameTile TILE_EMPTY
_overwriteGameTile TILE_LETTER_O
_overwriteGameTile TILE_LETTER_V
_overwriteGameTile TILE_LETTER_E
_overwriteGameTile TILE_LETTER_R
_overwriteGameTile TILE_EMPTY
jmp updateGameState_printPlayerNumber
copyToPlayer1Tiles entry
ldx #0
copyToPlayer1Tiles_loop anop
lda tileData,x
lda tileType,x
sta >player1Tiles,x
inx
inx
@ -230,7 +436,7 @@ copyToPlayer1Tiles_loop anop
copyToPlayer2Tiles entry
ldx #0
copyToPlayer2Tiles_loop anop
lda tileData,x
lda tileType,x
sta >player2Tiles,x
inx
inx
@ -243,9 +449,9 @@ copyFromPlayer1Tiles entry
ldx #0
copyFromPlayer1Tiles_loop anop
lda >player1Tiles,x
cmp tileData,x
cmp tileType,x
beq copyFromPlayer1Tiles_skip
sta tileData,x
sta tileType,x
lda TILE_STATE_DIRTY
sta tileDirty,x
copyFromPlayer1Tiles_skip anop
@ -260,9 +466,9 @@ copyFromPlayer2Tiles entry
ldx #0
copyFromPlayer2Tiles_loop anop
lda >player2Tiles,x
cmp tileData,x
cmp tileType,x
beq copyFromPlayer2Tiles_skip
sta tileData,x
sta tileType,x
lda TILE_STATE_DIRTY
sta tileDirty,x
copyFromPlayer2Tiles_skip anop
@ -460,15 +666,13 @@ setGameTile_skip anop
rts
gameOver entry
lda #1
sta gameRunning
setGameNotRunning entry
lda #GAME_STATE_NOT_RUNNING
sta gameState
jsl segmentsInitLevel
jsl scorpionInitLevel
jsl spiderInitLevel
jsl fleaInitLevel
jsl checkHighScore
jsl addRandomMushrooms
jmp staticGameBoard
@ -761,8 +965,8 @@ checkKey_loop2 anop
long i,m
and #$007f
ldx gameRunning
beq checkKey_pause
ldx gameState
bne checkKey_pause
cmp #'q'
beq checkKey_quit
@ -823,7 +1027,8 @@ vblLoop anop
rtl
shouldQuit dc i2'1'
borderColour dc i2'0'
shouldQuit dc i2'1'
borderColour dc i2'0'
frameCount dc i2'0'
end

View File

@ -96,8 +96,8 @@ updateFlea_explosionDone anop
rtl
updateFlea_maybeAdd anop
lda gameRunning
bne updateFlea_doNotAdd
lda gameState
beq updateFlea_doNotAdd
ldx playerNum
lda gameLevel,x
beq updateFlea_doNotAdd

View File

@ -38,10 +38,6 @@ initPlayer_loop1 anop
lda isSinglePlayer
beq initPlayer_done
; DEBUG
; lda #PLAYER_TWO
; sta playerNum
; DEBUG
ldy #STARTING_NUM_LIVES
sty numLives+2
ldx #P2_LIVES_OFFSET
@ -118,34 +114,18 @@ playerAddLife_cont anop
updatePlayer entry
lda gameRunning
beq updatePlayer_gameRunning
lda gameState
bne updatePlayer_gameRunning
rtl
updatePlayer_gameRunning anop
lda playerState
cmp #PLAYER_STATE_NONE
bne updatePlayer_notNone
lda playerFrameCount
bne updatePlayer_wait
ldx playerNum
lda numLives,x
beq updatePlayer_gameOver
lda numSegments
bne updatePlayer_notNextLevel
; If we are going to the next level, let updateLevel handle that for us.
rtl
updatePlayer_notNextLevel anop
jmp startLevel
updatePlayer_gameOver anop
jmp gameOver
updatePlayer_wait anop
dec a
sta playerFrameCount
rtl
updatePlayer_notNone anop
cmp #PLAYER_STATE_EXPLODING
beq updatePlayer_exploding
jmp updatePlayer_notExploding
jmp updatePlayer_onScreen
updatePlayer_exploding anop
lda playerFrameCount
beq updatePlayer_nextExplosion
@ -162,7 +142,7 @@ updatePlayer_nextExplosion anop
sta playerFrameCount
bra updatePlayer_drawExplosion
updatePlayer_doneExplosion anop
lda #PLAYER_STATE_MUSHROOMS
lda #PLAYER_STATE_NONE
sta playerState
rtl
@ -207,21 +187,7 @@ jumpInst anop
jmp >shipExplosion1
nop
updatePlayer_notExploding anop
cmp #PLAYER_STATE_MUSHROOMS
bne updatePlayer_notMushrooms
jsl resetMushrooms
bcc updatePlayer_doneMushrooms
rtl
updatePlayer_doneMushrooms anop
lda #PLAYER_RESTART_LEVEL_FRAME_COUNT
sta playerFrameCount
lda #PLAYER_STATE_NONE
sta playerState
rtl
updatePlayer_notMushrooms anop
updatePlayer_onScreen anop
ldx #0
ldy #0
; This code for reading the mouse data is based on some code which John Brooks helpfully provided, although I did things

View File

@ -595,8 +595,8 @@ soundInit entry
updateSounds entry
lda gameRunning
bne updateSounds_done
lda gameState
beq updateSounds_done
lda fleaSoundIsPlaying
bne updateSounds_done

View File

@ -294,8 +294,8 @@ updateSpider_done anop
rtl
updateSpider_maybeAdd anop
lda gameRunning
bne updateSpider_done
lda gameState
beq updateSpider_done
lda spiderAddTime
bne updateSpider_waitForAdd
lda #SPIDER_ADD_TIME

View File

@ -21,8 +21,16 @@ SEGMENT_DIR_RIGHT equ 1
PLAYER_STATE_NONE equ 0
PLAYER_STATE_EXPLODING equ 1
PLAYER_STATE_MUSHROOMS equ 2
PLAYER_STATE_ONSCREEN equ 3
PLAYER_STATE_ONSCREEN equ 2
GAME_STATE_NOT_RUNNING equ 0
GAME_STATE_LEVEL equ 1
GAME_STATE_NEXT_LEVEL equ 2
GAME_STATE_PLAYER_DYING equ 3
GAME_STATE_BONUS equ 4
GAME_STATE_NEXT_LIFE equ 5
GAME_STATE_NEXT_PLAYER equ 6
GAME_STATE_GAME_OVER equ 7
; The code uses segmentPixelOffset and the segment speed to figure out whether to draw the shifted sprite
; or the regular sprite. By AND-ing with the speed, if the result is 0, then we want a non-shifted sprite.
@ -138,7 +146,7 @@ PLAYER_ONE gequ 0
PLAYER_TWO gequ 2
gameRunning dc i2'1'
gameState dc i2'GAME_STATE_NOT_RUNNING'
; The following data values hold the game state and when/if 2 player is supported,
; this information will need to be copied to a backup location when the player

View File

@ -14,8 +14,6 @@ level start
using globalData
using tileData
NEXT_LEVEL_FRAME_COUNT equ 60
levelInit entry
stz gameLevel
@ -25,7 +23,8 @@ levelInit entry
stz colourLevelNum
stz colourLevelNum+2
lda #SEGMENT_SPEED_FAST
sta levelOne+2
sta levelSpeed
sta levelSpeed+2
rtl
@ -39,6 +38,8 @@ levelStart entry
ldx centipedeLevelNum,y
lda levelTable,x
tax
lda levelSpeed,y
sta |$2,x
lda |$0,x
sta centipedeNum
; We add centipedes in reverse order which means we need to load X up with the address
@ -72,35 +73,7 @@ levelStart_loop anop
bra levelStart_loop
levelStart_done anop
rtl
updateLevel entry
lda gameRunning
beq updateLevel_cont
stz nextLevelFrameCount
rtl
updateLevel_cont anop
lda playerState
cmp #PLAYER_STATE_EXPLODING
beq updateLevel_done
cmp #PLAYER_STATE_MUSHROOMS
beq updateLevel_done
lda nextLevelFrameCount
beq updateLevel_checkSegments
dec a
sta nextLevelFrameCount
bne updateLevel_done
jsl levelNext
jmp levelStart
updateLevel_checkSegments anop
bne updateLevel_done
lda numSegments
bne updateLevel_done
lda #NEXT_LEVEL_FRAME_COUNT
sta nextLevelFrameCount
jsl stopSegmentSound
updateLevel_done anop
rtl
levelNext entry
ldx playerNum
@ -119,17 +92,16 @@ levelNext_skip anop
bge levelNext_fastOnly
ldx playerNum
ldy centipedeLevelNum,x
ldx levelTable,y
lda |$2,x
lda levelSpeed,x
cmp #SEGMENT_SPEED_FAST
beq levelNext_slowIncrement
lda #SEGMENT_SPEED_FAST
sta |$2,x
sta levelSpeed,x
rtl
levelNext_slowIncrement anop
ldx playerNum
lda #SEGMENT_SPEED_SLOW
sta levelSpeed,x
lda centipedeLevelNum,x
cmp #LEVEL_TABLE_LAST_OFFSET
bge levelNext_slowWrap
@ -140,14 +112,12 @@ levelNext_slowWrap anop
lda #0
levelNext_slowNoWrap anop
sta centipedeLevelNum,x
tay
ldx levelTable,y
lda #SEGMENT_SPEED_SLOW
sta |$2,x
rtl
levelNext_fastOnly anop
ldx playerNum
lda #SEGMENT_SPEED_FAST
sta levelSpeed,x
lda centipedeLevelNum,x
cmp #LEVEL_TABLE_LAST_OFFSET
bge levelNext_fastWrap
@ -158,16 +128,12 @@ levelNext_fastWrap anop
lda #0
levelNext_fastNoWrap anop
sta centipedeLevelNum,x
tay
ldx levelTable,y
lda #SEGMENT_SPEED_FAST
sta |$2,x
rtl
centipedeNum dc i2'0'
nextLevelFrameCount dc i2'0'
centipedeNum dc i2'0'
levelSpeed dc i2'SEGMENT_SPEED_FAST'
dc i2'SEGMENT_SPEED_FAST'
; The level structure looks like this:
; number of independent centipedes (2 bytes)

View File

@ -400,6 +400,7 @@ checkHighScore_next anop
tay
cpy #SETTINGS_HIGH_SCORE_SIZE*10
blt checkHighScore_loop
clc
rtl
checkHighScore_isHighScore anop
sty scoreIndex
@ -766,7 +767,9 @@ checkHighScore_isInvalid anop
checkHighScore_doneInitials anop
jsl saveSettings
jmp updateHighScore
jsl updateHighScore
sec
rtl
scoreIndex dc i2'0'