diff --git a/src/chat_commands.c b/src/chat_commands.c index 2021404..7c13bcf 100644 --- a/src/chat_commands.c +++ b/src/chat_commands.c @@ -179,12 +179,6 @@ void cmd_game_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg UNUSED_VAR(window); UNUSED_VAR(m); - bool force_small = false; - - if (argc >= 2) { - force_small = strcasecmp(argv[2], "small") == 0; - } - if (!Friends.list[self->num].game_invite.pending) { line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending game invite."); return; @@ -200,7 +194,7 @@ void cmd_game_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg uint8_t *data = Friends.list[self->num].game_invite.data; size_t length = Friends.list[self->num].game_invite.data_length; - int ret = game_initialize(self, m, type, id, data, length, force_small); + int ret = game_initialize(self, m, type, id, data, length); switch (ret) { case 0: { diff --git a/src/game_base.c b/src/game_base.c index 90cd026..c84e87d 100644 --- a/src/game_base.c +++ b/src/game_base.c @@ -55,17 +55,17 @@ extern struct user_settings *user_settings; /* Determines if window is large enough for a respective window type */ -#define WINDOW_SIZE_LARGE_SQUARE_VALID(max_x, max_y)((((max_y) - 4) >= (GAME_MAX_SQUARE_Y))\ - && ((max_x) >= (GAME_MAX_SQUARE_X))) +#define WINDOW_SIZE_SQUARE_VALID(max_x, max_y)((((max_y) - 4) >= (GAME_MAX_SQUARE_Y_DEFAULT))\ + && ((max_x) >= (GAME_MAX_SQUARE_X_DEFAULT))) -#define WINDOW_SIZE_SMALL_SQUARE_VALID(max_x, max_y)((((max_y) - 4) >= (GAME_MAX_SQUARE_Y_SMALL))\ - && ((max_x) >= (GAME_MAX_SQUARE_X_SMALL))) +#define WINDOW_SIZE_LARGE_SQUARE_VALID(max_x, max_y)((((max_y) - 4) >= (GAME_MAX_SQUARE_Y_LARGE))\ + && ((max_x) >= (GAME_MAX_SQUARE_X_LARGE))) -#define WINDOW_SIZE_LARGE_RECT_VALID(max_x, max_y)((((max_y) - 4) >= (GAME_MAX_RECT_Y))\ - && ((max_x) >= (GAME_MAX_RECT_X))) +#define WINDOW_SIZE_RECT_VALID(max_x, max_y)((((max_y) - 4) >= (GAME_MAX_RECT_Y_DEFAULT))\ + && ((max_x) >= (GAME_MAX_RECT_X_DEFAULT))) -#define WINDOW_SIZE_SMALL_RECT_VALID(max_x, max_y)((((max_y) - 4) >= (GAME_MAX_RECT_Y_SMALL))\ - && ((max_x) >= (GAME_MAX_RECT_X_SMALL))) +#define WINDOW_SIZE_LARGE_RECT_VALID(max_x, max_y)((((max_y) - 4) >= (GAME_MAX_RECT_Y_LARGE))\ + && ((max_x) >= (GAME_MAX_RECT_X_LARGE))) static ToxWindow *game_new_window(Tox *m, GameType type, uint32_t friendnumber); @@ -229,7 +229,7 @@ static int game_initialize_type(GameData *game, const uint8_t *data, size_t leng } int game_initialize(const ToxWindow *parent, Tox *m, GameType type, uint32_t id, const uint8_t *multiplayer_data, - size_t length, bool force_small_window) + size_t length) { int max_x; int max_y; @@ -237,22 +237,6 @@ int game_initialize(const ToxWindow *parent, Tox *m, GameType type, uint32_t id, max_y -= (CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT); - int max_game_window_x = GAME_MAX_SQUARE_X; - int max_game_window_y = GAME_MAX_SQUARE_Y; - - if (!force_small_window && !WINDOW_SIZE_LARGE_SQUARE_VALID(max_x, max_y)) { - return -1; - } - - if (force_small_window) { - max_game_window_x = GAME_MAX_SQUARE_X_SMALL; - max_game_window_y = GAME_MAX_SQUARE_Y_SMALL; - - if (!WINDOW_SIZE_SMALL_SQUARE_VALID(max_x, max_y)) { - return -1; - } - } - ToxWindow *self = game_new_window(m, type, parent->num); if (self == NULL) { @@ -287,8 +271,6 @@ int game_initialize(const ToxWindow *parent, Tox *m, GameType type, uint32_t id, game->tox = m; game->window_shape = GW_ShapeSquare; - game->game_max_x = max_game_window_x; - game->game_max_y = max_game_window_y; game->parent_max_x = max_x; game->parent_max_y = max_y; game->update_interval = GAME_DEFAULT_UPDATE_INTERVAL; @@ -327,28 +309,53 @@ int game_set_window_shape(GameData *game, GameWindowShape shape) return -2; } - if (shape == game->window_shape) { - return 0; - } - - if (shape == GW_ShapeSquare) { - game->game_max_x = GAME_MAX_SQUARE_X; - return 0; - } - const int max_x = game->parent_max_x; const int max_y = game->parent_max_y; - if (WINDOW_SIZE_LARGE_RECT_VALID(max_x, max_y)) { - game->game_max_x = GAME_MAX_RECT_X; - game->game_max_y = GAME_MAX_RECT_Y; - return 0; - } + switch (shape) { + case GW_ShapeSquare: { + if (WINDOW_SIZE_SQUARE_VALID(max_x, max_y)) { + game->game_max_x = GAME_MAX_SQUARE_X_DEFAULT; + game->game_max_y = GAME_MAX_SQUARE_Y_DEFAULT; + return 0; + } - if (WINDOW_SIZE_SMALL_RECT_VALID(max_x, max_y)) { - game->game_max_x = GAME_MAX_RECT_X_SMALL; - game->game_max_y = GAME_MAX_RECT_Y_SMALL; - return 0; + break; + } + + case GW_ShapeSquareLarge: { + if (WINDOW_SIZE_LARGE_SQUARE_VALID(max_x, max_y)) { + game->game_max_x = GAME_MAX_SQUARE_X_LARGE; + game->game_max_y = GAME_MAX_SQUARE_Y_LARGE; + return 0; + } + + break; + } + + case GW_ShapeRectangle: { + if (WINDOW_SIZE_RECT_VALID(max_x, max_y)) { + game->game_max_x = GAME_MAX_RECT_X_DEFAULT; + game->game_max_y = GAME_MAX_RECT_Y_DEFAULT; + return 0; + } + + break; + } + + case GW_ShapeRectangleLarge: { + if (WINDOW_SIZE_LARGE_RECT_VALID(max_x, max_y)) { + game->game_max_x = GAME_MAX_RECT_X_LARGE; + game->game_max_y = GAME_MAX_RECT_Y_LARGE; + return 0; + } + + break; + } + + default: { + return -1; + } } return -1; diff --git a/src/game_base.h b/src/game_base.h index c6b49ce..43909d1 100644 --- a/src/game_base.h +++ b/src/game_base.h @@ -33,21 +33,22 @@ #define GAME_BORDER_COLOUR BAR_TEXT -/* Max size of a default size square game window */ -#define GAME_MAX_SQUARE_Y 26 -#define GAME_MAX_SQUARE_X (GAME_MAX_SQUARE_Y * 2) -/* Max size of a small square game window */ -#define GAME_MAX_SQUARE_Y_SMALL 18 -#define GAME_MAX_SQUARE_X_SMALL (GAME_MAX_SQUARE_Y_SMALL * 2) +/* Max size of a default square game window */ +#define GAME_MAX_SQUARE_Y_DEFAULT 26 +#define GAME_MAX_SQUARE_X_DEFAULT (GAME_MAX_SQUARE_Y_DEFAULT * 2) + +/* Max size of a large square game window */ +#define GAME_MAX_SQUARE_Y_LARGE 52 +#define GAME_MAX_SQUARE_X_LARGE (GAME_MAX_SQUARE_Y_LARGE * 2) /* Max size of a default size rectangle game window */ -#define GAME_MAX_RECT_Y 24 -#define GAME_MAX_RECT_X (GAME_MAX_RECT_Y * 4) +#define GAME_MAX_RECT_Y_DEFAULT 24 +#define GAME_MAX_RECT_X_DEFAULT (GAME_MAX_RECT_Y_DEFAULT * 4) -/* Max size of a small rectangle game window */ -#define GAME_MAX_RECT_Y_SMALL 14 -#define GAME_MAX_RECT_X_SMALL (GAME_MAX_RECT_Y_SMALL * 4) +/* Max size of a large rectangle game window */ +#define GAME_MAX_RECT_Y_LARGE 52 +#define GAME_MAX_RECT_X_LARGE (GAME_MAX_RECT_Y_LARGE * 4) /* Maximum length of a game message set with game_set_message() */ #define GAME_MAX_MESSAGE_SIZE 64 @@ -56,7 +57,7 @@ #define GAME_MESSAGE_DEFAULT_TIMEOUT 3 -/***** NETWORKING CONSTANTS *****/ +/***** START NETWORKING CONSTANTS *****/ /* Header starts after custom packet type byte. Comprised of: NetworkVersion (1b) + GameType (1b) + id (4b) */ #define GAME_PACKET_HEADER_SIZE (1 + 1 + sizeof(uint32_t)) @@ -70,6 +71,9 @@ /* Current version of networking protocol */ #define GAME_NETWORKING_VERSION 0x01 +/***** END NETWORKING CONSTANTS *****/ + + typedef void cb_game_update_state(GameData *game, void *cb_data); typedef void cb_game_render_window(GameData *game, WINDOW *window, void *cb_data); typedef void cb_game_kill(GameData *game, void *cb_data); @@ -84,7 +88,9 @@ typedef enum GamePacketType { typedef enum GameWindowShape { GW_ShapeSquare = 0u, + GW_ShapeSquareLarge, GW_ShapeRectangle, + GW_ShapeRectangleLarge, GW_ShapeInvalid, } GameWindowShape; @@ -210,8 +216,6 @@ void game_set_cb_on_packet(GameData *game, cb_game_on_packet *func, void *cb_dat * `id` should be a unique integer to indentify the game instance. If we're being invited to a game * this identifier should be sent via the invite packet. * - * `force_small_window` will make the game window small. - * * if `multiplayer_data` is non-null this indicates that we accepted a game invite from a contact. * The data contains any information we need to initialize the game state. * @@ -222,12 +226,12 @@ void game_set_cb_on_packet(GameData *game, cb_game_on_packet *func, void *cb_dat * Return -4 on other failure. */ int game_initialize(const ToxWindow *self, Tox *m, GameType type, uint32_t id, const uint8_t *multiplayer_data, - size_t length, bool force_small_window); + size_t length); /* - * Sets game window to `shape` and attempts to adjust size for best fit. + * Sets game window to `shape`. * - * This should be called in the game's initialize function. + * This must be called on game initialization. * * Return 0 on success. * Return -1 if window is too small or shape is invalid. diff --git a/src/game_centipede.c b/src/game_centipede.c index 098df4b..ccc53ea 100644 --- a/src/game_centipede.c +++ b/src/game_centipede.c @@ -33,7 +33,7 @@ #define CENT_MUSHROOMS_POP_CONSTANT 35000 /* Max number of mushrooms */ -#define CENT_MUSHROOMS_LENGTH (GAME_MAX_SQUARE_X * GAME_MAX_SQUARE_Y) +#define CENT_MUSHROOMS_LENGTH (GAME_MAX_SQUARE_X_DEFAULT * GAME_MAX_SQUARE_X_DEFAULT) /* Max number of individual centipedes at any given time */ #define CENT_MAX_NUM_HEADS 20 @@ -1714,6 +1714,7 @@ static int cent_init_state(GameData *game, CentState *state) int centipede_initialize(GameData *game) { + // note: If this changes we must update CENT_MUSHROOMS_LENGTH if (game_set_window_shape(game, GW_ShapeSquare) == -1) { return -1; } diff --git a/src/game_chess.c b/src/game_chess.c index 23ef4d8..9bcf93e 100644 --- a/src/game_chess.c +++ b/src/game_chess.c @@ -1864,7 +1864,7 @@ static void chess_notify(const GameData *game, ChessPacketType type) } case CHESS_PACKET_RESIGN: { - msg = "Opponnet has resigned"; + msg = "Opponent has resigned"; break; } diff --git a/src/game_life.c b/src/game_life.c index b4705de..cb31765 100644 --- a/src/game_life.c +++ b/src/game_life.c @@ -51,6 +51,7 @@ typedef struct LifeState { TIME_MS time_last_cycle; size_t speed; size_t generation; + bool paused; Cell **cells; int num_columns; @@ -321,7 +322,9 @@ void life_cb_render_window(GameData *game, WINDOW *win, void *cb_data) move(state->curs_y, state->curs_x); - curs_set(1); + if (state->generation == 0 || state->paused) { + curs_set(1); + } life_draw_cells(game, win, state); } @@ -478,6 +481,7 @@ void life_cb_on_keypress(GameData *game, int key, void *cb_data) case '\t': { life_toggle_display_candy(state); + break; } default: { @@ -501,6 +505,17 @@ static void life_free_cells(LifeState *state) free(state->cells); } +void life_cb_pause(GameData *game, bool is_paused, void *cb_data) +{ + if (!cb_data) { + return; + } + + LifeState *state = (LifeState *)cb_data; + + state->paused = is_paused; +} + void life_cb_kill(GameData *game, void *cb_data) { if (!cb_data) { @@ -574,8 +589,15 @@ static int life_init_state(GameData *game, LifeState *state) int life_initialize(GameData *game) { - if (game_set_window_shape(game, GW_ShapeRectangle) == -1) { - return -1; + // Try best fit from largest to smallest before giving up + if (game_set_window_shape(game, GW_ShapeRectangleLarge) == -1) { + if (game_set_window_shape(game, GW_ShapeSquareLarge) == -1) { + if (game_set_window_shape(game, GW_ShapeRectangle) == -1) { + if (game_set_window_shape(game, GW_ShapeSquare) == -1) { + return -1; + } + } + } } LifeState *state = calloc(1, sizeof(LifeState)); @@ -596,6 +618,7 @@ int life_initialize(GameData *game) game_set_cb_update_state(game, life_cb_update_game_state, state); game_set_cb_render_window(game, life_cb_render_window, state); game_set_cb_on_keypress(game, life_cb_on_keypress, state); + game_set_cb_on_pause(game, life_cb_pause, state); game_set_cb_kill(game, life_cb_kill, state); return 0; diff --git a/src/game_snake.c b/src/game_snake.c index 929a8cf..b3d2390 100644 --- a/src/game_snake.c +++ b/src/game_snake.c @@ -29,8 +29,8 @@ #include "game_snake.h" #include "misc_tools.h" -#define SNAKE_MAX_SNAKE_LENGTH (GAME_MAX_SQUARE_X * GAME_MAX_SQUARE_Y) -#define SNAKE_AGENT_MAX_LIST_SIZE (GAME_MAX_SQUARE_X * GAME_MAX_SQUARE_Y) +#define SNAKE_MAX_SNAKE_LENGTH (GAME_MAX_SQUARE_X_DEFAULT * GAME_MAX_SQUARE_Y_DEFAULT) +#define SNAKE_AGENT_MAX_LIST_SIZE (GAME_MAX_SQUARE_X_DEFAULT * GAME_MAX_SQUARE_Y_DEFAULT) #define SNAKE_DEFAULT_SNAKE_SPEED 6 #define SNAKE_DEFAULT_AGENT_SPEED 1 @@ -850,6 +850,7 @@ static void snake_initialize_snake_head(const GameData *game, Snake *snake) int snake_initialize(GameData *game) { + // note: if this changes we must update SNAKE_MAX_SNAKE_LENGTH and SNAKE_AGENT_MAX_LIST_SIZE if (game_set_window_shape(game, GW_ShapeSquare) == -1) { return -1; } diff --git a/src/game_util.h b/src/game_util.h index 36e5716..7ceb680 100644 --- a/src/game_util.h +++ b/src/game_util.h @@ -100,4 +100,3 @@ size_t game_util_pack_u32(uint8_t *bytes, uint32_t v); size_t game_util_unpack_u32(const uint8_t *bytes, uint32_t *v); #endif // GAME_UTIL - diff --git a/src/global_commands.c b/src/global_commands.c index 8350561..28536f5 100644 --- a/src/global_commands.c +++ b/src/global_commands.c @@ -367,19 +367,8 @@ void cmd_game(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA return; } - bool force_small = false; - - if (argc >= 2) { - force_small = strcasecmp(argv[2], "small") == 0; - - if (!force_small) { - line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Unknown argument."); - return; - } - } - uint32_t id = rand(); - int ret = game_initialize(self, m, type, id, NULL, 0, force_small); + int ret = game_initialize(self, m, type, id, NULL, 0); switch (ret) { case 0: { @@ -387,8 +376,7 @@ void cmd_game(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA } case -1: { - line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, - "Window is too small. Try enlarging your window or re-running the command with the 'small' argument."); + line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Window is too small."); return; }