aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mssola@mssola.com>2026-03-11 23:44:13 +0100
committerMiquel Sabaté Solà <mssola@mssola.com>2026-03-11 23:44:13 +0100
commit9ae51a4c210b8f01718e21eda592c498715a642b (patch)
tree90867f95c133b8c4383a9559075b73b77b92c98b /src
parenta0ef7b9c4d341de3f3f518626c40576e45cbf244 (diff)
downloadjetpac.nes-9ae51a4c210b8f01718e21eda592c498715a642b.tar.gz
jetpac.nes-9ae51a4c210b8f01718e21eda592c498715a642b.zip
Initial implementation for items
This now only supports the appearance of shuttle parts and the fact that the player can collect them at a very specific order and drop them so to stack up the final shuttle. This is of course just the skeleton and there's a bunch of TODO's left. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
Diffstat (limited to 'src')
-rw-r--r--src/assets.s2
-rw-r--r--src/driver.s42
-rw-r--r--src/interrupts.s18
-rw-r--r--src/items.s583
-rw-r--r--src/jetpac.s1
-rw-r--r--src/over.s47
-rw-r--r--src/player.s2
7 files changed, 682 insertions, 13 deletions
diff --git a/src/assets.s b/src/assets.s
index 139ed5f..18d6192 100644
--- a/src/assets.s
+++ b/src/assets.s
@@ -164,7 +164,7 @@
palettes:
;; Background
;; 0: score
- .byte $0F, $30, $2C, $28
+ .byte $0F, $30, $30, $28
;; 1: floating platforms
.byte $0F, $2C, $30, $2A
;; 2: ground
diff --git a/src/driver.s b/src/driver.s
index 7404b94..8b366b7 100644
--- a/src/driver.s
+++ b/src/driver.s
@@ -126,6 +126,9 @@
ora #%00001000
sta Player::zp_state
+ ;; Prepare the items for the scene.
+ jsr Items::prepare_scene
+
;; Mark the state of the game as "game". That is, the player has
;; started. Also set the `ppu` flag and unset the `title over` one.
lda #%01000001
@@ -159,6 +162,15 @@
dey
bne @bullets_reset_loop
+ ;; Invalidate all items.
+ ldx #0
+ ldy #Items::POOL_CAPACITY
+ @items_reset_loop:
+ sta Items::zp_pool_base, x
+ NEXT_ITEM_INDEX_X
+ dey
+ bne @items_reset_loop
+
;; Set that we have done this operation so it's not done in future
;; cycles.
lda #1
@@ -208,6 +220,7 @@
jsr Bullets::init
jsr Enemies::init
jsr Explosions::init
+ jsr Items::init
;; Initialize pause timer and some boolean values.
lda #0
@@ -286,6 +299,7 @@
jsr Enemies::update
@do_minimal_update:
jsr Explosions::update
+ jsr Items::update
;; Has the player died? If it is dead, then we need to remove all
;; sprites except for objects and explosions, and whenever
@@ -414,11 +428,24 @@
@set_next_enemies_cycle:
stx zp_next_enemy_cycle
- ;; TODO: ensure 1 item
- ;; iny
- ;; iny
- ;; iny
- ;; iny
+ ;; Allocate all valid items. Items, contrary to other sprites, don't get
+ ;; the special "you get a fixed first position" like others, mainly
+ ;; because there are so few of them on screen at any given time. For
+ ;; this reason as well, it's ok to just dump them all here before the
+ ;; rest of sprites are churned in.
+ ldx #0
+ @rest_o_items:
+ cpx #Items::POOL_CAPACITY_BYTES
+ beq @rest_o_bullets
+
+ lda Items::zp_pool_base, x
+ cmp #$FF
+ beq @next_item
+ jsr Items::allocate_x_y
+
+ @next_item:
+ NEXT_ITEM_INDEX_X
+ jmp @rest_o_items
;; Allocate the rest of valid bullets from the pool.
ldx #0
@@ -483,7 +510,7 @@
;; enemies, then jump to items. If the current indexed enemy is the one
;; we allocated as the first fixed one, then skip it.
cpx #Enemies::ENEMIES_POOL_CAPACITY_BYTES
- beq @rest_o_items
+ beq @do_explosions
cpx zp_first_enemy
beq @next_enemy
@@ -506,9 +533,6 @@
NEXT_ENEMY_INDEX_X
jmp @rest_o_enemies_loop
- @rest_o_items:
- ;;; TODO
-
;; At the very end, we allocate any active explosion.
@do_explosions:
ldx #0
diff --git a/src/interrupts.s b/src/interrupts.s
index c5eb306..81709ed 100644
--- a/src/interrupts.s
+++ b/src/interrupts.s
@@ -62,7 +62,7 @@
;; Do we need to update the lifes from players on the HUD?
lda Player::zp_state
and #%00001000
- beq @global_flags
+ beq @shuttle_update
;; Yeah!
@@ -97,9 +97,21 @@
and #%11110111
sta Player::zp_state
-@global_flags:
- ;; TODO: some actions here will depend on the status of the game...
+@shuttle_update:
+ ;; Should the shuttle be updated?
lda Globals::zp_flags
+ tax
+ and #%00100000
+ beq @game_status
+ jsr Items::update_shuttle
+
+ ;; And unset the flag.
+ lda Globals::zp_flags
+ and #%11011111
+ sta Globals::zp_flags
+
+@game_status:
+ txa
and #%00000001
bne @ppu_registers
diff --git a/src/items.s b/src/items.s
new file mode 100644
index 0000000..c66e293
--- /dev/null
+++ b/src/items.s
@@ -0,0 +1,583 @@
+.segment "CODE"
+
+;; Assuming that the 'x' register indexes an item on its pool, increment the
+;; register as many times as to point to the next one. Bound checking is not
+;; performed, it's up to the caller to implement that.
+.macro NEXT_ITEM_INDEX_X
+ inx
+ inx
+ inx
+.endmacro
+
+.scope Items
+ ;; Maximum amount of items allowed on screen at the same time.
+ POOL_CAPACITY = 3
+
+ ;; The amount of bytes each pool item takes.
+ SIZEOF_POOL_ITEM = 3
+
+ ;; The capacity of the items pool in bytes.
+ POOL_CAPACITY_BYTES = POOL_CAPACITY * SIZEOF_POOL_ITEM
+
+ ;; 1. State: $FF for invalid, otherwise:
+ ;; |PFD- CKKK|; where:
+ ;; |
+ ;; |- P: following the player
+ ;; |- F: falling.
+ ;; |- D: dropping: together with 'falling', but the player cannot re-grab it.
+ ;; |- C: 1: collectable (i.e. disappears on collision); 0: part (i.e. follows the player)
+ ;; |- K: object kind (00: high shuttle; 01: mid shuttle; 10: fuel; 11: regular item; 100: coin)
+ ;;
+ ;; 2. Y coordinate.
+ ;; 3. X coordinate.
+ zp_pool_base = $C0 ; asan:reserve POOL_CAPACITY_BYTES
+
+ ;; Preserves the index on 'zp_pool_base' in Items::update().
+ zp_pool_index = $C9
+
+ ;; TODO: stabilize and document.
+ ;;
+ ;; Y tile | X tile | palette
+ zp_current_tiles = $E7 ; asan:reserve POOL_CAPACITY_BYTES
+
+ ;;
+ ;; TODO: stabilize and document.
+ ;;
+ ;; |G--- FFAA|
+ ;; |
+ ;; |- G: the player is grabbing an item
+ ;; |- F: number of falling items.
+ ;; |- A: number of active items.
+ zp_state = $CA
+
+ ;; Number of shuttle parts (or fuel tanks) that have been collected so far.
+ zp_collected = $CB
+
+ ;; Coordinate where the dropping of items takes place. This comes in two
+ ;; versions, as the "collision" is done in the tile coordinates so to give
+ ;; some leeway to the player; but the dropping itself has to fall from the
+ ;; exact screen coordinates or otherwise the dropping would feel weird.z
+ DROPPING_SCREEN_X = $A8
+ DROPPING_TILE_X = $15
+
+ ;; Y screen coordinates in order for various parts to be considered as
+ ;; "collected".
+ MID_SHUTTLE_Y = $A7
+ HIGH_SHUTTLE_Y = $97
+ FUEL_SHUTTLE_Y = $C7
+
+ .proc init
+ lda Globals::zp_level_kind
+ bne @other_screens
+ JAL Items::init_first_screen
+
+ @other_screens:
+ ;; TODO
+
+ rts
+ .endproc
+
+ ;; TODO: this is only to be done for the first time we enter. Otherwise this
+ ;; will be reset every time.
+ .proc init_first_screen
+ ;; We are going to allocate two shuttle parts, and hence two items.
+ lda #2
+ sta Items::zp_state
+
+ ;; We haven't collected anything yet, but it's convenient for us to mock
+ ;; that the ship part on the right side of the screen is actually
+ ;; collected.
+ lda #1
+ sta Items::zp_collected
+
+ ;; State of the top part of the shuttle.
+ ldx #0
+ ldy #0
+ sty Items::zp_pool_base, x
+
+ ;; Screen and tile coordinates for the top part of the shuttle.
+ lda #$4F
+ sta Items::zp_pool_base + 1, x
+ lsr
+ lsr
+ lsr
+ sta Items::zp_current_tiles, x
+ lda #$29
+ sta Items::zp_pool_base + 2, x
+ lsr
+ lsr
+ lsr
+ sta Items::zp_current_tiles + 1, x
+
+ ;; State of the middle part of the shuttle.
+ iny
+ sty Items::zp_pool_base + 3, x
+
+ ;; Screen and tile coordinates for the middle part of the shuttle.
+ lda #$67
+ sta Items::zp_pool_base + 4, x
+ lsr
+ lsr
+ lsr
+ sta Items::zp_current_tiles + 3, x
+ lda #$81
+ sta Items::zp_pool_base + 5, x
+ lsr
+ lsr
+ lsr
+ sta Items::zp_current_tiles + 4, x
+
+ ;; Invalidte the third item.
+ ldy #$FF
+ sty Items::zp_pool_base + 6, x
+
+ ;; Palettes.
+ lda #0
+ sta Items::zp_current_tiles + 2, x
+ sta Items::zp_current_tiles + 6, x
+
+ rts
+ .endproc
+
+ ;; Allocate an item indexed by 'x' from the `zp_pool_base` buffer, and set
+ ;; it to OAM-reserved space indexed via 'y'.
+ ;;
+ ;; The 'y' register will be updated by increasing its value by 16,
+ ;; indicating the amount of bytes allocated in OAM space.
+ ;;
+ ;; The 'x' register will be _preserved_.
+ ;;
+ ;; NOTE: this function assumes that the item is in a valid state. That's up
+ ;; to the caller to check before calling this function.
+ .proc allocate_x_y
+ lda Items::zp_pool_base, x
+ and #$07
+
+ ;; Should we allocate a part from the shuttle?
+ bne @try_next_shuttle
+ lda #$04
+ JAL allocate_shuttle_x_y
+ @try_next_shuttle:
+ cmp #$01
+ bne @try_fuel
+ lda #$06
+ JAL allocate_shuttle_x_y
+
+ @try_fuel:
+ ;; TODO: validate whether we need to save/restore the 'x' register.
+ stx Globals::zp_tmp3
+ ;; TODO
+ ldx Globals::zp_tmp3
+ rts
+ .endproc
+
+ ;; Allocate a shuttle part on the same terms as
+ ;; Items::allocate_shuttle_x_y().
+ .proc allocate_shuttle_x_y
+ sta Globals::zp_tmp0
+
+ ;; Y coordinates
+ lda Items::zp_pool_base + 1, x
+ sta OAM::m_sprites, y ; top left
+ sta OAM::m_sprites + 4, y ; top right
+ clc
+ adc #8
+ sta OAM::m_sprites + 8, y ; bottom left
+ sta OAM::m_sprites + 12, y ; bottom right
+
+ ;; Tile IDs
+ lda Globals::zp_tmp0
+ sta OAM::m_sprites + 1, y ; top left
+ clc
+ adc #1
+ sta OAM::m_sprites + 5, y ; top right
+
+ lda Globals::zp_tmp0
+ clc
+ adc #$10
+ sta OAM::m_sprites + 9, y ; bottom left
+ clc
+ adc #1
+ sta OAM::m_sprites + 13, y ; bottom right
+
+ ;; Attributes
+ lda #0
+ sta OAM::m_sprites + 2, y ; top left
+ sta OAM::m_sprites + 6, y ; top right
+ sta OAM::m_sprites + 10, y ; bottom left
+ sta OAM::m_sprites + 14, y ; bottom right
+
+ ;; X coordinates.
+ lda Items::zp_pool_base + 2, x ; top left
+ sta OAM::m_sprites + 3, y
+ sta OAM::m_sprites + 11, y ; bottom left
+ clc
+ adc #8
+ sta OAM::m_sprites + 7, y ; top right
+ sta OAM::m_sprites + 15, y ; bottom right
+
+ ;; And update the 'y' register.
+ tya
+ clc
+ adc #16
+ tay
+
+ rts
+ .endproc
+
+ .proc update
+ ldx #0
+
+ ldy #POOL_CAPACITY
+ sty Globals::zp_idx
+
+ ;; The player's coordinates are cached into arguments in memory so they
+ ;; can be used for collision checking. Note that we are targetting for
+ ;; the center of the player, which feels at a fair point for item
+ ;; interactions.
+ lda Player::zp_screen_y
+ clc
+ adc #Player::PLAYER_WAIST
+ lsr
+ lsr
+ lsr
+ sta Globals::zp_arg0
+ lda Player::zp_screen_x
+ lsr
+ lsr
+ lsr
+ clc
+ adc #1
+ sta Globals::zp_arg1
+
+ @loop:
+ ;; TODO: check how relevant this really is.
+ stx Items::zp_pool_index
+
+ ;; Is it valid?
+ lda Items::zp_pool_base, x
+ cmp #$FF
+ bne @check_status
+ jmp @next
+
+ @check_status:
+ ;; If it's resting, then just check for collision. Otherwise, we either
+ ;; fall/drop or follow the player.
+ and #$C0
+ beq @check_collision
+ cmp #$40
+ beq @do_fall
+
+ ;;;
+ ;; Follow the player.
+
+ ;; Neither of the above. Then, just follow the player.
+ lda Player::zp_screen_y
+ clc
+ adc #8
+ sta Items::zp_pool_base + 1, x
+ lda Player::zp_screen_x
+ sta Items::zp_pool_base + 2, x
+
+ ;; Are we at the zone where we must drop items?
+ ldy Globals::zp_arg1
+ dey
+ cpy #DROPPING_TILE_X
+ beq @drop
+ jmp @next
+
+ @drop:
+ ;; Yeah! Then the item stops being in 'following player' mode and is
+ ;; dropped (F & D set).
+ lda Items::zp_pool_base, x
+ and #$7F
+ ora #%01100000
+ sta Items::zp_pool_base, x
+
+ ;; Unset the 'grabbing' bit and increase the number of falling items.
+ lda Items::zp_state
+ and #$7F
+ clc
+ adc #$04
+ sta Items::zp_state
+
+ ;; And we force the item to be on the exact X screen position so to
+ ;; adjust from the player's subpixel movement.
+ lda #DROPPING_SCREEN_X
+ sta Items::zp_pool_base + 2, x
+
+ jmp @next
+
+ ;;;
+ ;; Fall/drop.
+
+ @do_fall:
+ ;; Update the Y coordinate so the item is falling.
+ inc Items::zp_pool_base + 1, x
+
+ ;; Is the item being dropped? If not, then we just check for collision.
+ lda Items::zp_pool_base, x
+ and #$20
+ beq @check_collision
+
+ ;; This is a fuel tank or a shuttle part that is aligned with the
+ ;; shuttle platform. We will load in 'a' the exact screen coordinates
+ ;; where each part should stop.
+ lda Items::zp_pool_base, x
+ and #$07
+ beq @high_shuttle
+ cmp #1
+ beq @mid_shuttle
+ lda #FUEL_SHUTTLE_Y
+ bne @drop_check
+ @mid_shuttle:
+ lda #MID_SHUTTLE_Y
+ bne @drop_check
+ @high_shuttle:
+ lda #HIGH_SHUTTLE_Y
+
+ @drop_check:
+ ;; Does this item reach its dropping limit? If not just go to the next
+ ;; item.
+ ;; TODO: It should also work for "greater than".
+ cmp Items::zp_pool_base + 1, x
+ bne @next
+
+ ;; Enable the 'ppu' and the 'shuttle' flags.
+ lda Globals::zp_flags
+ ora #%01100000
+ sta Globals::zp_flags
+
+ ;; Decrease the number of falling/active items.
+ lda Items::zp_state
+ sec
+ sbc #$05 ; NOTE: $04 (falling) + $01 (active)
+ sta Items::zp_state
+
+ ;; Increase the number of collected items.
+ inc Items::zp_collected
+
+ ;; And invalidate this item.
+ lda #$FF
+ sta Items::zp_pool_base, x
+
+ ;; All collision checks that were needed for 'collision' mode have been
+ ;; done. We can just move to the next item.
+ jmp @next
+
+ ;;;
+ ;; Collision checks.
+
+ @check_collision:
+ ;; Collision with the player.
+ jsr Items::collides_with_player
+ beq @next
+ ;; TODO: background collision (when the item is not grabbed): if it
+ ;; happens, then the P, F, D are set to 0. The number of falling items
+ ;; is also decreased.
+
+ ;; A collision happened! Get collected or follow the player (if possible).
+ lda Items::zp_pool_base, x
+ tay
+ and #$08
+ beq @try_to_follow_player
+ jsr Items::collect
+ jmp @next
+
+ @try_to_follow_player:
+ ;; If the player is already grabbing another item, don't even try it.
+ bit Items::zp_state
+ bmi @next
+
+ ;; We don't need extra precautions except when the level kind is the
+ ;; first one. In that case we must guarantee the right shuttle order.
+ lda Globals::zp_level_kind
+ bne @do_follow_player
+
+ ;; Is this the first shuttle part to be collected?
+ lda Items::zp_collected
+ cmp #1
+ bne @do_follow_player
+
+ ;; Yes! Then it _must_ be the middle part.
+ lda Items::zp_pool_base, x
+ and #$07
+ cmp #$01
+ bne @next
+
+ @do_follow_player:
+ ;; TODO: If F was set, unset it and subtract the number of falling items.
+
+ ;; Mark this item to be in 'following' mode.
+ tya
+ ora #$80
+ sta Items::zp_pool_base, x
+
+ ;; Mark the player's to be already grabbing an item.
+ lda Items::zp_state
+ ora #$80
+ sta Items::zp_state
+
+ @next:
+ NEXT_ITEM_INDEX_X
+ dec Globals::zp_idx
+ beq @end
+ jmp @loop
+
+ @end:
+ rts
+ .endproc
+
+ ;; TODO: this assumes a 4-sprite item
+ .proc collides_with_player
+ ldx Items::zp_pool_index
+ lda Items::zp_current_tiles, x
+ cmp #$FF
+ beq @no
+
+ ;; Check for the Y tile coordinate. If it's not the same on either the
+ ;; upper or the bottom parts of the item, then it's a no.
+ cmp Globals::zp_arg0
+ beq @check_x
+ clc
+ adc #1
+ cmp Globals::zp_arg0
+ bne @no
+
+ @check_x:
+ ;; If the Y tile coordinate checks out, let's narrow it down to the X
+ ;; coordinate.
+ lda Items::zp_current_tiles + 1, x
+ cmp Globals::zp_arg1
+ beq @yes
+ clc
+ adc #1
+ cmp Globals::zp_arg1
+ bne @no
+
+ @yes:
+ lda #1
+ rts
+ @no:
+ lda #0
+ rts
+ .endproc
+
+ ;; TODO: guarantee 'x' and 'y' safety
+ .proc collect
+ ;; TODO
+ rts
+ .endproc
+
+ ;; Prepare the background scenary for items. Namely, the rocket parts which
+ ;; belong to the background.
+ ;;
+ ;; NOTE: this has to be called with the PPU disabled.
+ .proc prepare_scene
+ ;; The low part of the rocket.
+ bit PPU::m_status
+ lda #$2A
+ sta PPU::m_address
+ lda #$F5
+ sta PPU::m_address
+ ldx #$0C
+ stx PPU::m_data
+ inx
+ stx PPU::m_data
+
+ lda #$2B
+ sta PPU::m_address
+ lda #$15
+ sta PPU::m_address
+ inx
+ stx PPU::m_data
+ inx
+ stx PPU::m_data
+
+ lda Globals::zp_level_kind
+ beq @end
+
+ @rest_of_the_rocket:
+ jsr draw_high_part_shuttle
+ jsr draw_middle_part_shuttle
+
+ @end:
+ rts
+ .endproc
+
+ ;; Update the background scenary for the shuttle.
+ ;;
+ ;; NOTE: this has to be called with the PPU disabled.
+ .proc update_shuttle
+ lda Globals::zp_level_kind
+ bne @fuel
+
+ ;; Update the shuttle.
+ lda Items::zp_collected
+ cmp #3
+ bne @mid_shuttle
+ jsr draw_high_part_shuttle
+ @mid_shuttle:
+ jsr draw_middle_part_shuttle
+ rts
+
+ @fuel:
+ ;; TODO
+
+ rts
+ .endproc
+
+ ;; Update the background scenary to show the middle part of the shuttle.
+ ;;
+ ;; NOTE: this has to be called with the PPU disabled.
+ .proc draw_middle_part_shuttle
+ ldx #$08
+ ldy #$2A
+
+ bit PPU::m_status
+ sty PPU::m_address
+ lda #$B5
+ sta PPU::m_address
+ stx PPU::m_data
+ inx
+ stx PPU::m_data
+
+ bit PPU::m_status
+ sty PPU::m_address
+ lda #$D5
+ sta PPU::m_address
+ inx
+ stx PPU::m_data
+ inx
+ stx PPU::m_data
+
+ rts
+ .endproc
+
+ ;; Update the background scenary to show the high part of the shuttle.
+ ;;
+ ;; NOTE: this has to be called with the PPU disabled.
+ .proc draw_high_part_shuttle
+ ldx #$04
+ ldy #$2A
+
+ bit PPU::m_status
+ sty PPU::m_address
+ lda #$75
+ sta PPU::m_address
+ stx PPU::m_data
+ inx
+ stx PPU::m_data
+
+ bit PPU::m_status
+ sty PPU::m_address
+ lda #$95
+ sta PPU::m_address
+ inx
+ stx PPU::m_data
+ inx
+ stx PPU::m_data
+
+ rts
+ .endproc
+.endscope
diff --git a/src/jetpac.s b/src/jetpac.s
index 685c317..d2ed90b 100644
--- a/src/jetpac.s
+++ b/src/jetpac.s
@@ -45,6 +45,7 @@
.include "player.s"
.include "enemies.s"
.include "bullets.s"
+.include "items.s"
.include "title.s"
.include "over.s"
.include "driver.s"
diff --git a/src/over.s b/src/over.s
index 6d8ed8d..cb59ef8 100644
--- a/src/over.s
+++ b/src/over.s
@@ -144,6 +144,53 @@
dex
bne @clear_ground_loop
+ ;; The low part of the rocket.
+ bit PPU::m_status
+ ldx #$2B
+ stx PPU::m_address
+ ldx #$15
+ stx PPU::m_address
+ sta PPU::m_data
+ sta PPU::m_data
+
+ ;; High part of the rocket.
+ bit PPU::m_status
+ ldy #$2A
+ sty PPU::m_address
+ ldx #$75
+ stx PPU::m_address
+ sta PPU::m_data
+ sta PPU::m_data
+
+ bit PPU::m_status
+ sty PPU::m_address
+ ldx #$95
+ stx PPU::m_address
+ sta PPU::m_data
+ sta PPU::m_data
+
+ bit PPU::m_status
+ sty PPU::m_address
+ ldx #$B5
+ stx PPU::m_address
+ sta PPU::m_data
+ sta PPU::m_data
+
+ ;; Middle part of the rocket.
+ bit PPU::m_status
+ sty PPU::m_address
+ ldx #$D5
+ stx PPU::m_address
+ sta PPU::m_data
+ sta PPU::m_data
+
+ bit PPU::m_status
+ sty PPU::m_address
+ ldx #$F5
+ stx PPU::m_address
+ sta PPU::m_data
+ sta PPU::m_data
+
rts
.endproc
diff --git a/src/player.s b/src/player.s
index 08f7872..48b0bb0 100644
--- a/src/player.s
+++ b/src/player.s
@@ -841,6 +841,8 @@
dec Player::zp_lifes, x
bne @nmi_update
+ ;; TODO: if it was grabbing an item, turn it into 'falling' state.
+
;; If this poor guy is over, then mark it in the multiplayer bitmap.
cpx #0
bne @player_2_over