Skip to content

Commit

Permalink
Merge pull request #14 from boingoing/title_cursor
Browse files Browse the repository at this point in the history
Add a cursor sprite to the title screen for selecting the player count
  • Loading branch information
boingoing authored Apr 23, 2023
2 parents ba72516 + 4783461 commit f462a5d
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 106 deletions.
45 changes: 43 additions & 2 deletions jeznes.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ void main(void) {
// Clear all sprites from the sprite buffer.
oam_clear();

// Handle player pressing select.
title_change_mode();
// Handle player pressing start.
start_game();
title_press_start();

// Draw the cursor on the title screen.
draw_title_cursor();
} else if (game_state == GAME_STATE_PLAYING) {
// Clear all sprites from the sprite buffer.
oam_clear();
Expand Down Expand Up @@ -123,18 +128,28 @@ void init_title(void) {
vram_adr(NAMETABLE_A);
vram_unrle(title_screen);

// By default, select the "1 Player" option.
set_title_mode(TITLE_1_PLAYER);

// Starting or returning to the title screen.
game_state = GAME_STATE_TITLE;
}

void start_game(void) {
void title_press_start(void) {
if (pads[0] & PAD_START) {
if (get_player_is_pause_pressed(0)) {
return;
}

set_player_is_pause_pressed(0);

if (get_title_mode() == TITLE_1_PLAYER) {
player_count = 1;
} else {
// get_title_mode() == TITLE_2_PLAYER
player_count = 2;
}

// Fade to black
pal_fade_to(4, 0);
// Screen off
Expand All @@ -151,6 +166,24 @@ void start_game(void) {
}
}

void title_change_mode(void) {
if (pads[0] & PAD_SELECT) {
// Ignore the mode change if player holds the button.
if (get_player_is_select_pressed(0)) {
return;
}

// Track player is holding the button.
set_player_is_select_pressed(0);

// Toggle game over mode between retry and quit.
set_title_mode(get_title_mode() ^ 1);
} else {
// No longer holding down the button.
unset_player_is_select_pressed(0);
}
}

void init_game(void) {
static unsigned char player_default_x[2] = {0x56, 0x96};
static unsigned char player_default_y[2] = {0x46, 0x86};
Expand Down Expand Up @@ -484,6 +517,14 @@ void draw_tile_highlight(unsigned char player_index) {
}
}

void draw_title_cursor(void) {
if (get_title_mode() == TITLE_1_PLAYER) {
oam_spr(TITLE_CURSOR_1_PLAYER_X, TITLE_CURSOR_1_PLAYER_Y, TILE_INDEX_TILE_HIGHLIGHT, 1);
} else {
oam_spr(TITLE_CURSOR_2_PLAYERS_X, TITLE_CURSOR_2_PLAYERS_Y, TILE_INDEX_TILE_HIGHLIGHT, 1);
}
}

void draw_game_over_cursor(void) {
if (get_game_over_mode() == GAME_OVER_RETRY) {
oam_spr(GAME_OVER_CURSOR_RETRY_X, GAME_OVER_CURSOR_RETRY_Y, TILE_INDEX_TILE_HIGHLIGHT, 1);
Expand Down
226 changes: 122 additions & 104 deletions jeznes.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,66 +43,125 @@
#define HUD_TARGET_DISPLAY_TILE_X 18
#define HUD_TARGET_DISPLAY_TILE_Y 25

// Cursor sprite location for the title screen
#define TITLE_CURSOR_1_PLAYER_X 0x58
#define TITLE_CURSOR_1_PLAYER_Y 0xa8
#define TITLE_CURSOR_2_PLAYERS_X 0x58
#define TITLE_CURSOR_2_PLAYERS_Y 0xb8

// Cursor sprite location for the game over screen
#define GAME_OVER_CURSOR_RETRY_X 0x72
#define GAME_OVER_CURSOR_RETRY_X 0x70
#define GAME_OVER_CURSOR_RETRY_Y 0xc0
#define GAME_OVER_CURSOR_QUIT_X 0x72
#define GAME_OVER_CURSOR_QUIT_X 0x70
#define GAME_OVER_CURSOR_QUIT_Y 0xd0

// These macros enable various debugging features and should probably be turned off before release
#define DEBUG 1
#define DRAW_GRAY_LINE 1
#define DRAW_BALL_NEAREST_TILE_HIGHLIGHT 1

#define make_word(lo,hi) ((lo)|(hi << 8))

#define get_ball_count() (current_level+1)
#define get_player_count() (1)

#define get_playfield_index() (temp_int_3)
#define set_playfield_index(a) (temp_int_3 = (a))
#define inc_playfield_index() (++temp_int_3)

// Calculate the playfield tile position in (x,y) of the playfield tile |i|.
#define playfield_index_x(i) ((i)%32)
#define playfield_index_y(i) ((i)>>5)

// Calculate the bg tile position in pixel coords of the playfield tile |i|.
#define playfield_index_pixel_coord_x(i) (playfield_index_x((i)+PLAYFIELD_FIRST_TILE_INDEX)<<3)
#define playfield_index_pixel_coord_y(i) (playfield_index_y((i)+PLAYFIELD_FIRST_TILE_INDEX)<<3)
enum {
GAME_STATE_TITLE,
GAME_STATE_PLAYING,
GAME_STATE_LEVEL_UP,
GAME_STATE_GAME_OVER,
GAME_STATE_UPDATING_PLAYFIELD,
GAME_STATE_REQUEST_HUD_UPDATE
};

enum {
ORIENTATION_HORIZ,
ORIENTATION_VERT
};

enum {
LINE_DIRECTION_POSITIVE,
LINE_DIRECTION_NEGATIVE
};

enum {
PLAYFIELD_UNCLEARED,
PLAYFIELD_WALL,
PLAYFIELD_LINE
};

enum {
GAME_OVER_RETRY,
GAME_OVER_QUIT
};

#define get_game_over_mode() (temp_byte_6)
#define set_game_over_mode(a) (temp_byte_6 = (a))
enum {
TITLE_1_PLAYER,
TITLE_2_PLAYERS
};

struct Player {
// Player metasprite location in pixel-coords
unsigned char x;
unsigned char y;

// Pixel-coords of nearest bg tile under the player
unsigned char nearest_tile_x;
unsigned char nearest_tile_y;

// Playfield tile index for nearest tile
int nearest_playfield_tile;

// Hold bit-flags used to track state of this player.
unsigned char flags;
};

struct Ball {
// Ball sprite location in pixel-coords
unsigned char x;
unsigned char y;

signed char x_velocity;
signed char y_velocity;

// Playfield tile index for nearest tile
int nearest_playfield_tile;
};

struct Line {
// Origin playfield tile index for the line.
// This is the tile on which the player pressed the start line button.
// For the game, the origin tile is always part of the line segment which
// spreads in the negative direction and the tile to the right
// (for ORIENTATION_HORIZ lines) or the tile below it (for ORIENTATION_VERT
// lines) is where the line segment which spreads in the positive direction
// begins.
int origin;

// How many steps away from the origin playfield tiles have we taken?
unsigned char tile_step_count;

// Completion of the current block [0-7]
unsigned char current_block_completion;

// Hold bit-flags used to track state of this line.
unsigned char flags;
};

// Used by sprite collision detection code.
struct ObjectBase {
unsigned char x;
unsigned char y;
unsigned char width;
unsigned char height;
};

#pragma bss-name(push, "ZEROPAGE")

// Placeholder to track how many bytes are unused in the zeropage.
unsigned char unused_zp_bytes[13];
unsigned char unused_zp_bytes[12];

unsigned char pads[MAX_PLAYERS];
unsigned char pads_new[MAX_PLAYERS];

enum {
GAME_STATE_TITLE,
GAME_STATE_PLAYING,
GAME_STATE_LEVEL_UP,
GAME_STATE_GAME_OVER,
GAME_STATE_UPDATING_PLAYFIELD,
GAME_STATE_REQUEST_HUD_UPDATE
};

unsigned char game_state;
unsigned char current_level;
unsigned char player_count;
unsigned char lives_count;
unsigned char cleared_tile_percentage;
unsigned int cleared_tile_count;
Expand All @@ -122,6 +181,33 @@ int temp_int_2;
int temp_int_3;
int temp_int_4;

struct Player players[MAX_PLAYERS];
struct Ball balls[MAX_BALLS];
struct Line lines[MAX_PLAYERS];

#define make_word(lo,hi) ((lo)|(hi << 8))

#define get_ball_count() (current_level+1)
#define get_player_count() (player_count)

#define get_playfield_index() (temp_int_3)
#define set_playfield_index(a) (temp_int_3 = (a))
#define inc_playfield_index() (++temp_int_3)

#define get_game_over_mode() (temp_byte_6)
#define set_game_over_mode(a) (temp_byte_6 = (a))

#define get_title_mode() (temp_byte_6)
#define set_title_mode(a) (temp_byte_6 = (a))

// Calculate the playfield tile position in (x,y) of the playfield tile |i|.
#define playfield_index_x(i) ((i)%32)
#define playfield_index_y(i) ((i)>>5)

// Calculate the bg tile position in pixel coords of the playfield tile |i|.
#define playfield_index_pixel_coord_x(i) (playfield_index_x((i)+PLAYFIELD_FIRST_TILE_INDEX)<<3)
#define playfield_index_pixel_coord_y(i) (playfield_index_y((i)+PLAYFIELD_FIRST_TILE_INDEX)<<3)

#define get_flag(flags_byte, bitmask) (((flags_byte) & (bitmask)) != 0)
#define set_flag(flags_byte, bitmask) ((flags_byte) |= (bitmask))
#define unset_flag(flags_byte, bitmask) ((flags_byte) &= ~(bitmask))
Expand Down Expand Up @@ -163,38 +249,6 @@ int temp_int_4;
// Sets the orientation for |player_index| player to |orientation| which must be either ORIENTATION_HORIZ or ORIENTATION_VERT
#define set_player_orientation_flag(player_index, orientation) (players[(player_index)].flags = players[(player_index)].flags & ~LINE_BITMASK_ORIENTATION | (orientation))

struct Player {
// Player metasprite location in pixel-coords
unsigned char x;
unsigned char y;

// Pixel-coords of nearest bg tile under the player
unsigned char nearest_tile_x;
unsigned char nearest_tile_y;

// Playfield tile index for nearest tile
int nearest_playfield_tile;

// Hold bit-flags used to track state of this player.
unsigned char flags;
};

struct Player players[MAX_PLAYERS];

struct Ball {
// Ball sprite location in pixel-coords
unsigned char x;
unsigned char y;

signed char x_velocity;
signed char y_velocity;

// Playfield tile index for nearest tile
int nearest_playfield_tile;
};

struct Ball balls[MAX_BALLS];

#define LINE_BIT_ORIENTATION 0
#define LINE_BITMASK_ORIENTATION (1 << LINE_BIT_ORIENTATION)
#define LINE_BIT_IS_STARTED 1
Expand Down Expand Up @@ -231,42 +285,6 @@ struct Ball balls[MAX_BALLS];
// Indicate the line segment front tile completion via |completion| which should be [0,7].
#define get_line_sprite_index(orientation, completion) (SPRITE_INDEX_PLAYFIELD_LINE_HORIZ_BASE + (completion) + 0x10 * (orientation))

struct Line {
// Origin playfield tile index for the line.
// This is the tile on which the player pressed the start line button.
// For the game, the origin tile is always part of the line segment which
// spreads in the negative direction and the tile to the right
// (for ORIENTATION_HORIZ lines) or the tile below it (for ORIENTATION_VERT
// lines) is where the line segment which spreads in the positive direction
// begins.
int origin;

// How many steps away from the origin playfield tiles have we taken?
unsigned char tile_step_count;

// Completion of the current block [0-7]
unsigned char current_block_completion;

// Hold bit-flags used to track state of this line.
unsigned char flags;
};

struct Line lines[MAX_PLAYERS];

#pragma bss-name(push, "BSS")

struct ObjectBase {
unsigned char x;
unsigned char y;
unsigned char width;
unsigned char height;
};

enum {
LINE_DIRECTION_POSITIVE,
LINE_DIRECTION_NEGATIVE
};

#define PLAYFIELD_BIT_LINE_ORIENTATION 7
#define PLAYFIELD_BITMASK_LINE_ORIENTATION (1 << PLAYFIELD_BIT_LINE_ORIENTATION)
#define PLAYFIELD_BIT_LINE_INDEX 6
Expand Down Expand Up @@ -330,11 +348,8 @@ enum {
// Indicate horizontal or vertical via |orientation| which should be ORIENTATION_HORIZ or ORIENTATION_VERT.
#define get_playfield_bg_tile_line(orientation) (TILE_INDEX_PLAYFIELD_LINE_HORIZ + (orientation))

enum {
PLAYFIELD_UNCLEARED,
PLAYFIELD_WALL,
PLAYFIELD_LINE
};
#pragma bss-name(push, "BSS")

unsigned char playfield[PLAYFIELD_WIDTH * PLAYFIELD_HEIGHT];

#define STACK_MAX_HEIGHT 0x90
Expand All @@ -343,10 +358,13 @@ unsigned int stack[STACK_MAX_HEIGHT];
unsigned char stack_top;
unsigned int stack_temp;

// Must be included under BSS section
#include "graphics.h"

void init_title(void);
void start_game(void);
void title_change_mode(void);
void title_press_start(void);
void draw_title_cursor(void);

void init_game(void);
void reset_playfield(void);
Expand Down

0 comments on commit f462a5d

Please sign in to comment.