X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame.c;h=28905e562b1ef07e942ca56e23be27b128cfade2;hp=e75235853eec0be2caa54fbf912a3f6a5b933e36;hb=abe44529b439ad39b4d8dbf19cbd67c9b9844279;hpb=31b462a53d66e5d4fb8701c2b7d31180af1f5f6d diff --git a/src/game.c b/src/game.c index e7523585..28905e56 100644 --- a/src/game.c +++ b/src/game.c @@ -1,15 +1,13 @@ -/*********************************************************** -* Rocks'n'Diamonds -- McDuffin Strikes Back! * -*----------------------------------------------------------* -* (c) 1995-2006 Artsoft Entertainment * -* Holger Schemel * -* Detmolder Strasse 189 * -* 33604 Bielefeld * -* Germany * -* e-mail: info@artsoft.org * -*----------------------------------------------------------* -* game.c * -***********************************************************/ +// ============================================================================ +// Rocks'n'Diamonds - McDuffin Strikes Back! +// ---------------------------------------------------------------------------- +// (c) 1995-2014 by Artsoft Entertainment +// Holger Schemel +// info@artsoft.org +// http://www.artsoft.org/ +// ---------------------------------------------------------------------------- +// game.c +// ============================================================================ #include "libgame/libgame.h" @@ -21,6 +19,11 @@ #include "tape.h" #include "network.h" + +/* DEBUG SETTINGS */ +#define DEBUG_INIT_PLAYER 1 +#define DEBUG_PLAYER_ACTIONS 0 + /* EXPERIMENTAL STUFF */ #define USE_NEW_AMOEBA_CODE FALSE @@ -120,45 +123,7 @@ #define PANEL_XPOS(p) (DX + ALIGNED_TEXT_XPOS(p)) #define PANEL_YPOS(p) (DY + ALIGNED_TEXT_YPOS(p)) -/* special positions in the game control window (relative to control window) */ -#define XX_LEVEL1 (PANEL_XPOS(game.panel.level)) -#define XX_LEVEL2 (PANEL_XPOS(game.panel.level) - 1) -#define XX_LEVEL (PANEL_XPOS(game.panel.level)) -#define YY_LEVEL (PANEL_YPOS(game.panel.level)) -#define XX_EMERALDS (PANEL_XPOS(game.panel.gems)) -#define YY_EMERALDS (PANEL_YPOS(game.panel.gems)) -#define XX_DYNAMITE (PANEL_XPOS(game.panel.inventory)) -#define YY_DYNAMITE (PANEL_YPOS(game.panel.inventory)) -#define XX_KEYS (PANEL_XPOS(game.panel.keys)) -#define YY_KEYS (PANEL_YPOS(game.panel.keys)) -#define XX_SCORE (PANEL_XPOS(game.panel.score)) -#define YY_SCORE (PANEL_YPOS(game.panel.score)) -#define XX_TIME1 (PANEL_XPOS(game.panel.time)) -#define XX_TIME2 (PANEL_XPOS(game.panel.time) + 1) -#define XX_TIME (PANEL_XPOS(game.panel.time)) -#define YY_TIME (PANEL_YPOS(game.panel.time)) - -/* special positions in the game control window (relative to main window) */ -#define DX_LEVEL1 (DX + XX_LEVEL1) -#define DX_LEVEL2 (DX + XX_LEVEL2) -#define DX_LEVEL (DX + XX_LEVEL) -#define DY_LEVEL (DY + YY_LEVEL) -#define DX_EMERALDS (DX + XX_EMERALDS) -#define DY_EMERALDS (DY + YY_EMERALDS) -#define DX_DYNAMITE (DX + XX_DYNAMITE) -#define DY_DYNAMITE (DY + YY_DYNAMITE) -#define DX_KEYS (DX + XX_KEYS) -#define DY_KEYS (DY + YY_KEYS) -#define DX_SCORE (DX + XX_SCORE) -#define DY_SCORE (DY + YY_SCORE) -#define DX_TIME1 (DX + XX_TIME1) -#define DX_TIME2 (DX + XX_TIME2) -#define DX_TIME (DX + XX_TIME) -#define DY_TIME (DY + YY_TIME) - -#if 1 /* game panel display and control definitions */ - #define GAME_PANEL_LEVEL_NUMBER 0 #define GAME_PANEL_GEMS 1 #define GAME_PANEL_INVENTORY_COUNT 2 @@ -876,8 +841,6 @@ static struct GamePanelControlInfo game_panel_controls[] = -1, } }; -#endif - /* values for delayed check of falling and moving elements and for collision */ #define CHECK_DELAY_MOVING 3 @@ -1049,8 +1012,10 @@ static struct GamePanelControlInfo game_panel_controls[] = #define SOUND_CTRL_ID_MUSIC 3 #define SOUND_CTRL_ID_LOOPS 4 #define SOUND_CTRL_ID_SIMPLE 5 +#define GAME_CTRL_ID_SAVE 6 +#define GAME_CTRL_ID_LOAD 7 -#define NUM_GAME_BUTTONS 6 +#define NUM_GAME_BUTTONS 8 /* forward declaration for internal use */ @@ -1117,7 +1082,6 @@ static void PlayLevelSoundActionIfLoop(int, int, int); static void StopLevelSoundActionIfLoop(int, int, int); static void PlayLevelMusic(); -static void MapGameButtons(); static void HandleGameButtons(struct GadgetInfo *); int AmoebeNachbarNr(int, int); @@ -1780,14 +1744,16 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) StorePlayer[x][y] = Feld[x][y]; +#if DEBUG_INIT_PLAYER if (options.debug) { - printf("Player %d activated.\n", player->element_nr); - printf("[Local player is %d and currently %s.]\n", + printf("- player element %d activated", player->element_nr); + printf(" (local player is %d and currently %s)\n", local_player->element_nr, local_player->active ? "active" : "not active"); } } +#endif Feld[x][y] = EL_EMPTY; @@ -2076,8 +2042,6 @@ static inline void InitField_WithBug2(int x, int y, boolean init_game) */ } -#if 1 - static int get_key_element_from_nr(int key_nr) { int key_base_element = (key_nr >= STD_NUM_KEYS ? EL_EMC_KEY_5 - STD_NUM_KEYS : @@ -2229,7 +2193,7 @@ void UpdateGameControlValues() level.native_em_level->lev->time : level.game_engine_type == GAME_ENGINE_TYPE_SP ? level.native_sp_level->game_sp->time_played : - level.time == 0 ? TimePlayed : TimeLeft); + game.no_time_limit ? TimePlayed : TimeLeft); int score = (local_player->LevelSolved ? local_player->LevelSolved_CountingScore : level.game_engine_type == GAME_ENGINE_TYPE_EM ? @@ -2788,11 +2752,7 @@ void UpdateAndDisplayGameControlValues() void DrawGameValue_Emeralds(int value) { struct TextPosInfo *pos = &game.panel.gems; -#if 1 int font_nr = pos->font; -#else - int font_nr = FONT_TEXT_2; -#endif int font_width = getFontWidth(font_nr); int chars = pos->size; @@ -2811,11 +2771,7 @@ void DrawGameValue_Emeralds(int value) void DrawGameValue_Dynamite(int value) { struct TextPosInfo *pos = &game.panel.inventory_count; -#if 1 int font_nr = pos->font; -#else - int font_nr = FONT_TEXT_2; -#endif int font_width = getFontWidth(font_nr); int chars = pos->size; @@ -2834,11 +2790,7 @@ void DrawGameValue_Dynamite(int value) void DrawGameValue_Score(int value) { struct TextPosInfo *pos = &game.panel.score; -#if 1 int font_nr = pos->font; -#else - int font_nr = FONT_TEXT_2; -#endif int font_width = getFontWidth(font_nr); int chars = pos->size; @@ -2861,13 +2813,8 @@ void DrawGameValue_Time(int value) int chars1 = 3; int chars2 = 4; int chars = pos->size; -#if 1 int font1_nr = pos->font; int font2_nr = pos->font_alt; -#else - int font1_nr = FONT_TEXT_2; - int font2_nr = FONT_TEXT_1; -#endif int font_nr = font1_nr; boolean use_dynamic_chars = (chars == -1 ? TRUE : FALSE); @@ -2911,13 +2858,8 @@ void DrawGameValue_Level(int value) int chars1 = 2; int chars2 = 3; int chars = pos->size; -#if 1 int font1_nr = pos->font; int font2_nr = pos->font_alt; -#else - int font1_nr = FONT_TEXT_2; - int font2_nr = FONT_TEXT_1; -#endif int font_nr = font1_nr; boolean use_dynamic_chars = (chars == -1 ? TRUE : FALSE); @@ -2941,63 +2883,27 @@ void DrawGameValue_Level(int value) void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) { -#if 0 - struct TextPosInfo *pos = &game.panel.keys; -#endif -#if 0 - int base_key_graphic = EL_KEY_1; -#endif int i; #if 1 return; /* !!! USE NEW STUFF !!! */ #endif -#if 0 - if (PANEL_DEACTIVATED(pos)) - return; -#endif - -#if 0 - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - base_key_graphic = EL_EM_KEY_1; -#endif - -#if 0 - pos->width = 4 * MINI_TILEX; -#endif - -#if 1 for (i = 0; i < MAX_NUM_KEYS; i++) -#else - /* currently only 4 of 8 possible keys are displayed */ - for (i = 0; i < STD_NUM_KEYS; i++) -#endif { -#if 1 struct TextPosInfo *pos = &game.panel.key[i]; -#endif int src_x = DOOR_GFX_PAGEX5 + 18 + (i % 4) * MINI_TILEX; int src_y = DOOR_GFX_PAGEY1 + 123; -#if 1 int dst_x = PANEL_XPOS(pos); int dst_y = PANEL_YPOS(pos); -#else - int dst_x = PANEL_XPOS(pos) + i * MINI_TILEX; - int dst_y = PANEL_YPOS(pos); -#endif -#if 1 int element = (i >= STD_NUM_KEYS ? EL_EMC_KEY_5 - 4 : level.game_engine_type == GAME_ENGINE_TYPE_EM ? EL_EM_KEY_1 : EL_KEY_1) + i; int graphic = el2edimg(element); -#endif -#if 1 if (PANEL_DEACTIVATED(pos)) continue; -#endif #if 0 /* masked blit with tiles from half-size scaled bitmap does not work yet @@ -3009,9 +2915,6 @@ void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) if (key[i]) { -#if 0 - int graphic = el2edimg(base_key_graphic + i); -#endif Bitmap *src_bitmap; int src_x, src_y; @@ -3023,127 +2926,15 @@ void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) dst_x, dst_y); } #else -#if 1 if (key[i]) DrawMiniGraphicExt(drawto, dst_x, dst_y, graphic); else BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY, dst_x, dst_y); -#else - if (key[i]) - DrawMiniGraphicExt(drawto, dst_x, dst_y, el2edimg(base_key_graphic + i)); - else - BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, src_x, src_y, - MINI_TILEX, MINI_TILEY, dst_x, dst_y); -#endif -#endif - } -} - -#else - -void DrawGameValue_Emeralds(int value) -{ - int font_nr = FONT_TEXT_2; - int xpos = (3 * 14 - 3 * getFontWidth(font_nr)) / 2; - - if (PANEL_DEACTIVATED(game.panel.gems)) - return; - - DrawText(DX_EMERALDS + xpos, DY_EMERALDS, int2str(value, 3), font_nr); -} - -void DrawGameValue_Dynamite(int value) -{ - int font_nr = FONT_TEXT_2; - int xpos = (3 * 14 - 3 * getFontWidth(font_nr)) / 2; - - if (PANEL_DEACTIVATED(game.panel.inventory_count)) - return; - - DrawText(DX_DYNAMITE + xpos, DY_DYNAMITE, int2str(value, 3), font_nr); -} - -void DrawGameValue_Score(int value) -{ - int font_nr = FONT_TEXT_2; - int xpos = (5 * 14 - 5 * getFontWidth(font_nr)) / 2; - - if (PANEL_DEACTIVATED(game.panel.score)) - return; - - DrawText(DX_SCORE + xpos, DY_SCORE, int2str(value, 5), font_nr); -} - -void DrawGameValue_Time(int value) -{ - int font1_nr = FONT_TEXT_2; -#if 1 - int font2_nr = FONT_TEXT_1; -#else - int font2_nr = FONT_LEVEL_NUMBER; -#endif - int xpos3 = (3 * 14 - 3 * getFontWidth(font1_nr)) / 2; - int xpos4 = (4 * 10 - 4 * getFontWidth(font2_nr)) / 2; - - if (PANEL_DEACTIVATED(game.panel.time)) - return; - - /* clear background if value just changed its size */ - if (value == 999 || value == 1000) - ClearRectangleOnBackground(drawto, DX_TIME1, DY_TIME, 14 * 3, 14); - - if (value < 1000) - DrawText(DX_TIME1 + xpos3, DY_TIME, int2str(value, 3), font1_nr); - else - DrawText(DX_TIME2 + xpos4, DY_TIME, int2str(value, 4), font2_nr); -} - -void DrawGameValue_Level(int value) -{ - int font1_nr = FONT_TEXT_2; -#if 1 - int font2_nr = FONT_TEXT_1; -#else - int font2_nr = FONT_LEVEL_NUMBER; #endif - - if (PANEL_DEACTIVATED(game.panel.level)) - return; - - if (level_nr < 100) - DrawText(DX_LEVEL1, DY_LEVEL, int2str(value, 2), font1_nr); - else - DrawText(DX_LEVEL2, DY_LEVEL, int2str(value, 3), font2_nr); -} - -void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) -{ - int base_key_graphic = EL_KEY_1; - int i; - - if (PANEL_DEACTIVATED(game.panel.keys)) - return; - - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - base_key_graphic = EL_EM_KEY_1; - - /* currently only 4 of 8 possible keys are displayed */ - for (i = 0; i < STD_NUM_KEYS; i++) - { - int x = XX_KEYS + i * MINI_TILEX; - int y = YY_KEYS; - - if (key[i]) - DrawMiniGraphicExt(drawto, DX + x,DY + y, el2edimg(base_key_graphic + i)); - else - BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, - DOOR_GFX_PAGEX5 + x, y, MINI_TILEX, MINI_TILEY, DX + x,DY + y); } } -#endif - void DrawAllGameValues(int emeralds, int dynamite, int score, int time, int key_bits) { @@ -3180,7 +2971,7 @@ void DrawGameDoorValues() void DrawGameDoorValues_OLD() { - int time_value = (level.time == 0 ? TimePlayed : TimeLeft); + int time_value = (game.no_time_limit ? TimePlayed : TimeLeft); int dynamite_value = 0; int score_value = (local_player->LevelSolved ? local_player->score_final : local_player->score); @@ -3238,6 +3029,21 @@ static void InitGameEngine() game.engine_version = (tape.playing ? tape.engine_version : level.game_version); + /* set single or multi-player game mode (needed for re-playing tapes) */ + game.team_mode = setup.team_mode; + + if (tape.playing) + { + int num_players = 0; + + for (i = 0; i < MAX_PLAYERS; i++) + if (tape.player_participates[i]) + num_players++; + + /* multi-player tapes contain input data for more than one player */ + game.team_mode = (num_players > 1); + } + /* ---------------------------------------------------------------------- */ /* set flags for bugs and changes according to active game engine version */ /* ---------------------------------------------------------------------- */ @@ -3712,6 +3518,9 @@ int get_num_special_action(int element, int action_first, int action_last) void InitGame() { + int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0); + int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0); + boolean emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */ boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */ boolean emulate_sp = TRUE; /* unless non-SUPAPLEX elements found */ @@ -3725,7 +3534,46 @@ void InitGame() #endif int i, j, x, y; +#if 1 + game_status = GAME_MODE_PLAYING; +#endif + +#if 1 + + StopAnimation(); + + if (!game.restart_level) + CloseDoor(DOOR_CLOSE_1); + +#if 1 + if (level_editor_test_game) + FadeSkipNextFadeIn(); + else + FadeSetEnterScreen(); +#else + if (level_editor_test_game) + fading = fading_none; + else + fading = menu.destination; +#endif + +#if 1 + FadeOut(REDRAW_FIELD); +#else + if (do_fading) + FadeOut(REDRAW_FIELD); +#endif + +#endif + +#if 0 + printf("::: FADING OUT: DONE\n"); + Delay(1000); +#endif + +#if 0 game_status = GAME_MODE_PLAYING; +#endif #if 1 /* needed if different viewport properties defined for playing */ @@ -3923,6 +3771,8 @@ void InitGame() AllPlayersGone = FALSE; + game.no_time_limit = (level.time == 0); + game.yamyam_content_nr = 0; game.robot_wheel_active = FALSE; game.magic_wall_active = FALSE; @@ -3966,6 +3816,13 @@ void InitGame() for (i = 0; i < MAX_NUM_AMOEBA; i++) AmoebaCnt[i] = AmoebaCnt2[i] = 0; +#if DEBUG_INIT_PLAYER + if (options.debug) + { + printf("Player status at level initialization:\n"); + } +#endif + SCAN_PLAYFIELD(x, y) { Feld[x][y] = level.field[x][y]; @@ -4099,16 +3956,25 @@ void InitGame() local_player->connected = TRUE; /* !!! SAME AS init.c:InitPlayerInfo() -- FIX THIS !!! */ +#if 0 + printf("::: TEAM MODE: %d\n", game.team_mode); +#endif + if (tape.playing) { +#if 1 + for (i = 0; i < MAX_PLAYERS; i++) + stored_player[i].connected = tape.player_participates[i]; +#else /* try to guess locally connected team mode players (needed for correct assignment of player figures from level to locally playing players) */ for (i = 0; i < MAX_PLAYERS; i++) if (tape.player_participates[i]) stored_player[i].connected = TRUE; +#endif } - else if (setup.team_mode && !options.network) + else if (game.team_mode && !options.network) { /* try to guess locally connected team mode players (needed for correct assignment of player figures from level to locally playing players) */ @@ -4119,14 +3985,32 @@ void InitGame() stored_player[i].connected = TRUE; } -#if 0 - for (i = 0; i < MAX_PLAYERS; i++) - printf("::: player %d: %s\n", i, - (stored_player[i].connected ? "connected" : "not connected")); +#if DEBUG_INIT_PLAYER + if (options.debug) + { + printf("Player status after level initialization:\n"); - for (i = 0; i < MAX_PLAYERS; i++) - printf("::: player %d: %s\n", i, - (stored_player[i].present ? "present" : "not present")); + for (i = 0; i < MAX_PLAYERS; i++) + { + struct PlayerInfo *player = &stored_player[i]; + + printf("- player %d: present == %d, connected == %d, active == %d", + i + 1, + player->present, + player->connected, + player->active); + + if (local_player == player) + printf(" (local player)"); + + printf("\n"); + } + } +#endif + +#if DEBUG_INIT_PLAYER + if (options.debug) + printf("Reassigning players ...\n"); #endif /* check if any connected player was not found in playfield */ @@ -4138,12 +4022,29 @@ void InitGame() { struct PlayerInfo *field_player = NULL; -#if 0 - printf("::: looking for field player for player %d ...\n", i); +#if DEBUG_INIT_PLAYER + if (options.debug) + printf("- looking for field player for player %d ...\n", i + 1); #endif /* assign first free player found that is present in the playfield */ +#if 1 + /* first try: look for unmapped playfield player that is not connected */ + for (j = 0; j < MAX_PLAYERS; j++) + if (field_player == NULL && + stored_player[j].present && + !stored_player[j].mapped && + !stored_player[j].connected) + field_player = &stored_player[j]; + + /* second try: look for *any* unmapped playfield player */ + for (j = 0; j < MAX_PLAYERS; j++) + if (field_player == NULL && + stored_player[j].present && + !stored_player[j].mapped) + field_player = &stored_player[j]; +#else /* first try: look for unmapped playfield player that is not connected */ if (field_player == NULL) for (j = 0; j < MAX_PLAYERS; j++) @@ -4158,13 +4059,15 @@ void InitGame() if (stored_player[j].present && !stored_player[j].mapped) field_player = &stored_player[j]; +#endif if (field_player != NULL) { int jx = field_player->jx, jy = field_player->jy; -#if 0 - printf("::: found player figure %d\n", field_player->index_nr); +#if DEBUG_INIT_PLAYER + if (options.debug) + printf("- found player %d\n", field_player->index_nr + 1); #endif player->present = FALSE; @@ -4193,9 +4096,10 @@ void InitGame() field_player->mapped = TRUE; -#if 0 - printf("::: map_player_action[%d] == %d\n", - field_player->index_nr, i); +#if DEBUG_INIT_PLAYER + if (options.debug) + printf("- map_player_action[%d] == %d\n", + field_player->index_nr + 1, i + 1); #endif } } @@ -4204,6 +4108,29 @@ void InitGame() player->mapped = TRUE; } +#if DEBUG_INIT_PLAYER + if (options.debug) + { + printf("Player status after player assignment (first stage):\n"); + + for (i = 0; i < MAX_PLAYERS; i++) + { + struct PlayerInfo *player = &stored_player[i]; + + printf("- player %d: present == %d, connected == %d, active == %d", + i + 1, + player->present, + player->connected, + player->active); + + if (local_player == player) + printf(" (local player)"); + + printf("\n"); + } + } +#endif + #else /* check if any connected player was not found in playfield */ @@ -4254,6 +4181,11 @@ void InitGame() /* when playing a tape, eliminate all players who do not participate */ #if USE_NEW_PLAYER_ASSIGNMENTS + +#if 1 + if (!game.team_mode) +#endif + for (i = 0; i < MAX_PLAYERS; i++) { if (stored_player[i].active && @@ -4262,12 +4194,19 @@ void InitGame() struct PlayerInfo *player = &stored_player[i]; int jx = player->jx, jy = player->jy; +#if DEBUG_INIT_PLAYER + if (options.debug) + printf("Removing player %d at (%d, %d)\n", i + 1, jx, jy); +#endif + player->active = FALSE; StorePlayer[jx][jy] = 0; Feld[jx][jy] = EL_EMPTY; } } + #else + for (i = 0; i < MAX_PLAYERS; i++) { if (stored_player[i].active && @@ -4283,7 +4222,7 @@ void InitGame() } #endif } - else if (!options.network && !setup.team_mode) /* && !tape.playing */ + else if (!options.network && !game.team_mode) /* && !tape.playing */ { /* when in single player mode, eliminate all but the first active player */ @@ -4323,21 +4262,28 @@ void InitGame() #endif } +#if DEBUG_INIT_PLAYER if (options.debug) { + printf("Player status after player assignment (final stage):\n"); + for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; - printf("Player %d: present == %d, connected == %d, active == %d.\n", - i+1, + printf("- player %d: present == %d, connected == %d, active == %d", + i + 1, player->present, player->connected, player->active); + if (local_player == player) - printf("Player %d is local player.\n", i+1); + printf(" (local player)"); + + printf("\n"); } } +#endif if (BorderElement == EL_EMPTY) { @@ -4356,16 +4302,44 @@ void InitGame() #if NEW_TILESIZE + // printf("::: START-0: %d, %d\n", lev_fieldx, SCR_FIELDX); + // printf("::: START-1: %d, %d\n", SBX_Left, SBX_Right); + +#if 1 + if (full_lev_fieldx <= SCR_FIELDX) + SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2; + + if (full_lev_fieldy <= SCR_FIELDY) + SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2; +#else if (lev_fieldx + (SBX_Left < 0 ? 2 : 0) <= SCR_FIELDX) SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2; if (lev_fieldy + (SBY_Upper < 0 ? 2 : 0) <= SCR_FIELDY) SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2; +#endif + /* + printf("::: START-2: %d, %d (%d)\n", SBX_Left, SBX_Right, + SBX_Right - SBX_Left + 1); + */ + +#if 1 + if (EVEN(SCR_FIELDX) && full_lev_fieldx > SCR_FIELDX) + SBX_Left--; + if (EVEN(SCR_FIELDY) && full_lev_fieldy > SCR_FIELDY) + SBY_Upper--; +#else if (EVEN(SCR_FIELDX)) SBX_Left--; if (EVEN(SCR_FIELDY)) SBY_Upper--; +#endif + +#if 0 + printf("::: START-3: %d, %d\n", SBX_Left, SBX_Right); + printf("\n"); +#endif #else @@ -4494,6 +4468,8 @@ void InitGame() game_status = GAME_MODE_MAIN; #endif +#if 0 + StopAnimation(); if (!game.restart_level) @@ -4518,6 +4494,8 @@ void InitGame() FadeOut(REDRAW_FIELD); #endif +#endif + #if 0 game_status = GAME_MODE_PLAYING; #endif @@ -4527,35 +4505,49 @@ void InitGame() { InitGameEngine_EM(); +#if 0 /* blit playfield from scroll buffer to normal back buffer for fading in */ BlitScreenToBitmap_EM(backbuffer); +#endif } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { InitGameEngine_SP(); +#if 0 /* blit playfield from scroll buffer to normal back buffer for fading in */ BlitScreenToBitmap_SP(backbuffer); +#endif } else { - DrawLevel(); + DrawLevel(REDRAW_FIELD); DrawAllPlayers(); /* after drawing the level, correct some elements */ if (game.timegate_time_left == 0) CloseAllOpenTimegates(); +#if 0 + /* blit playfield from scroll buffer to normal back buffer for fading in */ #if NEW_TILESIZE BlitScreenToBitmap(backbuffer); #else - /* blit playfield from scroll buffer to normal back buffer for fading in */ if (setup.soft_scrolling) BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY); #endif +#endif +#if 0 redraw_mask |= REDRAW_FROM_BACKBUFFER; +#endif } +#if 1 + /* blit playfield from scroll buffer to normal back buffer for fading in */ + BlitScreenToBitmap(backbuffer); + + redraw_mask |= REDRAW_FROM_BACKBUFFER; +#endif /* !!! FIX THIS (END) !!! */ #if 1 @@ -4611,8 +4603,12 @@ void InitGame() MapTapeButtons(); /* copy actual game door content to door double buffer for OpenDoor() */ +#if 1 + BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0); +#else BlitBitmap(drawto, bitmap_db_door, DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); +#endif OpenDoor(DOOR_OPEN_ALL); @@ -4623,12 +4619,28 @@ void InitGame() KeyboardAutoRepeatOffUnlessAutoplay(); +#if DEBUG_INIT_PLAYER if (options.debug) { + printf("Player status (final):\n"); + for (i = 0; i < MAX_PLAYERS; i++) - printf("Player %d %sactive.\n", - i + 1, (stored_player[i].active ? "" : "not ")); + { + struct PlayerInfo *player = &stored_player[i]; + + printf("- player %d: present == %d, connected == %d, active == %d", + i + 1, + player->present, + player->connected, + player->active); + + if (local_player == player) + printf(" (local player)"); + + printf("\n"); + } } +#endif } #if 1 @@ -4867,7 +4879,8 @@ static void PlayerWins(struct PlayerInfo *player) player->score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->score : player->score); - player->LevelSolved_CountingTime = (level.time == 0 ? TimePlayed : TimeLeft); + player->LevelSolved_CountingTime = (game.no_time_limit ? TimePlayed : + TimeLeft); player->LevelSolved_CountingScore = player->score_final; } @@ -4913,7 +4926,7 @@ void GameWon() game_over_delay_1 = game_over_delay_value_1; game_over_delay_2 = game_over_delay_value_2; - time = time_final = (level.time == 0 ? TimePlayed : TimeLeft); + time = time_final = (game.no_time_limit ? TimePlayed : TimeLeft); score = score_final = local_player->score_final; if (TimeLeft > 0) @@ -4921,7 +4934,7 @@ void GameWon() time_final = 0; score_final += TimeLeft * level.score[SC_TIME_BONUS]; } - else if (level.time == 0 && TimePlayed < 999) + else if (game.no_time_limit && TimePlayed < 999) { time_final = 999; score_final += (999 - TimePlayed) * level.score[SC_TIME_BONUS]; @@ -9555,8 +9568,8 @@ void AmoebeUmwandelnBD(int ax, int ay, int new_element) void AmoebeWaechst(int x, int y) { - static unsigned long sound_delay = 0; - static unsigned long sound_delay_value = 0; + static unsigned int sound_delay = 0; + static unsigned int sound_delay_value = 0; if (!MovDelay[x][y]) /* start new growing cycle */ { @@ -9591,8 +9604,8 @@ void AmoebeWaechst(int x, int y) void AmoebaDisappearing(int x, int y) { - static unsigned long sound_delay = 0; - static unsigned long sound_delay_value = 0; + static unsigned int sound_delay = 0; + static unsigned int sound_delay_value = 0; if (!MovDelay[x][y]) /* start new shrinking cycle */ { @@ -12084,7 +12097,6 @@ static void CheckSingleStepMode(struct PlayerInfo *player) static byte PlayerActions(struct PlayerInfo *player, byte player_action) { - boolean moved = FALSE, snapped = FALSE, dropped = FALSE; int left = player_action & JOY_LEFT; int right = player_action & JOY_RIGHT; int up = player_action & JOY_UP; @@ -12100,13 +12112,13 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) if (player_action) { if (button1) - snapped = SnapField(player, dx, dy); + SnapField(player, dx, dy); else { if (button2) - dropped = DropElement(player); + DropElement(player); - moved = MovePlayer(player, dx, dy); + MovePlayer(player, dx, dy); } CheckSingleStepMode(player); @@ -12207,9 +12219,13 @@ static void CheckLevelTime() PlaySound(SND_GAME_RUNNING_OUT_OF_TIME); #if 1 + /* this does not make sense: game_panel_controls[GAME_PANEL_TIME].value + is reset from other values in UpdateGameDoorValues() -- FIX THIS */ + game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; - DisplayGameControlValues(); + /* (already called by UpdateAndDisplayGameControlValues() below) */ + // DisplayGameControlValues(); #else DrawGameValue_Time(TimeLeft); #endif @@ -12224,19 +12240,20 @@ static void CheckLevelTime() } } #if 1 - else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ + else if (game.no_time_limit && !AllPlayersGone) /* level w/o time limit */ { game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; - DisplayGameControlValues(); + /* (already called by UpdateAndDisplayGameControlValues() below) */ + // DisplayGameControlValues(); } #else - else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ + else if (game.no_time_limit && !AllPlayersGone) /* level w/o time limit */ DrawGameValue_Time(TimePlayed); #endif level.native_em_level->lev->time = - (level.time == 0 ? TimePlayed : TimeLeft); + (game.no_time_limit ? TimePlayed : TimeLeft); } if (tape.recording || tape.playing) @@ -12303,9 +12320,9 @@ void AdvanceFrameAndPlayerCounters(int player_nr) } void StartGameActions(boolean init_network_game, boolean record_tape, - long random_seed) + int random_seed) { - unsigned long new_random_seed = InitRND(random_seed); + unsigned int new_random_seed = InitRND(random_seed); if (record_tape) TapeStartRecording(new_random_seed); @@ -12324,8 +12341,8 @@ void StartGameActions(boolean init_network_game, boolean record_tape, void GameActions() { - static unsigned long game_frame_delay = 0; - unsigned long game_frame_delay_value; + static unsigned int game_frame_delay = 0; + unsigned int game_frame_delay_value; byte *recorded_player_action; byte summarized_player_action = 0; byte tape_action[MAX_PLAYERS]; @@ -12334,9 +12351,9 @@ void GameActions() /* detect endless loops, caused by custom element programming */ if (recursion_loop_detected && recursion_loop_depth == 0) { - char *message = getStringCat3("Internal Error ! Element ", + char *message = getStringCat3("Internal Error! Element ", EL_NAME(recursion_loop_element), - " caused endless loop ! Quit the game ?"); + " caused endless loop! Quit the game?"); Error(ERR_WARN, "element '%s' caused endless loop in game engine", EL_NAME(recursion_loop_element)); @@ -12451,8 +12468,13 @@ void GameActions() { summarized_player_action |= stored_player[i].action; +#if 1 + if (!network_playing && (game.team_mode || tape.playing)) + stored_player[i].effective_action = stored_player[i].action; +#else if (!network_playing) stored_player[i].effective_action = stored_player[i].action; +#endif } #if defined(NETWORK_AVALIABLE) @@ -12460,10 +12482,13 @@ void GameActions() SendToServer_MovePlayer(summarized_player_action); #endif - if (!options.network && !setup.team_mode) + if (!options.network && !game.team_mode) local_player->effective_action = summarized_player_action; - if (setup.team_mode && setup.input_on_focus && game.centered_player_nr != -1) + if (tape.recording && + setup.team_mode && + setup.input_on_focus && + game.centered_player_nr != -1) { for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].effective_action = @@ -12478,9 +12503,19 @@ void GameActions() { tape_action[i] = stored_player[i].effective_action; +#if 1 + /* (this may happen in the RND game engine if a player was not present on + the playfield on level start, but appeared later from a custom element */ + if (tape.recording && + setup.team_mode && + tape_action[i] && + !tape.player_participates[i]) + tape.player_participates[i] = TRUE; +#else /* (this can only happen in the R'n'D game engine) */ if (tape.recording && tape_action[i] && !tape.player_participates[i]) tape.player_participates[i] = TRUE; /* player just appeared from CE */ +#endif } /* only record actions from input devices, but not programmed actions */ @@ -12488,16 +12523,76 @@ void GameActions() TapeRecordAction(tape_action); #if USE_NEW_PLAYER_ASSIGNMENTS +#if 1 + if (game.team_mode) +#endif { byte mapped_action[MAX_PLAYERS]; +#if DEBUG_PLAYER_ACTIONS + printf(":::"); + for (i = 0; i < MAX_PLAYERS; i++) + printf(" %d, ", stored_player[i].effective_action); +#endif + for (i = 0; i < MAX_PLAYERS; i++) mapped_action[i] = stored_player[map_player_action[i]].effective_action; for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].effective_action = mapped_action[i]; + +#if DEBUG_PLAYER_ACTIONS + printf(" =>"); + for (i = 0; i < MAX_PLAYERS; i++) + printf(" %d, ", stored_player[i].effective_action); + printf("\n"); +#endif + } +#if DEBUG_PLAYER_ACTIONS + else + { + printf(":::"); + for (i = 0; i < MAX_PLAYERS; i++) + printf(" %d, ", stored_player[i].effective_action); + printf("\n"); } #endif +#endif + +#if 0 + printf("::: summarized_player_action == %d\n", + local_player->effective_action); +#endif + + + + +#if 0 +#if DEBUG_INIT_PLAYER + if (options.debug) + { + printf("Player status (final):\n"); + + for (i = 0; i < MAX_PLAYERS; i++) + { + struct PlayerInfo *player = &stored_player[i]; + + printf("- player %d: present == %d, connected == %d, active == %d", + i + 1, + player->present, + player->connected, + player->active); + + if (local_player == player) + printf(" (local player)"); + + printf("\n"); + } + } +#endif +#endif + + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { @@ -13093,7 +13188,7 @@ void GameActions_RND() /* new experimental amoeba growth stuff */ if (!(FrameCounter % 8)) { - static unsigned long random = 1684108901; + static unsigned int random = 1684108901; for (i = 0; i < level.amoeba_speed * 28 / 8; i++) { @@ -13277,9 +13372,9 @@ void GameActions_RND() if (options.debug) /* calculate frames per second */ { - static unsigned long fps_counter = 0; + static unsigned int fps_counter = 0; static int fps_frames = 0; - unsigned long fps_delay_ms = Counter() - fps_counter; + unsigned int fps_delay_ms = Counter() - fps_counter; fps_frames++; @@ -13710,7 +13805,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) int original_move_delay_value = player->move_delay_value; #if DEBUG - printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES. [%ld]\n", + printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES. [%d]\n", tape.counter); #endif @@ -14092,14 +14187,14 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) KillPlayer(&stored_player[i]); } #if 1 - else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ + else if (game.no_time_limit && !AllPlayersGone) /* level w/o time limit */ { game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; DisplayGameControlValues(); } #else - else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */ + else if (game.no_time_limit && !AllPlayersGone) /* level w/o time limit */ DrawGameValue_Time(TimePlayed); #endif } @@ -14112,7 +14207,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) void ScrollScreen(struct PlayerInfo *player, int mode) { - static unsigned long screen_frame_counter = 0; + static unsigned int screen_frame_counter = 0; if (mode == SCROLL_INIT) { @@ -15655,6 +15750,7 @@ static int DigField(struct PlayerInfo *player, if (level.time > 0 || level.use_time_orb_bug) { TimeLeft += level.time_orb_time; + game.no_time_limit = FALSE; #if 1 game_panel_controls[GAME_PANEL_TIME].value = TimeLeft; @@ -16009,14 +16105,19 @@ static boolean DropElement(struct PlayerInfo *player) if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) && element_info[new_element].move_pattern == MV_WHEN_DROPPED) { - int move_direction, nextx, nexty; +#if 0 + int move_direction; + int nextx, nexty; +#endif if (element_info[new_element].move_direction_initial == MV_START_AUTOMATIC) MovDir[dropx][dropy] = drop_direction; +#if 0 move_direction = MovDir[dropx][dropy]; nextx = dropx + GET_DX_FROM_DIR(move_direction); nexty = dropy + GET_DY_FROM_DIR(move_direction); +#endif ChangeCount[dropx][dropy] = 0; /* allow at least one more change */ @@ -16333,31 +16434,6 @@ void PlayLevelSound_SP(int xx, int yy, int element_sp, int action_sp) PlayLevelSoundElementAction(x, y, element, action); } -#if 0 -void ChangeTime(int value) -{ - int *time = (level.time == 0 ? &TimePlayed : &TimeLeft); - - *time += value; - - /* EMC game engine uses value from time counter of RND game engine */ - level.native_em_level->lev->time = *time; - - DrawGameValue_Time(*time); -} - -void RaiseScore(int value) -{ - /* EMC game engine and RND game engine have separate score counters */ - int *score = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? - &level.native_em_level->lev->score : &local_player->score); - - *score += value; - - DrawGameValue_Score(*score); -} -#endif - void RaiseScore(int value) { local_player->score += value; @@ -16455,6 +16531,12 @@ void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message) { if (skip_request || Request(message, REQ_ASK | REQ_STAY_CLOSED)) { +#if 1 + /* closing door required in case of envelope style request dialogs */ + if (!skip_request) + CloseDoor(DOOR_CLOSE_1); +#endif + #if defined(NETWORK_AVALIABLE) if (options.network) SendToServer_StopPlaying(NETWORK_STOP_BY_PLAYER); @@ -16513,7 +16595,7 @@ void RequestQuitGame(boolean ask_if_really_quit) boolean skip_request = AllPlayersGone || quick_quit; RequestQuitGameExt(skip_request, quick_quit, - "Do you really want to quit the game ?"); + "Do you really want to quit the game?"); } @@ -16521,7 +16603,7 @@ void RequestQuitGame(boolean ask_if_really_quit) /* random generator functions */ /* ------------------------------------------------------------------------- */ -unsigned int InitEngineRandom_RND(long seed) +unsigned int InitEngineRandom_RND(int seed) { game.num_random_calls = 0; @@ -16614,7 +16696,7 @@ static void SaveEngineSnapshotValues_RND() static void LoadEngineSnapshotValues_RND() { - unsigned long num_random_calls = game.num_random_calls; + unsigned int num_random_calls = game.num_random_calls; int i, j; for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) @@ -16658,6 +16740,14 @@ static void LoadEngineSnapshotValues_RND() } } +void FreeEngineSnapshot() +{ + FreeEngineSnapshotBuffers(); + + setString(&snapshot_level_identifier, NULL); + snapshot_level_nr = -1; +} + void SaveEngineSnapshot() { /* do not save snapshots from editor */ @@ -16667,6 +16757,25 @@ void SaveEngineSnapshot() /* free previous snapshot buffers, if needed */ FreeEngineSnapshotBuffers(); +#if 1 + /* copy some special values to a structure better suited for the snapshot */ + + if (level.game_engine_type == GAME_ENGINE_TYPE_RND) + SaveEngineSnapshotValues_RND(); + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + SaveEngineSnapshotValues_EM(); + if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + SaveEngineSnapshotValues_SP(); + + /* save values stored in special snapshot structure */ + + if (level.game_engine_type == GAME_ENGINE_TYPE_RND) + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd)); + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em)); + if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_sp)); +#else /* copy some special values to a structure better suited for the snapshot */ SaveEngineSnapshotValues_RND(); @@ -16678,6 +16787,7 @@ void SaveEngineSnapshot() SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_em)); SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_sp)); +#endif /* save further RND engine values */ @@ -16773,9 +16883,40 @@ void LoadEngineSnapshot() /* restore special values from snapshot structure */ +#if 1 + if (level.game_engine_type == GAME_ENGINE_TYPE_RND) + LoadEngineSnapshotValues_RND(); + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + LoadEngineSnapshotValues_EM(); + if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + LoadEngineSnapshotValues_SP(); +#else LoadEngineSnapshotValues_RND(); LoadEngineSnapshotValues_EM(); LoadEngineSnapshotValues_SP(); +#endif + +#if 0 + printf("::: %d, %d (LoadEngineSnapshot / 1)\n", scroll_x, scroll_y); +#endif + +#if 0 + // needed if tile size was different when saving and loading engine snapshot + if (local_player->present) + { + scroll_x = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left : + local_player->jx > SBX_Right + MIDPOSX ? SBX_Right : + local_player->jx - MIDPOSX); + + scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper : + local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower : + local_player->jy - MIDPOSY); + } +#endif + +#if 0 + printf("::: %d, %d (LoadEngineSnapshot / 1)\n", scroll_x, scroll_y); +#endif } boolean CheckEngineSnapshot() @@ -16818,6 +16959,14 @@ static struct { IMG_GAME_BUTTON_GFX_SOUND_SIMPLE, &game.button.sound_simple, SOUND_CTRL_ID_SIMPLE, "normal sounds on/off" + }, + { + IMG_GAME_BUTTON_GFX_SAVE, &game.button.save, + GAME_CTRL_ID_SAVE, "save game" + }, + { + IMG_GAME_BUTTON_GFX_LOAD, &game.button.load, + GAME_CTRL_ID_LOAD, "load game" } }; @@ -16832,7 +16981,9 @@ void CreateGameButtons() struct GadgetInfo *gi; int button_type; boolean checked; - unsigned long event_mask; + unsigned int event_mask; + int base_x = (tape.show_game_buttons ? VX : DX); + int base_y = (tape.show_game_buttons ? VY : DY); int gd_x = gfx->src_x; int gd_y = gfx->src_y; int gd_xp = gfx->src_x + gfx->pressed_xoffset; @@ -16843,9 +16994,18 @@ void CreateGameButtons() int gd_yap = gfx->src_y + gfx->active_yoffset + gfx->pressed_yoffset; int id = i; + if (gfx->bitmap == NULL) + { + game_gadget[id] = NULL; + + continue; + } + if (id == GAME_CTRL_ID_STOP || id == GAME_CTRL_ID_PAUSE || - id == GAME_CTRL_ID_PLAY) + id == GAME_CTRL_ID_PLAY || + id == GAME_CTRL_ID_SAVE || + id == GAME_CTRL_ID_LOAD) { button_type = GD_TYPE_NORMAL_BUTTON; checked = FALSE; @@ -16863,8 +17023,8 @@ void CreateGameButtons() gi = CreateGadget(GDI_CUSTOM_ID, id, GDI_INFO_TEXT, gamebutton_info[i].infotext, - GDI_X, DX + pos->x, - GDI_Y, DY + pos->y, + GDI_X, base_x + GDI_ACTIVE_POS(pos->x), + GDI_Y, base_y + GDI_ACTIVE_POS(pos->y), GDI_WIDTH, gfx->width, GDI_HEIGHT, gfx->height, GDI_TYPE, button_type, @@ -16894,7 +17054,7 @@ void FreeGameButtons() FreeGadget(game_gadget[i]); } -static void MapGameButtons() +void MapGameButtons() { int i; @@ -16916,24 +17076,35 @@ void RedrawGameButtons() for (i = 0; i < NUM_GAME_BUTTONS; i++) RedrawGadget(game_gadget[i]); + + // RedrawGadget() may have set REDRAW_ALL if buttons are defined off-area + redraw_mask &= ~REDRAW_ALL; } static void HandleGameButtonsExt(int id) { - if (game_status != GAME_MODE_PLAYING) + boolean handle_game_buttons = + (game_status == GAME_MODE_PLAYING || + (game_status == GAME_MODE_MAIN && tape.show_game_buttons)); + + if (!handle_game_buttons) return; switch (id) { case GAME_CTRL_ID_STOP: + if (game_status == GAME_MODE_MAIN) + break; + if (tape.playing) TapeStop(); else RequestQuitGame(TRUE); + break; case GAME_CTRL_ID_PAUSE: - if (options.network) + if (options.network && game_status == GAME_MODE_PLAYING) { #if defined(NETWORK_AVALIABLE) if (tape.pausing) @@ -16947,7 +17118,11 @@ static void HandleGameButtonsExt(int id) break; case GAME_CTRL_ID_PLAY: - if (tape.pausing) + if (game_status == GAME_MODE_MAIN) + { + StartGameActions(options.network, setup.autorecord, level.random_seed); + } + else if (tape.pausing) { #if defined(NETWORK_AVALIABLE) if (options.network) @@ -17000,6 +17175,14 @@ static void HandleGameButtonsExt(int id) } break; + case GAME_CTRL_ID_SAVE: + TapeQuickSave(); + break; + + case GAME_CTRL_ID_LOAD: + TapeQuickLoad(); + break; + default: break; }