X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame.c;h=99540b18d9622ef055a0066d41c7e32f8dbb53d6;hp=965e42308c307329d1b6b7a7c0e9c3599d455a81;hb=1b4dc75992f4992654cf9ae5da9e525cb676345b;hpb=f77bbb8fc772782a6d4169d22a45716e9d4d0813 diff --git a/src/game.c b/src/game.c index 965e4230..99540b18 100644 --- a/src/game.c +++ b/src/game.c @@ -22,14 +22,14 @@ #include "anim.h" -/* DEBUG SETTINGS */ +// DEBUG SETTINGS #define DEBUG_INIT_PLAYER 1 #define DEBUG_PLAYER_ACTIONS 0 -/* EXPERIMENTAL STUFF */ +// EXPERIMENTAL STUFF #define USE_NEW_AMOEBA_CODE FALSE -/* EXPERIMENTAL STUFF */ +// EXPERIMENTAL STUFF #define USE_QUICKSAND_BD_ROCK_BUGFIX 0 #define USE_QUICKSAND_IMPACT_BUGFIX 0 #define USE_DELAYED_GFX_REDRAW 0 @@ -56,22 +56,22 @@ #endif -/* for DigField() */ +// for DigField() #define DF_NO_PUSH 0 #define DF_DIG 1 #define DF_SNAP 2 -/* for MovePlayer() */ +// for MovePlayer() #define MP_NO_ACTION 0 #define MP_MOVING 1 #define MP_ACTION 2 #define MP_DONT_RUN_INTO (MP_MOVING | MP_ACTION) -/* for ScrollPlayer() */ +// for ScrollPlayer() #define SCROLL_INIT 0 #define SCROLL_GO_ON 1 -/* for Bang()/Explode() */ +// for Bang()/Explode() #define EX_PHASE_START 0 #define EX_TYPE_NONE 0 #define EX_TYPE_NORMAL (1 << 0) @@ -81,12 +81,12 @@ #define EX_TYPE_DYNA (1 << 4) #define EX_TYPE_SINGLE_TILE (EX_TYPE_CENTER | EX_TYPE_BORDER) -#define PANEL_OFF() (local_player->LevelSolved_PanelOff) +#define PANEL_OFF() (game.panel.active == FALSE) #define PANEL_DEACTIVATED(p) ((p)->x < 0 || (p)->y < 0 || PANEL_OFF()) #define PANEL_XPOS(p) (DX + ALIGNED_TEXT_XPOS(p)) #define PANEL_YPOS(p) (DY + ALIGNED_TEXT_YPOS(p)) -/* game panel display and control definitions */ +// game panel display and control definitions #define GAME_PANEL_LEVEL_NUMBER 0 #define GAME_PANEL_GEMS 1 #define GAME_PANEL_INVENTORY_COUNT 2 @@ -831,17 +831,17 @@ static struct GamePanelControlInfo game_panel_controls[] = } }; -/* values for delayed check of falling and moving elements and for collision */ +// values for delayed check of falling and moving elements and for collision #define CHECK_DELAY_MOVING 3 #define CHECK_DELAY_FALLING CHECK_DELAY_MOVING #define CHECK_DELAY_COLLISION 2 #define CHECK_DELAY_IMPACT CHECK_DELAY_COLLISION -/* values for initial player move delay (initial delay counter value) */ +// values for initial player move delay (initial delay counter value) #define INITIAL_MOVE_DELAY_OFF -1 #define INITIAL_MOVE_DELAY_ON 0 -/* values for player movement speed (which is in fact a delay value) */ +// values for player movement speed (which is in fact a delay value) #define MOVE_DELAY_MIN_SPEED 32 #define MOVE_DELAY_NORMAL_SPEED 8 #define MOVE_DELAY_HIGH_SPEED 4 @@ -853,7 +853,7 @@ static struct GamePanelControlInfo game_panel_controls[] = #define DOUBLE_PLAYER_SPEED(p) (HALVE_MOVE_DELAY( (p)->move_delay_value)) #define HALVE_PLAYER_SPEED(p) (DOUBLE_MOVE_DELAY((p)->move_delay_value)) -/* values for scroll positions */ +// values for scroll positions #define SCROLL_POSITION_X(x) ((x) < SBX_Left + MIDPOSX ? SBX_Left : \ (x) > SBX_Right + MIDPOSX ? SBX_Right :\ (x) - MIDPOSX) @@ -861,7 +861,7 @@ static struct GamePanelControlInfo game_panel_controls[] = (y) > SBY_Lower + MIDPOSY ? SBY_Lower :\ (y) - MIDPOSY) -/* values for other actions */ +// values for other actions #define MOVE_STEPSIZE_NORMAL (TILEX / MOVE_DELAY_NORMAL_SPEED) #define MOVE_STEPSIZE_MIN (1) #define MOVE_STEPSIZE_MAX (TILEX) @@ -1004,7 +1004,7 @@ static struct GamePanelControlInfo game_panel_controls[] = #define MM_HEALTH(x) (MIN(MAX(0, MAX_HEALTH - (x)), MAX_HEALTH)) -/* game button identifiers */ +// game button identifiers #define GAME_CTRL_ID_STOP 0 #define GAME_CTRL_ID_PAUSE 1 #define GAME_CTRL_ID_PLAY 2 @@ -1026,7 +1026,7 @@ static struct GamePanelControlInfo game_panel_controls[] = #define NUM_GAME_BUTTONS 17 -/* forward declaration for internal use */ +// forward declaration for internal use static void CreateField(int, int, int); @@ -1085,8 +1085,8 @@ static void PlayLevelSoundElementAction(int, int, int, int); static void PlayLevelSoundElementActionIfLoop(int, int, int, int); static void PlayLevelSoundActionIfLoop(int, int, int); static void StopLevelSoundActionIfLoop(int, int, int); -static void PlayLevelMusic(); -static void FadeLevelSoundsAndMusic(); +static void PlayLevelMusic(void); +static void FadeLevelSoundsAndMusic(void); static void HandleGameButtons(struct GadgetInfo *); @@ -1119,8 +1119,8 @@ static int getInvisibleFromInvisibleActiveElement(int); static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS]; -/* for detection of endless loops, caused by custom element programming */ -/* (using maximal playfield width x 10 is just a rough approximation) */ +// for detection of endless loops, caused by custom element programming +// (using maximal playfield width x 10 is just a rough approximation) #define MAX_ELEMENT_CHANGE_RECURSION_DEPTH (MAX_PLAYFIELD_WIDTH * 10) #define RECURSION_LOOP_DETECTION_START(e, rc) \ @@ -1149,12 +1149,12 @@ static boolean recursion_loop_element; static int map_player_action[MAX_PLAYERS]; -/* ------------------------------------------------------------------------- */ -/* definition of elements that automatically change to other elements after */ -/* a specified time, eventually calling a function when changing */ -/* ------------------------------------------------------------------------- */ +// ---------------------------------------------------------------------------- +// definition of elements that automatically change to other elements after +// a specified time, eventually calling a function when changing +// ---------------------------------------------------------------------------- -/* forward declaration for changer functions */ +// forward declaration for changer functions static void InitBuggyBase(int, int); static void WarnBuggyBase(int, int); @@ -1548,7 +1548,7 @@ static boolean trigger_events[MAX_NUM_ELEMENTS][NUM_CHANGE_EVENTS]; #define CE_PAGE(e, ce) (element_info[e].event_page[ce]) -/* static variables for playfield scan mode (scanning forward or backward) */ +// static variables for playfield scan mode (scanning forward or backward) static int playfield_scan_start_x = 0; static int playfield_scan_start_y = 0; static int playfield_scan_delta_x = 1; @@ -1562,7 +1562,7 @@ static int playfield_scan_delta_y = 1; (x) += playfield_scan_delta_x) #ifdef DEBUG -void DEBUG_SetMaximumDynamite() +void DEBUG_SetMaximumDynamite(void) { int i; @@ -1573,7 +1573,7 @@ void DEBUG_SetMaximumDynamite() } #endif -static void InitPlayfieldScanModeVars() +static void InitPlayfieldScanModeVars(void) { if (game.use_reverse_scan_direction) { @@ -1606,7 +1606,7 @@ static int get_move_delay_from_stepsize(int move_stepsize) move_stepsize = MIN(MAX(MOVE_STEPSIZE_MIN, move_stepsize), MOVE_STEPSIZE_MAX); - /* make sure that stepsize value is always a power of 2 */ + // make sure that stepsize value is always a power of 2 move_stepsize = (1 << log_2(move_stepsize)); return TILEX / move_stepsize; @@ -1619,10 +1619,10 @@ static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize, int move_delay = get_move_delay_from_stepsize(move_stepsize); boolean cannot_move = (move_stepsize == STEPSIZE_NOT_MOVING ? TRUE : FALSE); - /* do no immediately change move delay -- the player might just be moving */ + // do no immediately change move delay -- the player might just be moving player->move_delay_value_next = move_delay; - /* information if player can move must be set separately */ + // information if player can move must be set separately player->cannot_move = cannot_move; if (init_game) @@ -1636,7 +1636,7 @@ static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize, } } -void GetPlayerConfig() +void GetPlayerConfig(void) { GameFrameDelay = setup.game_frame_delay; @@ -1683,6 +1683,30 @@ int GetElementFromGroupElement(int element) return element; } +static void IncrementSokobanFieldsNeeded(void) +{ + if (level.sb_fields_needed) + game.sokoban_fields_still_needed++; +} + +static void IncrementSokobanObjectsNeeded(void) +{ + if (level.sb_objects_needed) + game.sokoban_objects_still_needed++; +} + +static void DecrementSokobanFieldsNeeded(void) +{ + if (game.sokoban_fields_still_needed > 0) + game.sokoban_fields_still_needed--; +} + +static void DecrementSokobanObjectsNeeded(void) +{ + if (game.sokoban_objects_still_needed > 0) + game.sokoban_objects_still_needed--; +} + static void InitPlayerField(int x, int y, int element, boolean init_game) { if (element == EL_SP_MURPHY) @@ -1719,16 +1743,16 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) level.sp_block_last_field : level.block_last_field); - /* ---------- initialize player's last field block delay --------------- */ + // ---------- initialize player's last field block delay ------------------ - /* always start with reliable default value (no adjustment needed) */ + // always start with reliable default value (no adjustment needed) player->block_delay_adjustment = 0; - /* special case 1: in Supaplex, Murphy blocks last field one more frame */ + // special case 1: in Supaplex, Murphy blocks last field one more frame if (player->block_last_field && element == EL_SP_MURPHY) player->block_delay_adjustment = 1; - /* special case 2: in game engines before 3.1.1, blocking was different */ + // special case 2: in game engines before 3.1.1, blocking was different if (game.use_block_last_field_bug) player->block_delay_adjustment = (player->block_last_field ? -1 : 1); @@ -1736,7 +1760,7 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) { player->active = TRUE; - /* remove potentially duplicate players */ + // remove potentially duplicate players if (StorePlayer[jx][jy] == Feld[x][y]) StorePlayer[jx][jy] = 0; @@ -1765,7 +1789,7 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) struct PlayerInfo *player = &stored_player[player_nr]; if (player->active && player->killed) - player->reanimated = TRUE; /* if player was just killed, reanimate him */ + player->reanimated = TRUE; // if player was just killed, reanimate him } } @@ -1792,7 +1816,11 @@ static void InitField(int x, int y, boolean init_game) break; case EL_SOKOBAN_FIELD_EMPTY: - local_player->sokobanfields_still_needed++; + IncrementSokobanFieldsNeeded(); + break; + + case EL_SOKOBAN_OBJECT: + IncrementSokobanObjectsNeeded(); break; case EL_STONEBLOCK: @@ -1877,11 +1905,11 @@ static void InitField(int x, int y, boolean init_game) break; case EL_LAMP: - local_player->lights_still_needed++; + game.lights_still_needed++; break; case EL_PENGUIN: - local_player->friends_still_needed++; + game.friends_still_needed++; break; case EL_PIG: @@ -1907,12 +1935,12 @@ static void InitField(int x, int y, boolean init_game) int belt_dir = getBeltDirFromBeltSwitchElement(Feld[x][y]); int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(Feld[x][y]); - if (game.belt_dir_nr[belt_nr] == 3) /* initial value */ + if (game.belt_dir_nr[belt_nr] == 3) // initial value { game.belt_dir[belt_nr] = belt_dir; game.belt_dir_nr[belt_nr] = belt_dir_nr; } - else /* more than one switch -- set it like the first switch */ + else // more than one switch -- set it like the first switch { Feld[x][y] = Feld[x][y] - belt_dir_nr + game.belt_dir_nr[belt_nr]; } @@ -1966,7 +1994,7 @@ static void InitField(int x, int y, boolean init_game) case EL_NEXT_CE_6: case EL_NEXT_CE_7: case EL_NEXT_CE_8: - /* reference elements should not be used on the playfield */ + // reference elements should not be used on the playfield Feld[x][y] = EL_EMPTY; break; @@ -1993,23 +2021,23 @@ static void InitField(int x, int y, boolean init_game) CheckTriggeredElementChange(x, y, element, CE_CREATION_OF_X); } -inline static void InitField_WithBug1(int x, int y, boolean init_game) +static void InitField_WithBug1(int x, int y, boolean init_game) { InitField(x, y, init_game); - /* not needed to call InitMovDir() -- already done by InitField()! */ + // not needed to call InitMovDir() -- already done by InitField()! if (game.engine_version < VERSION_IDENT(3,1,0,0) && CAN_MOVE(Feld[x][y])) InitMovDir(x, y); } -inline static void InitField_WithBug2(int x, int y, boolean init_game) +static void InitField_WithBug2(int x, int y, boolean init_game) { int old_element = Feld[x][y]; InitField(x, y, init_game); - /* not needed to call InitMovDir() -- already done by InitField()! */ + // not needed to call InitMovDir() -- already done by InitField()! if (game.engine_version < VERSION_IDENT(3,1,0,0) && CAN_MOVE(old_element) && (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN)) @@ -2046,8 +2074,8 @@ static int get_next_dropped_element(struct PlayerInfo *player) static int get_inventory_element_from_pos(struct PlayerInfo *player, int pos) { - /* pos >= 0: get element from bottom of the stack; - pos < 0: get element from top of the stack */ + // pos >= 0: get element from bottom of the stack; + // pos < 0: get element from top of the stack if (pos < 0) { @@ -2103,7 +2131,7 @@ int getPlayerInventorySize(int player_nr) return stored_player[player_nr].inventory_size; } -void InitGameControlValues() +static void InitGameControlValues(void) { int i; @@ -2121,12 +2149,12 @@ void InitGameControlValues() Error(ERR_EXIT, "this should not happen -- please debug"); } - /* force update of game controls after initialization */ + // force update of game controls after initialization gpc->value = gpc->last_value = -1; gpc->frame = gpc->last_frame = -1; gpc->gfx_frame = -1; - /* determine panel value width for later calculation of alignment */ + // determine panel value width for later calculation of alignment if (type == TYPE_INTEGER || type == TYPE_STRING) { pos->width = pos->size * getFontWidth(pos->font); @@ -2138,22 +2166,22 @@ void InitGameControlValues() pos->height = pos->size; } - /* fill structure for game panel draw order */ + // fill structure for game panel draw order gpo->nr = gpc->nr; gpo->sort_priority = pos->sort_priority; } - /* sort game panel controls according to sort_priority and control number */ + // sort game panel controls according to sort_priority and control number qsort(game_panel_order, NUM_GAME_PANEL_CONTROLS, sizeof(struct GamePanelOrderInfo), compareGamePanelOrderInfo); } -void UpdatePlayfieldElementCount() +static void UpdatePlayfieldElementCount(void) { boolean use_element_count = FALSE; int i, j, x, y; - /* first check if it is needed at all to calculate playfield element count */ + // first check if it is needed at all to calculate playfield element count for (i = GAME_PANEL_ELEMENT_COUNT_1; i <= GAME_PANEL_ELEMENT_COUNT_8; i++) if (!PANEL_DEACTIVATED(game_panel_controls[i].pos)) use_element_count = TRUE; @@ -2176,11 +2204,11 @@ void UpdatePlayfieldElementCount() element_info[j].element_count; } -void UpdateGameControlValues() +static void UpdateGameControlValues(void) { int i, k; - int time = (local_player->LevelSolved ? - local_player->LevelSolved_CountingTime : + int time = (game.LevelSolved ? + game.LevelSolved_CountingTime : level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->time : level.game_engine_type == GAME_ENGINE_TYPE_SP ? @@ -2188,22 +2216,22 @@ void UpdateGameControlValues() level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.energy_left : game.no_time_limit ? TimePlayed : TimeLeft); - int score = (local_player->LevelSolved ? - local_player->LevelSolved_CountingScore : + int score = (game.LevelSolved ? + game.LevelSolved_CountingScore : level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->score : level.game_engine_type == GAME_ENGINE_TYPE_SP ? level.native_sp_level->game_sp->score : level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.score : - local_player->score); + game.score); int gems = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->required : level.game_engine_type == GAME_ENGINE_TYPE_SP ? level.native_sp_level->game_sp->infotrons_still_needed : level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.kettles_still_needed : - local_player->gems_still_needed); + game.gems_still_needed); int exit_closed = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? level.native_em_level->lev->required > 0 : level.game_engine_type == GAME_ENGINE_TYPE_SP ? @@ -2211,20 +2239,21 @@ void UpdateGameControlValues() level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.kettles_still_needed > 0 || game_mm.lights_still_needed > 0 : - local_player->gems_still_needed > 0 || - local_player->sokobanfields_still_needed > 0 || - local_player->lights_still_needed > 0); - int health = (local_player->LevelSolved ? - local_player->LevelSolved_CountingHealth : + game.gems_still_needed > 0 || + game.sokoban_fields_still_needed > 0 || + game.sokoban_objects_still_needed > 0 || + game.lights_still_needed > 0); + int health = (game.LevelSolved ? + game.LevelSolved_CountingHealth : level.game_engine_type == GAME_ENGINE_TYPE_MM ? MM_HEALTH(game_mm.laser_overload_value) : - local_player->health); + game.health); UpdatePlayfieldElementCount(); - /* update game panel control values */ + // update game panel control values - /* used instead of "level_nr" (for network games) */ + // used instead of "level_nr" (for network games) game_panel_controls[GAME_PANEL_LEVEL_NUMBER].value = levelset.level_nr; game_panel_controls[GAME_PANEL_GEMS].value = gems; @@ -2238,7 +2267,7 @@ void UpdateGameControlValues() { for (i = 0; i < MAX_PLAYERS; i++) { - /* only one player in Supaplex game engine */ + // only one player in Supaplex game engine if (level.game_engine_type == GAME_ENGINE_TYPE_SP && i > 0) break; @@ -2378,12 +2407,12 @@ void UpdateGameControlValues() (local_player->dynabomb_xl ? EL_DYNABOMB_INCREASE_POWER : EL_EMPTY); game_panel_controls[GAME_PANEL_PENGUINS].value = - local_player->friends_still_needed; + game.friends_still_needed; game_panel_controls[GAME_PANEL_SOKOBAN_OBJECTS].value = - local_player->sokobanfields_still_needed; + game.sokoban_objects_still_needed; game_panel_controls[GAME_PANEL_SOKOBAN_FIELDS].value = - local_player->sokobanfields_still_needed; + game.sokoban_fields_still_needed; game_panel_controls[GAME_PANEL_ROBOT_WHEEL].value = (game.robot_wheel_active ? EL_ROBOT_WHEEL_ACTIVE : EL_ROBOT_WHEEL); @@ -2433,7 +2462,7 @@ void UpdateGameControlValues() game_panel_controls[GAME_PANEL_LEVEL_NAME].value = 0; game_panel_controls[GAME_PANEL_LEVEL_AUTHOR].value = 0; - /* update game panel control frames */ + // update game panel control frames for (i = 0; game_panel_controls[i].nr != -1; i++) { @@ -2507,7 +2536,7 @@ void UpdateGameControlValues() } } -void DisplayGameControlValues() +static void DisplayGameControlValues(void) { boolean redraw_panel = FALSE; int i; @@ -2529,14 +2558,14 @@ void DisplayGameControlValues() if (!redraw_panel) return; - /* copy default game door content to main double buffer */ + // copy default game door content to main double buffer - /* !!! CHECK AGAIN !!! */ + // !!! CHECK AGAIN !!! SetPanelBackground(); // SetDoorBackgroundImage(IMG_BACKGROUND_PANEL); DrawBackground(DX, DY, DXSIZE, DYSIZE); - /* redraw game control buttons */ + // redraw game control buttons RedrawGameButtons(); SetGameStatus(GAME_MODE_PSEUDO_PANEL); @@ -2567,7 +2596,7 @@ void DisplayGameControlValues() { boolean use_dynamic_size = (size == -1 ? TRUE : FALSE); - if (use_dynamic_size) /* use dynamic number of digits */ + if (use_dynamic_size) // use dynamic number of digits { int value_change = (nr == GAME_PANEL_LEVEL_NUMBER ? 100 : 1000); int size1 = (nr == GAME_PANEL_LEVEL_NUMBER ? 2 : 3); @@ -2580,11 +2609,11 @@ void DisplayGameControlValues() } } - /* correct text size if "digits" is zero or less */ + // correct text size if "digits" is zero or less if (size <= 0) size = strlen(int2str(value, size)); - /* dynamically correct text alignment */ + // dynamically correct text alignment pos->width = size * getFontWidth(font); DrawTextExt(drawto, PANEL_XPOS(pos), PANEL_YPOS(pos), @@ -2724,8 +2753,8 @@ void DisplayGameControlValues() if (nr == GAME_PANEL_GRAVITY_STATE) { - int font1 = pos->font; /* (used for normal state) */ - int font2 = pos->font_alt; /* (used for active state) */ + int font1 = pos->font; // (used for normal state) + int font2 = pos->font_alt; // (used for active state) font = (active ? font2 : font1); } @@ -2736,10 +2765,10 @@ void DisplayGameControlValues() if (size <= 0) { - /* don't truncate output if "chars" is zero or less */ + // don't truncate output if "chars" is zero or less size = strlen(s); - /* dynamically correct text alignment */ + // dynamically correct text alignment pos->width = size * getFontWidth(font); } @@ -2758,7 +2787,7 @@ void DisplayGameControlValues() SetGameStatus(GAME_MODE_PLAYING); } -void UpdateAndDisplayGameControlValues() +void UpdateAndDisplayGameControlValues(void) { if (tape.deactivate_display) return; @@ -2767,34 +2796,34 @@ void UpdateAndDisplayGameControlValues() DisplayGameControlValues(); } -void UpdateGameDoorValues() +#if 0 +static void UpdateGameDoorValues(void) { UpdateGameControlValues(); } +#endif -void DrawGameDoorValues() +void DrawGameDoorValues(void) { DisplayGameControlValues(); } -/* - ============================================================================= - InitGameEngine() - ----------------------------------------------------------------------------- - initialize game engine due to level / tape version number - ============================================================================= -*/ +// ============================================================================ +// InitGameEngine() +// ---------------------------------------------------------------------------- +// initialize game engine due to level / tape version number +// ============================================================================ -static void InitGameEngine() +static void InitGameEngine(void) { int i, j, k, l, x, y; - /* set game engine from tape file when re-playing, else from level file */ + // set game engine from tape file when re-playing, else from level file game.engine_version = (tape.playing ? tape.engine_version : level.game_version); - /* set single or multi-player game mode (needed for re-playing tapes) */ + // set single or multi-player game mode (needed for re-playing tapes) game.team_mode = setup.team_mode; if (tape.playing) @@ -2805,13 +2834,13 @@ static void InitGameEngine() if (tape.player_participates[i]) num_players++; - /* multi-player tapes contain input data for more than one player */ + // 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 */ - /* ---------------------------------------------------------------------- */ + // -------------------------------------------------------------------------- + // set flags for bugs and changes according to active game engine version + // -------------------------------------------------------------------------- /* Summary of bugfix/change: @@ -2881,15 +2910,15 @@ static void InitGameEngine() game_em.use_snap_key_bug = (game.engine_version < VERSION_IDENT(4,0,1,0)); - /* ---------------------------------------------------------------------- */ + // -------------------------------------------------------------------------- - /* set maximal allowed number of custom element changes per game frame */ + // set maximal allowed number of custom element changes per game frame game.max_num_changes_per_frame = 1; - /* default scan direction: scan playfield from top/left to bottom/right */ + // default scan direction: scan playfield from top/left to bottom/right InitPlayfieldScanMode(CA_ARG_SCAN_MODE_NORMAL); - /* dynamically adjust element properties according to game engine version */ + // dynamically adjust element properties according to game engine version InitElementPropertiesEngine(game.engine_version); #if 0 @@ -2900,33 +2929,33 @@ static void InitGameEngine() printf(" => game.engine_version == %06d\n", game.engine_version); #endif - /* ---------- initialize player's initial move delay --------------------- */ + // ---------- initialize player's initial move delay ------------------------ - /* dynamically adjust player properties according to level information */ + // dynamically adjust player properties according to level information for (i = 0; i < MAX_PLAYERS; i++) game.initial_move_delay_value[i] = get_move_delay_from_stepsize(level.initial_player_stepsize[i]); - /* dynamically adjust player properties according to game engine version */ + // dynamically adjust player properties according to game engine version for (i = 0; i < MAX_PLAYERS; i++) game.initial_move_delay[i] = (game.engine_version <= VERSION_IDENT(2,0,1,0) ? game.initial_move_delay_value[i] : 0); - /* ---------- initialize player's initial push delay --------------------- */ + // ---------- initialize player's initial push delay ------------------------ - /* dynamically adjust player properties according to game engine version */ + // dynamically adjust player properties according to game engine version game.initial_push_delay_value = (game.engine_version < VERSION_IDENT(3,0,7,1) ? 5 : -1); - /* ---------- initialize changing elements ------------------------------- */ + // ---------- initialize changing elements ---------------------------------- - /* initialize changing elements information */ + // initialize changing elements information for (i = 0; i < MAX_NUM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[i]; - /* this pointer might have been changed in the level editor */ + // this pointer might have been changed in the level editor ei->change = &ei->change_page[0]; if (!IS_CUSTOM_ELEMENT(i)) @@ -2946,7 +2975,7 @@ static void InitGameEngine() } } - /* add changing elements from pre-defined list */ + // add changing elements from pre-defined list for (i = 0; change_delay_list[i].element != EL_UNDEFINED; i++) { struct ChangingElementInfo *ch_delay = &change_delay_list[i]; @@ -2968,7 +2997,7 @@ static void InitGameEngine() SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE_OR_HAS_ACTION, TRUE); } - /* ---------- initialize internal run-time variables --------------------- */ + // ---------- initialize internal run-time variables ------------------------ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { @@ -2982,7 +3011,7 @@ static void InitGameEngine() } } - /* add change events from custom element configuration */ + // add change events from custom element configuration for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i]; @@ -2994,7 +3023,7 @@ static void InitGameEngine() for (k = 0; k < NUM_CHANGE_EVENTS; k++) { - /* only add event page for the first page found with this event */ + // only add event page for the first page found with this event if (ei->change_page[j].has_event[k] && !(ei->has_change_event[k])) { ei->has_change_event[k] = TRUE; @@ -3006,7 +3035,7 @@ static void InitGameEngine() } } - /* ---------- initialize reference elements in change conditions --------- */ + // ---------- initialize reference elements in change conditions ------------ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { @@ -3025,7 +3054,7 @@ static void InitGameEngine() } } - /* ---------- initialize run-time trigger player and element ------------- */ + // ---------- initialize run-time trigger player and element ---------------- for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { @@ -3042,14 +3071,14 @@ static void InitGameEngine() } } - /* ---------- initialize trigger events ---------------------------------- */ + // ---------- initialize trigger events ------------------------------------- - /* initialize trigger events information */ + // initialize trigger events information for (i = 0; i < MAX_NUM_ELEMENTS; i++) for (j = 0; j < NUM_CHANGE_EVENTS; j++) trigger_events[i][j] = FALSE; - /* add trigger events from element change event properties */ + // add trigger events from element change event properties for (i = 0; i < MAX_NUM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[i]; @@ -3086,14 +3115,14 @@ static void InitGameEngine() } } - /* ---------- initialize push delay -------------------------------------- */ + // ---------- initialize push delay ----------------------------------------- - /* initialize push delay values to default */ + // initialize push delay values to default for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (!IS_CUSTOM_ELEMENT(i)) { - /* set default push delay values (corrected since version 3.0.7-1) */ + // set default push delay values (corrected since version 3.0.7-1) if (game.engine_version < VERSION_IDENT(3,0,7,1)) { element_info[i].push_delay_fixed = 2; @@ -3107,7 +3136,7 @@ static void InitGameEngine() } } - /* set push delay value for certain elements from pre-defined list */ + // set push delay value for certain elements from pre-defined list for (i = 0; push_delay_list[i].element != EL_UNDEFINED; i++) { int e = push_delay_list[i].element; @@ -3116,14 +3145,14 @@ static void InitGameEngine() element_info[e].push_delay_random = push_delay_list[i].push_delay_random; } - /* set push delay value for Supaplex elements for newer engine versions */ + // set push delay value for Supaplex elements for newer engine versions if (game.engine_version >= VERSION_IDENT(3,1,0,0)) { for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (IS_SP_ELEMENT(i)) { - /* set SP push delay to just enough to push under a falling zonk */ + // set SP push delay to just enough to push under a falling zonk int delay = (game.engine_version >= VERSION_IDENT(3,1,1,0) ? 8 : 6); element_info[i].push_delay_fixed = delay; @@ -3132,14 +3161,14 @@ static void InitGameEngine() } } - /* ---------- initialize move stepsize ----------------------------------- */ + // ---------- initialize move stepsize -------------------------------------- - /* initialize move stepsize values to default */ + // initialize move stepsize values to default for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (!IS_CUSTOM_ELEMENT(i)) element_info[i].move_stepsize = MOVE_STEPSIZE_NORMAL; - /* set move stepsize value for certain elements from pre-defined list */ + // set move stepsize value for certain elements from pre-defined list for (i = 0; move_stepsize_list[i].element != EL_UNDEFINED; i++) { int e = move_stepsize_list[i].element; @@ -3147,38 +3176,38 @@ static void InitGameEngine() element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize; } - /* ---------- initialize collect score ----------------------------------- */ + // ---------- initialize collect score -------------------------------------- - /* initialize collect score values for custom elements from initial value */ + // initialize collect score values for custom elements from initial value for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (IS_CUSTOM_ELEMENT(i)) element_info[i].collect_score = element_info[i].collect_score_initial; - /* ---------- initialize collect count ----------------------------------- */ + // ---------- initialize collect count -------------------------------------- - /* initialize collect count values for non-custom elements */ + // initialize collect count values for non-custom elements for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (!IS_CUSTOM_ELEMENT(i)) element_info[i].collect_count_initial = 0; - /* add collect count values for all elements from pre-defined list */ + // add collect count values for all elements from pre-defined list for (i = 0; collect_count_list[i].element != EL_UNDEFINED; i++) element_info[collect_count_list[i].element].collect_count_initial = collect_count_list[i].count; - /* ---------- initialize access direction -------------------------------- */ + // ---------- initialize access direction ----------------------------------- - /* initialize access direction values to default (access from every side) */ + // initialize access direction values to default (access from every side) for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (!IS_CUSTOM_ELEMENT(i)) element_info[i].access_direction = MV_ALL_DIRECTIONS; - /* set access direction value for certain elements from pre-defined list */ + // set access direction value for certain elements from pre-defined list for (i = 0; access_direction_list[i].element != EL_UNDEFINED; i++) element_info[access_direction_list[i].element].access_direction = access_direction_list[i].direction; - /* ---------- initialize explosion content ------------------------------- */ + // ---------- initialize explosion content ---------------------------------- for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (IS_CUSTOM_ELEMENT(i)) @@ -3186,7 +3215,7 @@ static void InitGameEngine() for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) { - /* (content for EL_YAMYAM set at run-time with game.yamyam_content_nr) */ + // (content for EL_YAMYAM set at run-time with game.yamyam_content_nr) element_info[i].content.e[x][y] = (i == EL_PLAYER_1 ? EL_EMERALD_YELLOW : @@ -3211,19 +3240,19 @@ static void InitGameEngine() } } - /* ---------- initialize recursion detection ------------------------------ */ + // ---------- initialize recursion detection -------------------------------- recursion_loop_depth = 0; recursion_loop_detected = FALSE; recursion_loop_element = EL_UNDEFINED; - /* ---------- initialize graphics engine ---------------------------------- */ + // ---------- initialize graphics engine ------------------------------------ game.scroll_delay_value = (game.forced_scroll_delay_value != -1 ? game.forced_scroll_delay_value : setup.scroll_delay ? setup.scroll_delay_value : 0); game.scroll_delay_value = MIN(MAX(MIN_SCROLL_DELAY, game.scroll_delay_value), MAX_SCROLL_DELAY); - /* ---------- initialize game engine snapshots ---------------------------- */ + // ---------- initialize game engine snapshots ------------------------------ for (i = 0; i < MAX_PLAYERS; i++) game.snapshot.last_action[i] = 0; game.snapshot.changed_action = FALSE; @@ -3237,13 +3266,14 @@ static void InitGameEngine() SNAPSHOT_MODE_EVERY_COLLECT : SNAPSHOT_MODE_OFF); game.snapshot.save_snapshot = FALSE; - /* ---------- initialize level time for Supaplex engine ------------------- */ - /* Supaplex levels with time limit currently unsupported -- should be added */ + // ---------- initialize level time for Supaplex engine --------------------- + // Supaplex levels with time limit currently unsupported -- should be added if (level.game_engine_type == GAME_ENGINE_TYPE_SP) level.time = 0; } -int get_num_special_action(int element, int action_first, int action_last) +static int get_num_special_action(int element, int action_first, + int action_last) { int num_special_action = 0; int i, j; @@ -3267,13 +3297,11 @@ int get_num_special_action(int element, int action_first, int action_last) } -/* - ============================================================================= - InitGame() - ----------------------------------------------------------------------------- - initialize and start new game - ============================================================================= -*/ +// ============================================================================ +// InitGame() +// ---------------------------------------------------------------------------- +// initialize and start new game +// ============================================================================ #if DEBUG_INIT_PLAYER static void DebugPrintPlayerStatus(char *message) @@ -3305,15 +3333,15 @@ static void DebugPrintPlayerStatus(char *message) } #endif -void InitGame() +void InitGame(void) { int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0); int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0); int fade_mask = REDRAW_FIELD; - 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 */ + 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 int initial_move_dir = MV_DOWN; int i, j, x, y; @@ -3330,16 +3358,17 @@ void InitGame() else FadeSetEnterScreen(); - if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) + if (CheckFadeAll()) fade_mask = REDRAW_ALL; FadeLevelSoundsAndMusic(); ExpireSoundLoops(TRUE); - FadeOut(fade_mask); + if (!level_editor_test_game) + FadeOut(fade_mask); - /* needed if different viewport properties defined for playing */ + // needed if different viewport properties defined for playing ChangeViewportPropertiesIfNeeded(); ClearField(); @@ -3351,7 +3380,7 @@ void InitGame() InitGameEngine(); InitGameControlValues(); - /* don't play tapes over network */ + // don't play tapes over network network_playing = (network.enabled && !tape.playing); for (i = 0; i < MAX_PLAYERS; i++) @@ -3368,6 +3397,7 @@ void InitGame() player->killed = FALSE; player->reanimated = FALSE; + player->buried = FALSE; player->action = 0; player->effective_action = 0; @@ -3383,18 +3413,6 @@ void InitGame() player->effective_mouse_action.button = 0; player->effective_mouse_action.button_hint = 0; - player->score = 0; - player->score_final = 0; - - player->health = MAX_HEALTH; - player->health_final = MAX_HEALTH; - - player->gems_still_needed = level.gems_needed; - player->sokobanfields_still_needed = 0; - player->lights_still_needed = 0; - player->players_still_needed = 0; - player->friends_still_needed = 0; - for (j = 0; j < MAX_NUM_KEYS; j++) player->key[j] = FALSE; @@ -3419,8 +3437,8 @@ void InitGame() player->element_nr); player->use_murphy = FALSE; - player->block_last_field = FALSE; /* initialized in InitPlayerField() */ - player->block_delay_adjustment = 0; /* initialized in InitPlayerField() */ + player->block_last_field = FALSE; // initialized in InitPlayerField() + player->block_delay_adjustment = 0; // initialized in InitPlayerField() player->gravity = level.initial_player_gravity[i]; @@ -3477,7 +3495,7 @@ void InitGame() SetPlayerMoveSpeed(player, level.initial_player_stepsize[i], TRUE); - player->push_delay = -1; /* initialized when pushing starts */ + player->push_delay = -1; // initialized when pushing starts player->push_delay_value = game.initial_push_delay_value; player->drop_delay = 0; @@ -3517,31 +3535,15 @@ void InitGame() DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH); SnapField(player, 0, 0); - player->LevelSolved = FALSE; - player->GameOver = FALSE; - - player->LevelSolved_GameWon = FALSE; - player->LevelSolved_GameEnd = FALSE; - player->LevelSolved_PanelOff = FALSE; - player->LevelSolved_SaveTape = FALSE; - player->LevelSolved_SaveScore = FALSE; - - player->LevelSolved_CountingTime = 0; - player->LevelSolved_CountingScore = 0; - player->LevelSolved_CountingHealth = 0; - map_player_action[i] = i; } network_player_action_received = FALSE; - /* initial null action */ + // initial null action if (network_playing) SendToServer_MovePlayer(MV_NONE); - ZX = ZY = -1; - ExitX = ExitY = -1; - FrameCounter = 0; TimeFrames = 0; TimePlayed = 0; @@ -3552,9 +3554,31 @@ void InitGame() ScreenMovPos = 0; ScreenGfxPos = 0; - ScrollStepSize = 0; /* will be correctly initialized by ScrollScreen() */ + ScrollStepSize = 0; // will be correctly initialized by ScrollScreen() + + game.robot_wheel_x = -1; + game.robot_wheel_y = -1; + + game.exit_x = -1; + game.exit_y = -1; + + game.all_players_gone = FALSE; - AllPlayersGone = FALSE; + game.LevelSolved = FALSE; + game.GameOver = FALSE; + + game.GamePlayed = !tape.playing; + + game.LevelSolved_GameWon = FALSE; + game.LevelSolved_GameEnd = FALSE; + game.LevelSolved_SaveTape = FALSE; + game.LevelSolved_SaveScore = FALSE; + + game.LevelSolved_CountingTime = 0; + game.LevelSolved_CountingScore = 0; + game.LevelSolved_CountingHealth = 0; + + game.panel.active = TRUE; game.no_time_limit = (level.time == 0); @@ -3567,18 +3591,33 @@ void InitGame() game.switchgate_pos = 0; game.wind_direction = level.wind_direction_initial; + game.score = 0; + game.score_final = 0; + + game.health = MAX_HEALTH; + game.health_final = MAX_HEALTH; + + game.gems_still_needed = level.gems_needed; + game.sokoban_fields_still_needed = 0; + game.sokoban_objects_still_needed = 0; + game.lights_still_needed = 0; + game.players_still_needed = 0; + game.friends_still_needed = 0; + game.lenses_time_left = 0; game.magnify_time_left = 0; game.ball_state = level.ball_state_initial; game.ball_content_nr = 0; + game.explosions_delayed = TRUE; + game.envelope_active = FALSE; for (i = 0; i < NUM_BELTS; i++) { game.belt_dir[i] = MV_NONE; - game.belt_dir_nr[i] = 3; /* not moving, next moving left */ + game.belt_dir_nr[i] = 3; // not moving, next moving left } for (i = 0; i < MAX_NUM_AMOEBA; i++) @@ -3590,11 +3629,11 @@ void InitGame() SCAN_PLAYFIELD(x, y) { - Feld[x][y] = level.field[x][y]; + Feld[x][y] = Last[x][y] = level.field[x][y]; MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; - CustomValue[x][y] = 0; /* initialized in InitField() */ + CustomValue[x][y] = 0; // initialized in InitField() Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0; AmoebaNr[x][y] = 0; WasJustMoving[x][y] = 0; @@ -3642,7 +3681,7 @@ void InitGame() { struct PlayerInfo *player = &stored_player[i]; - /* set number of special actions for bored and sleeping animation */ + // set number of special actions for bored and sleeping animation player->num_special_action_bored = get_num_special_action(player->artwork_element, ACTION_BORING_1, ACTION_BORING_LAST); @@ -3655,25 +3694,25 @@ void InitGame() emulate_sb ? EMU_SOKOBAN : emulate_sp ? EMU_SUPAPLEX : EMU_NONE); - /* initialize type of slippery elements */ + // initialize type of slippery elements for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (!IS_CUSTOM_ELEMENT(i)) { - /* default: elements slip down either to the left or right randomly */ + // default: elements slip down either to the left or right randomly element_info[i].slippery_type = SLIPPERY_ANY_RANDOM; - /* SP style elements prefer to slip down on the left side */ + // SP style elements prefer to slip down on the left side if (game.engine_version >= VERSION_IDENT(3,1,1,0) && IS_SP_ELEMENT(i)) element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT; - /* BD style elements prefer to slip down on the left side */ + // BD style elements prefer to slip down on the left side if (game.emulation == EMU_BOULDERDASH) element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT; } } - /* initialize explosion and ignition delay */ + // initialize explosion and ignition delay for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (!IS_CUSTOM_ELEMENT(i)) @@ -3693,17 +3732,17 @@ void InitGame() } } - /* correct non-moving belts to start moving left */ + // correct non-moving belts to start moving left for (i = 0; i < NUM_BELTS; i++) if (game.belt_dir[i] == MV_NONE) - game.belt_dir_nr[i] = 3; /* not moving, next moving left */ + game.belt_dir_nr[i] = 3; // not moving, next moving left #if USE_NEW_PLAYER_ASSIGNMENTS for (i = 0; i < MAX_PLAYERS; i++) { stored_player[i].connected = FALSE; - /* in network game mode, the local player might not be the first player */ + // in network game mode, the local player might not be the first player if (stored_player[i].connected_locally) local_player = &stored_player[i]; } @@ -3718,8 +3757,8 @@ void InitGame() } else if (network.enabled) { - /* add team mode players connected over the network (needed for correct - assignment of player figures from level to locally playing players) */ + // add team mode players connected over the network (needed for correct + // assignment of player figures from level to locally playing players) for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].connected_network) @@ -3727,8 +3766,8 @@ void InitGame() } else if (game.team_mode) { - /* try to guess locally connected team mode players (needed for correct - assignment of player figures from level to locally playing players) */ + // 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 (setup.input[i].use_joystick || @@ -3745,7 +3784,7 @@ void InitGame() printf("Reassigning players ...\n"); #endif - /* check if any connected player was not found in playfield */ + // check if any connected player was not found in playfield for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; @@ -3759,9 +3798,9 @@ void InitGame() printf("- looking for field player for player %d ...\n", i + 1); #endif - /* assign first free player found that is present in the playfield */ + // assign first free player found that is present in the playfield - /* first try: look for unmapped playfield player that is not connected */ + // 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 && @@ -3769,7 +3808,7 @@ void InitGame() !stored_player[j].connected) field_player = &stored_player[j]; - /* second try: look for *any* unmapped playfield player */ + // second try: look for *any* unmapped playfield player for (j = 0; j < MAX_PLAYERS; j++) if (field_player == NULL && stored_player[j].present && @@ -3829,7 +3868,7 @@ void InitGame() #else - /* check if any connected player was not found in playfield */ + // check if any connected player was not found in playfield for (i = 0; i < MAX_PLAYERS; i++) { struct PlayerInfo *player = &stored_player[i]; @@ -3841,7 +3880,7 @@ void InitGame() struct PlayerInfo *field_player = &stored_player[j]; int jx = field_player->jx, jy = field_player->jy; - /* assign first free player found that is present in the playfield */ + // assign first free player found that is present in the playfield if (field_player->present && !field_player->connected) { player->present = TRUE; @@ -3872,21 +3911,21 @@ void InitGame() printf("::: local_player->present == %d\n", local_player->present); #endif - /* set focus to local player for network games, else to all players */ + // set focus to local player for network games, else to all players game.centered_player_nr = (network_playing ? local_player->index_nr : -1); game.centered_player_nr_next = game.centered_player_nr; game.set_centered_player = FALSE; if (network_playing && tape.recording) { - /* store client dependent player focus when recording network games */ + // store client dependent player focus when recording network games tape.centered_player_nr_next = game.centered_player_nr_next; tape.set_centered_player = TRUE; } if (tape.playing) { - /* when playing a tape, eliminate all players who do not participate */ + // when playing a tape, eliminate all players who do not participate #if USE_NEW_PLAYER_ASSIGNMENTS @@ -3929,9 +3968,9 @@ void InitGame() } #endif } - else if (!network.enabled && !game.team_mode) /* && !tape.playing */ + else if (!network.enabled && !game.team_mode) // && !tape.playing { - /* when in single player mode, eliminate all but the local player */ + // when in single player mode, eliminate all but the local player for (i = 0; i < MAX_PLAYERS; i++) { @@ -3952,9 +3991,12 @@ void InitGame() for (i = 0; i < MAX_PLAYERS; i++) if (stored_player[i].active) - local_player->players_still_needed++; + game.players_still_needed++; + + if (level.solved_by_one_player) + game.players_still_needed = 1; - /* when recording the game, store which players take part in the game */ + // when recording the game, store which players take part in the game if (tape.recording) { #if USE_NEW_PLAYER_ASSIGNMENTS @@ -3997,8 +4039,8 @@ void InitGame() if (EVEN(SCR_FIELDY) && full_lev_fieldy > SCR_FIELDY) SBY_Upper--; - /* if local player not found, look for custom element that might create - the player (make some assumptions about the right custom element) */ + // if local player not found, look for custom element that might create + // the player (make some assumptions about the right custom element) if (!local_player->present) { int start_x = 0, start_y = 0; @@ -4031,7 +4073,7 @@ void InitGame() { for (i = 0; i < element_info[element].num_change_pages; i++) { - /* check for player created from custom element as single target */ + // check for player created from custom element as single target content = element_info[element].change_page[i].target_element; is_player = ELEM_IS_PLAYER(content); @@ -4049,7 +4091,7 @@ void InitGame() for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3; xx++) { - /* check for player created from custom element as explosion content */ + // check for player created from custom element as explosion content content = element_info[element].content.e[xx][yy]; is_player = ELEM_IS_PLAYER(content); @@ -4068,7 +4110,7 @@ void InitGame() for (i = 0; i < element_info[element].num_change_pages; i++) { - /* check for player created from custom element as extended target */ + // check for player created from custom element as extended target content = element_info[element].change_page[i].target_content.e[xx][yy]; @@ -4096,7 +4138,7 @@ void InitGame() scroll_y = SCROLL_POSITION_Y(local_player->jy); } - /* !!! FIX THIS (START) !!! */ + // !!! FIX THIS (START) !!! if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { InitGameEngine_EM(); @@ -4114,14 +4156,14 @@ void InitGame() DrawLevel(REDRAW_FIELD); DrawAllPlayers(); - /* after drawing the level, correct some elements */ + // after drawing the level, correct some elements if (game.timegate_time_left == 0) CloseAllOpenTimegates(); } - /* blit playfield from scroll buffer to normal back buffer for fading in */ + // blit playfield from scroll buffer to normal back buffer for fading in BlitScreenToBitmap(backbuffer); - /* !!! FIX THIS (END) !!! */ + // !!! FIX THIS (END) !!! DrawMaskedBorder(fade_mask); @@ -4137,9 +4179,9 @@ void InitGame() if (!game.restart_level) { - /* copy default game door content to main double buffer */ + // copy default game door content to main double buffer - /* !!! CHECK AGAIN !!! */ + // !!! CHECK AGAIN !!! SetPanelBackground(); // SetDoorBackgroundImage(IMG_BACKGROUND_PANEL); DrawBackground(DX, DY, DXSIZE, DYSIZE); @@ -4161,7 +4203,7 @@ void InitGame() MapGameButtons(); MapTapeButtons(); - /* copy actual game door content to door double buffer for OpenDoor() */ + // copy actual game door content to door double buffer for OpenDoor() BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0); OpenDoor(DOOR_OPEN_ALL); @@ -4187,6 +4229,7 @@ void InitGame() game.restart_level = FALSE; game.restart_game_message = NULL; + game.request_active = FALSE; if (level.game_engine_type == GAME_ENGINE_TYPE_MM) InitGameActions_MM(); @@ -4205,7 +4248,7 @@ void InitGame() void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y, int actual_player_x, int actual_player_y) { - /* this is used for non-R'n'D game engines to update certain engine values */ + // this is used for non-R'n'D game engines to update certain engine values if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { @@ -4213,11 +4256,11 @@ void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y, actual_player_y = correctLevelPosY_EM(actual_player_y); } - /* needed to determine if sounds are played within the visible screen area */ + // needed to determine if sounds are played within the visible screen area scroll_x = actual_scroll_x; scroll_y = actual_scroll_y; - /* needed to get player position for "follow finger" playing input method */ + // needed to get player position for "follow finger" playing input method local_player->jx = actual_player_x; local_player->jy = actual_player_y; } @@ -4340,7 +4383,7 @@ void InitMovDir(int x, int y) else if (move_pattern == MV_ALONG_LEFT_SIDE || move_pattern == MV_ALONG_RIGHT_SIDE) { - /* use random direction as default start direction */ + // use random direction as default start direction if (game.engine_version >= VERSION_IDENT(3,1,0,0)) MovDir[x][y] = 1 << RND(4); @@ -4420,31 +4463,30 @@ void InitAmoebaNr(int x, int y) AmoebaCnt2[group_nr]++; } -static void PlayerWins(struct PlayerInfo *player) +static void LevelSolved(void) { if (level.game_engine_type == GAME_ENGINE_TYPE_RND && - local_player->players_still_needed > 0) + game.players_still_needed > 0) return; - player->LevelSolved = TRUE; - player->GameOver = TRUE; + game.LevelSolved = TRUE; + game.GameOver = TRUE; - player->score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? - level.native_em_level->lev->score : - level.game_engine_type == GAME_ENGINE_TYPE_MM ? - game_mm.score : - player->score); - player->health_final = (level.game_engine_type == GAME_ENGINE_TYPE_MM ? - MM_HEALTH(game_mm.laser_overload_value) : - player->health); + game.score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ? + level.native_em_level->lev->score : + level.game_engine_type == GAME_ENGINE_TYPE_MM ? + game_mm.score : + game.score); + game.health_final = (level.game_engine_type == GAME_ENGINE_TYPE_MM ? + MM_HEALTH(game_mm.laser_overload_value) : + game.health); - player->LevelSolved_CountingTime = (game.no_time_limit ? TimePlayed : - TimeLeft); - player->LevelSolved_CountingScore = player->score_final; - player->LevelSolved_CountingHealth = player->health_final; + game.LevelSolved_CountingTime = (game.no_time_limit ? TimePlayed : TimeLeft); + game.LevelSolved_CountingScore = game.score_final; + game.LevelSolved_CountingHealth = game.health_final; } -void GameWon() +void GameWon(void) { static int time_count_steps; static int time, time_final; @@ -4457,17 +4499,17 @@ void GameWon() int game_over_delay_value_2 = 25; int game_over_delay_value_3 = 50; - if (!local_player->LevelSolved_GameWon) + if (!game.LevelSolved_GameWon) { int i; - /* do not start end game actions before the player stops moving (to exit) */ - if (local_player->MovPos) + // do not start end game actions before the player stops moving (to exit) + if (local_player->active && local_player->MovPos) return; - local_player->LevelSolved_GameWon = TRUE; - local_player->LevelSolved_SaveTape = tape.recording; - local_player->LevelSolved_SaveScore = !tape.playing; + game.LevelSolved_GameWon = TRUE; + game.LevelSolved_SaveTape = tape.recording; + game.LevelSolved_SaveScore = !tape.playing; if (!tape.playing) { @@ -4476,7 +4518,7 @@ void GameWon() SaveLevelSetup_SeriesInfo(); } - if (tape.auto_play) /* tape might already be stopped here */ + if (tape.auto_play) // tape might already be stopped here tape.auto_play_level_solved = TRUE; TapeStop(); @@ -4486,8 +4528,8 @@ void GameWon() game_over_delay_3 = game_over_delay_value_3; time = time_final = (game.no_time_limit ? TimePlayed : TimeLeft); - score = score_final = local_player->score_final; - health = health_final = local_player->health_final; + score = score_final = game.score_final; + health = health_final = game.health_final; if (level.score[SC_TIME_BONUS] > 0) { @@ -4514,8 +4556,8 @@ void GameWon() game_over_delay_2 = game_over_delay_value_2; } - local_player->score_final = score_final; - local_player->health_final = health_final; + game.score_final = score_final; + game.health_final = health_final; } if (level_editor_test_game) @@ -4523,8 +4565,8 @@ void GameWon() time = time_final; score = score_final; - local_player->LevelSolved_CountingTime = time; - local_player->LevelSolved_CountingScore = score; + game.LevelSolved_CountingTime = time; + game.LevelSolved_CountingScore = score; game_panel_controls[GAME_PANEL_TIME].value = time; game_panel_controls[GAME_PANEL_SCORE].value = score; @@ -4534,30 +4576,35 @@ void GameWon() if (level.game_engine_type == GAME_ENGINE_TYPE_RND) { - if (ExitX >= 0 && ExitY >= 0) /* local player has left the level */ + // check if last player has left the level + if (game.exit_x >= 0 && + game.exit_y >= 0) { - /* close exit door after last player */ - if ((AllPlayersGone && - (Feld[ExitX][ExitY] == EL_EXIT_OPEN || - Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN || - Feld[ExitX][ExitY] == EL_STEEL_EXIT_OPEN)) || - Feld[ExitX][ExitY] == EL_EM_EXIT_OPEN || - Feld[ExitX][ExitY] == EL_EM_STEEL_EXIT_OPEN) + int x = game.exit_x; + int y = game.exit_y; + int element = Feld[x][y]; + + // close exit door after last player + if ((game.all_players_gone && + (element == EL_EXIT_OPEN || + element == EL_SP_EXIT_OPEN || + element == EL_STEEL_EXIT_OPEN)) || + element == EL_EM_EXIT_OPEN || + element == EL_EM_STEEL_EXIT_OPEN) { - int element = Feld[ExitX][ExitY]; - Feld[ExitX][ExitY] = + Feld[x][y] = (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING : - element == EL_EM_EXIT_OPEN ? EL_EM_EXIT_CLOSING : - element == EL_SP_EXIT_OPEN ? EL_SP_EXIT_CLOSING: + element == EL_EM_EXIT_OPEN ? EL_EM_EXIT_CLOSING : + element == EL_SP_EXIT_OPEN ? EL_SP_EXIT_CLOSING: element == EL_STEEL_EXIT_OPEN ? EL_STEEL_EXIT_CLOSING: EL_EM_STEEL_EXIT_CLOSING); - PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING); + PlayLevelSoundElementAction(x, y, element, ACTION_CLOSING); } - /* player disappears */ - DrawLevelField(ExitX, ExitY); + // player disappears + DrawLevelField(x, y); } for (i = 0; i < MAX_PLAYERS; i++) @@ -4568,7 +4615,7 @@ void GameWon() { RemovePlayer(player); - /* player disappears */ + // player disappears DrawLevelField(player->jx, player->jy); } } @@ -4595,8 +4642,8 @@ void GameWon() time += time_count_steps * time_count_dir; score += time_count_steps * level.score[SC_TIME_BONUS]; - local_player->LevelSolved_CountingTime = time; - local_player->LevelSolved_CountingScore = score; + game.LevelSolved_CountingTime = time; + game.LevelSolved_CountingScore = score; game_panel_controls[GAME_PANEL_TIME].value = time; game_panel_controls[GAME_PANEL_SCORE].value = score; @@ -4627,8 +4674,8 @@ void GameWon() health += health_count_dir; score += level.score[SC_TIME_BONUS]; - local_player->LevelSolved_CountingHealth = health; - local_player->LevelSolved_CountingScore = score; + game.LevelSolved_CountingHealth = health; + game.LevelSolved_CountingScore = score; game_panel_controls[GAME_PANEL_HEALTH].value = health; game_panel_controls[GAME_PANEL_SCORE].value = score; @@ -4645,7 +4692,7 @@ void GameWon() return; } - local_player->LevelSolved_PanelOff = TRUE; + game.panel.active = FALSE; if (game_over_delay_3 > 0) { @@ -4657,22 +4704,24 @@ void GameWon() GameEnd(); } -void GameEnd() +void GameEnd(void) { + // used instead of "level_nr" (needed for network games) + int last_level_nr = levelset.level_nr; int hi_pos; - local_player->LevelSolved_GameEnd = TRUE; + game.LevelSolved_GameEnd = TRUE; - if (local_player->LevelSolved_SaveTape) + if (game.LevelSolved_SaveTape) { - /* make sure that request dialog to save tape does not open door again */ + // make sure that request dialog to save tape does not open door again if (!global.use_envelope_request) CloseDoor(DOOR_CLOSE_1); - SaveTapeChecked_LevelSolved(tape.level_nr); /* ask to save tape */ + SaveTapeChecked_LevelSolved(tape.level_nr); // ask to save tape } - /* if no tape is to be saved, close both doors simultaneously */ + // if no tape is to be saved, close both doors simultaneously CloseDoor(DOOR_CLOSE_ALL); if (level_editor_test_game) @@ -4684,7 +4733,7 @@ void GameEnd() return; } - if (!local_player->LevelSolved_SaveScore) + if (!game.LevelSolved_SaveScore) { SetGameStatus(GAME_MODE_MAIN); @@ -4704,8 +4753,8 @@ void GameEnd() level_nr < leveldir_current->last_level && !network_playing) { - level_nr++; /* advance to next level */ - TapeErase(); /* start with empty tape */ + level_nr++; // advance to next level + TapeErase(); // start with empty tape if (setup.auto_play_next_level) { @@ -4715,16 +4764,16 @@ void GameEnd() } } - /* used instead of last "level_nr" (for network games) */ - hi_pos = NewHiScore(levelset.level_nr); + hi_pos = NewHiScore(last_level_nr); if (hi_pos >= 0 && !setup.skip_scores_after_game) { SetGameStatus(GAME_MODE_SCORES); - DrawHallOfFame(levelset.level_nr, hi_pos); + DrawHallOfFame(last_level_nr, hi_pos); } else if (setup.auto_play_next_level && setup.increment_levels && + last_level_nr < leveldir_current->last_level && !network_playing) { StartGameActions(network.enabled, setup.autorecord, level.random_seed); @@ -4746,14 +4795,14 @@ int NewHiScore(int level_nr) LoadScore(level_nr); if (strEqual(setup.player_name, EMPTY_PLAYER_NAME) || - local_player->score_final < highscore[MAX_SCORE_ENTRIES - 1].Score) + game.score_final < highscore[MAX_SCORE_ENTRIES - 1].Score) return -1; - for (k = 0; k < MAX_SCORE_ENTRIES; k++) + for (k = 0; k < MAX_SCORE_ENTRIES; k++) { - if (local_player->score_final > highscore[k].Score) + if (game.score_final > highscore[k].Score) { - /* player has made it to the hall of fame */ + // player has made it to the hall of fame if (k < MAX_SCORE_ENTRIES - 1) { @@ -4765,7 +4814,7 @@ int NewHiScore(int level_nr) if (strEqual(setup.player_name, highscore[l].Name)) m = l; - if (m == k) /* player's new highscore overwrites his old one */ + if (m == k) // player's new highscore overwrites his old one goto put_into_list; } @@ -4780,7 +4829,7 @@ int NewHiScore(int level_nr) strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN); highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0'; - highscore[k].Score = local_player->score_final; + highscore[k].Score = game.score_final; position = k; break; @@ -4788,7 +4837,7 @@ int NewHiScore(int level_nr) else if (one_score_entry_per_name && !strncmp(setup.player_name, highscore[k].Name, MAX_PLAYER_NAME_LEN)) - break; /* player already there with a higher score */ + break; // player already there with a higher score } if (position >= 0) @@ -4797,7 +4846,7 @@ int NewHiScore(int level_nr) return position; } -inline static int getElementMoveStepsizeExt(int x, int y, int direction) +static int getElementMoveStepsizeExt(int x, int y, int direction) { int element = Feld[x][y]; int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); @@ -4806,7 +4855,7 @@ inline static int getElementMoveStepsizeExt(int x, int y, int direction) int sign = (horiz_move ? dx : dy); int step = sign * element_info[element].move_stepsize; - /* special values for move stepsize for spring and things on conveyor belt */ + // special values for move stepsize for spring and things on conveyor belt if (horiz_move) { if (CAN_FALL(element) && @@ -4819,7 +4868,7 @@ inline static int getElementMoveStepsizeExt(int x, int y, int direction) return step; } -inline static int getElementMoveStepsize(int x, int y) +static int getElementMoveStepsize(int x, int y) { return getElementMoveStepsizeExt(x, y, MovDir[x][y]); } @@ -4868,7 +4917,7 @@ static void ResetRandomAnimationValue(int x, int y) GfxRandom[x][y] = INIT_GFX_RANDOM(); } -void InitMovingField(int x, int y, int direction) +static void InitMovingField(int x, int y, int direction) { int element = Feld[x][y]; int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); @@ -4877,13 +4926,13 @@ void InitMovingField(int x, int y, int direction) int newy = y + dy; boolean is_moving_before, is_moving_after; - /* check if element was/is moving or being moved before/after mode change */ + // check if element was/is moving or being moved before/after mode change is_moving_before = (WasJustMoving[x][y] != 0); is_moving_after = (getElementMoveStepsizeExt(x, y, direction) != 0); - /* reset animation only for moving elements which change direction of moving - or which just started or stopped moving - (else CEs with property "can move" / "not moving" are reset each frame) */ + // reset animation only for moving elements which change direction of moving + // or which just started or stopped moving + // (else CEs with property "can move" / "not moving" are reset each frame) if (is_moving_before != is_moving_after || direction != MovDir[x][y]) ResetGfxAnimation(x, y); @@ -4895,7 +4944,7 @@ void InitMovingField(int x, int y, int direction) direction == MV_DOWN && CAN_FALL(element) ? ACTION_FALLING : ACTION_MOVING); - /* this is needed for CEs with property "can move" / "not moving" */ + // this is needed for CEs with property "can move" / "not moving" if (is_moving_after) { @@ -4941,7 +4990,7 @@ void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y) *comes_from_y = oldy; } -int MovingOrBlocked2Element(int x, int y) +static int MovingOrBlocked2Element(int x, int y) { int element = Feld[x][y]; @@ -4958,9 +5007,9 @@ int MovingOrBlocked2Element(int x, int y) static int MovingOrBlocked2ElementIfNotLeaving(int x, int y) { - /* like MovingOrBlocked2Element(), but if element is moving - and (x,y) is the field the moving element is just leaving, - return EL_BLOCKED instead of the element value */ + // like MovingOrBlocked2Element(), but if element is moving + // and (x,y) is the field the moving element is just leaving, + // return EL_BLOCKED instead of the element value int element = Feld[x][y]; if (IS_MOVING(x, y)) @@ -4999,7 +5048,7 @@ static void RemoveField(int x, int y) GfxDir[x][y] = MV_NONE; } -void RemoveMovingField(int x, int y) +static void RemoveMovingField(int x, int y) { int oldx = x, oldy = y, newx = x, newy = y; int element = Feld[x][y]; @@ -5014,9 +5063,9 @@ void RemoveMovingField(int x, int y) if (Feld[newx][newy] != EL_BLOCKED) { - /* element is moving, but target field is not free (blocked), but - already occupied by something different (example: acid pool); - in this case, only remove the moving field, but not the target */ + // element is moving, but target field is not free (blocked), but + // already occupied by something different (example: acid pool); + // in this case, only remove the moving field, but not the target RemoveField(oldx, oldy); @@ -5080,9 +5129,9 @@ void DrawDynamite(int x, int y) DrawGraphic(sx, sy, graphic, frame); } -void CheckDynamite(int x, int y) +static void CheckDynamite(int x, int y) { - if (MovDelay[x][y] != 0) /* dynamite is still waiting to explode */ + if (MovDelay[x][y] != 0) // dynamite is still waiting to explode { MovDelay[x][y]--; @@ -5130,7 +5179,7 @@ static void setMinimalPlayerBoundaries(int *sx1, int *sy1, int *sx2, int *sy2) } } -static boolean checkIfAllPlayersFitToScreen_RND() +static boolean checkIfAllPlayersFitToScreen_RND(void) { int sx1 = 0, sy1 = 0, sx2 = 0, sy2 = 0; @@ -5150,8 +5199,8 @@ static void setScreenCenteredToAllPlayers(int *sx, int *sy) *sy = (sy1 + sy2) / 2; } -void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, - boolean center_screen, boolean quick_relocation) +static void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, + boolean center_screen, boolean quick_relocation) { unsigned int frame_delay_value_old = GetVideoFrameDelay(); boolean ffwd_delay = (tape.playing && tape.fast_forward); @@ -5162,7 +5211,7 @@ void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, if (level.lazy_relocation && IN_VIS_FIELD(SCREENX(x), SCREENY(y))) { - /* case 1: quick relocation inside visible screen (without scrolling) */ + // case 1: quick relocation inside visible screen (without scrolling) RedrawPlayfield(); @@ -5171,28 +5220,28 @@ void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, if (!level.shifted_relocation || center_screen) { - /* relocation _with_ centering of screen */ + // relocation _with_ centering of screen new_scroll_x = SCROLL_POSITION_X(x); new_scroll_y = SCROLL_POSITION_Y(y); } else { - /* relocation _without_ centering of screen */ + // relocation _without_ centering of screen int center_scroll_x = SCROLL_POSITION_X(old_x); int center_scroll_y = SCROLL_POSITION_Y(old_y); int offset_x = x + (scroll_x - center_scroll_x); int offset_y = y + (scroll_y - center_scroll_y); - /* for new screen position, apply previous offset to center position */ + // for new screen position, apply previous offset to center position new_scroll_x = SCROLL_POSITION_X(offset_x); new_scroll_y = SCROLL_POSITION_Y(offset_y); } if (quick_relocation) { - /* case 2: quick relocation (redraw without visible scrolling) */ + // case 2: quick relocation (redraw without visible scrolling) scroll_x = new_scroll_x; scroll_y = new_scroll_y; @@ -5202,9 +5251,9 @@ void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, return; } - /* case 3: visible relocation (with scrolling to new position) */ + // case 3: visible relocation (with scrolling to new position) - ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */ + ScrollScreen(NULL, SCROLL_GO_ON); // scroll last frame to full tile SetVideoFrameDelay(wait_delay_value); @@ -5216,7 +5265,7 @@ void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, dx = (new_scroll_x < scroll_x ? +1 : new_scroll_x > scroll_x ? -1 : 0); dy = (new_scroll_y < scroll_y ? +1 : new_scroll_y > scroll_y ? -1 : 0); - if (dx == 0 && dy == 0) /* no scrolling needed at all */ + if (dx == 0 && dy == 0) // no scrolling needed at all break; scroll_x -= dx; @@ -5228,10 +5277,10 @@ void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, ScrollLevel(dx, dy); DrawAllPlayers(); - /* scroll in two steps of half tile size to make things smoother */ + // scroll in two steps of half tile size to make things smoother BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY); - /* scroll second step to align at full tile size */ + // scroll second step to align at full tile size BlitScreenToBitmap(window); } @@ -5241,7 +5290,7 @@ void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir, SetVideoFrameDelay(frame_delay_value_old); } -void RelocatePlayer(int jx, int jy, int el_player_raw) +static void RelocatePlayer(int jx, int jy, int el_player_raw) { int el_player = GET_PLAYER_ELEMENT(el_player_raw); int player_nr = GET_PLAYER_NR(el_player); @@ -5265,15 +5314,15 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) int enter_side = enter_side_horiz | enter_side_vert; int leave_side = leave_side_horiz | leave_side_vert; - if (player->GameOver) /* do not reanimate dead player */ + if (player->buried) // do not reanimate dead player return; - if (!player_relocated) /* no need to relocate the player */ + if (!player_relocated) // no need to relocate the player return; - if (IS_PLAYER(jx, jy)) /* player already placed at new position */ + if (IS_PLAYER(jx, jy)) // player already placed at new position { - RemoveField(jx, jy); /* temporarily remove newly placed player */ + RemoveField(jx, jy); // temporarily remove newly placed player DrawLevelField(jx, jy); } @@ -5291,8 +5340,8 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) BackToFront_WithFrameDelay(wait_delay_value); } - DrawPlayer(player); /* needed here only to cleanup last field */ - DrawLevelField(player->jx, player->jy); /* remove player graphic */ + DrawPlayer(player); // needed here only to cleanup last field + DrawLevelField(player->jx, player->jy); // remove player graphic player->is_moving = FALSE; } @@ -5313,12 +5362,12 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) possible that the relocation target field did not contain a player element, but a walkable element, to which the new player was relocated -- in this case, restore that (already initialized!) element on the player field */ - if (!ELEM_IS_PLAYER(element)) /* player may be set on walkable element */ + if (!ELEM_IS_PLAYER(element)) // player may be set on walkable element { - Feld[jx][jy] = element; /* restore previously existing element */ + Feld[jx][jy] = element; // restore previously existing element } - /* only visually relocate centered player */ + // only visually relocate centered player DrawRelocateScreen(old_jx, old_jy, player->jx, player->jy, player->MovDir, FALSE, level.instant_relocation); @@ -5346,13 +5395,13 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) } } -void Explode(int ex, int ey, int phase, int mode) +static void Explode(int ex, int ey, int phase, int mode) { int x, y; int last_phase; int border_element; - /* !!! eliminate this variable !!! */ + // !!! eliminate this variable !!! int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2); if (game.explosions_delayed) @@ -5361,26 +5410,26 @@ void Explode(int ex, int ey, int phase, int mode) return; } - if (phase == EX_PHASE_START) /* initialize 'Store[][]' field */ + if (phase == EX_PHASE_START) // initialize 'Store[][]' field { int center_element = Feld[ex][ey]; - int artwork_element, explosion_element; /* set these values later */ + int artwork_element, explosion_element; // set these values later - /* remove things displayed in background while burning dynamite */ + // remove things displayed in background while burning dynamite if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey])) Back[ex][ey] = 0; if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) { - /* put moving element to center field (and let it explode there) */ + // put moving element to center field (and let it explode there) center_element = MovingOrBlocked2Element(ex, ey); RemoveMovingField(ex, ey); Feld[ex][ey] = center_element; } - /* now "center_element" is finally determined -- set related values now */ - artwork_element = center_element; /* for custom player artwork */ - explosion_element = center_element; /* for custom player artwork */ + // now "center_element" is finally determined -- set related values now + artwork_element = center_element; // for custom player artwork + explosion_element = center_element; // for custom player artwork if (IS_PLAYER(ex, ey)) { @@ -5423,7 +5472,7 @@ void Explode(int ex, int ey, int phase, int mode) RemoveMovingField(x, y); } - /* indestructible elements can only explode in center (but not flames) */ + // indestructible elements can only explode in center (but not flames) if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey || mode == EX_TYPE_BORDER)) || element == EL_FLAMES) @@ -5432,7 +5481,7 @@ void Explode(int ex, int ey, int phase, int mode) /* no idea why this was changed from 3.0.8 to 3.1.0 -- this causes buggy behaviour, for example when touching a yamyam that explodes to rocks with active deadly shield, a rock is created under the player !!! */ - /* (case 1 (surely buggy): >= 3.1.0, case 2 (maybe buggy): <= 3.0.8) */ + // (case 1 (surely buggy): >= 3.1.0, case 2 (maybe buggy): <= 3.0.8) #if 0 if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)) && (game.engine_version < VERSION_IDENT(3,1,0,0) || @@ -5443,7 +5492,7 @@ void Explode(int ex, int ey, int phase, int mode) { if (IS_ACTIVE_BOMB(element)) { - /* re-activate things under the bomb like gate or penguin */ + // re-activate things under the bomb like gate or penguin Feld[x][y] = (Back[x][y] ? Back[x][y] : EL_EMPTY); Back[x][y] = 0; } @@ -5451,12 +5500,12 @@ void Explode(int ex, int ey, int phase, int mode) continue; } - /* save walkable background elements while explosion on same tile */ + // save walkable background elements while explosion on same tile if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) && (x != ex || y != ey || mode == EX_TYPE_BORDER)) Back[x][y] = element; - /* ignite explodable elements reached by other explosion */ + // ignite explodable elements reached by other explosion if (element == EL_EXPLOSION) element = Store2[x][y]; @@ -5481,8 +5530,8 @@ void Explode(int ex, int ey, int phase, int mode) Store[x][y] = EL_EMPTY; } - /* !!! check this case -- currently needed for rnd_rado_negundo_v, - !!! levels 015 018 019 020 021 022 023 026 027 028 !!! */ + // !!! check this case -- currently needed for rnd_rado_negundo_v, + // !!! levels 015 018 019 020 021 022 023 026 027 028 !!! else if (ELEM_IS_PLAYER(center_element)) Store[x][y] = EL_EMPTY; else if (center_element == EL_YAMYAM) @@ -5490,9 +5539,9 @@ void Explode(int ex, int ey, int phase, int mode) else if (element_info[center_element].content.e[xx][yy] != EL_EMPTY) Store[x][y] = element_info[center_element].content.e[xx][yy]; #if 1 - /* needed because EL_BD_BUTTERFLY is not defined as "CAN_EXPLODE" - (killing EL_BD_BUTTERFLY with dynamite would result in BD diamond - otherwise) -- FIX THIS !!! */ + // needed because EL_BD_BUTTERFLY is not defined as "CAN_EXPLODE" + // (killing EL_BD_BUTTERFLY with dynamite would result in BD diamond + // otherwise) -- FIX THIS !!! else if (!CAN_EXPLODE(element) && element != EL_BD_BUTTERFLY) Store[x][y] = element_info[element].content.e[1][1]; #else @@ -5529,13 +5578,13 @@ void Explode(int ex, int ey, int phase, int mode) y = ey; if (phase == 1) - GfxFrame[x][y] = 0; /* restart explosion animation */ + GfxFrame[x][y] = 0; // restart explosion animation last_phase = ExplodeDelay[x][y]; ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0); - /* this can happen if the player leaves an explosion just in time */ + // this can happen if the player leaves an explosion just in time if (GfxElement[x][y] == EL_UNDEFINED) GfxElement[x][y] = EL_EMPTY; @@ -5568,9 +5617,9 @@ void Explode(int ex, int ey, int phase, int mode) border_explosion = TRUE; } - /* if an element just explodes due to another explosion (chain-reaction), - do not immediately end the new explosion when it was the last frame of - the explosion (as it would be done in the following "if"-statement!) */ + // if an element just explodes due to another explosion (chain-reaction), + // do not immediately end the new explosion when it was the last frame of + // the explosion (as it would be done in the following "if"-statement!) if (border_explosion && phase == last_phase) return; } @@ -5583,7 +5632,7 @@ void Explode(int ex, int ey, int phase, int mode) Store[x][y] = Store2[x][y] = 0; GfxElement[x][y] = EL_UNDEFINED; - /* player can escape from explosions and might therefore be still alive */ + // player can escape from explosions and might therefore be still alive if (element >= EL_PLAYER_IS_EXPLODING_1 && element <= EL_PLAYER_IS_EXPLODING_4) { @@ -5599,7 +5648,7 @@ void Explode(int ex, int ey, int phase, int mode) element_info[explosion_element].content.e[xx][yy]); } - /* restore probably existing indestructible background element */ + // restore probably existing indestructible background element if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y])) element = Feld[x][y] = Back[x][y]; Back[x][y] = 0; @@ -5649,7 +5698,7 @@ void Explode(int ex, int ey, int phase, int mode) } } -void DynaExplode(int ex, int ey) +static void DynaExplode(int ex, int ey) { int i, j; int dynabomb_element = Feld[ex][ey]; @@ -5687,7 +5736,7 @@ void DynaExplode(int ex, int ey) element = Feld[x][y]; - /* do not restart explosions of fields with active bombs */ + // do not restart explosions of fields with active bombs if (element == EL_EXPLOSION && IS_ACTIVE_BOMB(Store2[x][y])) continue; @@ -5754,7 +5803,7 @@ void Bang(int x, int y) case EL_LAMP: case EL_LAMP_ACTIVE: case EL_AMOEBA_TO_DIAMOND: - if (!IS_PLAYER(x, y)) /* penguin and player may be at same field */ + if (!IS_PLAYER(x, y)) // penguin and player may be at same field explosion_type = EX_TYPE_CENTER; break; @@ -5774,7 +5823,7 @@ void Bang(int x, int y) CheckTriggeredElementChange(x, y, element, CE_EXPLOSION_OF_X); } -void SplashAcid(int x, int y) +static void SplashAcid(int x, int y) { if (IN_LEV_FIELD(x - 1, y - 1) && IS_FREE(x - 1, y - 1) && (!IN_LEV_FIELD(x - 1, y - 2) || @@ -5789,7 +5838,7 @@ void SplashAcid(int x, int y) PlayLevelSound(x, y, SND_ACID_SPLASHING); } -static void InitBeltMovement() +static void InitBeltMovement(void) { static int belt_base_element[4] = { @@ -5808,7 +5857,7 @@ static void InitBeltMovement() int x, y, i, j; - /* set frame order for belt animation graphic according to belt direction */ + // set frame order for belt animation graphic according to belt direction for (i = 0; i < NUM_BELTS; i++) { int belt_nr = i; @@ -5900,7 +5949,7 @@ static void ToggleBeltSwitch(int x, int y) if (belt_dir_nr == 3) belt_dir_nr = 1; - /* set frame order for belt animation graphic according to belt direction */ + // set frame order for belt animation graphic according to belt direction for (i = 0; i < NUM_BELT_PARTS; i++) { int element = belt_base_active_element[belt_nr] + i; @@ -6023,7 +6072,7 @@ static int getInvisibleFromInvisibleActiveElement(int element) element); } -static void RedrawAllLightSwitchesAndInvisibleElements() +static void RedrawAllLightSwitchesAndInvisibleElements(void) { int x, y; @@ -6064,7 +6113,7 @@ static void RedrawAllLightSwitchesAndInvisibleElements() TEST_DrawLevelField(x, y); - /* uncrumble neighbour fields, if needed */ + // uncrumble neighbour fields, if needed if (element == EL_INVISIBLE_SAND) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } @@ -6077,14 +6126,14 @@ static void RedrawAllLightSwitchesAndInvisibleElements() TEST_DrawLevelField(x, y); - /* re-crumble neighbour fields, if needed */ + // re-crumble neighbour fields, if needed if (element == EL_INVISIBLE_SAND) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } } } -static void RedrawAllInvisibleElementsForLenses() +static void RedrawAllInvisibleElementsForLenses(void) { int x, y; @@ -6113,7 +6162,7 @@ static void RedrawAllInvisibleElementsForLenses() TEST_DrawLevelField(x, y); - /* uncrumble neighbour fields, if needed */ + // uncrumble neighbour fields, if needed if (element == EL_INVISIBLE_SAND) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } @@ -6126,14 +6175,14 @@ static void RedrawAllInvisibleElementsForLenses() TEST_DrawLevelField(x, y); - /* re-crumble neighbour fields, if needed */ + // re-crumble neighbour fields, if needed if (element == EL_INVISIBLE_SAND) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } } } -static void RedrawAllInvisibleElementsForMagnifier() +static void RedrawAllInvisibleElementsForMagnifier(void) { int x, y; @@ -6226,7 +6275,7 @@ static void ActivateTimegateSwitch(int x, int y) EL_DC_TIMEGATE_SWITCH_ACTIVE); } -void Impact(int x, int y) +static void Impact(int x, int y) { boolean last_line = (y == lev_fieldy - 1); boolean object_hit = FALSE; @@ -6234,7 +6283,7 @@ void Impact(int x, int y) int element = Feld[x][y]; int smashed = EL_STEELWALL; - if (!last_line) /* check if element below was hit */ + if (!last_line) // check if element below was hit { if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING) return; @@ -6243,7 +6292,7 @@ void Impact(int x, int y) MovDir[x][y + 1] != MV_DOWN || MovPos[x][y + 1] <= TILEY / 2)); - /* do not smash moving elements that left the smashed field in time */ + // do not smash moving elements that left the smashed field in time if (game.engine_version >= VERSION_IDENT(2,2,0,7) && IS_MOVING(x, y + 1) && ABS(MovPos[x][y + 1] + getElementMoveStepsize(x, y + 1)) >= TILEX) object_hit = FALSE; @@ -6276,14 +6325,14 @@ void Impact(int x, int y) impact = (last_line || object_hit); } - if (!last_line && smashed == EL_ACID) /* element falls into acid */ + if (!last_line && smashed == EL_ACID) // element falls into acid { SplashAcid(x, y + 1); return; } - /* !!! not sufficient for all cases -- see EL_PEARL below !!! */ - /* only reset graphic animation if graphic really changes after impact */ + // !!! not sufficient for all cases -- see EL_PEARL below !!! + // only reset graphic animation if graphic really changes after impact if (impact && el_act_dir2img(element, GfxAction[x][y], MV_DOWN) != el2img(element)) { @@ -6328,7 +6377,7 @@ void Impact(int x, int y) return; } - if (object_hit) /* check which object was hit */ + if (object_hit) // check which object was hit { if ((CAN_PASS_MAGIC_WALL(element) && (smashed == EL_MAGIC_WALL || @@ -6342,7 +6391,7 @@ void Impact(int x, int y) smashed == EL_BD_MAGIC_WALL ? EL_BD_MAGIC_WALL_ACTIVE : EL_DC_MAGIC_WALL_ACTIVE); - /* activate magic wall / mill */ + // activate magic wall / mill SCAN_PLAYFIELD(xx, yy) { if (Feld[xx][yy] == smashed) @@ -6464,7 +6513,7 @@ void Impact(int x, int y) } } - /* play sound of magic wall / mill */ + // play sound of magic wall / mill if (!last_line && (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE || Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE || @@ -6480,12 +6529,12 @@ void Impact(int x, int y) return; } - /* play sound of object that hits the ground */ + // play sound of object that hits the ground if (last_line || object_hit) PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT); } -inline static void TurnRoundExt(int x, int y) +static void TurnRoundExt(int x, int y) { static struct { @@ -6546,7 +6595,7 @@ inline static void TurnRoundExt(int x, int y) if (element == EL_BUG && MovDir[x][y] != old_move_dir) MovDelay[x][y] = 9; - else if (element == EL_BD_BUTTERFLY) /* && MovDir[x][y] == left_dir) */ + else if (element == EL_BD_BUTTERFLY) // && MovDir[x][y] == left_dir) MovDelay[x][y] = 1; } else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY) @@ -6560,7 +6609,7 @@ inline static void TurnRoundExt(int x, int y) if (element == EL_SPACESHIP && MovDir[x][y] != old_move_dir) MovDelay[x][y] = 9; - else if (element == EL_BD_FIREFLY) /* && MovDir[x][y] == right_dir) */ + else if (element == EL_BD_FIREFLY) // && MovDir[x][y] == right_dir) MovDelay[x][y] = 1; } else if (element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON) @@ -6775,10 +6824,10 @@ inline static void TurnRoundExt(int x, int y) { int attr_x = -1, attr_y = -1; - if (AllPlayersGone) + if (game.all_players_gone) { - attr_x = ExitX; - attr_y = ExitY; + attr_x = game.exit_x; + attr_y = game.exit_y; } else { @@ -6801,12 +6850,14 @@ inline static void TurnRoundExt(int x, int y) } } - if (element == EL_ROBOT && ZX >= 0 && ZY >= 0 && - (Feld[ZX][ZY] == EL_ROBOT_WHEEL_ACTIVE || + if (element == EL_ROBOT && + game.robot_wheel_x >= 0 && + game.robot_wheel_y >= 0 && + (Feld[game.robot_wheel_x][game.robot_wheel_y] == EL_ROBOT_WHEEL_ACTIVE || game.engine_version < VERSION_IDENT(3,1,0,0))) { - attr_x = ZX; - attr_y = ZY; + attr_x = game.robot_wheel_x; + attr_y = game.robot_wheel_y; } if (element == EL_PENGUIN) @@ -6839,13 +6890,13 @@ inline static void TurnRoundExt(int x, int y) MovDir[x][y] = MV_NONE; if (attr_x < x) - MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT); + MovDir[x][y] |= (game.all_players_gone ? MV_RIGHT : MV_LEFT); else if (attr_x > x) - MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT); + MovDir[x][y] |= (game.all_players_gone ? MV_LEFT : MV_RIGHT); if (attr_y < y) - MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP); + MovDir[x][y] |= (game.all_players_gone ? MV_DOWN : MV_UP); else if (attr_y > y) - MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN); + MovDir[x][y] |= (game.all_players_gone ? MV_UP : MV_DOWN); if (element == EL_ROBOT) { @@ -6922,22 +6973,22 @@ inline static void TurnRoundExt(int x, int y) { static int check_pos[16] = { - -1, /* 0 => (invalid) */ - 7, /* 1 => MV_LEFT */ - 3, /* 2 => MV_RIGHT */ - -1, /* 3 => (invalid) */ - 1, /* 4 => MV_UP */ - 0, /* 5 => MV_LEFT | MV_UP */ - 2, /* 6 => MV_RIGHT | MV_UP */ - -1, /* 7 => (invalid) */ - 5, /* 8 => MV_DOWN */ - 6, /* 9 => MV_LEFT | MV_DOWN */ - 4, /* 10 => MV_RIGHT | MV_DOWN */ - -1, /* 11 => (invalid) */ - -1, /* 12 => (invalid) */ - -1, /* 13 => (invalid) */ - -1, /* 14 => (invalid) */ - -1, /* 15 => (invalid) */ + -1, // 0 => (invalid) + 7, // 1 => MV_LEFT + 3, // 2 => MV_RIGHT + -1, // 3 => (invalid) + 1, // 4 => MV_UP + 0, // 5 => MV_LEFT | MV_UP + 2, // 6 => MV_RIGHT | MV_UP + -1, // 7 => (invalid) + 5, // 8 => MV_DOWN + 6, // 9 => MV_LEFT | MV_DOWN + 4, // 10 => MV_RIGHT | MV_DOWN + -1, // 11 => (invalid) + -1, // 12 => (invalid) + -1, // 13 => (invalid) + -1, // 14 => (invalid) + -1, // 15 => (invalid) }; static struct { @@ -6958,7 +7009,7 @@ inline static void TurnRoundExt(int x, int y) boolean can_clone = FALSE; int i; - /* check if there is any free field around current position */ + // check if there is any free field around current position for (i = 0; i < 8; i++) { int newx = x + check_xy[i].dx; @@ -6972,7 +7023,7 @@ inline static void TurnRoundExt(int x, int y) } } - if (can_clone) /* randomly find an element to clone */ + if (can_clone) // randomly find an element to clone { can_clone = FALSE; @@ -7000,7 +7051,7 @@ inline static void TurnRoundExt(int x, int y) } } - if (can_clone) /* randomly find a direction to move */ + if (can_clone) // randomly find a direction to move { can_clone = FALSE; @@ -7027,17 +7078,17 @@ inline static void TurnRoundExt(int x, int y) } } - if (can_clone) /* cloning and moving successful */ + if (can_clone) // cloning and moving successful return; - /* cannot clone -- try to move towards player */ + // cannot clone -- try to move towards player start_pos = check_pos[MovDir[x][y] & 0x0f]; check_order = (RND(2) ? -1 : +1); for (i = 0; i < 3; i++) { - /* first check start_pos, then previous/next or (next/previous) pos */ + // first check start_pos, then previous/next or (next/previous) pos int pos_raw = start_pos + (i < 2 ? i : -1) * check_order; int pos = (pos_raw + 8) % 8; int newx = x + check_xy[pos].dx; @@ -7069,7 +7120,7 @@ inline static void TurnRoundExt(int x, int y) boolean can_turn_right = CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y); - if (element_info[element].move_stepsize == 0) /* "not moving" */ + if (element_info[element].move_stepsize == 0) // "not moving" return; if (move_pattern == MV_TURNING_LEFT) @@ -7144,10 +7195,10 @@ inline static void TurnRoundExt(int x, int y) int newx, newy; boolean move_away = (move_pattern == MV_AWAY_FROM_PLAYER); - if (AllPlayersGone) + if (game.all_players_gone) { - attr_x = ExitX; - attr_y = ExitY; + attr_x = game.exit_x; + attr_y = game.exit_y; } else { @@ -7187,7 +7238,7 @@ inline static void TurnRoundExt(int x, int y) boolean first_horiz = RND(2); int new_move_dir = MovDir[x][y]; - if (element_info[element].move_stepsize == 0) /* "not moving" */ + if (element_info[element].move_stepsize == 0) // "not moving" { first_horiz = (ABS(attr_x - x) >= ABS(attr_y - y)); MovDir[x][y] &= (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); @@ -7243,7 +7294,7 @@ inline static void TurnRoundExt(int x, int y) MV_RIGHT, }; boolean hunter_mode = (move_pattern == MV_MAZE_HUNTER); - int move_preference = -1000000; /* start with very low preference */ + int move_preference = -1000000; // start with very low preference int new_move_dir = MV_NONE; int start_test = RND(4); int i; @@ -7273,14 +7324,14 @@ inline static void TurnRoundExt(int x, int y) if (move_dir_preference > move_preference) { - /* prefer field that has not been visited for the longest time */ + // prefer field that has not been visited for the longest time move_preference = move_dir_preference; new_move_dir = move_dir; } else if (move_dir_preference == move_preference && move_dir == old_move_dir) { - /* prefer last direction when all directions are preferred equally */ + // prefer last direction when all directions are preferred equally move_preference = move_dir_preference; new_move_dir = move_dir; } @@ -7330,9 +7381,9 @@ static boolean JustBeingPushed(int x, int y) return FALSE; } -void StartMoving(int x, int y) +static void StartMoving(int x, int y) { - boolean started_moving = FALSE; /* some elements can fall _and_ move */ + boolean started_moving = FALSE; // some elements can fall _and_ move int element = Feld[x][y]; if (Stop[x][y]) @@ -7659,7 +7710,7 @@ void StartMoving(int x, int y) } else if (IS_FREE(x, y + 1) || Feld[x][y + 1] == EL_DIAMOND_BREAKING) { - if (WasJustFalling[x][y]) /* prevent animation from being restarted */ + if (WasJustFalling[x][y]) // prevent animation from being restarted MovDir[x][y] = MV_DOWN; InitMovingField(x, y, MV_DOWN); @@ -7703,7 +7754,7 @@ void StartMoving(int x, int y) if (can_fall_both) { if (element == EL_BD_ROCK || element == EL_BD_DIAMOND) - can_fall_right = FALSE; /* slip down on left side */ + can_fall_right = FALSE; // slip down on left side else can_fall_left = !(can_fall_right = RND(2)); @@ -7712,7 +7763,7 @@ void StartMoving(int x, int y) if (can_fall_any) { - /* if not determined otherwise, prefer left side for slipping down */ + // if not determined otherwise, prefer left side for slipping down InitMovingField(x, y, can_fall_left ? MV_LEFT : MV_RIGHT); started_moving = TRUE; } @@ -7739,12 +7790,12 @@ void StartMoving(int x, int y) } else { - MovDir[x][y] = 0; /* if element was moving, stop it */ + MovDir[x][y] = 0; // if element was moving, stop it } } } - /* not "else if" because of elements that can fall and move (EL_SPRING) */ + // not "else if" because of elements that can fall and move (EL_SPRING) if (CAN_MOVE(element) && !started_moving) { int move_pattern = element_info[element].move_pattern; @@ -7763,14 +7814,14 @@ void StartMoving(int x, int y) TestIfElementHitsCustomElement(x, y, MovDir[x][y]); - if (Feld[x][y] != element) /* element has changed */ + if (Feld[x][y] != element) // element has changed return; } - if (!MovDelay[x][y]) /* start new movement phase */ + if (!MovDelay[x][y]) // start new movement phase { - /* all objects that can change their move direction after each step - (YAMYAM, DARK_YAMYAM and PACMAN go straight until they hit a wall */ + // all objects that can change their move direction after each step + // (YAMYAM, DARK_YAMYAM and PACMAN go straight until they hit a wall if (element != EL_YAMYAM && element != EL_DARK_YAMYAM && @@ -7793,7 +7844,7 @@ void StartMoving(int x, int y) } } - if (MovDelay[x][y]) /* wait some time before next movement */ + if (MovDelay[x][y]) // wait some time before next movement { MovDelay[x][y]--; @@ -7866,7 +7917,7 @@ void StartMoving(int x, int y) } } - if (MovDelay[x][y]) /* element still has to wait some time */ + if (MovDelay[x][y]) // element still has to wait some time { PlayLevelSoundAction(x, y, ACTION_WAITING); @@ -7874,9 +7925,9 @@ void StartMoving(int x, int y) } } - /* now make next step */ + // now make next step - Moving2Blocked(x, y, &newx, &newy); /* get next screen position */ + Moving2Blocked(x, y, &newx, &newy); // get next screen position if (DONT_COLLIDE_WITH(element) && IN_LEV_FIELD(newx, newy) && IS_PLAYER(newx, newy) && @@ -7910,10 +7961,11 @@ void StartMoving(int x, int y) if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy))) DrawGraphicThruMask(SCREENX(newx),SCREENY(newy), el2img(element), 0); - local_player->friends_still_needed--; - if (!local_player->friends_still_needed && - !local_player->GameOver && AllPlayersGone) - PlayerWins(local_player); + game.friends_still_needed--; + if (!game.friends_still_needed && + !game.GameOver && + game.all_players_gone) + LevelSolved(); return; } @@ -7967,7 +8019,7 @@ void StartMoving(int x, int y) boolean can_clone = FALSE; int xx, yy; - /* check if element to clone is still there */ + // check if element to clone is still there for (yy = y - 1; yy <= y + 1; yy++) for (xx = x - 1; xx <= x + 1; xx++) { if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == Store[x][y]) @@ -7978,7 +8030,7 @@ void StartMoving(int x, int y) } } - /* cannot clone or target field not free anymore -- do not clone */ + // cannot clone or target field not free anymore -- do not clone if (!can_clone || !ANDROID_CAN_ENTER_FIELD(element, newx, newy)) Store[x][y] = EL_EMPTY; } @@ -7992,7 +8044,7 @@ void StartMoving(int x, int y) int change_delay = 8; int graphic; - /* android is moving diagonally */ + // android is moving diagonally CreateField(x, y, EL_DIAGONAL_SHRINKING); @@ -8053,7 +8105,7 @@ void StartMoving(int x, int y) if (move_pattern & MV_MAZE_RUNNER_STYLE) { RunnerVisit[x][y] = FrameCounter; - PlayerVisit[x][y] /= 8; /* expire player visit path */ + PlayerVisit[x][y] /= 8; // expire player visit path } } else if (element == EL_DRAGON && IN_LEV_FIELD(newx, newy)) @@ -8162,11 +8214,11 @@ void StartMoving(int x, int y) GfxAction[x][y] = ACTION_DIGGING; TEST_DrawLevelField(x, y); - MovDelay[newx][newy] = 0; /* start amoeba shrinking delay */ + MovDelay[newx][newy] = 0; // start amoeba shrinking delay - return; /* wait for shrinking amoeba */ + return; // wait for shrinking amoeba } - else /* element == EL_PACMAN */ + else // element == EL_PACMAN { Feld[newx][newy] = EL_EMPTY; TEST_DrawLevelField(newx, newy); @@ -8177,16 +8229,16 @@ void StartMoving(int x, int y) (Feld[newx][newy] == EL_AMOEBA_SHRINKING || (Feld[newx][newy] == EL_EMPTY && Stop[newx][newy]))) { - /* wait for shrinking amoeba to completely disappear */ + // wait for shrinking amoeba to completely disappear return; } else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy)) { - /* object was running against a wall */ + // object was running against a wall TurnRound(x, y); - if (GFX_ELEMENT(element) != EL_SAND) /* !!! FIX THIS (crumble) !!! */ + if (GFX_ELEMENT(element) != EL_SAND) // !!! FIX THIS (crumble) !!! DrawLevelElementAnimation(x, y, element); if (DONT_TOUCH(element)) @@ -8220,23 +8272,23 @@ void ContinueMoving(int x, int y) MovPos[x][y] += getElementMoveStepsize(x, y); - if (pushed_by_player) /* special case: moving object pushed by player */ + if (pushed_by_player) // special case: moving object pushed by player MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos)); if (ABS(MovPos[x][y]) < TILEX) { TEST_DrawLevelField(x, y); - return; /* element is still moving */ + return; // element is still moving } - /* element reached destination field */ + // element reached destination field Feld[x][y] = EL_EMPTY; Feld[newx][newy] = element; - MovPos[x][y] = 0; /* force "not moving" for "crumbled sand" */ + MovPos[x][y] = 0; // force "not moving" for "crumbled sand" - if (Store[x][y] == EL_ACID) /* element is moving into acid pool */ + if (Store[x][y] == EL_ACID) // element is moving into acid pool { element = Feld[newx][newy] = EL_ACID; } @@ -8339,7 +8391,7 @@ void ContinueMoving(int x, int y) if (CAN_CHANGE_OR_HAS_ACTION(element)) { - /* copy element change control values to new field */ + // copy element change control values to new field ChangeDelay[newx][newy] = ChangeDelay[x][y]; ChangePage[newx][newy] = ChangePage[x][y]; ChangeCount[newx][newy] = ChangeCount[x][y]; @@ -8355,22 +8407,22 @@ void ContinueMoving(int x, int y) CustomValue[x][y] = 0; - /* copy animation control values to new field */ + // copy animation control values to new field GfxFrame[newx][newy] = GfxFrame[x][y]; - GfxRandom[newx][newy] = GfxRandom[x][y]; /* keep same random value */ - GfxAction[newx][newy] = GfxAction[x][y]; /* keep action one frame */ - GfxDir[newx][newy] = GfxDir[x][y]; /* keep element direction */ + GfxRandom[newx][newy] = GfxRandom[x][y]; // keep same random value + GfxAction[newx][newy] = GfxAction[x][y]; // keep action one frame + GfxDir[newx][newy] = GfxDir[x][y]; // keep element direction Pushed[x][y] = Pushed[newx][newy] = FALSE; - /* some elements can leave other elements behind after moving */ + // some elements can leave other elements behind after moving if (ei->move_leave_element != EL_EMPTY && (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) && (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element))) { int move_leave_element = ei->move_leave_element; - /* this makes it possible to leave the removed element again */ + // this makes it possible to leave the removed element again if (ei->move_leave_element == EL_TRIGGER_ELEMENT) move_leave_element = (stored == EL_ACID ? EL_EMPTY : stored); @@ -8388,8 +8440,8 @@ void ContinueMoving(int x, int y) RelocatePlayer(x, y, move_leave_element); } - /* do this after checking for left-behind element */ - ResetGfxAnimation(x, y); /* reset animation values for old field */ + // do this after checking for left-behind element + ResetGfxAnimation(x, y); // reset animation values for old field if (!CAN_MOVE(element) || (CAN_FALL(element) && direction == MV_DOWN && @@ -8401,15 +8453,15 @@ void ContinueMoving(int x, int y) TEST_DrawLevelField(x, y); TEST_DrawLevelField(newx, newy); - Stop[newx][newy] = TRUE; /* ignore this element until the next frame */ + Stop[newx][newy] = TRUE; // ignore this element until the next frame - /* prevent pushed element from moving on in pushed direction */ + // prevent pushed element from moving on in pushed direction if (pushed_by_player && CAN_MOVE(element) && element_info[element].move_pattern & MV_ANY_DIRECTION && !(element_info[element].move_pattern & direction)) TurnRound(newx, newy); - /* prevent elements on conveyor belt from moving on in last direction */ + // prevent elements on conveyor belt from moving on in last direction if (pushed_by_conveyor && CAN_FALL(element) && direction & MV_HORIZONTAL) MovDir[newx][newy] = 0; @@ -8431,7 +8483,7 @@ void ContinueMoving(int x, int y) CheckImpact[newx][newy] = CHECK_DELAY_IMPACT; } - if (DONT_TOUCH(element)) /* object may be nasty to player or others */ + if (DONT_TOUCH(element)) // object may be nasty to player or others { TestIfBadThingTouchesPlayer(newx, newy); TestIfBadThingTouchesFriend(newx, newy); @@ -8447,7 +8499,7 @@ void ContinueMoving(int x, int y) TestIfGoodThingGetsHitByBadThing(newx, newy, direction); } - /* give the player one last chance (one more frame) to move away */ + // give the player one last chance (one more frame) to move away if (CAN_FALL(element) && direction == MV_DOWN && (last_line || (!IS_FREE(x, newy + 1) && (!IS_PLAYER(x, newy + 1) || @@ -8465,12 +8517,12 @@ void ContinueMoving(int x, int y) player->index_bit, push_side); } - if (element == EL_EMC_ANDROID && pushed_by_player) /* make another move */ + if (element == EL_EMC_ANDROID && pushed_by_player) // make another move MovDelay[newx][newy] = 1; CheckTriggeredElementChangeBySide(x, y, element, CE_MOVE_OF_X, direction); - TestIfElementTouchesCustomElement(x, y); /* empty or new element */ + TestIfElementTouchesCustomElement(x, y); // empty or new element TestIfElementHitsCustomElement(newx, newy, direction); TestIfPlayerTouchesCustomElement(newx, newy); TestIfElementTouchesCustomElement(newx, newy); @@ -8509,7 +8561,7 @@ int AmoebeNachbarNr(int ax, int ay) return group_nr; } -void AmoebenVereinigen(int ax, int ay) +static void AmoebenVereinigen(int ax, int ay) { int i, x, y, xx, yy; int new_group_nr = AmoebaNr[ax][ay]; @@ -8616,7 +8668,7 @@ void AmoebeUmwandeln(int ax, int ay) } } -void AmoebeUmwandelnBD(int ax, int ay, int new_element) +static void AmoebeUmwandelnBD(int ax, int ay, int new_element) { int x, y; int group_nr = AmoebaNr[ax][ay]; @@ -8652,12 +8704,12 @@ void AmoebeUmwandelnBD(int ax, int ay, int new_element) SND_BD_AMOEBA_TURNING_TO_GEM)); } -void AmoebeWaechst(int x, int y) +static void AmoebeWaechst(int x, int y) { static unsigned int sound_delay = 0; static unsigned int sound_delay_value = 0; - if (!MovDelay[x][y]) /* start new growing cycle */ + if (!MovDelay[x][y]) // start new growing cycle { MovDelay[x][y] = 7; @@ -8668,7 +8720,7 @@ void AmoebeWaechst(int x, int y) } } - if (MovDelay[x][y]) /* wait some time before growing bigger */ + if (MovDelay[x][y]) // wait some time before growing bigger { MovDelay[x][y]--; if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) @@ -8688,12 +8740,12 @@ void AmoebeWaechst(int x, int y) } } -void AmoebaDisappearing(int x, int y) +static void AmoebaDisappearing(int x, int y) { static unsigned int sound_delay = 0; static unsigned int sound_delay_value = 0; - if (!MovDelay[x][y]) /* start new shrinking cycle */ + if (!MovDelay[x][y]) // start new shrinking cycle { MovDelay[x][y] = 7; @@ -8701,7 +8753,7 @@ void AmoebaDisappearing(int x, int y) sound_delay_value = 30; } - if (MovDelay[x][y]) /* wait some time before shrinking */ + if (MovDelay[x][y]) // wait some time before shrinking { MovDelay[x][y]--; if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) @@ -8717,14 +8769,14 @@ void AmoebaDisappearing(int x, int y) Feld[x][y] = EL_EMPTY; TEST_DrawLevelField(x, y); - /* don't let mole enter this field in this cycle; - (give priority to objects falling to this field from above) */ + // don't let mole enter this field in this cycle; + // (give priority to objects falling to this field from above) Stop[x][y] = TRUE; } } } -void AmoebeAbleger(int ax, int ay) +static void AmoebeAbleger(int ax, int ay) { int i; int element = Feld[ax][ay]; @@ -8749,17 +8801,17 @@ void AmoebeAbleger(int ax, int ay) if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); - if (!MovDelay[ax][ay]) /* start making new amoeba field */ + if (!MovDelay[ax][ay]) // start making new amoeba field MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed)); - if (MovDelay[ax][ay]) /* wait some time before making new amoeba */ + if (MovDelay[ax][ay]) // wait some time before making new amoeba { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) return; } - if (can_drop) /* EL_AMOEBA_WET or EL_EMC_DRIPPER */ + if (can_drop) // EL_AMOEBA_WET or EL_EMC_DRIPPER { int start = RND(4); int x = ax + xy[start][0]; @@ -8780,7 +8832,7 @@ void AmoebeAbleger(int ax, int ay) if (newax == ax && neway == ay) return; } - else /* normal or "filled" (BD style) amoeba */ + else // normal or "filled" (BD style) amoeba { int start = RND(4); boolean waiting_for_player = FALSE; @@ -8807,7 +8859,7 @@ void AmoebeAbleger(int ax, int ay) waiting_for_player = TRUE; } - if (newax == ax && neway == ay) /* amoeba cannot grow */ + if (newax == ax && neway == ay) // amoeba cannot grow { if (i == 4 && (!waiting_for_player || element == EL_BD_AMOEBA)) { @@ -8815,7 +8867,7 @@ void AmoebeAbleger(int ax, int ay) TEST_DrawLevelField(ax, ay); AmoebaCnt[AmoebaNr[ax][ay]]--; - if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0) /* amoeba is completely dead */ + if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0) // amoeba is completely dead { if (element == EL_AMOEBA_FULL) AmoebeUmwandeln(ax, ay); @@ -8827,7 +8879,7 @@ void AmoebeAbleger(int ax, int ay) } else if (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA) { - /* amoeba gets larger by growing in some direction */ + // amoeba gets larger by growing in some direction int new_group_nr = AmoebaNr[ax][ay]; @@ -8844,7 +8896,7 @@ void AmoebeAbleger(int ax, int ay) AmoebaCnt[new_group_nr]++; AmoebaCnt2[new_group_nr]++; - /* if amoeba touches other amoeba(s) after growing, unify them */ + // if amoeba touches other amoeba(s) after growing, unify them AmoebenVereinigen(newax, neway); if (element == EL_BD_AMOEBA && AmoebaCnt2[new_group_nr] >= 200) @@ -8858,18 +8910,18 @@ void AmoebeAbleger(int ax, int ay) if (!can_drop || neway < ay || !IS_FREE(newax, neway) || (neway == lev_fieldy - 1 && newax != ax)) { - Feld[newax][neway] = EL_AMOEBA_GROWING; /* creation of new amoeba */ + Feld[newax][neway] = EL_AMOEBA_GROWING; // creation of new amoeba Store[newax][neway] = element; } else if (neway == ay || element == EL_EMC_DRIPPER) { - Feld[newax][neway] = EL_AMOEBA_DROP; /* drop left/right of amoeba */ + Feld[newax][neway] = EL_AMOEBA_DROP; // drop left/right of amoeba PlayLevelSoundAction(newax, neway, ACTION_GROWING); } else { - InitMovingField(ax, ay, MV_DOWN); /* drop dripping from amoeba */ + InitMovingField(ax, ay, MV_DOWN); // drop dripping from amoeba Feld[ax][ay] = EL_AMOEBA_DROPPING; Store[ax][ay] = EL_AMOEBA_DROP; ContinueMoving(ax, ay); @@ -8879,7 +8931,7 @@ void AmoebeAbleger(int ax, int ay) TEST_DrawLevelField(newax, neway); } -void Life(int ax, int ay) +static void Life(int ax, int ay) { int x1, y1, x2, y2; int life_time = 40; @@ -8895,10 +8947,10 @@ void Life(int ax, int ay) if (Stop[ax][ay]) return; - if (!MovDelay[ax][ay]) /* start new "game of life" cycle */ + if (!MovDelay[ax][ay]) // start new "game of life" cycle MovDelay[ax][ay] = life_time; - if (MovDelay[ax][ay]) /* wait some time before next cycle */ + if (MovDelay[ax][ay]) // wait some time before next cycle { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) @@ -8908,7 +8960,8 @@ void Life(int ax, int ay) for (y1 = -1; y1 < 2; y1++) for (x1 = -1; x1 < 2; x1++) { int xx = ax+x1, yy = ay+y1; - int nachbarn = 0; + int old_element = Feld[xx][yy]; + int num_neighbours = 0; if (!IN_LEV_FIELD(xx, yy)) continue; @@ -8920,33 +8973,48 @@ void Life(int ax, int ay) if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy)) continue; - if (((Feld[x][y] == element || - (element == EL_GAME_OF_LIFE && IS_PLAYER(x, y))) && - !Stop[x][y]) || - (IS_FREE(x, y) && Stop[x][y])) - nachbarn++; + boolean is_player_cell = (element == EL_GAME_OF_LIFE && IS_PLAYER(x, y)); + boolean is_neighbour = FALSE; + + if (level.use_life_bugs) + is_neighbour = + (((Feld[x][y] == element || is_player_cell) && !Stop[x][y]) || + (IS_FREE(x, y) && Stop[x][y])); + else + is_neighbour = + (Last[x][y] == element || is_player_cell); + + if (is_neighbour) + num_neighbours++; } - if (xx == ax && yy == ay) /* field in the middle */ + boolean is_free = FALSE; + + if (level.use_life_bugs) + is_free = (IS_FREE(xx, yy)); + else + is_free = (IS_FREE(xx, yy) && Last[xx][yy] == EL_EMPTY); + + if (xx == ax && yy == ay) // field in the middle { - if (nachbarn < life_parameter[0] || - nachbarn > life_parameter[1]) + if (num_neighbours < life_parameter[0] || + num_neighbours > life_parameter[1]) { Feld[xx][yy] = EL_EMPTY; - if (!Stop[xx][yy]) + if (Feld[xx][yy] != old_element) TEST_DrawLevelField(xx, yy); Stop[xx][yy] = TRUE; changed = TRUE; } } - else if (IS_FREE(xx, yy) || CAN_GROW_INTO(Feld[xx][yy])) - { /* free border field */ - if (nachbarn >= life_parameter[2] && - nachbarn <= life_parameter[3]) + else if (is_free || CAN_GROW_INTO(Feld[xx][yy])) + { // free border field + if (num_neighbours >= life_parameter[2] && + num_neighbours <= life_parameter[3]) { Feld[xx][yy] = element; MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1); - if (!Stop[xx][yy]) + if (Feld[xx][yy] != old_element) TEST_DrawLevelField(xx, yy); Stop[xx][yy] = TRUE; changed = TRUE; @@ -8971,10 +9039,11 @@ static void RunRobotWheel(int x, int y) static void StopRobotWheel(int x, int y) { - if (ZX == x && ZY == y) + if (game.robot_wheel_x == x && + game.robot_wheel_y == y) { - ZX = ZY = -1; - + game.robot_wheel_x = -1; + game.robot_wheel_y = -1; game.robot_wheel_active = FALSE; } } @@ -9000,7 +9069,7 @@ static void ActivateMagicBall(int bx, int by) if (level.ball_random) { - int pos_border = RND(8); /* select one of the eight border elements */ + int pos_border = RND(8); // select one of the eight border elements int pos_content = (pos_border > 3 ? pos_border + 1 : pos_border); int xx = pos_content % 3; int yy = pos_content / 3; @@ -9026,11 +9095,12 @@ static void ActivateMagicBall(int bx, int by) game.ball_content_nr = (game.ball_content_nr + 1) % level.num_ball_contents; } -void CheckExit(int x, int y) +static void CheckExit(int x, int y) { - if (local_player->gems_still_needed > 0 || - local_player->sokobanfields_still_needed > 0 || - local_player->lights_still_needed > 0) + if (game.gems_still_needed > 0 || + game.sokoban_fields_still_needed > 0 || + game.sokoban_objects_still_needed > 0 || + game.lights_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); @@ -9041,7 +9111,8 @@ void CheckExit(int x, int y) return; } - if (AllPlayersGone) /* do not re-open exit door closed after last player */ + // do not re-open exit door closed after last player + if (game.all_players_gone) return; Feld[x][y] = EL_EXIT_OPENING; @@ -9049,11 +9120,12 @@ void CheckExit(int x, int y) PlayLevelSoundNearest(x, y, SND_CLASS_EXIT_OPENING); } -void CheckExitEM(int x, int y) +static void CheckExitEM(int x, int y) { - if (local_player->gems_still_needed > 0 || - local_player->sokobanfields_still_needed > 0 || - local_player->lights_still_needed > 0) + if (game.gems_still_needed > 0 || + game.sokoban_fields_still_needed > 0 || + game.sokoban_objects_still_needed > 0 || + game.lights_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); @@ -9064,7 +9136,8 @@ void CheckExitEM(int x, int y) return; } - if (AllPlayersGone) /* do not re-open exit door closed after last player */ + // do not re-open exit door closed after last player + if (game.all_players_gone) return; Feld[x][y] = EL_EM_EXIT_OPENING; @@ -9072,11 +9145,12 @@ void CheckExitEM(int x, int y) PlayLevelSoundNearest(x, y, SND_CLASS_EM_EXIT_OPENING); } -void CheckExitSteel(int x, int y) +static void CheckExitSteel(int x, int y) { - if (local_player->gems_still_needed > 0 || - local_player->sokobanfields_still_needed > 0 || - local_player->lights_still_needed > 0) + if (game.gems_still_needed > 0 || + game.sokoban_fields_still_needed > 0 || + game.sokoban_objects_still_needed > 0 || + game.lights_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); @@ -9087,7 +9161,8 @@ void CheckExitSteel(int x, int y) return; } - if (AllPlayersGone) /* do not re-open exit door closed after last player */ + // do not re-open exit door closed after last player + if (game.all_players_gone) return; Feld[x][y] = EL_STEEL_EXIT_OPENING; @@ -9095,11 +9170,12 @@ void CheckExitSteel(int x, int y) PlayLevelSoundNearest(x, y, SND_CLASS_STEEL_EXIT_OPENING); } -void CheckExitSteelEM(int x, int y) +static void CheckExitSteelEM(int x, int y) { - if (local_player->gems_still_needed > 0 || - local_player->sokobanfields_still_needed > 0 || - local_player->lights_still_needed > 0) + if (game.gems_still_needed > 0 || + game.sokoban_fields_still_needed > 0 || + game.sokoban_objects_still_needed > 0 || + game.lights_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); @@ -9110,7 +9186,8 @@ void CheckExitSteelEM(int x, int y) return; } - if (AllPlayersGone) /* do not re-open exit door closed after last player */ + // do not re-open exit door closed after last player + if (game.all_players_gone) return; Feld[x][y] = EL_EM_STEEL_EXIT_OPENING; @@ -9118,9 +9195,9 @@ void CheckExitSteelEM(int x, int y) PlayLevelSoundNearest(x, y, SND_CLASS_EM_STEEL_EXIT_OPENING); } -void CheckExitSP(int x, int y) +static void CheckExitSP(int x, int y) { - if (local_player->gems_still_needed > 0) + if (game.gems_still_needed > 0) { int element = Feld[x][y]; int graphic = el2img(element); @@ -9131,7 +9208,8 @@ void CheckExitSP(int x, int y) return; } - if (AllPlayersGone) /* do not re-open exit door closed after last player */ + // do not re-open exit door closed after last player + if (game.all_players_gone) return; Feld[x][y] = EL_SP_EXIT_OPENING; @@ -9139,7 +9217,7 @@ void CheckExitSP(int x, int y) PlayLevelSoundNearest(x, y, SND_CLASS_SP_EXIT_OPENING); } -static void CloseAllOpenTimegates() +static void CloseAllOpenTimegates(void) { int x, y; @@ -9156,7 +9234,7 @@ static void CloseAllOpenTimegates() } } -void DrawTwinkleOnField(int x, int y) +static void DrawTwinkleOnField(int x, int y) { if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y)) return; @@ -9164,10 +9242,10 @@ void DrawTwinkleOnField(int x, int y) if (Feld[x][y] == EL_BD_DIAMOND) return; - if (MovDelay[x][y] == 0) /* next animation frame */ + if (MovDelay[x][y] == 0) // next animation frame MovDelay[x][y] = 11 * !GetSimpleRandom(500); - if (MovDelay[x][y] != 0) /* wait some time before next frame */ + if (MovDelay[x][y] != 0) // wait some time before next frame { MovDelay[x][y]--; @@ -9183,14 +9261,14 @@ void DrawTwinkleOnField(int x, int y) } } -void MauerWaechst(int x, int y) +static void MauerWaechst(int x, int y) { int delay = 6; - if (!MovDelay[x][y]) /* next animation frame */ + if (!MovDelay[x][y]) // next animation frame MovDelay[x][y] = 3 * delay; - if (MovDelay[x][y]) /* wait some time before next frame */ + if (MovDelay[x][y]) // wait some time before next frame { MovDelay[x][y]--; @@ -9233,7 +9311,7 @@ void MauerWaechst(int x, int y) } } -void MauerAbleger(int ax, int ay) +static void MauerAbleger(int ax, int ay) { int element = Feld[ax][ay]; int graphic = el2img(element); @@ -9246,10 +9324,10 @@ void MauerAbleger(int ax, int ay) if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); - if (!MovDelay[ax][ay]) /* start building new wall */ + if (!MovDelay[ax][ay]) // start building new wall MovDelay[ax][ay] = 6; - if (MovDelay[ax][ay]) /* wait some time before building new wall */ + if (MovDelay[ax][ay]) // wait some time before building new wall { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) @@ -9341,7 +9419,7 @@ void MauerAbleger(int ax, int ay) PlayLevelSoundAction(ax, ay, ACTION_GROWING); } -void MauerAblegerStahl(int ax, int ay) +static void MauerAblegerStahl(int ax, int ay) { int element = Feld[ax][ay]; int graphic = el2img(element); @@ -9354,10 +9432,10 @@ void MauerAblegerStahl(int ax, int ay) if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic); - if (!MovDelay[ax][ay]) /* start building new wall */ + if (!MovDelay[ax][ay]) // start building new wall MovDelay[ax][ay] = 6; - if (MovDelay[ax][ay]) /* wait some time before building new wall */ + if (MovDelay[ax][ay]) // wait some time before building new wall { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) @@ -9443,7 +9521,7 @@ void MauerAblegerStahl(int ax, int ay) PlayLevelSoundAction(ax, ay, ACTION_GROWING); } -void CheckForDragon(int x, int y) +static void CheckForDragon(int x, int y) { int i, j; boolean dragon_found = FALSE; @@ -9545,7 +9623,7 @@ static void ChangeActiveTrap(int x, int y) { int graphic = IMG_TRAP_ACTIVE; - /* if new animation frame was drawn, correct crumbled sand border */ + // if new animation frame was drawn, correct crumbled sand border if (IS_NEW_FRAME(GfxFrame[x][y], graphic)) TEST_DrawLevelFieldCrumbled(x, y); } @@ -9587,7 +9665,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) if (!change->has_action) return; - /* ---------- determine action paramater values -------------------------- */ + // ---------- determine action paramater values ----------------------------- int level_time_value = (level.time > 0 ? TimeLeft : @@ -9647,8 +9725,8 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score : action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CE_DELAY_VALUE(change) : action_arg == CA_ARG_NUMBER_LEVEL_TIME ? level_time_value : - action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? local_player->gems_still_needed : - action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score : + action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? game.gems_still_needed : + action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? game.score : action_arg == CA_ARG_ELEMENT_CV_TARGET ? GET_NEW_CE_VALUE(target_element): action_arg == CA_ARG_ELEMENT_CV_TRIGGER ? change->actual_trigger_ce_value: action_arg == CA_ARG_ELEMENT_CV_ACTION ? GET_NEW_CE_VALUE(action_element): @@ -9661,9 +9739,9 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) -1); int action_arg_number_old = - (action_type == CA_SET_LEVEL_GEMS ? local_player->gems_still_needed : + (action_type == CA_SET_LEVEL_GEMS ? game.gems_still_needed : action_type == CA_SET_LEVEL_TIME ? TimeLeft : - action_type == CA_SET_LEVEL_SCORE ? local_player->score : + action_type == CA_SET_LEVEL_SCORE ? game.score : action_type == CA_SET_CE_VALUE ? CustomValue[x][y] : action_type == CA_SET_CE_SCORE ? ei->collect_score : 0); @@ -9684,7 +9762,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_arg == CA_ARG_PLAYER_ACTION ? 1 << GET_PLAYER_NR(action_element) : PLAYER_BITS_ANY); - /* ---------- execute action -------------------------------------------- */ + // ---------- execute action ----------------------------------------------- switch (action_type) { @@ -9693,7 +9771,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) return; } - /* ---------- level actions ------------------------------------------- */ + // ---------- level actions ---------------------------------------------- case CA_RESTART_LEVEL: { @@ -9715,7 +9793,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) case CA_SET_LEVEL_TIME: { - if (level.time > 0) /* only modify limited time value */ + if (level.time > 0) // only modify limited time value { TimeLeft = action_arg_number_new; @@ -9733,9 +9811,9 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) case CA_SET_LEVEL_SCORE: { - local_player->score = action_arg_number_new; + game.score = action_arg_number_new; - game_panel_controls[GAME_PANEL_SCORE].value = local_player->score; + game_panel_controls[GAME_PANEL_SCORE].value = game.score; DisplayGameControlValues(); @@ -9744,12 +9822,11 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) case CA_SET_LEVEL_GEMS: { - local_player->gems_still_needed = action_arg_number_new; + game.gems_still_needed = action_arg_number_new; game.snapshot.collected_item = TRUE; - game_panel_controls[GAME_PANEL_GEMS].value = - local_player->gems_still_needed; + game_panel_controls[GAME_PANEL_GEMS].value = game.gems_still_needed; DisplayGameControlValues(); @@ -9765,17 +9842,17 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) case CA_SET_LEVEL_RANDOM_SEED: { - /* ensure that setting a new random seed while playing is predictable */ + // ensure that setting a new random seed while playing is predictable InitRND(action_arg_number_new ? action_arg_number_new : RND(1000000) + 1); break; } - /* ---------- player actions ------------------------------------------ */ + // ---------- player actions --------------------------------------------- case CA_MOVE_PLAYER: { - /* automatically move to the next field in specified direction */ + // 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; @@ -9789,8 +9866,8 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) if (action_arg_player_bits & (1 << i)) ExitPlayer(&stored_player[i]); - if (AllPlayersGone) - PlayerWins(local_player); + if (game.players_still_needed == 0) + LevelSolved(); break; } @@ -9928,7 +10005,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) SetPlayerWaiting(&stored_player[i], FALSE); - /* set number of special actions for bored and sleeping animation */ + // set number of special actions for bored and sleeping animation stored_player[i].num_special_action_bored = get_num_special_action(artwork_element, ACTION_BORING_1, ACTION_BORING_LAST); @@ -10039,7 +10116,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } - /* ---------- CE actions ---------------------------------------------- */ + // ---------- CE actions ------------------------------------------------- case CA_SET_CE_VALUE: { @@ -10135,7 +10212,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } - /* ---------- engine actions ------------------------------------------ */ + // ---------- engine actions --------------------------------------------- case CA_SET_ENGINE_SCAN_MODE: { @@ -10178,7 +10255,7 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) InitField_WithBug1(x, y, FALSE); - new_element = Feld[x][y]; /* element may have changed */ + new_element = Feld[x][y]; // element may have changed ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); @@ -10189,9 +10266,9 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) TEST_DrawLevelFieldCrumbledNeighbours(x, y); } - /* check if element under the player changes from accessible to unaccessible - (needed for special case of dropping element which then changes) */ - /* (must be checked after creating new element for walkable group elements) */ + // check if element under the player changes from accessible to unaccessible + // (needed for special case of dropping element which then changes) + // (must be checked after creating new element for walkable group elements) if (IS_PLAYER(x, y) && !player_explosion_protected && IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element)) { @@ -10200,12 +10277,12 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) return; } - /* "ChangeCount" not set yet to allow "entered by player" change one time */ + // "ChangeCount" not set yet to allow "entered by player" change one time if (new_element_is_player) RelocatePlayer(x, y, new_element); if (is_change) - ChangeCount[x][y]++; /* count number of changes in the same frame */ + ChangeCount[x][y]++; // count number of changes in the same frame TestIfBadThingTouchesPlayer(x, y); TestIfPlayerTouchesCustomElement(x, y); @@ -10225,8 +10302,8 @@ static void CreateElementFromChange(int x, int y, int element) { int old_element = Feld[x][y]; - /* prevent changed element from moving in same engine frame - unless both old and new element can either fall or move */ + // prevent changed element from moving in same engine frame + // unless both old and new element can either fall or move if ((!CAN_FALL(old_element) || !CAN_FALL(element)) && (!CAN_MOVE(old_element) || !CAN_MOVE(element))) Stop[x][y] = TRUE; @@ -10244,13 +10321,13 @@ static boolean ChangeElement(int x, int y, int element, int page) int target_element; int old_element = Feld[x][y]; - /* always use default change event to prevent running into a loop */ + // always use default change event to prevent running into a loop if (ChangeEvent[x][y] == -1) ChangeEvent[x][y] = CE_DELAY; if (ChangeEvent[x][y] == CE_DELAY) { - /* reset actual trigger element, trigger player and action element */ + // reset actual trigger element, trigger player and action element change->actual_trigger_element = EL_EMPTY; change->actual_trigger_player = EL_EMPTY; change->actual_trigger_player_bits = CH_PLAYER_NONE; @@ -10259,11 +10336,11 @@ static boolean ChangeElement(int x, int y, int element, int page) change->actual_trigger_ce_score = 0; } - /* do not change elements more than a specified maximum number of changes */ + // do not change elements more than a specified maximum number of changes if (ChangeCount[x][y] >= game.max_num_changes_per_frame) return FALSE; - ChangeCount[x][y]++; /* count number of changes in the same frame */ + ChangeCount[x][y]++; // count number of changes in the same frame if (change->explode) { @@ -10293,12 +10370,12 @@ static boolean ChangeElement(int x, int y, int element, int page) can_replace[xx][yy] = TRUE; - if (ex == x && ey == y) /* do not check changing element itself */ + if (ex == x && ey == y) // do not check changing element itself continue; if (content_element == EL_EMPTY_SPACE) { - can_replace[xx][yy] = FALSE; /* do not replace border with space */ + can_replace[xx][yy] = FALSE; // do not replace border with space continue; } @@ -10368,9 +10445,9 @@ static boolean ChangeElement(int x, int y, int element, int page) something_has_changed = TRUE; - /* for symmetry reasons, freeze newly created border elements */ + // for symmetry reasons, freeze newly created border elements if (ex != x || ey != y) - Stop[ex][ey] = TRUE; /* no more moving in this frame */ + Stop[ex][ey] = TRUE; // no more moving in this frame } } @@ -10400,7 +10477,7 @@ static boolean ChangeElement(int x, int y, int element, int page) PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + page); } - /* this uses direct change before indirect change */ + // this uses direct change before indirect change CheckTriggeredElementChangeByPage(x, y, old_element, CE_CHANGE_OF_X, page); return TRUE; @@ -10425,21 +10502,21 @@ static void HandleElementChange(int x, int y, int page) } #endif - /* this can happen with classic bombs on walkable, changing elements */ + // this can happen with classic bombs on walkable, changing elements if (!CAN_CHANGE_OR_HAS_ACTION(element)) { return; } - if (ChangeDelay[x][y] == 0) /* initialize element change */ + if (ChangeDelay[x][y] == 0) // initialize element change { ChangeDelay[x][y] = GET_CHANGE_DELAY(change) + 1; if (change->can_change) { - /* !!! not clear why graphic animation should be reset at all here !!! */ - /* !!! UPDATE: but is needed for correct Snake Bite tail animation !!! */ - /* !!! SOLUTION: do not reset if graphics engine set to 4 or above !!! */ + // !!! not clear why graphic animation should be reset at all here !!! + // !!! UPDATE: but is needed for correct Snake Bite tail animation !!! + // !!! SOLUTION: do not reset if graphics engine set to 4 or above !!! /* GRAPHICAL BUG ADDRESSED BY CHECKING GRAPHICS ENGINE VERSION: @@ -10479,8 +10556,8 @@ static void HandleElementChange(int x, int y, int page) This can also be seen from the debug output for this test element.) */ - /* when a custom element is about to change (for example by change delay), - do not reset graphic animation when the custom element is moving */ + // when a custom element is about to change (for example by change delay), + // do not reset graphic animation when the custom element is moving if (game.graphics_engine_version < 4 && !IS_MOVING(x, y)) { @@ -10495,7 +10572,7 @@ static void HandleElementChange(int x, int y, int page) ChangeDelay[x][y]--; - if (ChangeDelay[x][y] != 0) /* continue element change */ + if (ChangeDelay[x][y] != 0) // continue element change { if (change->can_change) { @@ -10508,9 +10585,9 @@ static void HandleElementChange(int x, int y, int page) change->change_function(x, y); } } - else /* finish element change */ + else // finish element change { - if (ChangePage[x][y] != -1) /* remember page from delayed change */ + if (ChangePage[x][y] != -1) // remember page from delayed change { page = ChangePage[x][y]; ChangePage[x][y] = -1; @@ -10518,15 +10595,15 @@ static void HandleElementChange(int x, int y, int page) change = &ei->change_page[page]; } - if (IS_MOVING(x, y)) /* never change a running system ;-) */ + if (IS_MOVING(x, y)) // never change a running system ;-) { - ChangeDelay[x][y] = 1; /* try change after next move step */ - ChangePage[x][y] = page; /* remember page to use for change */ + ChangeDelay[x][y] = 1; // try change after next move step + ChangePage[x][y] = page; // remember page to use for change return; } - /* special case: set new level random seed before changing element */ + // special case: set new level random seed before changing element if (change->has_action && change->action_type == CA_SET_LEVEL_RANDOM_SEED) handle_action_before_change = TRUE; @@ -10601,9 +10678,9 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, { if (change->can_change && !change_done) { - /* if element already changed in this frame, not only prevent - another element change (checked in ChangeElement()), but - also prevent additional element actions for this element */ + // if element already changed in this frame, not only prevent + // another element change (checked in ChangeElement()), but + // also prevent additional element actions for this element if (ChangeCount[x][y] >= game.max_num_changes_per_frame && !level.use_action_after_change_bug) @@ -10616,9 +10693,9 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, } else if (change->has_action) { - /* if element already changed in this frame, not only prevent - another element change (checked in ChangeElement()), but - also prevent additional element actions for this element */ + // if element already changed in this frame, not only prevent + // another element change (checked in ChangeElement()), but + // also prevent additional element actions for this element if (ChangeCount[x][y] >= game.max_num_changes_per_frame && !level.use_action_after_change_bug) @@ -10665,7 +10742,7 @@ static boolean CheckElementChangeExt(int x, int y, element = Feld[x][y]; } - /* check if element has already changed or is about to change after moving */ + // check if element has already changed or is about to change after moving if ((game.engine_version < VERSION_IDENT(3,2,0,7) && Feld[x][y] != element) || @@ -10688,7 +10765,7 @@ static boolean CheckElementChangeExt(int x, int y, (trigger_event == CE_TOUCHING_X || trigger_event == CE_HITTING_X || trigger_event == CE_HIT_BY_X || - trigger_event == CE_DIGGING_X); /* this one was forgotten until 3.2.3 */ + trigger_event == CE_DIGGING_X); // this one was forgotten until 3.2.3 if (change->can_change_or_has_action && change->has_event[trigger_event] && @@ -10704,7 +10781,7 @@ static boolean CheckElementChangeExt(int x, int y, change->actual_trigger_ce_value = CustomValue[x][y]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); - /* special case: trigger element not at (x,y) position for some events */ + // special case: trigger element not at (x,y) position for some events if (check_trigger_element) { static struct @@ -10774,7 +10851,7 @@ static void PlayPlayerSound(struct PlayerInfo *player) } } -static void PlayAllPlayersSound() +static void PlayAllPlayersSound(void) { int i; @@ -10793,7 +10870,7 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) if (is_waiting) { - if (!last_waiting) /* not waiting -> waiting */ + if (!last_waiting) // not waiting -> waiting { player->is_waiting = TRUE; @@ -10826,7 +10903,7 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) if (player->is_sleeping && player->use_murphy) { - /* special case for sleeping Murphy when leaning against non-free tile */ + // special case for sleeping Murphy when leaning against non-free tile if (!IN_LEV_FIELD(player->jx - 1, player->jy) || (Feld[player->jx - 1][player->jy] != EL_EMPTY && @@ -10912,7 +10989,7 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) } } } - else if (last_waiting) /* waiting -> not waiting */ + else if (last_waiting) // waiting -> not waiting { player->is_waiting = FALSE; player->is_bored = FALSE; @@ -10970,7 +11047,7 @@ static void CheckSingleStepMode(struct PlayerInfo *player) !player->is_dropping_pressed) { TapeTogglePause(TAPE_TOGGLE_AUTOMATIC); - SnapField(player, 0, 0); /* stop snapping */ + SnapField(player, 0, 0); // stop snapping } } @@ -11011,7 +11088,7 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) } else { - /* no actions for this player (no input at player's configured device) */ + // no actions for this player (no input at player's configured device) DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH); SnapField(player, 0, 0); @@ -11020,7 +11097,7 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) if (player->MovPos == 0) SetPlayerWaiting(player, TRUE); - if (player->MovPos == 0) /* needed for tape.playing */ + if (player->MovPos == 0) // needed for tape.playing player->is_moving = FALSE; player->is_dropping = FALSE; @@ -11055,58 +11132,58 @@ static void SetTapeActionFromMouseAction(byte *tape_action, tape_action[TAPE_ACTION_BUTTON] = mouse_action->button; } -static void CheckLevelTime() +static void CheckLevelSolved(void) { - int i; - - /* !!! SAME CODE AS IN "GameActions()" -- FIX THIS !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { - if (level.native_em_level->lev->home == 0) /* all players at home */ + if (game_em.level_solved && + !game_em.game_over) // game won { - PlayerWins(local_player); + LevelSolved(); - AllPlayersGone = TRUE; + game_em.game_over = TRUE; - level.native_em_level->lev->home = -1; + game.all_players_gone = TRUE; } - if (level.native_em_level->ply[0]->alive == 0 && - level.native_em_level->ply[1]->alive == 0 && - level.native_em_level->ply[2]->alive == 0 && - level.native_em_level->ply[3]->alive == 0) /* all dead */ - AllPlayersGone = TRUE; + if (game_em.game_over) // game lost + game.all_players_gone = TRUE; } else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) { - if (game_sp.LevelSolved && - !game_sp.GameOver) /* game won */ + if (game_sp.level_solved && + !game_sp.game_over) // game won { - PlayerWins(local_player); + LevelSolved(); - game_sp.GameOver = TRUE; + game_sp.game_over = TRUE; - AllPlayersGone = TRUE; + game.all_players_gone = TRUE; } - if (game_sp.GameOver) /* game lost */ - AllPlayersGone = TRUE; + if (game_sp.game_over) // game lost + game.all_players_gone = TRUE; } else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) { if (game_mm.level_solved && - !game_mm.game_over) /* game won */ + !game_mm.game_over) // game won { - PlayerWins(local_player); + LevelSolved(); game_mm.game_over = TRUE; - AllPlayersGone = TRUE; + game.all_players_gone = TRUE; } - if (game_mm.game_over) /* game lost */ - AllPlayersGone = TRUE; + if (game_mm.game_over) // game lost + game.all_players_gone = TRUE; } +} + +static void CheckLevelTime(void) +{ + int i; if (TimeFrames >= FRAMES_PER_SECOND) { @@ -11126,7 +11203,7 @@ static void CheckLevelTime() } } - if (!local_player->LevelSolved && !level.use_step_counter) + if (!game.LevelSolved && !level.use_step_counter) { TimePlayed++; @@ -11151,7 +11228,7 @@ static void CheckLevelTime() KillPlayer(&stored_player[i]); } } - else if (game.no_time_limit && !AllPlayersGone) /* level w/o time limit */ + else if (game.no_time_limit && !game.all_players_gone) { game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; } @@ -11174,21 +11251,21 @@ void AdvanceFrameAndPlayerCounters(int player_nr) { int i; - /* advance frame counters (global frame counter and time frame counter) */ + // advance frame counters (global frame counter and time frame counter) FrameCounter++; TimeFrames++; - /* advance player counters (counters for move delay, move animation etc.) */ + // advance player counters (counters for move delay, move animation etc.) for (i = 0; i < MAX_PLAYERS; i++) { boolean advance_player_counters = (player_nr == -1 || player_nr == i); int move_delay_value = stored_player[i].move_delay_value; int move_frames = MOVE_DELAY_NORMAL_SPEED / move_delay_value; - if (!advance_player_counters) /* not all players may be affected */ + if (!advance_player_counters) // not all players may be affected continue; - if (move_frames == 0) /* less than one move per game frame */ + if (move_frames == 0) // less than one move per game frame { int stepsize = TILEX / move_delay_value; int delay = move_delay_value / MOVE_DELAY_NORMAL_SPEED; @@ -11207,7 +11284,7 @@ void AdvanceFrameAndPlayerCounters(int player_nr) if (stored_player[i].move_delay > 0) stored_player[i].move_delay--; - /* due to bugs in previous versions, counter must count up, not down */ + // due to bugs in previous versions, counter must count up, not down if (stored_player[i].push_delay != -1) stored_player[i].push_delay++; @@ -11238,7 +11315,7 @@ void StartGameActions(boolean init_network_game, boolean record_tape, InitGame(); } -void GameActionsExt() +static void GameActionsExt(void) { #if 0 static unsigned int game_frame_delay = 0; @@ -11249,7 +11326,7 @@ void GameActionsExt() byte tape_action[MAX_PLAYERS]; int i; - /* detect endless loops, caused by custom element programming */ + // detect endless loops, caused by custom element programming if (recursion_loop_detected && recursion_loop_depth == 0) { char *message = getStringCat3("Internal Error! Element ", @@ -11261,7 +11338,7 @@ void GameActionsExt() RequestQuitGameExt(FALSE, level_editor_test_game, message); - recursion_loop_detected = FALSE; /* if game should be continued */ + recursion_loop_detected = FALSE; // if game should be continued free(message); @@ -11271,62 +11348,15 @@ void GameActionsExt() if (game.restart_level) StartGameActions(network.enabled, setup.autorecord, level.random_seed); - /* !!! SAME CODE AS IN "CheckLevelTime()" -- FIX THIS !!! */ - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - { - if (level.native_em_level->lev->home == 0) /* all players at home */ - { - PlayerWins(local_player); - - AllPlayersGone = TRUE; - - level.native_em_level->lev->home = -1; - } - - if (level.native_em_level->ply[0]->alive == 0 && - level.native_em_level->ply[1]->alive == 0 && - level.native_em_level->ply[2]->alive == 0 && - level.native_em_level->ply[3]->alive == 0) /* all dead */ - AllPlayersGone = TRUE; - } - else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) - { - if (game_sp.LevelSolved && - !game_sp.GameOver) /* game won */ - { - PlayerWins(local_player); - - game_sp.GameOver = TRUE; - - AllPlayersGone = TRUE; - } - - if (game_sp.GameOver) /* game lost */ - AllPlayersGone = TRUE; - } - else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) - { - if (game_mm.level_solved && - !game_mm.game_over) /* game won */ - { - PlayerWins(local_player); - - game_mm.game_over = TRUE; + CheckLevelSolved(); - AllPlayersGone = TRUE; - } - - if (game_mm.game_over) /* game lost */ - AllPlayersGone = TRUE; - } - - if (local_player->LevelSolved && !local_player->LevelSolved_GameEnd) + if (game.LevelSolved && !game.LevelSolved_GameEnd) GameWon(); - if (AllPlayersGone && !TAPE_IS_STOPPED(tape)) + if (game.all_players_gone && !TAPE_IS_STOPPED(tape)) TapeStop(); - if (game_status != GAME_MODE_PLAYING) /* status might have changed */ + if (game_status != GAME_MODE_PLAYING) // status might have changed return; game_frame_delay_value = @@ -11337,16 +11367,25 @@ void GameActionsExt() SetVideoFrameDelay(game_frame_delay_value); + // (de)activate virtual buttons depending on current game status + if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS)) + { + if (game.all_players_gone) // if no players there to be controlled anymore + SetOverlayActive(FALSE); + else if (!tape.playing) // if game continues after tape stopped playing + SetOverlayActive(TRUE); + } + #if 0 #if 0 - /* ---------- main game synchronization point ---------- */ + // ---------- main game synchronization point ---------- int skip = WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value); printf("::: skip == %d\n", skip); #else - /* ---------- main game synchronization point ---------- */ + // ---------- main game synchronization point ---------- WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value); #endif @@ -11354,29 +11393,30 @@ void GameActionsExt() if (network_playing && !network_player_action_received) { - /* try to get network player actions in time */ + // try to get network player actions in time - /* last chance to get network player actions without main loop delay */ + // last chance to get network player actions without main loop delay HandleNetworking(); - /* game was quit by network peer */ + // game was quit by network peer if (game_status != GAME_MODE_PLAYING) return; - if (!network_player_action_received) - return; /* failed to get network player actions in time */ + // check if network player actions still missing and game still running + if (!network_player_action_received && !checkGameEnded()) + return; // failed to get network player actions in time - /* do not yet reset "network_player_action_received" (for tape.pausing) */ + // do not yet reset "network_player_action_received" (for tape.pausing) } if (tape.pausing) return; - /* at this point we know that we really continue executing the game */ + // at this point we know that we really continue executing the game network_player_action_received = FALSE; - /* when playing tape, read previously recorded player input from tape data */ + // when playing tape, read previously recorded player input from tape data recorded_player_action = (tape.playing ? TapePlayAction() : NULL); local_player->effective_mouse_action = local_player->mouse_action; @@ -11385,7 +11425,7 @@ void GameActionsExt() SetMouseActionFromTapeAction(&local_player->effective_mouse_action, recorded_player_action); - /* TapePlayAction() may return NULL when toggling to "pause before death" */ + // TapePlayAction() may return NULL when toggling to "pause before death" if (tape.pausing) return; @@ -11403,7 +11443,7 @@ void GameActionsExt() stored_player[i].effective_action = stored_player[i].action; } - if (network_playing) + if (network_playing && !checkGameEnded()) SendToServer_MovePlayer(summarized_player_action); // summarize all actions at local players mapped input device position @@ -11442,10 +11482,14 @@ void GameActionsExt() SetTapeActionFromMouseAction(tape_action, &local_player->effective_mouse_action); - /* only record actions from input devices, but not programmed actions */ + // only record actions from input devices, but not programmed actions if (tape.recording) TapeRecordAction(tape_action); + // remember if game was played (especially after tape stopped playing) + if (!tape.playing && summarized_player_action) + game.GamePlayed = TRUE; + #if USE_NEW_PLAYER_ASSIGNMENTS // !!! also map player actions in single player mode !!! // if (game.team_mode) @@ -11517,9 +11561,10 @@ void GameActionsExt() BlitScreenToBitmap(backbuffer); + CheckLevelSolved(); CheckLevelTime(); - AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ + AdvanceFrameAndPlayerCounters(-1); // advance counters for all players if (global.show_frames_per_second) { @@ -11529,24 +11574,24 @@ void GameActionsExt() fps_frames++; - if (fps_delay_ms >= 500) /* calculate FPS every 0.5 seconds */ + if (fps_delay_ms >= 500) // calculate FPS every 0.5 seconds { global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms; fps_frames = 0; fps_counter = Counter(); - /* always draw FPS to screen after FPS value was updated */ + // always draw FPS to screen after FPS value was updated redraw_mask |= REDRAW_FPS; } - /* only draw FPS if no screen areas are deactivated (invisible warp mode) */ + // only draw FPS if no screen areas are deactivated (invisible warp mode) if (GetDrawDeactivationMask() == REDRAW_NONE) redraw_mask |= REDRAW_FPS; } } -static void GameActions_CheckSaveEngineSnapshot() +static void GameActions_CheckSaveEngineSnapshot(void) { if (!game.snapshot.save_snapshot) return; @@ -11557,14 +11602,14 @@ static void GameActions_CheckSaveEngineSnapshot() SaveEngineSnapshotToList(); } -void GameActions() +void GameActions(void) { GameActionsExt(); GameActions_CheckSaveEngineSnapshot(); } -void GameActions_EM_Main() +void GameActions_EM_Main(void) { byte effective_action[MAX_PLAYERS]; boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); @@ -11576,7 +11621,7 @@ void GameActions_EM_Main() GameActions_EM(effective_action, warp_mode); } -void GameActions_SP_Main() +void GameActions_SP_Main(void) { byte effective_action[MAX_PLAYERS]; boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); @@ -11596,19 +11641,19 @@ void GameActions_SP_Main() } } -void GameActions_MM_Main() +void GameActions_MM_Main(void) { boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); GameActions_MM(local_player->effective_mouse_action, warp_mode); } -void GameActions_RND_Main() +void GameActions_RND_Main(void) { GameActions_RND(); } -void GameActions_RND() +void GameActions_RND(void) { int magic_wall_x = 0, magic_wall_y = 0; int i, x, y, element, graphic, last_gfx_frame; @@ -11628,14 +11673,14 @@ void GameActions_RND() { boolean all_players_fit_to_screen = checkIfAllPlayersFitToScreen_RND(); - /* switching to "all players" only possible if all players fit to screen */ + // switching to "all players" only possible if all players fit to screen if (game.centered_player_nr_next == -1 && !all_players_fit_to_screen) { game.centered_player_nr_next = game.centered_player_nr; game.set_centered_player = FALSE; } - /* do not switch focus to non-existing (or non-active) player */ + // do not switch focus to non-existing (or non-active) player if (game.centered_player_nr_next >= 0 && !stored_player[game.centered_player_nr_next].active) { @@ -11645,7 +11690,7 @@ void GameActions_RND() } if (game.set_centered_player && - ScreenMovPos == 0) /* screen currently aligned at tile position */ + ScreenMovPos == 0) // screen currently aligned at tile position { int sx, sy; @@ -11681,7 +11726,7 @@ void GameActions_RND() CheckGravityMovement(&stored_player[i]); #endif - /* overwrite programmed action with tape action */ + // overwrite programmed action with tape action if (stored_player[i].programmed_action) actual_player_action = stored_player[i].programmed_action; @@ -11715,7 +11760,7 @@ void GameActions_RND() { ContinueMoving(x, y); - /* continue moving after pushing (this is actually a bug) */ + // continue moving after pushing (this is actually a bug) if (!IS_MOVING(x, y)) Stop[x][y] = FALSE; } @@ -11724,10 +11769,12 @@ void GameActions_RND() SCAN_PLAYFIELD(x, y) { + Last[x][y] = Feld[x][y]; + ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; - /* this must be handled before main playfield loop */ + // this must be handled before main playfield loop if (Feld[x][y] == EL_PLAYER_IS_LEAVING) { MovDelay[x][y]--; @@ -11743,7 +11790,7 @@ void GameActions_RND() RemoveField(x, y); TEST_DrawLevelField(x, y); - TestIfElementTouchesCustomElement(x, y); /* for empty space */ + TestIfElementTouchesCustomElement(x, y); // for empty space } } @@ -11821,7 +11868,7 @@ void GameActions_RND() continue; } - /* this may take place after moving, so 'element' may have changed */ + // this may take place after moving, so 'element' may have changed if (IS_CHANGING(x, y) && (game.engine_version < VERSION_IDENT(3,0,7,1) || !Stop[x][y])) { @@ -11907,7 +11954,7 @@ void GameActions_RND() else if (element == EL_FLAMES) CheckForDragon(x, y); else if (element == EL_EXPLOSION) - ; /* drawing of correct explosion animation is handled separately */ + ; // drawing of correct explosion animation is handled separately else if (element == EL_ELEMENT_SNAPPING || element == EL_DIAGONAL_SHRINKING || element == EL_DIAGONAL_GROWING) @@ -11926,7 +11973,7 @@ void GameActions_RND() { int jx = local_player->jx, jy = local_player->jy; - /* play the element sound at the position nearest to the player */ + // play the element sound at the position nearest to the player if ((element == EL_MAGIC_WALL_FULL || element == EL_MAGIC_WALL_ACTIVE || element == EL_MAGIC_WALL_EMPTYING || @@ -11945,7 +11992,7 @@ void GameActions_RND() } #if USE_NEW_AMOEBA_CODE - /* new experimental amoeba growth stuff */ + // new experimental amoeba growth stuff if (!(FrameCounter % 8)) { static unsigned int random = 1684108901; @@ -12118,14 +12165,15 @@ void GameActions_RND() DrawAllPlayers(); PlayAllPlayersSound(); - if (local_player->show_envelope != 0 && local_player->MovPos == 0) + if (local_player->show_envelope != 0 && (!local_player->active || + local_player->MovPos == 0)) { ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1); local_player->show_envelope = 0; } - /* use random number generator in every frame to make it less predictable */ + // use random number generator in every frame to make it less predictable if (game.engine_version >= VERSION_IDENT(3,1,1,0)) RND(1); } @@ -12151,7 +12199,7 @@ static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y) return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY); } -static boolean AllPlayersInVisibleScreen() +static boolean AllPlayersInVisibleScreen(void) { int i; @@ -12326,9 +12374,9 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, if (can_move != MP_MOVING) return can_move; - /* check if DigField() has caused relocation of the player */ + // check if DigField() has caused relocation of the player if (player->jx != jx || player->jy != jy) - return MP_NO_ACTION; /* <-- !!! CHECK THIS [-> MP_ACTION ?] !!! */ + return MP_NO_ACTION; // <-- !!! CHECK THIS [-> MP_ACTION ?] !!! StorePlayer[jx][jy] = 0; player->last_jx = jx; @@ -12353,7 +12401,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, player->is_moving = TRUE; #if 1 - /* should better be called in MovePlayer(), but this breaks some tapes */ + // should better be called in MovePlayer(), but this breaks some tapes ScrollPlayer(player, SCROLL_INIT); #endif @@ -12386,18 +12434,18 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) if (player->move_delay > 0) return FALSE; - player->move_delay = -1; /* set to "uninitialized" value */ + player->move_delay = -1; // set to "uninitialized" value - /* store if player is automatically moved to next field */ + // store if player is automatically moved to next field player->is_auto_moving = (player->programmed_action != MV_NONE); - /* remove the last programmed player action */ + // remove the last programmed player action player->programmed_action = 0; if (player->MovPos) { - /* should only happen if pre-1.2 tape recordings are played */ - /* this is only for backward compatibility */ + // should only happen if pre-1.2 tape recordings are played + // this is only for backward compatibility int original_move_delay_value = player->move_delay_value; @@ -12406,7 +12454,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) tape.counter); #endif - /* scroll remaining steps with finest movement resolution */ + // scroll remaining steps with finest movement resolution player->move_delay_value = MOVE_DELAY_NORMAL_SPEED; while (player->MovPos) @@ -12457,46 +12505,46 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy))) { - /* actual player has left the screen -- scroll in that direction */ - if (jx != old_jx) /* player has moved horizontally */ + // actual player has left the screen -- scroll in that direction + if (jx != old_jx) // player has moved horizontally scroll_x += (jx - old_jx); - else /* player has moved vertically */ + else // player has moved vertically scroll_y += (jy - old_jy); } else { - if (jx != old_jx) /* player has moved horizontally */ + if (jx != old_jx) // player has moved horizontally { if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) || (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset)) scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset); - /* don't scroll over playfield boundaries */ + // don't scroll over playfield boundaries if (scroll_x < SBX_Left || scroll_x > SBX_Right) scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right); - /* don't scroll more than one field at a time */ + // don't scroll more than one field at a time scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x); - /* don't scroll against the player's moving direction */ + // don't scroll against the player's moving direction if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) || (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x)) scroll_x = old_scroll_x; } - else /* player has moved vertically */ + else // player has moved vertically { if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) || (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset)) scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset); - /* don't scroll over playfield boundaries */ + // don't scroll over playfield boundaries if (scroll_y < SBY_Upper || scroll_y > SBY_Lower) scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower); - /* don't scroll more than one field at a time */ + // don't scroll more than one field at a time scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y); - /* don't scroll against the player's moving direction */ + // don't scroll against the player's moving direction if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) || (player->MovDir == MV_DOWN && scroll_y < old_scroll_y)) scroll_y = old_scroll_y; @@ -12528,7 +12576,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) else if (old_jx == jx && old_jy != jy) player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP); - TEST_DrawLevelField(jx, jy); /* for "crumbled sand" */ + TEST_DrawLevelField(jx, jy); // for "crumbled sand" player->last_move_dir = player->MovDir; player->is_moving = TRUE; @@ -12539,7 +12587,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) player->drop_pressed_delay = 0; #if 0 - /* should better be called here than above, but this breaks some tapes */ + // should better be called here than above, but this breaks some tapes ScrollPlayer(player, SCROLL_INIT); #endif } @@ -12555,10 +12603,10 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) the player was forced to wait again for eight frames before next try) */ if (game.engine_version >= VERSION_IDENT(3,1,1,0)) - player->move_delay = 0; /* allow direct movement in the next frame */ + player->move_delay = 0; // allow direct movement in the next frame } - if (player->move_delay == -1) /* not yet initialized by DigField() */ + if (player->move_delay == -1) // not yet initialized by DigField() player->move_delay = player->move_delay_value; if (game.engine_version < VERSION_IDENT(3,0,7,0)) @@ -12582,7 +12630,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) if (!player->active) return; - if (player->MovPos == 0 && mode == SCROLL_GO_ON) /* player not moving */ + if (player->MovPos == 0 && mode == SCROLL_GO_ON) // player not moving return; if (mode == SCROLL_INIT) @@ -12593,27 +12641,27 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) if ((player->block_last_field || player->block_delay_adjustment > 0) && Feld[last_jx][last_jy] == EL_EMPTY) { - int last_field_block_delay = 0; /* start with no blocking at all */ + int last_field_block_delay = 0; // start with no blocking at all int block_delay_adjustment = player->block_delay_adjustment; - /* if player blocks last field, add delay for exactly one move */ + // if player blocks last field, add delay for exactly one move if (player->block_last_field) { last_field_block_delay += player->move_delay_value; - /* when blocking enabled, prevent moving up despite gravity */ + // when blocking enabled, prevent moving up despite gravity if (player->gravity && player->MovDir == MV_UP) block_delay_adjustment = -1; } - /* add block delay adjustment (also possible when not blocking) */ + // add block delay adjustment (also possible when not blocking) last_field_block_delay += block_delay_adjustment; Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING; MovDelay[last_jx][last_jy] = last_field_block_delay + 1; } - if (player->MovPos != 0) /* player has not yet reached destination */ + if (player->MovPos != 0) // player has not yet reached destination return; } else if (!FrameReached(&player->actual_frame_counter, 1)) @@ -12624,12 +12672,12 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize; player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); - /* before DrawPlayer() to draw correct player graphic for this case */ + // before DrawPlayer() to draw correct player graphic for this case if (player->MovPos == 0) CheckGravityMovement(player); } - if (player->MovPos == 0) /* player reached destination field */ + if (player->MovPos == 0) // player reached destination field { if (player->move_delay_reset_counter > 0) { @@ -12637,10 +12685,10 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) if (player->move_delay_reset_counter == 0) { - /* continue with normal speed after quickly moving through gate */ + // continue with normal speed after quickly moving through gate HALVE_PLAYER_SPEED(player); - /* be able to make the next move without delay */ + // be able to make the next move without delay player->move_delay = 0; } } @@ -12655,17 +12703,17 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) Feld[jx][jy] == EL_EM_STEEL_EXIT_OPEN || Feld[jx][jy] == EL_EM_STEEL_EXIT_OPENING || Feld[jx][jy] == EL_SP_EXIT_OPEN || - Feld[jx][jy] == EL_SP_EXIT_OPENING) /* <-- special case */ + Feld[jx][jy] == EL_SP_EXIT_OPENING) // <-- special case { ExitPlayer(player); - if ((local_player->friends_still_needed == 0 || - IS_SP_ELEMENT(Feld[jx][jy])) && - AllPlayersGone) - PlayerWins(local_player); + if (game.players_still_needed == 0 && + (game.friends_still_needed == 0 || + IS_SP_ELEMENT(Feld[jx][jy]))) + LevelSolved(); } - /* this breaks one level: "machine", level 000 */ + // this breaks one level: "machine", level 000 { int move_direction = player->MovDir; int enter_side = MV_DIR_OPPOSITE(move_direction); @@ -12704,13 +12752,13 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) /* needed because pushed element has not yet reached its destination, so it would trigger a change event at its previous field location */ if (!player->is_pushing) - TestIfElementTouchesCustomElement(jx, jy); /* for empty space */ + TestIfElementTouchesCustomElement(jx, jy); // for empty space if (!player->active) RemovePlayer(player); } - if (!local_player->LevelSolved && level.use_step_counter) + if (!game.LevelSolved && level.use_step_counter) { int i; @@ -12731,7 +12779,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) for (i = 0; i < MAX_PLAYERS; i++) KillPlayer(&stored_player[i]); } - else if (game.no_time_limit && !AllPlayersGone) /* level w/o time limit */ + else if (game.no_time_limit && !game.all_players_gone) { game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; @@ -12754,7 +12802,7 @@ void ScrollScreen(struct PlayerInfo *player, int mode) if (mode == SCROLL_INIT) { - /* set scrolling step size according to actual player's moving speed */ + // set scrolling step size according to actual player's moving speed ScrollStepSize = TILEX / player->move_delay_value; screen_frame_counter = FrameCounter; @@ -12787,11 +12835,11 @@ void TestIfPlayerTouchesCustomElement(int x, int y) }; static int trigger_sides[4][2] = { - /* center side border side */ - { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */ - { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */ - { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */ - { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */ + // center side border side + { CH_SIDE_TOP, CH_SIDE_BOTTOM }, // check top + { CH_SIDE_LEFT, CH_SIDE_RIGHT }, // check left + { CH_SIDE_RIGHT, CH_SIDE_LEFT }, // check right + { CH_SIDE_BOTTOM, CH_SIDE_TOP } // check bottom }; static int touch_dir[4] = { @@ -12800,7 +12848,7 @@ void TestIfPlayerTouchesCustomElement(int x, int y) MV_UP | MV_DOWN, MV_LEFT | MV_RIGHT }; - int center_element = Feld[x][y]; /* should always be non-moving! */ + int center_element = Feld[x][y]; // should always be non-moving! int i; for (i = 0; i < NUM_DIRECTIONS; i++) @@ -12814,18 +12862,18 @@ void TestIfPlayerTouchesCustomElement(int x, int y) if (!IN_LEV_FIELD(xx, yy)) continue; - if (IS_PLAYER(x, y)) /* player found at center element */ + if (IS_PLAYER(x, y)) // player found at center element { struct PlayerInfo *player = PLAYERINFO(x, y); if (game.engine_version < VERSION_IDENT(3,0,7,0)) - border_element = Feld[xx][yy]; /* may be moving! */ + border_element = Feld[xx][yy]; // may be moving! else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy)) border_element = Feld[xx][yy]; - else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */ + else if (MovDir[xx][yy] & touch_dir[i]) // elements are touching border_element = MovingOrBlocked2Element(xx, yy); else - continue; /* center and border element do not touch */ + continue; // center and border element do not touch CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER, player->index_bit, border_side); @@ -12844,14 +12892,14 @@ void TestIfPlayerTouchesCustomElement(int x, int y) CE_TOUCHING_X, border_side); } } - else if (IS_PLAYER(xx, yy)) /* player found at border element */ + else if (IS_PLAYER(xx, yy)) // player found at border element { struct PlayerInfo *player = PLAYERINFO(xx, yy); if (game.engine_version >= VERSION_IDENT(3,0,7,0)) { if (player->MovPos != 0 && !(player->MovDir & touch_dir[i])) - continue; /* center and border element do not touch */ + continue; // center and border element do not touch } CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER, @@ -12887,11 +12935,11 @@ void TestIfElementTouchesCustomElement(int x, int y) }; static int trigger_sides[4][2] = { - /* center side border side */ - { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */ - { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */ - { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */ - { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */ + // center side border side + { CH_SIDE_TOP, CH_SIDE_BOTTOM }, // check top + { CH_SIDE_LEFT, CH_SIDE_RIGHT }, // check left + { CH_SIDE_RIGHT, CH_SIDE_LEFT }, // check right + { CH_SIDE_BOTTOM, CH_SIDE_TOP } // check bottom }; static int touch_dir[4] = { @@ -12901,7 +12949,7 @@ void TestIfElementTouchesCustomElement(int x, int y) MV_LEFT | MV_RIGHT }; boolean change_center_element = FALSE; - int center_element = Feld[x][y]; /* should always be non-moving! */ + int center_element = Feld[x][y]; // should always be non-moving! int border_element_old[NUM_DIRECTIONS]; int i; @@ -12917,13 +12965,13 @@ void TestIfElementTouchesCustomElement(int x, int y) continue; if (game.engine_version < VERSION_IDENT(3,0,7,0)) - border_element = Feld[xx][yy]; /* may be moving! */ + border_element = Feld[xx][yy]; // may be moving! else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy)) border_element = Feld[xx][yy]; - else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */ + else if (MovDir[xx][yy] & touch_dir[i]) // elements are touching border_element = MovingOrBlocked2Element(xx, yy); else - continue; /* center and border element do not touch */ + continue; // center and border element do not touch border_element_old[i] = border_element; } @@ -12938,11 +12986,11 @@ void TestIfElementTouchesCustomElement(int x, int y) if (border_element == -1) continue; - /* check for change of border element */ + // check for change of border element CheckElementChangeBySide(xx, yy, border_element, center_element, CE_TOUCHING_X, center_side); - /* (center element cannot be player, so we dont have to check this here) */ + // (center element cannot be player, so we dont have to check this here) } for (i = 0; i < NUM_DIRECTIONS; i++) @@ -12955,7 +13003,7 @@ void TestIfElementTouchesCustomElement(int x, int y) if (border_element == -1) continue; - /* check for change of center element (but change it only once) */ + // check for change of center element (but change it only once) if (!change_center_element) change_center_element = CheckElementChangeBySide(x, y, center_element, border_element, @@ -13025,7 +13073,7 @@ void TestIfElementHitsCustomElement(int x, int y, int direction) } } - /* "hitting something" is also true when hitting the playfield border */ + // "hitting something" is also true when hitting the playfield border CheckElementChangeBySide(x, y, hitting_element, touched_element, CE_HITTING_SOMETHING, direction); } @@ -13122,7 +13170,7 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) MV_DOWN }; - if (bad_element == EL_EXPLOSION) /* skip just exploding bad things */ + if (bad_element == EL_EXPLOSION) // skip just exploding bad things return; for (i = 0; i < NUM_DIRECTIONS; i++) @@ -13146,18 +13194,18 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) if ((DONT_RUN_INTO(bad_element) && bad_move_dir == test_dir[i]) || (DONT_TOUCH(bad_element) && test_move_dir != test_dir[i])) { - /* good thing is player or penguin that does not move away */ + // good thing is player or penguin that does not move away if (IS_PLAYER(test_x, test_y)) { struct PlayerInfo *player = PLAYERINFO(test_x, test_y); if (bad_element == EL_ROBOT && player->is_moving) - continue; /* robot does not kill player if he is moving */ + continue; // robot does not kill player if he is moving if (game.engine_version >= VERSION_IDENT(3,0,7,0)) { if (player->MovPos != 0 && !(player->MovDir & touch_dir[i])) - continue; /* center and border element do not touch */ + continue; // center and border element do not touch } kill_x = test_x; @@ -13211,7 +13259,7 @@ void TestIfGoodThingGetsHitByBadThing(int bad_x, int bad_y, int bad_move_dir) if (test_move_dir != bad_move_dir) { - /* good thing can be player or penguin that does not move away */ + // good thing can be player or penguin that does not move away if (IS_PLAYER(test_x, test_y)) { struct PlayerInfo *player = PLAYERINFO(test_x, test_y); @@ -13220,7 +13268,7 @@ void TestIfGoodThingGetsHitByBadThing(int bad_x, int bad_y, int bad_move_dir) player as being hit when he is moving towards the bad thing, because the "get hit by" condition would be lost after the player stops) */ if (player->MovPos != 0 && player->MovDir == bad_move_dir) - return; /* player moves away from bad thing */ + return; // player moves away from bad thing kill_x = test_x; kill_y = test_y; @@ -13342,10 +13390,10 @@ void KillPlayer(struct PlayerInfo *player) player->killed = TRUE; - /* remove accessible field at the player's position */ + // remove accessible field at the player's position Feld[jx][jy] = EL_EMPTY; - /* deactivate shield (else Bang()/Explode() would not work right) */ + // deactivate shield (else Bang()/Explode() would not work right) player->shield_normal_time_left = 0; player->shield_deadly_time_left = 0; @@ -13361,7 +13409,7 @@ void KillPlayer(struct PlayerInfo *player) player->killed, player->active, player->reanimated); #endif - if (player->reanimated) /* killed player may have been reanimated */ + if (player->reanimated) // killed player may have been reanimated player->killed = player->reanimated = FALSE; else BuryPlayer(player); @@ -13389,8 +13437,12 @@ void BuryPlayer(struct PlayerInfo *player) PlayLevelSoundElementAction(jx, jy, player->artwork_element, ACTION_DYING); PlayLevelSound(jx, jy, SND_GAME_LOSING); - player->GameOver = TRUE; RemovePlayer(player); + + player->buried = TRUE; + + if (game.all_players_gone) + game.GameOver = TRUE; } void RemovePlayer(struct PlayerInfo *player) @@ -13401,6 +13453,9 @@ void RemovePlayer(struct PlayerInfo *player) player->present = FALSE; player->active = FALSE; + // required for some CE actions (even if the player is not active anymore) + player->MovPos = 0; + if (!ExplodeField[jx][jy]) StorePlayer[jx][jy] = 0; @@ -13412,18 +13467,22 @@ void RemovePlayer(struct PlayerInfo *player) found = TRUE; if (!found) - AllPlayersGone = TRUE; + { + game.all_players_gone = TRUE; + game.GameOver = TRUE; + } - ExitX = ZX = jx; - ExitY = ZY = jy; + game.exit_x = game.robot_wheel_x = jx; + game.exit_y = game.robot_wheel_y = jy; } void ExitPlayer(struct PlayerInfo *player) { - DrawPlayer(player); /* needed here only to cleanup last field */ + DrawPlayer(player); // needed here only to cleanup last field RemovePlayer(player); - local_player->players_still_needed--; + if (game.players_still_needed > 0) + game.players_still_needed--; } static void setFieldForSnapping(int x, int y, int element, int direction) @@ -13459,10 +13518,10 @@ static boolean checkDiagonalPushing(struct PlayerInfo *player, { int jx, jy, dx, dy, xx, yy; - if (real_dx == 0 || real_dy == 0) /* no diagonal direction => push */ + if (real_dx == 0 || real_dy == 0) // no diagonal direction => push return TRUE; - /* diagonal direction: check alternative direction */ + // diagonal direction: check alternative direction jx = player->jx; jy = player->jy; dx = x - jx; @@ -13503,7 +13562,7 @@ static int DigField(struct PlayerInfo *player, int element = MovingOrBlocked2ElementIfNotLeaving(x, y); int collect_count; - if (is_player) /* function can also be called by EL_PENGUIN */ + if (is_player) // function can also be called by EL_PENGUIN { if (player->MovPos == 0) { @@ -13511,10 +13570,10 @@ static int DigField(struct PlayerInfo *player, player->is_collecting = FALSE; } - if (player->MovPos == 0) /* last pushing move finished */ + if (player->MovPos == 0) // last pushing move finished player->is_pushing = FALSE; - if (mode == DF_NO_PUSH) /* player just stopped pushing */ + if (mode == DF_NO_PUSH) // player just stopped pushing { player->is_switching = FALSE; player->push_delay = -1; @@ -13526,16 +13585,16 @@ static int DigField(struct PlayerInfo *player, if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0)) old_element = Back[jx][jy]; - /* in case of element dropped at player position, check background */ + // in case of element dropped at player position, check background else if (Back[jx][jy] != EL_EMPTY && game.engine_version >= VERSION_IDENT(2,2,0,0)) old_element = Back[jx][jy]; if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction)) - return MP_NO_ACTION; /* field has no opening in this direction */ + return MP_NO_ACTION; // field has no opening in this direction if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction)) - return MP_NO_ACTION; /* field has no opening in this direction */ + return MP_NO_ACTION; // field has no opening in this direction if (player_can_move && element == EL_ACID && move_direction == MV_DOWN) { @@ -13562,7 +13621,7 @@ static int DigField(struct PlayerInfo *player, collect_count = element_info[element].collect_count_initial; - if (!is_player && !IS_COLLECTIBLE(element)) /* penguin cannot collect it */ + if (!is_player && !IS_COLLECTIBLE(element)) // penguin cannot collect it return MP_NO_ACTION; if (game.engine_version < VERSION_IDENT(2,2,0,0)) @@ -13579,7 +13638,7 @@ static int DigField(struct PlayerInfo *player, if (element == EL_DC_LANDMINE) Bang(x, y); - if (Feld[x][y] != element) /* field changed by snapping */ + if (Feld[x][y] != element) // field changed by snapping return MP_ACTION; return MP_NO_ACTION; @@ -13588,7 +13647,7 @@ static int DigField(struct PlayerInfo *player, if (player->gravity && is_player && !player->is_auto_moving && canFallDown(player) && move_direction != MV_DOWN && !canMoveToValidFieldWithGravity(jx, jy, move_direction)) - return MP_NO_ACTION; /* player cannot walk here due to gravity */ + return MP_NO_ACTION; // player cannot walk here due to gravity if (player_can_move && IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction)) @@ -13620,14 +13679,14 @@ static int DigField(struct PlayerInfo *player, element == EL_SP_EXIT_OPEN || element == EL_SP_EXIT_OPENING) { - sound_action = ACTION_PASSING; /* player is passing exit */ + sound_action = ACTION_PASSING; // player is passing exit } else if (element == EL_EMPTY) { - sound_action = ACTION_MOVING; /* nothing to walk on */ + sound_action = ACTION_MOVING; // nothing to walk on } - /* play sound from background or player, whatever is available */ + // play sound from background or player, whatever is available if (element_info[sound_element].sound[sound_action] != SND_UNDEFINED) PlayLevelSoundElementAction(x, y, sound_element, sound_action); else @@ -13637,9 +13696,9 @@ static int DigField(struct PlayerInfo *player, IS_PASSABLE(element) && canPassField(x, y, move_direction)) { if (!ACCESS_FROM(element, opposite_direction)) - return MP_NO_ACTION; /* field not accessible from this direction */ + return MP_NO_ACTION; // field not accessible from this direction - if (CAN_MOVE(element)) /* only fixed elements can be passed! */ + if (CAN_MOVE(element)) // only fixed elements can be passed! return MP_NO_ACTION; if (IS_EM_GATE(element)) @@ -13700,12 +13759,12 @@ static int DigField(struct PlayerInfo *player, player->gravity = FALSE; } - /* automatically move to the next field with double speed */ + // automatically move to the next field with double speed player->programmed_action = move_direction; if (player->move_delay_reset_counter == 0) { - player->move_delay_reset_counter = 2; /* two double speed steps */ + player->move_delay_reset_counter = 2; // two double speed steps DOUBLE_PLAYER_SPEED(player); } @@ -13732,7 +13791,7 @@ static int DigField(struct PlayerInfo *player, if (level.block_snap_field) setFieldForSnapping(x, y, element, move_direction); else - TestIfElementTouchesCustomElement(x, y); /* for empty space */ + TestIfElementTouchesCustomElement(x, y); // for empty space CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X, player->index_bit, dig_side); @@ -13798,8 +13857,8 @@ static int DigField(struct PlayerInfo *player, { player->num_white_keys++; - /* display white keys? */ - /* DrawGameDoorValues(); */ + // display white keys? + // DrawGameDoorValues(); } else if (IS_ENVELOPE(element)) { @@ -13818,7 +13877,7 @@ static int DigField(struct PlayerInfo *player, RedrawAllInvisibleElementsForMagnifier(); } else if (IS_DROPPABLE(element) || - IS_THROWABLE(element)) /* can be collected and dropped */ + IS_THROWABLE(element)) // can be collected and dropped { int i; @@ -13833,13 +13892,13 @@ static int DigField(struct PlayerInfo *player, } else if (collect_count > 0) { - local_player->gems_still_needed -= collect_count; - if (local_player->gems_still_needed < 0) - local_player->gems_still_needed = 0; + game.gems_still_needed -= collect_count; + if (game.gems_still_needed < 0) + game.gems_still_needed = 0; game.snapshot.collected_item = TRUE; - game_panel_controls[GAME_PANEL_GEMS].value = local_player->gems_still_needed; + game_panel_controls[GAME_PANEL_GEMS].value = game.gems_still_needed; DisplayGameControlValues(); } @@ -13856,7 +13915,7 @@ static int DigField(struct PlayerInfo *player, if (level.block_snap_field) setFieldForSnapping(x, y, element, move_direction); else - TestIfElementTouchesCustomElement(x, y); /* for empty space */ + TestIfElementTouchesCustomElement(x, y); // for empty space CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X, player->index_bit, dig_side); @@ -13887,7 +13946,7 @@ static int DigField(struct PlayerInfo *player, IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1)))))) return MP_NO_ACTION; - /* do not push elements already moving away faster than player */ + // do not push elements already moving away faster than player if (CAN_MOVE(element) && MovDir[x][y] == move_direction && ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL) return MP_NO_ACTION; @@ -13922,14 +13981,14 @@ static int DigField(struct PlayerInfo *player, if (!checkDiagonalPushing(player, x, y, real_dx, real_dy)) return MP_NO_ACTION; - if (player->push_delay == -1) /* new pushing; restart delay */ + if (player->push_delay == -1) // new pushing; restart delay player->push_delay = 0; if (player->push_delay < player->push_delay_value && !(tape.playing && tape.file_version < FILE_VERSION_2_0) && element != EL_SPRING && element != EL_BALLOON) { - /* make sure that there is no move delay before next try to push */ + // make sure that there is no move delay before next try to push if (game.engine_version >= VERSION_IDENT(3,0,7,1)) player->move_delay = 0; @@ -13945,16 +14004,26 @@ static int DigField(struct PlayerInfo *player, if (IS_SB_ELEMENT(element)) { + boolean sokoban_task_solved = FALSE; + if (element == EL_SOKOBAN_FIELD_FULL) { Back[x][y] = EL_SOKOBAN_FIELD_EMPTY; - local_player->sokobanfields_still_needed++; + + IncrementSokobanFieldsNeeded(); + IncrementSokobanObjectsNeeded(); } if (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY) { Back[nextx][nexty] = EL_SOKOBAN_FIELD_EMPTY; - local_player->sokobanfields_still_needed--; + + DecrementSokobanFieldsNeeded(); + DecrementSokobanObjectsNeeded(); + + // sokoban object was pushed from empty field to sokoban field + if (Back[x][y] == EL_EMPTY) + sokoban_task_solved = TRUE; } Feld[x][y] = EL_SOKOBAN_OBJECT; @@ -13968,12 +14037,14 @@ static int DigField(struct PlayerInfo *player, PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY, ACTION_FILLING); - if (local_player->sokobanfields_still_needed == 0 && + if (sokoban_task_solved && + game.sokoban_fields_still_needed == 0 && + game.sokoban_objects_still_needed == 0 && (game.emulation == EMU_SOKOBAN || level.auto_exit_sokoban)) { - local_player->players_still_needed = 0; + game.players_still_needed = 0; - PlayerWins(player); + LevelSolved(); PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING); } @@ -13995,9 +14066,9 @@ static int DigField(struct PlayerInfo *player, if (game.engine_version < VERSION_IDENT(2,2,0,7)) player->push_delay_value = GET_NEW_PUSH_DELAY(element); else - player->push_delay_value = -1; /* get new value later */ + player->push_delay_value = -1; // get new value later - /* check for element change _after_ element has been pushed */ + // check for element change _after_ element has been pushed if (game.use_change_when_pushing_bug) { CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER, @@ -14025,9 +14096,9 @@ static int DigField(struct PlayerInfo *player, if (element == EL_ROBOT_WHEEL) { Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE; - ZX = x; - ZY = y; + game.robot_wheel_x = x; + game.robot_wheel_y = y; game.robot_wheel_active = TRUE; TEST_DrawLevelField(x, y); @@ -14089,7 +14160,7 @@ static int DigField(struct PlayerInfo *player, else if (element == EL_LAMP) { Feld[x][y] = EL_LAMP_ACTIVE; - local_player->lights_still_needed--; + game.lights_still_needed--; ResetGfxAnimation(x, y); TEST_DrawLevelField(x, y); @@ -14179,9 +14250,9 @@ static int DigField(struct PlayerInfo *player, player->push_delay = -1; - if (is_player) /* function can also be called by EL_PENGUIN */ + if (is_player) // function can also be called by EL_PENGUIN { - if (Feld[x][y] != element) /* really digged/collected something */ + if (Feld[x][y] != element) // really digged/collected something { player->is_collecting = !player->is_digging; player->is_active = TRUE; @@ -14201,7 +14272,7 @@ static boolean DigFieldByCE(int x, int y, int digging_element) IS_COLLECTIBLE(element) ? ACTION_COLLECTING : ACTION_BREAKING); - /* no element can dig solid indestructible elements */ + // no element can dig solid indestructible elements if (IS_INDESTRUCTIBLE(element) && !IS_DIGGABLE(element) && !IS_COLLECTIBLE(element)) @@ -14224,7 +14295,7 @@ static boolean DigFieldByCE(int x, int y, int digging_element) TEST_DrawLevelField(x, y); } - /* if digged element was about to explode, prevent the explosion */ + // if digged element was about to explode, prevent the explosion ExplodeField[x][y] = EX_TYPE_NONE; PlayLevelSoundAction(x, y, action); @@ -14232,7 +14303,7 @@ static boolean DigFieldByCE(int x, int y, int digging_element) Store[x][y] = EL_EMPTY; - /* this makes it possible to leave the removed element again */ + // this makes it possible to leave the removed element again if (IS_EQUAL_OR_IN_GROUP(element, MOVE_ENTER_EL(digging_element))) Store[x][y] = element; @@ -14276,7 +14347,7 @@ static boolean SnapField(struct PlayerInfo *player, int dx, int dy) return FALSE; } - /* prevent snapping with already pressed snap key when not allowed */ + // prevent snapping with already pressed snap key when not allowed if (player->is_snapping && !can_continue_snapping) return FALSE; @@ -14306,7 +14377,7 @@ static boolean SnapField(struct PlayerInfo *player, int dx, int dy) player->is_collecting = FALSE; } - if (player->MovPos != 0) /* prevent graphic bugs in versions < 2.2.0 */ + if (player->MovPos != 0) // prevent graphic bugs in versions < 2.2.0 TEST_DrawLevelField(player->last_jx, player->last_jy); TEST_DrawLevelField(x, y); @@ -14338,34 +14409,34 @@ static boolean DropElement(struct PlayerInfo *player) return FALSE; } - old_element = Feld[dropx][dropy]; /* old element at dropping position */ - new_element = drop_element; /* default: no change when dropping */ + old_element = Feld[dropx][dropy]; // old element at dropping position + new_element = drop_element; // default: no change when dropping - /* check if player is active, not moving and ready to drop */ + // check if player is active, not moving and ready to drop if (!player->active || player->MovPos || player->drop_delay > 0) return FALSE; - /* check if player has anything that can be dropped */ + // check if player has anything that can be dropped if (new_element == EL_UNDEFINED) return FALSE; - /* only set if player has anything that can be dropped */ + // only set if player has anything that can be dropped player->is_dropping_pressed = TRUE; - /* check if drop key was pressed long enough for EM style dynamite */ + // check if drop key was pressed long enough for EM style dynamite if (new_element == EL_EM_DYNAMITE && player->drop_pressed_delay < 40) return FALSE; - /* check if anything can be dropped at the current position */ + // check if anything can be dropped at the current position if (IS_ACTIVE_BOMB(old_element) || old_element == EL_EXPLOSION) return FALSE; - /* collected custom elements can only be dropped on empty fields */ + // collected custom elements can only be dropped on empty fields if (IS_CUSTOM_ELEMENT(new_element) && old_element != EL_EMPTY) return FALSE; if (old_element != EL_EMPTY) - Back[dropx][dropy] = old_element; /* store old element on this field */ + Back[dropx][dropy] = old_element; // store old element on this field ResetGfxAnimation(dropx, dropy); ResetRandomAnimationValue(dropx, dropy); @@ -14395,8 +14466,8 @@ static boolean DropElement(struct PlayerInfo *player) PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING); - /* needed if previous element just changed to "empty" in the last frame */ - ChangeCount[dropx][dropy] = 0; /* allow at least one more change */ + // needed if previous element just changed to "empty" in the last frame + ChangeCount[dropx][dropy] = 0; // allow at least one more change CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER, player->index_bit, drop_side); @@ -14406,7 +14477,7 @@ static boolean DropElement(struct PlayerInfo *player) TestIfElementTouchesCustomElement(dropx, dropy); } - else /* player is dropping a dyna bomb */ + else // player is dropping a dyna bomb { player->dynabombs_left--; @@ -14419,10 +14490,10 @@ static boolean DropElement(struct PlayerInfo *player) PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING); } - if (Feld[dropx][dropy] == new_element) /* uninitialized unless CE change */ + if (Feld[dropx][dropy] == new_element) // uninitialized unless CE change InitField_WithBug1(dropx, dropy, FALSE); - new_element = Feld[dropx][dropy]; /* element might have changed */ + new_element = Feld[dropx][dropy]; // element might have changed if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) && element_info[new_element].move_pattern == MV_WHEN_DROPPED) @@ -14430,9 +14501,9 @@ static boolean DropElement(struct PlayerInfo *player) if (element_info[new_element].move_direction_initial == MV_START_AUTOMATIC) MovDir[dropx][dropy] = drop_direction; - ChangeCount[dropx][dropy] = 0; /* allow at least one more change */ + ChangeCount[dropx][dropy] = 0; // allow at least one more change - /* do not cause impact style collision by dropping elements that can fall */ + // do not cause impact style collision by dropping elements that can fall CheckCollision[dropx][dropy] = CHECK_DELAY_COLLISION; } @@ -14448,14 +14519,14 @@ static boolean DropElement(struct PlayerInfo *player) return TRUE; } -/* ------------------------------------------------------------------------- */ -/* game sound playing functions */ -/* ------------------------------------------------------------------------- */ +// ---------------------------------------------------------------------------- +// game sound playing functions +// ---------------------------------------------------------------------------- static int *loop_sound_frame = NULL; static int *loop_sound_volume = NULL; -void InitPlayLevelSound() +void InitPlayLevelSound(void) { int num_sounds = getSoundListSize(); @@ -14558,20 +14629,20 @@ static void StopLevelSoundActionIfLoop(int x, int y, int action) StopSound(sound_effect); } -static int getLevelMusicNr() +static int getLevelMusicNr(void) { if (levelset.music[level_nr] != MUS_UNDEFINED) - return levelset.music[level_nr]; /* from config file */ + return levelset.music[level_nr]; // from config file else - return MAP_NOCONF_MUSIC(level_nr); /* from music dir */ + return MAP_NOCONF_MUSIC(level_nr); // from music dir } -static void FadeLevelSounds() +static void FadeLevelSounds(void) { FadeSounds(); } -static void FadeLevelMusic() +static void FadeLevelMusic(void) { int music_nr = getLevelMusicNr(); char *curr_music = getCurrentlyPlayingMusicFilename(); @@ -14581,20 +14652,20 @@ static void FadeLevelMusic() FadeMusic(); } -void FadeLevelSoundsAndMusic() +void FadeLevelSoundsAndMusic(void) { FadeLevelSounds(); FadeLevelMusic(); } -static void PlayLevelMusic() +static void PlayLevelMusic(void) { int music_nr = getLevelMusicNr(); char *curr_music = getCurrentlyPlayingMusicFilename(); char *next_music = getMusicInfoEntryFilename(music_nr); if (!strEqual(curr_music, next_music)) - PlayMusic(music_nr); + PlayMusicLoop(music_nr); } void PlayLevelSound_EM(int xx, int yy, int element_em, int sample) @@ -14671,7 +14742,7 @@ void PlayLevelSound_EM(int xx, int yy, int element_em, int sample) break; case SAMPLE_squash: - /* !!! CHECK THIS !!! */ + // !!! CHECK THIS !!! #if 1 PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING); #else @@ -14814,9 +14885,9 @@ void StopSound_MM(int sound_mm) void RaiseScore(int value) { - local_player->score += value; + game.score += value; - game_panel_controls[GAME_PANEL_SCORE].value = local_player->score; + game_panel_controls[GAME_PANEL_SCORE].value = game.score; DisplayGameControlValues(); } @@ -14905,9 +14976,14 @@ void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message) { if (skip_request || Request(message, REQ_ASK | REQ_STAY_CLOSED)) { - /* closing door required in case of envelope style request dialogs */ + // closing door required in case of envelope style request dialogs if (!skip_request) + { + // prevent short reactivation of overlay buttons while closing door + SetOverlayActive(FALSE); + CloseDoor(DOOR_CLOSE_1); + } if (network.enabled) SendToServer_StopPlaying(NETWORK_STOP_BY_PLAYER); @@ -14921,7 +14997,7 @@ void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message) DrawMainMenu(); } } - else /* continue playing the game */ + else // continue playing the game { if (tape.playing && tape.deactivate_display) TapeDeactivateDisplayOff(TRUE); @@ -14936,7 +15012,7 @@ void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message) void RequestQuitGame(boolean ask_if_really_quit) { boolean quick_quit = (!ask_if_really_quit || level_editor_test_game); - boolean skip_request = AllPlayersGone || quick_quit; + boolean skip_request = game.all_players_gone || quick_quit; RequestQuitGameExt(skip_request, quick_quit, "Do you really want to quit the game?"); @@ -14946,7 +15022,10 @@ void RequestRestartGame(char *message) { game.restart_game_message = NULL; - if (Request(message, REQ_ASK | REQ_STAY_CLOSED)) + boolean has_started_game = hasStartedNetworkGame(); + int request_mode = (has_started_game ? REQ_ASK : REQ_CONFIRM); + + if (Request(message, request_mode | REQ_STAY_CLOSED) && has_started_game) { StartGameActions(network.enabled, setup.autorecord, level.random_seed); } @@ -14958,10 +15037,71 @@ void RequestRestartGame(char *message) } } +void CheckGameOver(void) +{ + static boolean last_game_over = FALSE; + static int game_over_delay = 0; + int game_over_delay_value = 50; + boolean game_over = checkGameFailed(); + + // do not handle game over if request dialog is already active + if (game.request_active) + return; + + // do not ask to play again if game was never actually played + if (!game.GamePlayed) + return; + + if (!game_over) + { + last_game_over = FALSE; + game_over_delay = game_over_delay_value; + + return; + } + + if (game_over_delay > 0) + { + game_over_delay--; + + return; + } + + if (last_game_over != game_over) + game.restart_game_message = (hasStartedNetworkGame() ? + "Game over! Play it again?" : + "Game over!"); + + last_game_over = game_over; +} + +boolean checkGameSolved(void) +{ + // set for all game engines if level was solved + return game.LevelSolved_GameEnd; +} -/* ------------------------------------------------------------------------- */ -/* random generator functions */ -/* ------------------------------------------------------------------------- */ +boolean checkGameFailed(void) +{ + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + return (game_em.game_over && !game_em.level_solved); + else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + return (game_sp.game_over && !game_sp.level_solved); + else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + return (game_mm.game_over && !game_mm.level_solved); + else // GAME_ENGINE_TYPE_RND + return (game.GameOver && !game.LevelSolved); +} + +boolean checkGameEnded(void) +{ + return (checkGameSolved() || checkGameFailed()); +} + + +// ---------------------------------------------------------------------------- +// random generator functions +// ---------------------------------------------------------------------------- unsigned int InitEngineRandom_RND(int seed) { @@ -14983,19 +15123,19 @@ unsigned int RND(int max) } -/* ------------------------------------------------------------------------- */ -/* game engine snapshot handling functions */ -/* ------------------------------------------------------------------------- */ +// ---------------------------------------------------------------------------- +// game engine snapshot handling functions +// ---------------------------------------------------------------------------- struct EngineSnapshotInfo { - /* runtime values for custom element collect score */ + // runtime values for custom element collect score int collect_score[NUM_CUSTOM_ELEMENTS]; - /* runtime values for group element choice position */ + // runtime values for group element choice position int choice_pos[NUM_GROUP_ELEMENTS]; - /* runtime values for belt position animations */ + // runtime values for belt position animations int belt_graphic[4][NUM_BELT_PARTS]; int belt_anim_mode[4][NUM_BELT_PARTS]; }; @@ -15004,7 +15144,7 @@ static struct EngineSnapshotInfo engine_snapshot_rnd; static char *snapshot_level_identifier = NULL; static int snapshot_level_nr = -1; -static void SaveEngineSnapshotValues_RND() +static void SaveEngineSnapshotValues_RND(void) { static int belt_base_active_element[4] = { @@ -15043,7 +15183,7 @@ static void SaveEngineSnapshotValues_RND() } } -static void LoadEngineSnapshotValues_RND() +static void LoadEngineSnapshotValues_RND(void) { unsigned int num_random_calls = game.num_random_calls; int i, j; @@ -15089,7 +15229,7 @@ static void LoadEngineSnapshotValues_RND() } } -void FreeEngineSnapshotSingle() +void FreeEngineSnapshotSingle(void) { FreeSnapshotSingle(); @@ -15097,16 +15237,16 @@ void FreeEngineSnapshotSingle() snapshot_level_nr = -1; } -void FreeEngineSnapshotList() +void FreeEngineSnapshotList(void) { FreeSnapshotList(); } -ListNode *SaveEngineSnapshotBuffers() +static ListNode *SaveEngineSnapshotBuffers(void) { ListNode *buffers = NULL; - /* copy some special values to a structure better suited for the snapshot */ + // copy some special values to a structure better suited for the snapshot if (level.game_engine_type == GAME_ENGINE_TYPE_RND) SaveEngineSnapshotValues_RND(); @@ -15117,7 +15257,7 @@ ListNode *SaveEngineSnapshotBuffers() if (level.game_engine_type == GAME_ENGINE_TYPE_MM) SaveEngineSnapshotValues_MM(&buffers); - /* save values stored in special snapshot structure */ + // save values stored in special snapshot structure if (level.game_engine_type == GAME_ENGINE_TYPE_RND) SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_rnd)); @@ -15128,17 +15268,12 @@ ListNode *SaveEngineSnapshotBuffers() if (level.game_engine_type == GAME_ENGINE_TYPE_MM) SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(engine_snapshot_mm)); - /* save further RND engine values */ + // save further RND engine values SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(stored_player)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(game)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(tape)); - SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ZX)); - SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ZY)); - SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExitX)); - SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ExitY)); - SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(FrameCounter)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeFrames)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimePlayed)); @@ -15151,8 +15286,6 @@ ListNode *SaveEngineSnapshotBuffers() SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScrollStepSize)); - SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AllPlayersGone)); - SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt)); SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt2)); @@ -15211,19 +15344,19 @@ ListNode *SaveEngineSnapshotBuffers() return buffers; } -void SaveEngineSnapshotSingle() +void SaveEngineSnapshotSingle(void) { ListNode *buffers = SaveEngineSnapshotBuffers(); - /* finally save all snapshot buffers to single snapshot */ + // finally save all snapshot buffers to single snapshot SaveSnapshotSingle(buffers); - /* save level identification information */ + // save level identification information setString(&snapshot_level_identifier, leveldir_current->identifier); snapshot_level_nr = level_nr; } -boolean CheckSaveEngineSnapshotToList() +boolean CheckSaveEngineSnapshotToList(void) { boolean save_snapshot = ((game.snapshot.mode == SNAPSHOT_MODE_EVERY_STEP) || @@ -15239,7 +15372,7 @@ boolean CheckSaveEngineSnapshotToList() return save_snapshot; } -void SaveEngineSnapshotToList() +void SaveEngineSnapshotToList(void) { if (game.snapshot.mode == SNAPSHOT_MODE_OFF || tape.quick_resume) @@ -15247,20 +15380,20 @@ void SaveEngineSnapshotToList() ListNode *buffers = SaveEngineSnapshotBuffers(); - /* finally save all snapshot buffers to snapshot list */ + // finally save all snapshot buffers to snapshot list SaveSnapshotToList(buffers); } -void SaveEngineSnapshotToListInitial() +void SaveEngineSnapshotToListInitial(void) { FreeEngineSnapshotList(); SaveEngineSnapshotToList(); } -void LoadEngineSnapshotValues() +static void LoadEngineSnapshotValues(void) { - /* restore special values from snapshot structure */ + // restore special values from snapshot structure if (level.game_engine_type == GAME_ENGINE_TYPE_RND) LoadEngineSnapshotValues_RND(); @@ -15272,40 +15405,40 @@ void LoadEngineSnapshotValues() LoadEngineSnapshotValues_MM(); } -void LoadEngineSnapshotSingle() +void LoadEngineSnapshotSingle(void) { LoadSnapshotSingle(); LoadEngineSnapshotValues(); } -void LoadEngineSnapshot_Undo(int steps) +static void LoadEngineSnapshot_Undo(int steps) { LoadSnapshotFromList_Older(steps); LoadEngineSnapshotValues(); } -void LoadEngineSnapshot_Redo(int steps) +static void LoadEngineSnapshot_Redo(int steps) { LoadSnapshotFromList_Newer(steps); LoadEngineSnapshotValues(); } -boolean CheckEngineSnapshotSingle() +boolean CheckEngineSnapshotSingle(void) { return (strEqual(snapshot_level_identifier, leveldir_current->identifier) && snapshot_level_nr == level_nr); } -boolean CheckEngineSnapshotList() +boolean CheckEngineSnapshotList(void) { return CheckSnapshotList(); } -/* ---------- new game button stuff ---------------------------------------- */ +// ---------- new game button stuff ------------------------------------------- static struct { @@ -15404,7 +15537,7 @@ static struct } }; -void CreateGameButtons() +void CreateGameButtons(void) { int i; @@ -15490,7 +15623,7 @@ void CreateGameButtons() } } -void FreeGameButtons() +void FreeGameButtons(void) { int i; @@ -15509,7 +15642,7 @@ static void UnmapGameButtonsAtSamePosition(int id) UnmapGadget(game_gadget[i]); } -static void UnmapGameButtonsAtSamePosition_All() +static void UnmapGameButtonsAtSamePosition_All(void) { if (setup.show_snapshot_buttons) { @@ -15542,7 +15675,7 @@ static void MapGameButtonsAtSamePosition(int id) UnmapGameButtonsAtSamePosition_All(); } -void MapUndoRedoButtons() +void MapUndoRedoButtons(void) { UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO); @@ -15553,7 +15686,7 @@ void MapUndoRedoButtons() ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, TRUE, GDI_END); } -void UnmapUndoRedoButtons() +void UnmapUndoRedoButtons(void) { UnmapGadget(game_gadget[GAME_CTRL_ID_UNDO]); UnmapGadget(game_gadget[GAME_CTRL_ID_REDO]); @@ -15564,7 +15697,7 @@ void UnmapUndoRedoButtons() ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, FALSE, GDI_END); } -void MapGameButtonsExt(boolean on_tape) +static void MapGameButtonsExt(boolean on_tape) { int i; @@ -15579,7 +15712,7 @@ void MapGameButtonsExt(boolean on_tape) RedrawGameButtons(); } -void UnmapGameButtonsExt(boolean on_tape) +static void UnmapGameButtonsExt(boolean on_tape) { int i; @@ -15588,7 +15721,7 @@ void UnmapGameButtonsExt(boolean on_tape) UnmapGadget(game_gadget[i]); } -void RedrawGameButtonsExt(boolean on_tape) +static void RedrawGameButtonsExt(boolean on_tape) { int i; @@ -15600,7 +15733,7 @@ void RedrawGameButtonsExt(boolean on_tape) redraw_mask &= ~REDRAW_ALL; } -void SetGadgetState(struct GadgetInfo *gi, boolean state) +static void SetGadgetState(struct GadgetInfo *gi, boolean state) { if (gi == NULL) return; @@ -15608,7 +15741,7 @@ void SetGadgetState(struct GadgetInfo *gi, boolean state) gi->checked = state; } -void RedrawSoundButtonGadget(int id) +static void RedrawSoundButtonGadget(int id) { int id2 = (id == SOUND_CTRL_ID_MUSIC ? SOUND_CTRL_ID_PANEL_MUSIC : id == SOUND_CTRL_ID_LOOPS ? SOUND_CTRL_ID_PANEL_LOOPS : @@ -15622,37 +15755,37 @@ void RedrawSoundButtonGadget(int id) RedrawGadget(game_gadget[id2]); } -void MapGameButtons() +void MapGameButtons(void) { MapGameButtonsExt(FALSE); } -void UnmapGameButtons() +void UnmapGameButtons(void) { UnmapGameButtonsExt(FALSE); } -void RedrawGameButtons() +void RedrawGameButtons(void) { RedrawGameButtonsExt(FALSE); } -void MapGameButtonsOnTape() +void MapGameButtonsOnTape(void) { MapGameButtonsExt(TRUE); } -void UnmapGameButtonsOnTape() +void UnmapGameButtonsOnTape(void) { UnmapGameButtonsExt(TRUE); } -void RedrawGameButtonsOnTape() +void RedrawGameButtonsOnTape(void) { RedrawGameButtonsExt(TRUE); } -void GameUndoRedoExt() +static void GameUndoRedoExt(void) { ClearPlayerAction(); @@ -15669,7 +15802,7 @@ void GameUndoRedoExt() BackToFront(); } -void GameUndo(int steps) +static void GameUndo(int steps) { if (!CheckEngineSnapshotList()) return; @@ -15679,7 +15812,7 @@ void GameUndo(int steps) GameUndoRedoExt(); } -void GameRedo(int steps) +static void GameRedo(int steps) { if (!CheckEngineSnapshotList()) return;