X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=803eebb327f93d0ca0f6cc636a4f388025ceafbb;hb=3264a0dc5f07a6873bd99fb094b48879d4e6ed6b;hp=128c677f603ed1bac536fd04480b656e20160d9d;hpb=76966ac62fb1c36c12b64d60915afcbe149635ff;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 128c677f..803eebb3 100644 --- a/src/game.c +++ b/src/game.c @@ -4,7 +4,7 @@ // (c) 1995-2014 by Artsoft Entertainment // Holger Schemel // info@artsoft.org -// http://www.artsoft.org/ +// https://www.artsoft.org/ // ---------------------------------------------------------------------------- // game.c // ============================================================================ @@ -1785,7 +1785,7 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) player->jy = player->last_jy = y; } - if (!init_game) + // always check if player was just killed and should be reanimated { int player_nr = GET_PLAYER_NR(element); struct PlayerInfo *player = &stored_player[player_nr]; @@ -1877,6 +1877,8 @@ static void InitField(int x, int y, boolean init_game) case EL_MOLE_RIGHT: case EL_MOLE_UP: case EL_MOLE_DOWN: + case EL_SPRING_LEFT: + case EL_SPRING_RIGHT: InitMovDir(x, y); break; @@ -2840,10 +2842,84 @@ static void InitGameEngine(void) game.team_mode = (num_players > 1); } +#if 0 + printf("level %d: level.game_version == %06d\n", level_nr, + level.game_version); + printf(" tape.file_version == %06d\n", + tape.file_version); + printf(" tape.game_version == %06d\n", + tape.game_version); + printf(" tape.engine_version == %06d\n", + tape.engine_version); + printf(" => game.engine_version == %06d [tape mode: %s]\n", + game.engine_version, (tape.playing ? "PLAYING" : "RECORDING")); +#endif + // -------------------------------------------------------------------------- // set flags for bugs and changes according to active game engine version // -------------------------------------------------------------------------- + /* + Summary of bugfix: + Fixed property "can fall" for run-time element "EL_AMOEBA_DROPPING" + + Bug was introduced in version: + 2.0.1 + + Bug was fixed in version: + 4.1.4.2 + + Description: + In version 2.0.1, a new run-time element "EL_AMOEBA_DROPPING" was added, + but the property "can fall" was missing, which caused some levels to be + unsolvable. This was fixed in version 4.1.4.2. + + Affected levels/tapes: + An example for a tape that was fixed by this bugfix is tape 029 from the + level set "rnd_sam_bateman". + The wrong behaviour will still be used for all levels or tapes that were + created/recorded with it. An example for this is tape 023 from the level + set "rnd_gerhard_haeusler", which was recorded with a buggy game engine. + */ + + boolean use_amoeba_dropping_cannot_fall_bug = + ((game.engine_version >= VERSION_IDENT(2,0,1,0) && + game.engine_version <= VERSION_IDENT(4,1,4,1)) || + (tape.playing && + tape.game_version >= VERSION_IDENT(2,0,1,0) && + tape.game_version <= VERSION_IDENT(4,1,4,1))); + + /* + Summary of bugfix/change: + Fixed move speed of elements entering or leaving magic wall. + + Fixed/changed in version: + 2.0.1 + + Description: + Before 2.0.1, move speed of elements entering or leaving magic wall was + twice as fast as it is now. + Since 2.0.1, this is set to a lower value by using move_stepsize_list[]. + + Affected levels/tapes: + The first condition is generally needed for all levels/tapes before version + 2.0.1, which might use the old behaviour before it was changed; known tapes + that are affected: Tape 014 from the level set "rnd_conor_mancone". + The second condition is an exception from the above case and is needed for + the special case of tapes recorded with game (not engine!) version 2.0.1 or + above, but before it was known that this change would break tapes like the + above and was fixed in 4.1.4.2, so that the changed behaviour was active + although the engine version while recording maybe was before 2.0.1. There + are a lot of tapes that are affected by this exception, like tape 006 from + the level set "rnd_conor_mancone". + */ + + boolean use_old_move_stepsize_for_magic_wall = + (game.engine_version < VERSION_IDENT(2,0,1,0) && + !(tape.playing && + tape.game_version >= VERSION_IDENT(2,0,1,0) && + tape.game_version < VERSION_IDENT(4,1,4,2))); + /* Summary of bugfix/change: Fixed handling for custom elements that change when pushed by the player. @@ -2917,6 +2993,18 @@ static void InitGameEngine(void) game_em.use_old_explosions = (game.engine_version < VERSION_IDENT(4,1,4,2)); + game_em.use_old_android = + (game.engine_version < VERSION_IDENT(4,1,4,2)); + + game_em.use_old_push_elements = + (game.engine_version < VERSION_IDENT(4,1,4,2)); + + game_em.use_old_push_into_acid = + (game.engine_version < VERSION_IDENT(4,1,4,2)); + + game_em.use_wrap_around = + (game.engine_version > VERSION_IDENT(4,1,4,1)); + // -------------------------------------------------------------------------- // set maximal allowed number of custom element changes per game frame @@ -2928,13 +3016,11 @@ static void InitGameEngine(void) // dynamically adjust element properties according to game engine version InitElementPropertiesEngine(game.engine_version); -#if 0 - printf("level %d: level version == %06d\n", level_nr, level.game_version); - printf(" tape version == %06d [%s] [file: %06d]\n", - tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"), - tape.file_version); - printf(" => game.engine_version == %06d\n", game.engine_version); -#endif + // ---------- initialize special element properties ------------------------- + + // "EL_AMOEBA_DROPPING" missed property "can fall" between 2.0.1 and 4.1.4.1 + if (use_amoeba_dropping_cannot_fall_bug) + SET_PROPERTY(EL_AMOEBA_DROPPING, EP_CAN_FALL, FALSE); // ---------- initialize player's initial move delay ------------------------ @@ -3181,6 +3267,16 @@ static void InitGameEngine(void) int e = move_stepsize_list[i].element; element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize; + + // set move stepsize value for certain elements for older engine versions + if (use_old_move_stepsize_for_magic_wall) + { + if (e == EL_MAGIC_WALL_FILLING || + e == EL_MAGIC_WALL_EMPTYING || + e == EL_BD_MAGIC_WALL_FILLING || + e == EL_BD_MAGIC_WALL_EMPTYING) + element_info[e].move_stepsize *= 2; + } } // ---------- initialize collect score -------------------------------------- @@ -3279,6 +3375,34 @@ static void InitGameEngine(void) // Supaplex levels with time limit currently unsupported -- should be added if (level.game_engine_type == GAME_ENGINE_TYPE_SP) level.time = 0; + + // ---------- initialize flags for handling game actions -------------------- + + // set flags for game actions to default values + game.use_key_actions = TRUE; + game.use_mouse_actions = FALSE; + + // when using Mirror Magic game engine, handle mouse events only + if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + { + game.use_key_actions = FALSE; + game.use_mouse_actions = TRUE; + } + + // check for custom elements with mouse click events + if (level.game_engine_type == GAME_ENGINE_TYPE_RND) + { + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + + if (HAS_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) || + HAS_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) || + HAS_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) || + HAS_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X)) + game.use_mouse_actions = TRUE; + } + } } static int get_num_special_action(int element, int action_first, @@ -3391,6 +3515,13 @@ void InitGame(void) InitGameEngine(); InitGameControlValues(); + // initialize tape actions from game when recording tape + if (tape.recording) + { + tape.use_key_actions = game.use_key_actions; + tape.use_mouse_actions = game.use_mouse_actions; + } + // don't play tapes over network network_playing = (network.enabled && !tape.playing); @@ -3753,12 +3884,13 @@ void InitGame(void) // use preferred player also in local single-player mode if (!network.enabled && !game.team_mode) { - int old_index_nr = local_player->index_nr; int new_index_nr = setup.network_player_nr; if (new_index_nr >= 0 && new_index_nr < MAX_PLAYERS) { - stored_player[old_index_nr].connected_locally = FALSE; + for (i = 0; i < MAX_PLAYERS; i++) + stored_player[i].connected_locally = FALSE; + stored_player[new_index_nr].connected_locally = TRUE; } } @@ -4276,12 +4408,6 @@ void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y, { // this is used for non-R'n'D game engines to update certain engine values - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - { - actual_player_x = correctLevelPosX_EM(actual_player_x); - actual_player_y = correctLevelPosY_EM(actual_player_y); - } - // needed to determine if sounds are played within the visible screen area scroll_x = actual_scroll_x; scroll_y = actual_scroll_y; @@ -4374,6 +4500,12 @@ void InitMovDir(int x, int y) MovDir[x][y] = direction[2][element - EL_MOLE_LEFT]; break; + case EL_SPRING_LEFT: + case EL_SPRING_RIGHT: + Feld[x][y] = EL_SPRING; + MovDir[x][y] = direction[2][element - EL_SPRING_LEFT]; + break; + default: if (IS_CUSTOM_ELEMENT(element)) { @@ -9879,11 +10011,14 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) // ---------- player actions --------------------------------------------- case CA_MOVE_PLAYER: + case CA_MOVE_PLAYER_NEW: { // automatically move to the next field in specified direction for (i = 0; i < MAX_PLAYERS; i++) if (trigger_player_bits & (1 << i)) - stored_player[i].programmed_action = action_arg_direction; + if (action_type == CA_MOVE_PLAYER || + stored_player[i].MovPos == 0) + stored_player[i].programmed_action = action_arg_direction; break; } @@ -10159,6 +10294,9 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) if (CustomValue[x][y] == 0) { + // reset change counter (else CE_VALUE_GETS_ZERO would not work) + ChangeCount[x][y] = 0; // allow at least one more change + CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO); CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X); } @@ -10182,6 +10320,9 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) { int xx, yy; + // reset change counter (else CE_SCORE_GETS_ZERO would not work) + ChangeCount[x][y] = 0; // allow at least one more change + CheckElementChange(x, y, element, EL_UNDEFINED, CE_SCORE_GETS_ZERO); CheckTriggeredElementChange(x, y, element, CE_SCORE_GETS_ZERO_OF_X); @@ -11138,7 +11279,7 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) static void SetMouseActionFromTapeAction(struct MouseActionInfo *mouse_action, byte *tape_action) { - if (!tape.use_mouse) + if (!tape.use_mouse_actions) return; mouse_action->lx = tape_action[TAPE_ACTION_LX]; @@ -11149,7 +11290,7 @@ static void SetMouseActionFromTapeAction(struct MouseActionInfo *mouse_action, static void SetTapeActionFromMouseAction(byte *tape_action, struct MouseActionInfo *mouse_action) { - if (!tape.use_mouse) + if (!tape.use_mouse_actions) return; tape_action[TAPE_ACTION_LX] = mouse_action->lx; @@ -11347,7 +11488,7 @@ static void GameActionsExt(void) unsigned int game_frame_delay_value; byte *recorded_player_action; byte summarized_player_action = 0; - byte tape_action[MAX_PLAYERS]; + byte tape_action[MAX_TAPE_ACTIONS] = { 0 }; int i; // detect endless loops, caused by custom element programming @@ -11680,6 +11821,8 @@ void GameActions_RND_Main(void) void GameActions_RND(void) { + static struct MouseActionInfo mouse_action_last = { 0 }; + struct MouseActionInfo mouse_action = local_player->effective_mouse_action; int magic_wall_x = 0, magic_wall_y = 0; int i, x, y, element, graphic, last_gfx_frame; @@ -11866,6 +12009,24 @@ void GameActions_RND(void) #endif } + if (mouse_action.button) + { + int new_button = (mouse_action.button && mouse_action_last.button == 0); + + x = mouse_action.lx; + y = mouse_action.ly; + element = Feld[x][y]; + + if (new_button) + { + CheckElementChange(x, y, element, EL_UNDEFINED, CE_CLICKED_BY_MOUSE); + CheckTriggeredElementChange(x, y, element, CE_MOUSE_CLICKED_ON_X); + } + + CheckElementChange(x, y, element, EL_UNDEFINED, CE_PRESSED_BY_MOUSE); + CheckTriggeredElementChange(x, y, element, CE_MOUSE_PRESSED_ON_X); + } + SCAN_PLAYFIELD(x, y) { element = Feld[x][y]; @@ -12207,6 +12368,8 @@ void GameActions_RND(void) // use random number generator in every frame to make it less predictable if (game.engine_version >= VERSION_IDENT(3,1,1,0)) RND(1); + + mouse_action_last = mouse_action; } static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y) @@ -14709,9 +14872,9 @@ static void PlayLevelMusic(void) void PlayLevelSound_EM(int xx, int yy, int element_em, int sample) { int element = (element_em > -1 ? map_element_EM_to_RND_game(element_em) : 0); - int offset = (BorderElement == EL_STEELWALL ? 1 : 0); - int x = xx - 1 - offset; - int y = yy - 1 - offset; + int offset = 0; + int x = xx - offset; + int y = yy - offset; switch (sample) {