aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/driver.s13
-rw-r--r--src/jetpac.s32
-rw-r--r--src/over.s196
-rw-r--r--src/player.s18
4 files changed, 244 insertions, 15 deletions
diff --git a/src/driver.s b/src/driver.s
index b90cabe..c4bd8e7 100644
--- a/src/driver.s
+++ b/src/driver.s
@@ -236,7 +236,18 @@
lda Explosions::zp_active
bne @sprite_cycling
- ;; Nope! Then set the player's timer.
+ ;; After all the explosions have been done, do we have any life left?
+ lda Player::zp_lifes
+ bne @reset_timer
+
+ ;; No! Toggle the game over bit.
+ ;; TODO: missing the coin game over.
+ lda Globals::zp_flags
+ ora #%00000010
+ sta Globals::zp_flags
+
+ @reset_timer:
+ ;; Reset the player's timer to enter the game screen again.
lda #PLAYER_TIMER_VALUE
sta zp_player_timer
diff --git a/src/jetpac.s b/src/jetpac.s
index 2e55771..5c1c099 100644
--- a/src/jetpac.s
+++ b/src/jetpac.s
@@ -46,6 +46,7 @@
.include "enemies.s"
.include "bullets.s"
.include "title.s"
+.include "over.s"
.include "driver.s"
.include "interrupts.s"
@@ -109,8 +110,10 @@
__fallthrough__ main
.endproc
-
.proc main
+ ;; TODO: score initialization has to happen here.
+
+@init:
;; Disable the PPU and zero out variables which shadow PPU registers.
lda #0
sta PPU::m_mask
@@ -140,6 +143,9 @@
;; Initialize the assets for the game.
jsr Assets::init
+ ;; Initialize some variables from the "Game Over" side of the game.
+ jsr Over::init
+
;; Initialize some PAL-specific constants.
.ifdef PAL
lda #0
@@ -209,8 +215,28 @@
jmp @main_game_loop
@over:
- ;; TODO: allow to start over, reset flags, control register, etc.
- jmp @over
+ ;; Display the "Game over" screen if it hasn't been displayed yet. After
+ ;; that, if we detect that the user wants to go back to the title screen we
+ ;; go back to @init to initialize everything again except for the score
+ ;; which should be preserved. Otherwise we go back to the main game loop,
+ ;; which effectively means to just sit and wait until for the right player
+ ;; input.
+ jsr Over::handle
+ sta Globals::zp_tmp0
+
+ ;; Wait for the PPU to render the screen.
+@set_flags_over:
+ lda #%10000000
+ ora Globals::zp_flags
+ sta Globals::zp_flags
+@wait_for_render_over:
+ bit Globals::zp_flags
+ bmi @wait_for_render_over
+
+ ;; Did the user want to start over?
+ lda Globals::zp_tmp0
+ beq @main_game_loop
+ jmp @init
.endproc
.segment "VECTORS"
diff --git a/src/over.s b/src/over.s
new file mode 100644
index 0000000..a2a0f9f
--- /dev/null
+++ b/src/over.s
@@ -0,0 +1,196 @@
+.segment "CODE"
+
+.scope Over
+ ;; Has the "Game over" screen been displayed yet?
+ zp_displayed = $10
+
+ ;; Timer set whenever the "Game over" screen has been displayed. Whenever it
+ ;; times out, then the player is redirected to the title screen.
+ zp_timer = $11
+
+ ;; Amount of time the player has to wait for the title screen to appear
+ ;; again.
+ TIMER_VALUE = HZ * 3
+
+ ;; Initialize all variables for the "Game over" screens.
+ .proc init
+ lda #0
+ sta Over::zp_displayed
+ sta Over::zp_timer
+
+ rts
+ .endproc
+
+ ;; Handle a "Game over" screen. It has two phases:
+ ;; 1. Render a "Game over" message.
+ ;; 2. Wait for a timer to time out.
+ ;; It will set 1 to the 'a' register if the timer has run out, signaling
+ ;; that the game can start over. Otherwise it sets 0 to the 'a' register.
+ .proc handle
+ ldy #0
+
+ ;; Has the "Game over" screen been displayed? If not do it now.
+ lda Over::zp_displayed
+ bne @do_handle
+ jsr Over::render
+ jmp @end
+
+ @do_handle:
+ lda Over::zp_timer
+ bne @dec_timer
+ iny
+ beq @end
+ @dec_timer:
+ dec Over::zp_timer
+
+ @end:
+ tya
+ rts
+ .endproc
+
+ ;; Render the "Game over" message to the screen. This is done in two
+ ;; phases. We first ensure to disable the PPU, and in the second phase we do
+ ;; the actual writing.
+ .proc render
+ ;; Is PPU disabled? If it is then jump into rendering the screen
+ ;; directly.
+ lda PPU::zp_mask
+ beq @do_render
+
+ ;; Nope! Force the PPU to be disabled and quit.
+ lda Globals::zp_flags
+ ora #%01000000
+ sta Globals::zp_flags
+ lda #$00
+ sta PPU::zp_mask
+ rts
+
+ @do_render:
+ jsr Over::clear_out_screen
+ ;; TODO: coin game over.
+ jsr Over::render_regular_game_over
+
+ ;; Enable back the PPU (only background).
+ lda #%00001110
+ sta PPU::zp_mask
+
+ ;; Update PPU registers.
+ lda #%01000000
+ ora Globals::zp_flags
+ sta Globals::zp_flags
+
+ ;; Set the "Game over" message as displayed and fire up the timer.
+ lda #1
+ sta Over::zp_displayed
+ lda #Over::TIMER_VALUE
+ sta Over::zp_timer
+
+ rts
+ .endproc
+
+ ;; Remove all platforms and the ground.
+ .proc clear_out_screen
+ ;; Remove left platform.
+ bit PPU::m_status
+ ldx #$29
+ stx PPU::m_address
+ ldx #$83
+ stx PPU::m_address
+ lda #$00
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+
+ ;; Remove center platform.
+ bit PPU::m_status
+ ldx #$29
+ stx PPU::m_address
+ ldx #$EF
+ stx PPU::m_address
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+
+ ;; Remove right platform.
+ bit PPU::m_status
+ ldx #$29
+ stx PPU::m_address
+ ldx #$38
+ stx PPU::m_address
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+
+ ;; Ground
+ bit PPU::m_status
+ ldx #$2B
+ stx PPU::m_address
+ ldx #$20
+ stx PPU::m_address
+
+ ldx #$20
+ @clear_ground_loop:
+ sta PPU::m_data
+ dex
+ bne @clear_ground_loop
+
+ rts
+ .endproc
+
+ ;; Render the regular "Game over player X" screen.
+ ;;
+ ;; TODO: multiplayer support.
+ .proc render_regular_game_over
+ ;; Set the position.
+ bit PPU::m_status
+ ldx #$29
+ stx PPU::m_address
+ ldx #$67
+ stx PPU::m_address
+
+ ;; And just iterate over the "message" until we reach the end of string
+ ;; $FF character.
+ ldx #0
+ @message_loop:
+ lda message, x
+ cmp #$FF
+ beq @out
+ sta PPU::m_data
+ inx
+ bne @message_loop
+
+ @out:
+ ;; Reset attributes for the end of the message.
+ bit PPU::m_status
+ ldx #$2B
+ stx PPU::m_address
+ ldx #$D5
+ stx PPU::m_address
+ lda #0
+ sta PPU::m_data
+ sta PPU::m_data
+ sta PPU::m_data
+
+ rts
+
+ message:
+ ;; "GAME "
+ .byte $21, $1B, $27, $1F, $00
+ ;; "OVER "
+ .byte $29, $30, $1F, $2C, $00
+ ;; "PLAYER "
+ .byte $2A, $26, $1B, $33, $1F, $2C, $00
+ ;; "1"
+ .byte $11, $FF
+ .endproc
+.endscope
diff --git a/src/player.s b/src/player.s
index 73ff20e..7e215a5 100644
--- a/src/player.s
+++ b/src/player.s
@@ -834,14 +834,19 @@
;; That's just german for "the Bart, the".
.proc die_bart_die
- ;; Decrement the life.
+ ;; Decrement the life. If we reach zero, then there's no point on
+ ;; signaling the NMI code to render this change.
+ ;;
;; TODO: this is just considering the first player only!.
dec Player::zp_lifes
- beq @over
+ beq @skip_life_update
+
+ ;; Notify NMI code to render lifes again, as they have changed.
lda Player::zp_state
ora #%00001000
sta Player::zp_state
+ @skip_life_update:
;; Move the player's sprites out of the screen.
ldx #0
lda #$FF
@@ -863,14 +868,5 @@
lda Player::zp_screen_x
sta Globals::zp_arg3
JAL Explosions::create
-
- @over:
- ;; Set the proper flag for game over.
- ;; TODO: game over (coin)
- lda Globals::zp_flags
- ora #%00000010
- sta Globals::zp_flags
-
- rts
.endproc
.endscope