X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame.c;h=410fec92a79180a7c5b014b1c95e375750c3c171;hp=1bfe0100d1084c4214ad9cbaff4026f1456bf450;hb=820c0cf7d64247d3f75f9cb10d214cbf988557fe;hpb=7e68d10c8f4c814e532cc30f6fc721c269a99cb6 diff --git a/src/game.c b/src/game.c index 1bfe0100..410fec92 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) @@ -1002,7 +1002,9 @@ static struct GamePanelControlInfo game_panel_controls[] = #define IS_PASSABLE_FROM(e, d) (IS_PASSABLE(e) && ACCESS_FROM(e, d)) #define IS_ACCESSIBLE_FROM(e, d) (IS_ACCESSIBLE(e) && ACCESS_FROM(e, d)) -/* game button identifiers */ +#define MM_HEALTH(x) (MIN(MAX(0, MAX_HEALTH - (x)), MAX_HEALTH)) + +// game button identifiers #define GAME_CTRL_ID_STOP 0 #define GAME_CTRL_ID_PAUSE 1 #define GAME_CTRL_ID_PLAY 2 @@ -1011,14 +1013,20 @@ static struct GamePanelControlInfo game_panel_controls[] = #define GAME_CTRL_ID_SAVE 5 #define GAME_CTRL_ID_PAUSE2 6 #define GAME_CTRL_ID_LOAD 7 -#define SOUND_CTRL_ID_MUSIC 8 -#define SOUND_CTRL_ID_LOOPS 9 -#define SOUND_CTRL_ID_SIMPLE 10 +#define GAME_CTRL_ID_PANEL_STOP 8 +#define GAME_CTRL_ID_PANEL_PAUSE 9 +#define GAME_CTRL_ID_PANEL_PLAY 10 +#define SOUND_CTRL_ID_MUSIC 11 +#define SOUND_CTRL_ID_LOOPS 12 +#define SOUND_CTRL_ID_SIMPLE 13 +#define SOUND_CTRL_ID_PANEL_MUSIC 14 +#define SOUND_CTRL_ID_PANEL_LOOPS 15 +#define SOUND_CTRL_ID_PANEL_SIMPLE 16 -#define NUM_GAME_BUTTONS 11 +#define NUM_GAME_BUTTONS 17 -/* forward declaration for internal use */ +// forward declaration for internal use static void CreateField(int, int, int); @@ -1077,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 *); @@ -1088,7 +1096,7 @@ void ContinueMoving(int, int); void Bang(int, int); void InitMovDir(int, int); void InitAmoebaNr(int, int); -int NewHiScore(void); +int NewHiScore(int); void TestIfGoodThingHitsBadThing(int, int, int); void TestIfBadThingHitsGoodThing(int, int, int); @@ -1104,14 +1112,15 @@ void TestIfGoodThingGetsHitByBadThing(int, int, int); void KillPlayer(struct PlayerInfo *); void BuryPlayer(struct PlayerInfo *); void RemovePlayer(struct PlayerInfo *); +void ExitPlayer(struct PlayerInfo *); static int getInvisibleActiveFromInvisibleElement(int); 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) \ @@ -1140,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); @@ -1539,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; @@ -1553,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; @@ -1564,7 +1573,7 @@ void DEBUG_SetMaximumDynamite() } #endif -static void InitPlayfieldScanModeVars() +static void InitPlayfieldScanModeVars(void) { if (game.use_reverse_scan_direction) { @@ -1597,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; @@ -1610,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) @@ -1627,7 +1636,7 @@ static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize, } } -void GetPlayerConfig() +void GetPlayerConfig(void) { GameFrameDelay = setup.game_frame_delay; @@ -1674,6 +1683,30 @@ int GetElementFromGroupElement(int element) return element; } +static void IncrementPlayerSokobanFieldsNeeded(void) +{ + if (level.sb_fields_needed) + local_player->sokoban_fields_still_needed++; +} + +static void IncrementPlayerSokobanObjectsNeeded(void) +{ + if (level.sb_objects_needed) + local_player->sokoban_objects_still_needed++; +} + +static void DecrementPlayerSokobanFieldsNeeded(void) +{ + if (local_player->sokoban_fields_still_needed > 0) + local_player->sokoban_fields_still_needed--; +} + +static void DecrementPlayerSokobanObjectsNeeded(void) +{ + if (local_player->sokoban_objects_still_needed > 0) + local_player->sokoban_objects_still_needed--; +} + static void InitPlayerField(int x, int y, int element, boolean init_game) { if (element == EL_SP_MURPHY) @@ -1710,24 +1743,24 @@ 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); - if (!options.network || player->connected) + if (!network.enabled || player->connected_network) { player->active = TRUE; - /* remove potentially duplicate players */ + // remove potentially duplicate players if (StorePlayer[jx][jy] == Feld[x][y]) StorePlayer[jx][jy] = 0; @@ -1756,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 } } @@ -1783,7 +1816,11 @@ static void InitField(int x, int y, boolean init_game) break; case EL_SOKOBAN_FIELD_EMPTY: - local_player->sokobanfields_still_needed++; + IncrementPlayerSokobanFieldsNeeded(); + break; + + case EL_SOKOBAN_OBJECT: + IncrementPlayerSokobanObjectsNeeded(); break; case EL_STONEBLOCK: @@ -1898,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]; } @@ -1957,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; @@ -1984,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)) @@ -2037,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) { @@ -2094,7 +2131,7 @@ int getPlayerInventorySize(int player_nr) return stored_player[player_nr].inventory_size; } -void InitGameControlValues() +static void InitGameControlValues(void) { int i; @@ -2112,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); @@ -2129,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; @@ -2167,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 ? @@ -2179,8 +2216,8 @@ 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 ? @@ -2203,16 +2240,21 @@ void UpdateGameControlValues() 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->sokoban_fields_still_needed > 0 || + local_player->sokoban_objects_still_needed > 0 || local_player->lights_still_needed > 0); - int health = (level.game_engine_type == GAME_ENGINE_TYPE_MM ? - MIN(MAX(0, 100 - game_mm.laser_overload_value), 100) : 100); + 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); UpdatePlayfieldElementCount(); - /* update game panel control values */ + // update game panel control values - game_panel_controls[GAME_PANEL_LEVEL_NUMBER].value = level_nr; + // 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; game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value = 0; @@ -2225,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; @@ -2297,7 +2339,7 @@ void UpdateGameControlValues() game_panel_controls[GAME_PANEL_TIME_MM].value = (time / 60) % 60; game_panel_controls[GAME_PANEL_TIME_SS].value = time % 60; - if (game.no_time_limit) + if (level.time == 0) game_panel_controls[GAME_PANEL_TIME_ANIM].value = 100; else game_panel_controls[GAME_PANEL_TIME_ANIM].value = time * 100 / level.time; @@ -2368,9 +2410,9 @@ void UpdateGameControlValues() local_player->friends_still_needed; game_panel_controls[GAME_PANEL_SOKOBAN_OBJECTS].value = - local_player->sokobanfields_still_needed; + local_player->sokoban_objects_still_needed; game_panel_controls[GAME_PANEL_SOKOBAN_FIELDS].value = - local_player->sokobanfields_still_needed; + local_player->sokoban_fields_still_needed; game_panel_controls[GAME_PANEL_ROBOT_WHEEL].value = (game.robot_wheel_active ? EL_ROBOT_WHEEL_ACTIVE : EL_ROBOT_WHEEL); @@ -2420,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++) { @@ -2494,7 +2536,7 @@ void UpdateGameControlValues() } } -void DisplayGameControlValues() +static void DisplayGameControlValues(void) { boolean redraw_panel = FALSE; int i; @@ -2516,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); @@ -2554,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); @@ -2567,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), @@ -2711,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); } @@ -2723,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); } @@ -2745,7 +2787,7 @@ void DisplayGameControlValues() SetGameStatus(GAME_MODE_PLAYING); } -void UpdateAndDisplayGameControlValues() +void UpdateAndDisplayGameControlValues(void) { if (tape.deactivate_display) return; @@ -2754,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) @@ -2792,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: @@ -2868,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 @@ -2887,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)) @@ -2933,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]; @@ -2955,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++) { @@ -2969,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]; @@ -2981,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; @@ -2993,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++) { @@ -3012,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++) { @@ -3029,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]; @@ -3073,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; @@ -3094,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; @@ -3103,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; @@ -3119,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; @@ -3134,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)) @@ -3173,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 : @@ -3198,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; @@ -3224,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; @@ -3254,23 +3297,51 @@ 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) +{ + int i; + + if (!options.debug) + return; + + printf("%s:\n", message); -void InitGame() + for (i = 0; i < MAX_PLAYERS; i++) + { + struct PlayerInfo *player = &stored_player[i]; + + printf("- player %d: present == %d, connected == %d [%d/%d], active == %d", + i + 1, + player->present, + player->connected, + player->connected_locally, + player->connected_network, + player->active); + + if (local_player == player) + printf(" (local player)"); + + printf("\n"); + } +} +#endif + +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; @@ -3287,7 +3358,7 @@ void InitGame() else FadeSetEnterScreen(); - if (CheckIfGlobalBorderHasChanged()) + if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) fade_mask = REDRAW_ALL; FadeLevelSoundsAndMusic(); @@ -3296,20 +3367,20 @@ void InitGame() FadeOut(fade_mask); - /* needed if different viewport properties defined for playing */ + // needed if different viewport properties defined for playing ChangeViewportPropertiesIfNeeded(); ClearField(); - OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); - DrawCompleteVideoDisplay(); + OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); + InitGameEngine(); InitGameControlValues(); - /* don't play tapes over network */ - network_playing = (options.network && !tape.playing); + // don't play tapes over network + network_playing = (network.enabled && !tape.playing); for (i = 0; i < MAX_PLAYERS; i++) { @@ -3333,13 +3404,24 @@ void InitGame() player->mouse_action.lx = 0; player->mouse_action.ly = 0; player->mouse_action.button = 0; + player->mouse_action.button_hint = 0; + + player->effective_mouse_action.lx = 0; + player->effective_mouse_action.ly = 0; + 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->sokoban_fields_still_needed = 0; + player->sokoban_objects_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++) @@ -3366,8 +3448,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]; @@ -3424,7 +3506,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; @@ -3464,27 +3546,16 @@ 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; - map_player_action[i] = i; } network_player_action_received = FALSE; -#if defined(NETWORK_AVALIABLE) - /* initial null action */ + // initial null action if (network_playing) SendToServer_MovePlayer(MV_NONE); -#endif ZX = ZY = -1; ExitX = ExitY = -1; @@ -3499,10 +3570,23 @@ void InitGame() ScreenMovPos = 0; ScreenGfxPos = 0; - ScrollStepSize = 0; /* will be correctly initialized by ScrollScreen() */ + ScrollStepSize = 0; // will be correctly initialized by ScrollScreen() AllPlayersGone = FALSE; + game.LevelSolved = FALSE; + + 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); game.yamyam_content_nr = 0; @@ -3520,43 +3604,30 @@ void InitGame() game.ball_state = level.ball_state_initial; game.ball_content_nr = 0; - game.envelope_active = FALSE; - - /* 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; + game.explosions_delayed = TRUE; - if (network_playing && tape.recording) - { - /* store client dependent player focus when recording network games */ - tape.centered_player_nr_next = game.centered_player_nr_next; - tape.set_centered_player = 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++) AmoebaCnt[i] = AmoebaCnt2[i] = 0; #if DEBUG_INIT_PLAYER - if (options.debug) - { - printf("Player status at level initialization:\n"); - } + DebugPrintPlayerStatus("Player status at level initialization"); #endif 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; @@ -3604,7 +3675,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); @@ -3617,25 +3688,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)) @@ -3655,59 +3726,51 @@ 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 - /* !!! SAME AS init.c:InitPlayerInfo() -- FIX THIS !!! */ - /* choose default local player */ - local_player = &stored_player[0]; - for (i = 0; i < MAX_PLAYERS; i++) + { stored_player[i].connected = FALSE; - local_player->connected = TRUE; - /* !!! SAME AS init.c:InitPlayerInfo() -- FIX THIS !!! */ + // in network game mode, the local player might not be the first player + if (stored_player[i].connected_locally) + local_player = &stored_player[i]; + } + + if (!network.enabled) + local_player->connected = TRUE; if (tape.playing) { for (i = 0; i < MAX_PLAYERS; i++) stored_player[i].connected = tape.player_participates[i]; } - else if (game.team_mode && !options.network) + else if (network.enabled) { - /* try to guess locally connected team mode players (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 (setup.input[i].use_joystick || - setup.input[i].key.left != KSYM_UNDEFINED) + if (stored_player[i].connected_network) stored_player[i].connected = TRUE; } - -#if DEBUG_INIT_PLAYER - if (options.debug) + else if (game.team_mode) { - printf("Player status after level initialization:\n"); + // 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++) - { - struct PlayerInfo *player = &stored_player[i]; - - printf("- player %d: present == %d, connected == %d, active == %d", - i + 1, - player->present, - player->connected, - player->active); - - if (local_player == player) - printf(" (local player)"); - - printf("\n"); - } + if (setup.input[i].use_joystick || + setup.input[i].key.left != KSYM_UNDEFINED) + stored_player[i].connected = TRUE; } + +#if DEBUG_INIT_PLAYER + DebugPrintPlayerStatus("Player status after level initialization"); #endif #if DEBUG_INIT_PLAYER @@ -3715,7 +3778,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]; @@ -3729,9 +3792,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 && @@ -3739,7 +3802,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 && @@ -3794,31 +3857,12 @@ void InitGame() } #if DEBUG_INIT_PLAYER - if (options.debug) - { - printf("Player status after player assignment (first stage):\n"); - - for (i = 0; i < MAX_PLAYERS; i++) - { - struct PlayerInfo *player = &stored_player[i]; - - printf("- player %d: present == %d, connected == %d, active == %d", - i + 1, - player->present, - player->connected, - player->active); - - if (local_player == player) - printf(" (local player)"); - - printf("\n"); - } - } + DebugPrintPlayerStatus("Player status after player assignment (first stage)"); #endif #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]; @@ -3830,7 +3874,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; @@ -3861,9 +3905,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 + 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 + 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 @@ -3906,33 +3962,35 @@ void InitGame() } #endif } - else if (!options.network && !game.team_mode) /* && !tape.playing */ + else if (!network.enabled && !game.team_mode) // && !tape.playing { - /* when in single player mode, eliminate all but the first active player */ + // when in single player mode, eliminate all but the local player for (i = 0; i < MAX_PLAYERS; i++) { - if (stored_player[i].active) + struct PlayerInfo *player = &stored_player[i]; + + if (player->active && player != local_player) { - for (j = i + 1; j < MAX_PLAYERS; j++) - { - if (stored_player[j].active) - { - struct PlayerInfo *player = &stored_player[j]; - int jx = player->jx, jy = player->jy; + int jx = player->jx, jy = player->jy; - player->active = FALSE; - player->present = FALSE; + player->active = FALSE; + player->present = FALSE; - StorePlayer[jx][jy] = 0; - Feld[jx][jy] = EL_EMPTY; - } - } + StorePlayer[jx][jy] = 0; + Feld[jx][jy] = EL_EMPTY; } } } - /* when recording the game, store which players take part in the game */ + for (i = 0; i < MAX_PLAYERS; i++) + if (stored_player[i].active) + local_player->players_still_needed++; + + if (level.solved_by_one_player) + local_player->players_still_needed = 1; + + // when recording the game, store which players take part in the game if (tape.recording) { #if USE_NEW_PLAYER_ASSIGNMENTS @@ -3947,26 +4005,7 @@ void InitGame() } #if DEBUG_INIT_PLAYER - if (options.debug) - { - printf("Player status after player assignment (final stage):\n"); - - for (i = 0; i < MAX_PLAYERS; i++) - { - struct PlayerInfo *player = &stored_player[i]; - - printf("- player %d: present == %d, connected == %d, active == %d", - i + 1, - player->present, - player->connected, - player->active); - - if (local_player == player) - printf(" (local player)"); - - printf("\n"); - } - } + DebugPrintPlayerStatus("Player status after player assignment (final stage)"); #endif if (BorderElement == EL_EMPTY) @@ -3994,8 +4033,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; @@ -4028,7 +4067,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); @@ -4046,7 +4085,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); @@ -4065,7 +4104,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]; @@ -4093,7 +4132,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(); @@ -4111,14 +4150,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); @@ -4134,9 +4173,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); @@ -4155,46 +4194,18 @@ void InitGame() FreeGameButtons(); CreateGameButtons(); - game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music; - game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops; - game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple; - 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); - PlaySound(SND_GAME_STARTING); - - if (setup.sound_music) - PlayLevelMusic(); - KeyboardAutoRepeatOffUnlessAutoplay(); #if DEBUG_INIT_PLAYER - if (options.debug) - { - printf("Player status (final):\n"); - - for (i = 0; i < MAX_PLAYERS; i++) - { - struct PlayerInfo *player = &stored_player[i]; - - printf("- player %d: present == %d, connected == %d, active == %d", - i + 1, - player->present, - player->connected, - player->active); - - if (local_player == player) - printf(" (local player)"); - - printf("\n"); - } - } + DebugPrintPlayerStatus("Player status (final)"); #endif } @@ -4211,17 +4222,27 @@ 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(); SaveEngineSnapshotToListInitial(); + + if (!game.restart_level) + { + PlaySound(SND_GAME_STARTING); + + if (setup.sound_music) + PlayLevelMusic(); + } } 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) { @@ -4229,11 +4250,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; } @@ -4356,7 +4377,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); @@ -4436,42 +4457,54 @@ void InitAmoebaNr(int x, int y) AmoebaCnt2[group_nr]++; } -static void PlayerWins(struct PlayerInfo *player) +static void LevelSolved(void) { - player->LevelSolved = TRUE; - player->GameOver = TRUE; + if (level.game_engine_type == GAME_ENGINE_TYPE_RND && + local_player->players_still_needed > 0) + return; + + game.LevelSolved = TRUE; + + local_player->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); + local_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 : + local_player->score); + local_player->health_final = (level.game_engine_type == GAME_ENGINE_TYPE_MM ? + MM_HEALTH(game_mm.laser_overload_value) : + local_player->health); - player->LevelSolved_CountingTime = (game.no_time_limit ? TimePlayed : - TimeLeft); - player->LevelSolved_CountingScore = player->score_final; + game.LevelSolved_CountingTime = (game.no_time_limit ? TimePlayed : TimeLeft); + game.LevelSolved_CountingScore = local_player->score_final; + game.LevelSolved_CountingHealth = local_player->health_final; } -void GameWon() +void GameWon(void) { + static int time_count_steps; static int time, time_final; static int score, score_final; + static int health, health_final; static int game_over_delay_1 = 0; static int game_over_delay_2 = 0; + static int game_over_delay_3 = 0; int game_over_delay_value_1 = 50; - int game_over_delay_value_2 = 50; + 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) */ + // do not start end game actions before the player stops moving (to exit) if (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) { @@ -4480,37 +4513,55 @@ 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(); - game_over_delay_1 = game_over_delay_value_1; - game_over_delay_2 = game_over_delay_value_2; + game_over_delay_1 = 0; + game_over_delay_2 = 0; + 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; - if (TimeLeft > 0) + if (level.score[SC_TIME_BONUS] > 0) { - time_final = 0; - score_final += TimeLeft * level.score[SC_TIME_BONUS]; - } - else if (game.no_time_limit && TimePlayed < 999) - { - time_final = 999; - score_final += (999 - TimePlayed) * level.score[SC_TIME_BONUS]; - } + if (TimeLeft > 0) + { + time_final = 0; + score_final += TimeLeft * level.score[SC_TIME_BONUS]; + } + else if (game.no_time_limit && TimePlayed < 999) + { + time_final = 999; + score_final += (999 - TimePlayed) * level.score[SC_TIME_BONUS]; + } + + time_count_steps = MAX(1, ABS(time_final - time) / 100); + + game_over_delay_1 = game_over_delay_value_1; - local_player->score_final = score_final; + if (level.game_engine_type == GAME_ENGINE_TYPE_MM) + { + health_final = 0; + score_final += health * level.score[SC_TIME_BONUS]; + + game_over_delay_2 = game_over_delay_value_2; + } + + local_player->score_final = score_final; + local_player->health_final = health_final; + } if (level_editor_test_game) { 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; @@ -4520,9 +4571,9 @@ void GameWon() if (level.game_engine_type == GAME_ENGINE_TYPE_RND) { - if (ExitX >= 0 && ExitY >= 0) /* local player has left the level */ + if (ExitX >= 0 && ExitY >= 0) // local player has left the level { - /* close exit door after last player */ + // close exit door after last player if ((AllPlayersGone && (Feld[ExitX][ExitY] == EL_EXIT_OPEN || Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN || @@ -4534,15 +4585,15 @@ void GameWon() Feld[ExitX][ExitY] = (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); } - /* player disappears */ + // player disappears DrawLevelField(ExitX, ExitY); } @@ -4554,7 +4605,7 @@ void GameWon() { RemovePlayer(player); - /* player disappears */ + // player disappears DrawLevelField(player->jx, player->jy); } } @@ -4574,13 +4625,15 @@ void GameWon() { int time_to_go = ABS(time_final - time); int time_count_dir = (time < time_final ? +1 : -1); - int time_count_steps = (time_to_go > 100 && time_to_go % 10 == 0 ? 10 : 1); + + if (time_to_go < time_count_steps) + time_count_steps = 1; 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; @@ -4597,8 +4650,6 @@ void GameWon() return; } - local_player->LevelSolved_PanelOff = TRUE; - if (game_over_delay_2 > 0) { game_over_delay_2--; @@ -4606,24 +4657,61 @@ void GameWon() return; } + if (health != health_final) + { + int health_count_dir = (health < health_final ? +1 : -1); + + health += health_count_dir; + score += level.score[SC_TIME_BONUS]; + + game.LevelSolved_CountingHealth = health; + game.LevelSolved_CountingScore = score; + + game_panel_controls[GAME_PANEL_HEALTH].value = health; + game_panel_controls[GAME_PANEL_SCORE].value = score; + + DisplayGameControlValues(); + + if (health == health_final) + StopSound(SND_GAME_LEVELTIME_BONUS); + else if (setup.sound_loops) + PlaySoundLoop(SND_GAME_LEVELTIME_BONUS); + else + PlaySound(SND_GAME_LEVELTIME_BONUS); + + return; + } + + game.panel.active = FALSE; + + if (game_over_delay_3 > 0) + { + game_over_delay_3--; + + return; + } + 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; - boolean raise_level = FALSE; - - local_player->LevelSolved_GameEnd = TRUE; - if (!global.use_envelope_request) - CloseDoor(DOOR_CLOSE_1); + game.LevelSolved_GameEnd = TRUE; - if (local_player->LevelSolved_SaveTape) + if (game.LevelSolved_SaveTape) { - SaveTapeChecked(tape.level_nr); /* ask to save tape */ + // 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 } + // if no tape is to be saved, close both doors simultaneously CloseDoor(DOOR_CLOSE_ALL); if (level_editor_test_game) @@ -4635,7 +4723,7 @@ void GameEnd() return; } - if (!local_player->LevelSolved_SaveScore) + if (!game.LevelSolved_SaveScore) { SetGameStatus(GAME_MODE_MAIN); @@ -4652,36 +4740,43 @@ void GameEnd() } if (setup.increment_levels && - level_nr < leveldir_current->last_level) - raise_level = TRUE; /* advance to next level */ - - if ((hi_pos = NewHiScore()) >= 0) + level_nr < leveldir_current->last_level && + !network_playing) { - SetGameStatus(GAME_MODE_SCORES); + level_nr++; // advance to next level + TapeErase(); // start with empty tape - DrawHallOfFame(hi_pos); - - if (raise_level) + if (setup.auto_play_next_level) { - level_nr++; - TapeErase(); + LoadLevel(level_nr); + + SaveLevelSetup_SeriesInfo(); } } + + hi_pos = NewHiScore(last_level_nr); + + if (hi_pos >= 0 && !setup.skip_scores_after_game) + { + SetGameStatus(GAME_MODE_SCORES); + + 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); + } else { SetGameStatus(GAME_MODE_MAIN); - if (raise_level) - { - level_nr++; - TapeErase(); - } - DrawMainMenu(); } } -int NewHiScore() +int NewHiScore(int level_nr) { int k, l; int position = -1; @@ -4697,7 +4792,7 @@ int NewHiScore() { if (local_player->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) { @@ -4709,7 +4804,7 @@ int NewHiScore() 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; } @@ -4732,7 +4827,7 @@ int NewHiScore() 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) @@ -4741,7 +4836,7 @@ int NewHiScore() 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); @@ -4750,7 +4845,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) && @@ -4763,7 +4858,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]); } @@ -4812,7 +4907,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); @@ -4821,13 +4916,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); @@ -4839,7 +4934,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) { @@ -4885,7 +4980,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]; @@ -4902,9 +4997,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)) @@ -4943,7 +5038,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]; @@ -4958,9 +5053,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); @@ -5024,9 +5119,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]--; @@ -5074,7 +5169,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; @@ -5094,8 +5189,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); @@ -5106,7 +5201,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(); @@ -5115,28 +5210,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; @@ -5146,9 +5241,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); @@ -5160,7 +5255,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; @@ -5172,10 +5267,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); } @@ -5185,7 +5280,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); @@ -5209,15 +5304,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->GameOver) // 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); } @@ -5235,8 +5330,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; } @@ -5257,12 +5352,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); @@ -5290,13 +5385,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) @@ -5305,26 +5400,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)) { @@ -5367,7 +5462,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) @@ -5376,7 +5471,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) || @@ -5387,7 +5482,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; } @@ -5395,12 +5490,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]; @@ -5425,8 +5520,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) @@ -5434,9 +5529,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 @@ -5473,13 +5568,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; @@ -5512,9 +5607,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; } @@ -5527,7 +5622,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) { @@ -5543,7 +5638,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; @@ -5593,7 +5688,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]; @@ -5631,7 +5726,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; @@ -5698,7 +5793,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; @@ -5718,7 +5813,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) || @@ -5733,7 +5828,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] = { @@ -5752,7 +5847,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; @@ -5844,7 +5939,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; @@ -5967,7 +6062,7 @@ static int getInvisibleFromInvisibleActiveElement(int element) element); } -static void RedrawAllLightSwitchesAndInvisibleElements() +static void RedrawAllLightSwitchesAndInvisibleElements(void) { int x, y; @@ -6008,7 +6103,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); } @@ -6021,14 +6116,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; @@ -6057,7 +6152,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); } @@ -6070,14 +6165,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; @@ -6170,7 +6265,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; @@ -6178,7 +6273,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; @@ -6187,7 +6282,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; @@ -6220,14 +6315,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)) { @@ -6272,7 +6367,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 || @@ -6286,7 +6381,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) @@ -6408,7 +6503,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 || @@ -6424,12 +6519,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 { @@ -6490,7 +6585,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) @@ -6504,7 +6599,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) @@ -6866,22 +6961,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 { @@ -6902,7 +6997,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; @@ -6916,7 +7011,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; @@ -6944,7 +7039,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; @@ -6971,17 +7066,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; @@ -7013,7 +7108,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) @@ -7131,7 +7226,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); @@ -7187,7 +7282,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; @@ -7217,14 +7312,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; } @@ -7274,9 +7369,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]) @@ -7603,7 +7698,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); @@ -7647,7 +7742,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)); @@ -7656,7 +7751,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; } @@ -7683,12 +7778,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; @@ -7707,14 +7802,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 && @@ -7737,7 +7832,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]--; @@ -7810,7 +7905,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); @@ -7818,9 +7913,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) && @@ -7857,7 +7952,7 @@ void StartMoving(int x, int y) local_player->friends_still_needed--; if (!local_player->friends_still_needed && !local_player->GameOver && AllPlayersGone) - PlayerWins(local_player); + LevelSolved(); return; } @@ -7911,7 +8006,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]) @@ -7922,7 +8017,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; } @@ -7936,7 +8031,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); @@ -7997,7 +8092,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)) @@ -8106,11 +8201,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); @@ -8121,16 +8216,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)) @@ -8164,23 +8259,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; } @@ -8283,7 +8378,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]; @@ -8299,22 +8394,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); @@ -8332,8 +8427,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 && @@ -8345,15 +8440,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; @@ -8375,7 +8470,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); @@ -8391,7 +8486,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) || @@ -8409,12 +8504,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); @@ -8453,7 +8548,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]; @@ -8560,7 +8655,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]; @@ -8596,12 +8691,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; @@ -8612,7 +8707,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))) @@ -8632,12 +8727,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; @@ -8645,7 +8740,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))) @@ -8661,14 +8756,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]; @@ -8693,17 +8788,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]; @@ -8724,7 +8819,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; @@ -8751,7 +8846,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)) { @@ -8759,7 +8854,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); @@ -8771,7 +8866,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]; @@ -8788,7 +8883,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) @@ -8802,18 +8897,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); @@ -8823,7 +8918,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; @@ -8839,10 +8934,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]) @@ -8852,7 +8947,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; @@ -8864,33 +8960,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; @@ -8944,7 +9055,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; @@ -8970,10 +9081,11 @@ 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->sokoban_fields_still_needed > 0 || + local_player->sokoban_objects_still_needed > 0 || local_player->lights_still_needed > 0) { int element = Feld[x][y]; @@ -8985,7 +9097,7 @@ void CheckExit(int x, int y) return; } - if (AllPlayersGone) /* do not re-open exit door closed after last player */ + if (AllPlayersGone) // do not re-open exit door closed after last player return; Feld[x][y] = EL_EXIT_OPENING; @@ -8993,10 +9105,11 @@ 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->sokoban_fields_still_needed > 0 || + local_player->sokoban_objects_still_needed > 0 || local_player->lights_still_needed > 0) { int element = Feld[x][y]; @@ -9008,7 +9121,7 @@ void CheckExitEM(int x, int y) return; } - if (AllPlayersGone) /* do not re-open exit door closed after last player */ + if (AllPlayersGone) // do not re-open exit door closed after last player return; Feld[x][y] = EL_EM_EXIT_OPENING; @@ -9016,10 +9129,11 @@ 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->sokoban_fields_still_needed > 0 || + local_player->sokoban_objects_still_needed > 0 || local_player->lights_still_needed > 0) { int element = Feld[x][y]; @@ -9031,7 +9145,7 @@ void CheckExitSteel(int x, int y) return; } - if (AllPlayersGone) /* do not re-open exit door closed after last player */ + if (AllPlayersGone) // do not re-open exit door closed after last player return; Feld[x][y] = EL_STEEL_EXIT_OPENING; @@ -9039,10 +9153,11 @@ 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->sokoban_fields_still_needed > 0 || + local_player->sokoban_objects_still_needed > 0 || local_player->lights_still_needed > 0) { int element = Feld[x][y]; @@ -9054,7 +9169,7 @@ void CheckExitSteelEM(int x, int y) return; } - if (AllPlayersGone) /* do not re-open exit door closed after last player */ + if (AllPlayersGone) // do not re-open exit door closed after last player return; Feld[x][y] = EL_EM_STEEL_EXIT_OPENING; @@ -9062,7 +9177,7 @@ 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) { @@ -9075,7 +9190,7 @@ void CheckExitSP(int x, int y) return; } - if (AllPlayersGone) /* do not re-open exit door closed after last player */ + if (AllPlayersGone) // do not re-open exit door closed after last player return; Feld[x][y] = EL_SP_EXIT_OPENING; @@ -9083,7 +9198,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; @@ -9100,7 +9215,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; @@ -9108,10 +9223,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]--; @@ -9127,14 +9242,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]--; @@ -9177,7 +9292,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); @@ -9190,10 +9305,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]) @@ -9285,7 +9400,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); @@ -9298,10 +9413,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]) @@ -9387,7 +9502,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; @@ -9489,7 +9604,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); } @@ -9531,7 +9646,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 : @@ -9628,7 +9743,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) { @@ -9637,7 +9752,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) return; } - /* ---------- level actions ------------------------------------------- */ + // ---------- level actions ---------------------------------------------- case CA_RESTART_LEVEL: { @@ -9659,7 +9774,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; @@ -9709,17 +9824,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; @@ -9731,7 +9846,10 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) { for (i = 0; i < MAX_PLAYERS; i++) if (action_arg_player_bits & (1 << i)) - PlayerWins(&stored_player[i]); + ExitPlayer(&stored_player[i]); + + if (AllPlayersGone) + LevelSolved(); break; } @@ -9869,7 +9987,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); @@ -9980,7 +10098,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } - /* ---------- CE actions ---------------------------------------------- */ + // ---------- CE actions ------------------------------------------------- case CA_SET_CE_VALUE: { @@ -10076,7 +10194,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } - /* ---------- engine actions ------------------------------------------ */ + // ---------- engine actions --------------------------------------------- case CA_SET_ENGINE_SCAN_MODE: { @@ -10119,7 +10237,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); @@ -10130,9 +10248,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)) { @@ -10141,12 +10259,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); @@ -10166,8 +10284,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; @@ -10185,13 +10303,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; @@ -10200,11 +10318,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) { @@ -10234,12 +10352,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; } @@ -10309,9 +10427,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 } } @@ -10341,7 +10459,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; @@ -10366,21 +10484,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: @@ -10420,8 +10538,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)) { @@ -10436,7 +10554,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) { @@ -10449,9 +10567,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; @@ -10459,15 +10577,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; @@ -10542,9 +10660,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) @@ -10557,9 +10675,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) @@ -10606,7 +10724,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) || @@ -10629,7 +10747,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] && @@ -10645,7 +10763,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 @@ -10715,7 +10833,7 @@ static void PlayPlayerSound(struct PlayerInfo *player) } } -static void PlayAllPlayersSound() +static void PlayAllPlayersSound(void) { int i; @@ -10734,7 +10852,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; @@ -10767,7 +10885,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 && @@ -10853,7 +10971,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; @@ -10911,7 +11029,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 } } @@ -10952,7 +11070,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); @@ -10961,7 +11079,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; @@ -10974,58 +11092,80 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) } } -static void CheckLevelTime() +static void SetMouseActionFromTapeAction(struct MouseActionInfo *mouse_action, + byte *tape_action) { - int i; + if (!tape.use_mouse) + return; + + mouse_action->lx = tape_action[TAPE_ACTION_LX]; + mouse_action->ly = tape_action[TAPE_ACTION_LY]; + mouse_action->button = tape_action[TAPE_ACTION_BUTTON]; +} + +static void SetTapeActionFromMouseAction(byte *tape_action, + struct MouseActionInfo *mouse_action) +{ + if (!tape.use_mouse) + return; + + tape_action[TAPE_ACTION_LX] = mouse_action->lx; + tape_action[TAPE_ACTION_LY] = mouse_action->ly; + tape_action[TAPE_ACTION_BUTTON] = mouse_action->button; +} - /* !!! SAME CODE AS IN "GameActions()" -- FIX THIS !!! */ +static void CheckLevelSolved(void) +{ 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; + AllPlayersGone = 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 */ + if (game_em.game_over) // game lost AllPlayersGone = 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; } - if (game_sp.GameOver) /* game lost */ + if (game_sp.game_over) // 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 */ + !game_mm.game_over) // game won { - PlayerWins(local_player); + LevelSolved(); game_mm.game_over = TRUE; AllPlayersGone = TRUE; } - if (game_mm.game_over) /* game lost */ + if (game_mm.game_over) // game lost AllPlayersGone = TRUE; } +} + +static void CheckLevelTime(void) +{ + int i; if (TimeFrames >= FRAMES_PER_SECOND) { @@ -11045,7 +11185,7 @@ static void CheckLevelTime() } } - if (!local_player->LevelSolved && !level.use_step_counter) + if (!game.LevelSolved && !level.use_step_counter) { TimePlayed++; @@ -11070,7 +11210,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 && !AllPlayersGone) // level w/o time limit { game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; } @@ -11093,21 +11233,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; @@ -11126,7 +11266,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++; @@ -11146,19 +11286,18 @@ void StartGameActions(boolean init_network_game, boolean record_tape, if (record_tape) TapeStartRecording(new_random_seed); -#if defined(NETWORK_AVALIABLE) if (init_network_game) { + SendToServer_LevelFile(); SendToServer_StartPlaying(); return; } -#endif InitGame(); } -void GameActionsExt() +static void GameActionsExt(void) { #if 0 static unsigned int game_frame_delay = 0; @@ -11169,7 +11308,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 ", @@ -11181,7 +11320,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); @@ -11189,64 +11328,17 @@ void GameActionsExt() } if (game.restart_level) - StartGameActions(options.network, 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); + StartGameActions(network.enabled, setup.autorecord, level.random_seed); - game_sp.GameOver = TRUE; + CheckLevelSolved(); - 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; - - 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)) 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 = @@ -11259,14 +11351,14 @@ void GameActionsExt() #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 @@ -11274,34 +11366,39 @@ 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 -#if defined(NETWORK_AVALIABLE) - /* last chance to get network player actions without main loop delay */ + // last chance to get network player actions without main loop delay HandleNetworking(); -#endif - /* 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); - /* TapePlayAction() may return NULL when toggling to "pause before death" */ + local_player->effective_mouse_action = local_player->mouse_action; + + if (recorded_player_action != NULL) + SetMouseActionFromTapeAction(&local_player->effective_mouse_action, + recorded_player_action); + + // TapePlayAction() may return NULL when toggling to "pause before death" if (tape.pausing) return; @@ -11319,14 +11416,12 @@ void GameActionsExt() stored_player[i].effective_action = stored_player[i].action; } -#if defined(NETWORK_AVALIABLE) - if (network_playing) + if (network_playing && !checkGameEnded()) SendToServer_MovePlayer(summarized_player_action); -#endif // summarize all actions at local players mapped input device position // (this allows using different input devices in single player mode) - if (!options.network && !game.team_mode) + if (!network.enabled && !game.team_mode) stored_player[map_player_action[local_player->index_nr]].effective_action = summarized_player_action; @@ -11357,7 +11452,10 @@ void GameActionsExt() tape.player_participates[i] = TRUE; } - /* only record actions from input devices, but not programmed actions */ + SetTapeActionFromMouseAction(tape_action, + &local_player->effective_mouse_action); + + // only record actions from input devices, but not programmed actions if (tape.recording) TapeRecordAction(tape_action); @@ -11432,9 +11530,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) { @@ -11444,24 +11543,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; @@ -11472,14 +11571,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); @@ -11491,7 +11590,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); @@ -11511,19 +11610,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->mouse_action, warp_mode); + 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; @@ -11543,14 +11642,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) { @@ -11560,7 +11659,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; @@ -11596,7 +11695,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; @@ -11630,7 +11729,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; } @@ -11639,10 +11738,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]--; @@ -11658,7 +11759,7 @@ void GameActions_RND() RemoveField(x, y); TEST_DrawLevelField(x, y); - TestIfElementTouchesCustomElement(x, y); /* for empty space */ + TestIfElementTouchesCustomElement(x, y); // for empty space } } @@ -11736,7 +11837,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])) { @@ -11822,7 +11923,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) @@ -11841,7 +11942,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 || @@ -11860,7 +11961,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; @@ -12040,7 +12141,7 @@ void GameActions_RND() 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); } @@ -12066,7 +12167,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; @@ -12233,7 +12334,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, } } - if (!options.network && game.centered_player_nr == -1 && + if (!network.enabled && game.centered_player_nr == -1 && !AllPlayersInSight(player, new_jx, new_jy)) return MP_NO_ACTION; @@ -12241,9 +12342,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; @@ -12268,7 +12369,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 @@ -12301,18 +12402,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; @@ -12321,7 +12422,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) @@ -12372,46 +12473,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; @@ -12420,7 +12521,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) if (scroll_x != old_scroll_x || scroll_y != old_scroll_y) { - if (!options.network && game.centered_player_nr == -1 && + if (!network.enabled && game.centered_player_nr == -1 && !AllPlayersInVisibleScreen()) { scroll_x = old_scroll_x; @@ -12443,7 +12544,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; @@ -12454,7 +12555,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 } @@ -12470,10 +12571,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)) @@ -12497,7 +12598,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) @@ -12508,27 +12609,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)) @@ -12539,12 +12640,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) { @@ -12552,10 +12653,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; } } @@ -12570,17 +12671,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 { - DrawPlayer(player); /* needed here only to cleanup last field */ - RemovePlayer(player); + ExitPlayer(player); - if (local_player->friends_still_needed == 0 || - IS_SP_ELEMENT(Feld[jx][jy])) - PlayerWins(player); + if ((local_player->friends_still_needed == 0 || + IS_SP_ELEMENT(Feld[jx][jy])) && + AllPlayersGone) + 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); @@ -12619,13 +12720,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; @@ -12646,7 +12747,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 && !AllPlayersGone) // level w/o time limit { game_panel_controls[GAME_PANEL_TIME].value = TimePlayed; @@ -12669,7 +12770,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; @@ -12702,11 +12803,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] = { @@ -12715,7 +12816,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++) @@ -12729,18 +12830,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); @@ -12759,14 +12860,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, @@ -12802,11 +12903,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] = { @@ -12816,7 +12917,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; @@ -12832,13 +12933,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; } @@ -12853,11 +12954,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++) @@ -12870,7 +12971,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, @@ -12940,7 +13041,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); } @@ -13037,7 +13138,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++) @@ -13061,18 +13162,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; @@ -13126,7 +13227,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); @@ -13135,7 +13236,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; @@ -13257,10 +13358,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; @@ -13276,7 +13377,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); @@ -13333,6 +13434,19 @@ void RemovePlayer(struct PlayerInfo *player) ExitY = ZY = jy; } +void ExitPlayer(struct PlayerInfo *player) +{ + DrawPlayer(player); // needed here only to cleanup last field + RemovePlayer(player); + + if (local_player->players_still_needed > 0) + local_player->players_still_needed--; + + // also set if some players not yet gone, but not needed to solve level + if (local_player->players_still_needed == 0) + AllPlayersGone = TRUE; +} + static void setFieldForSnapping(int x, int y, int element, int direction) { struct ElementInfo *ei = &element_info[element]; @@ -13366,10 +13480,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; @@ -13410,7 +13524,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) { @@ -13418,10 +13532,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; @@ -13433,16 +13547,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) { @@ -13469,7 +13583,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)) @@ -13486,7 +13600,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; @@ -13495,7 +13609,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)) @@ -13527,14 +13641,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 @@ -13544,9 +13658,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)) @@ -13607,12 +13721,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); } @@ -13639,7 +13753,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); @@ -13705,8 +13819,8 @@ static int DigField(struct PlayerInfo *player, { player->num_white_keys++; - /* display white keys? */ - /* DrawGameDoorValues(); */ + // display white keys? + // DrawGameDoorValues(); } else if (IS_ENVELOPE(element)) { @@ -13725,7 +13839,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; @@ -13763,7 +13877,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); @@ -13794,7 +13908,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; @@ -13829,14 +13943,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; @@ -13852,16 +13966,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++; + + IncrementPlayerSokobanFieldsNeeded(); + IncrementPlayerSokobanObjectsNeeded(); } if (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY) { Back[nextx][nexty] = EL_SOKOBAN_FIELD_EMPTY; - local_player->sokobanfields_still_needed--; + + DecrementPlayerSokobanFieldsNeeded(); + DecrementPlayerSokobanObjectsNeeded(); + + // 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; @@ -13875,10 +13999,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 && + local_player->sokoban_fields_still_needed == 0 && + local_player->sokoban_objects_still_needed == 0 && (game.emulation == EMU_SOKOBAN || level.auto_exit_sokoban)) { - PlayerWins(player); + local_player->players_still_needed = 0; + + LevelSolved(); PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING); } @@ -13900,9 +14028,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, @@ -14084,9 +14212,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; @@ -14106,7 +14234,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)) @@ -14129,7 +14257,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); @@ -14137,7 +14265,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; @@ -14181,7 +14309,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; @@ -14211,7 +14339,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); @@ -14243,34 +14371,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); @@ -14300,8 +14428,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); @@ -14311,7 +14439,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--; @@ -14324,10 +14452,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) @@ -14335,9 +14463,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; } @@ -14353,14 +14481,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(); @@ -14463,20 +14591,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(); @@ -14486,20 +14614,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) @@ -14576,7 +14704,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 @@ -14673,6 +14801,50 @@ void PlayLevelSound_SP(int xx, int yy, int element_sp, int action_sp) PlayLevelSoundElementAction(x, y, element, action); } +void PlayLevelSound_MM(int xx, int yy, int element_mm, int action_mm) +{ + int element = map_element_MM_to_RND(element_mm); + int action = map_action_MM_to_RND(action_mm); + int offset = 0; + int x = xx - offset; + int y = yy - offset; + + if (!IS_MM_ELEMENT(element)) + element = EL_MM_DEFAULT; + + PlayLevelSoundElementAction(x, y, element, action); +} + +void PlaySound_MM(int sound_mm) +{ + int sound = map_sound_MM_to_RND(sound_mm); + + if (sound == SND_UNDEFINED) + return; + + PlaySound(sound); +} + +void PlaySoundLoop_MM(int sound_mm) +{ + int sound = map_sound_MM_to_RND(sound_mm); + + if (sound == SND_UNDEFINED) + return; + + PlaySoundLoop(sound); +} + +void StopSound_MM(int sound_mm) +{ + int sound = map_sound_MM_to_RND(sound_mm); + + if (sound == SND_UNDEFINED) + return; + + StopSound(sound); +} + void RaiseScore(int value) { local_player->score += value; @@ -14766,15 +14938,13 @@ 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) CloseDoor(DOOR_CLOSE_1); -#if defined(NETWORK_AVALIABLE) - if (options.network) + if (network.enabled) SendToServer_StopPlaying(NETWORK_STOP_BY_PLAYER); else -#endif { if (quick_quit) FadeSkipNextFadeIn(); @@ -14784,7 +14954,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); @@ -14805,10 +14975,89 @@ void RequestQuitGame(boolean ask_if_really_quit) "Do you really want to quit the game?"); } +void RequestRestartGame(char *message) +{ + game.restart_game_message = NULL; + + 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); + } + else + { + SetGameStatus(GAME_MODE_MAIN); + + DrawMainMenu(); + } +} + +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; + + if (!game_over) + { + last_game_over = FALSE; + game_over_delay = game_over_delay_value; -/* ------------------------------------------------------------------------- */ -/* random generator functions */ -/* ------------------------------------------------------------------------- */ + 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; +} + +boolean checkGameFailed(void) +{ + if (!AllPlayersGone) + return FALSE; + + 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 (local_player->GameOver && !game.LevelSolved); +} + +boolean checkGameEnded(void) +{ + return (checkGameSolved() || checkGameFailed()); +} + + +// ---------------------------------------------------------------------------- +// random generator functions +// ---------------------------------------------------------------------------- unsigned int InitEngineRandom_RND(int seed) { @@ -14830,19 +15079,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]; }; @@ -14851,7 +15100,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] = { @@ -14890,7 +15139,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; @@ -14936,7 +15185,7 @@ static void LoadEngineSnapshotValues_RND() } } -void FreeEngineSnapshotSingle() +void FreeEngineSnapshotSingle(void) { FreeSnapshotSingle(); @@ -14944,16 +15193,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(); @@ -14964,7 +15213,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)); @@ -14975,7 +15224,7 @@ 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)); @@ -15058,19 +15307,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) || @@ -15086,7 +15335,7 @@ boolean CheckSaveEngineSnapshotToList() return save_snapshot; } -void SaveEngineSnapshotToList() +void SaveEngineSnapshotToList(void) { if (game.snapshot.mode == SNAPSHOT_MODE_OFF || tape.quick_resume) @@ -15094,20 +15343,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(); @@ -15115,113 +15364,159 @@ void LoadEngineSnapshotValues() LoadEngineSnapshotValues_EM(); if (level.game_engine_type == GAME_ENGINE_TYPE_SP) LoadEngineSnapshotValues_SP(); - if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + if (level.game_engine_type == GAME_ENGINE_TYPE_MM) 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 { int graphic; struct XY *pos; int gadget_id; + boolean *setup_value; + boolean allowed_on_tape; char *infotext; } gamebutton_info[NUM_GAME_BUTTONS] = { { - IMG_GFX_GAME_BUTTON_STOP, &game.button.stop, - GAME_CTRL_ID_STOP, "stop game" + IMG_GFX_GAME_BUTTON_STOP, &game.button.stop, + GAME_CTRL_ID_STOP, NULL, + TRUE, "stop game" + }, + { + IMG_GFX_GAME_BUTTON_PAUSE, &game.button.pause, + GAME_CTRL_ID_PAUSE, NULL, + TRUE, "pause game" + }, + { + IMG_GFX_GAME_BUTTON_PLAY, &game.button.play, + GAME_CTRL_ID_PLAY, NULL, + TRUE, "play game" + }, + { + IMG_GFX_GAME_BUTTON_UNDO, &game.button.undo, + GAME_CTRL_ID_UNDO, NULL, + TRUE, "undo step" + }, + { + IMG_GFX_GAME_BUTTON_REDO, &game.button.redo, + GAME_CTRL_ID_REDO, NULL, + TRUE, "redo step" + }, + { + IMG_GFX_GAME_BUTTON_SAVE, &game.button.save, + GAME_CTRL_ID_SAVE, NULL, + TRUE, "save game" + }, + { + IMG_GFX_GAME_BUTTON_PAUSE2, &game.button.pause2, + GAME_CTRL_ID_PAUSE2, NULL, + TRUE, "pause game" }, { - IMG_GFX_GAME_BUTTON_PAUSE, &game.button.pause, - GAME_CTRL_ID_PAUSE, "pause game" + IMG_GFX_GAME_BUTTON_LOAD, &game.button.load, + GAME_CTRL_ID_LOAD, NULL, + TRUE, "load game" }, { - IMG_GFX_GAME_BUTTON_PLAY, &game.button.play, - GAME_CTRL_ID_PLAY, "play game" + IMG_GFX_GAME_BUTTON_PANEL_STOP, &game.button.panel_stop, + GAME_CTRL_ID_PANEL_STOP, NULL, + FALSE, "stop game" }, { - IMG_GFX_GAME_BUTTON_UNDO, &game.button.undo, - GAME_CTRL_ID_UNDO, "undo step" + IMG_GFX_GAME_BUTTON_PANEL_PAUSE, &game.button.panel_pause, + GAME_CTRL_ID_PANEL_PAUSE, NULL, + FALSE, "pause game" }, { - IMG_GFX_GAME_BUTTON_REDO, &game.button.redo, - GAME_CTRL_ID_REDO, "redo step" + IMG_GFX_GAME_BUTTON_PANEL_PLAY, &game.button.panel_play, + GAME_CTRL_ID_PANEL_PLAY, NULL, + FALSE, "play game" }, { - IMG_GFX_GAME_BUTTON_SAVE, &game.button.save, - GAME_CTRL_ID_SAVE, "save game" + IMG_GFX_GAME_BUTTON_SOUND_MUSIC, &game.button.sound_music, + SOUND_CTRL_ID_MUSIC, &setup.sound_music, + TRUE, "background music on/off" }, { - IMG_GFX_GAME_BUTTON_PAUSE2, &game.button.pause2, - GAME_CTRL_ID_PAUSE2, "pause game" + IMG_GFX_GAME_BUTTON_SOUND_LOOPS, &game.button.sound_loops, + SOUND_CTRL_ID_LOOPS, &setup.sound_loops, + TRUE, "sound loops on/off" }, { - IMG_GFX_GAME_BUTTON_LOAD, &game.button.load, - GAME_CTRL_ID_LOAD, "load game" + IMG_GFX_GAME_BUTTON_SOUND_SIMPLE, &game.button.sound_simple, + SOUND_CTRL_ID_SIMPLE, &setup.sound_simple, + TRUE, "normal sounds on/off" }, { - IMG_GFX_GAME_BUTTON_SOUND_MUSIC, &game.button.sound_music, - SOUND_CTRL_ID_MUSIC, "background music on/off" + IMG_GFX_GAME_BUTTON_PANEL_SOUND_MUSIC, &game.button.panel_sound_music, + SOUND_CTRL_ID_PANEL_MUSIC, &setup.sound_music, + FALSE, "background music on/off" }, { - IMG_GFX_GAME_BUTTON_SOUND_LOOPS, &game.button.sound_loops, - SOUND_CTRL_ID_LOOPS, "sound loops on/off" + IMG_GFX_GAME_BUTTON_PANEL_SOUND_LOOPS, &game.button.panel_sound_loops, + SOUND_CTRL_ID_PANEL_LOOPS, &setup.sound_loops, + FALSE, "sound loops on/off" }, { - IMG_GFX_GAME_BUTTON_SOUND_SIMPLE, &game.button.sound_simple, - SOUND_CTRL_ID_SIMPLE, "normal sounds on/off" + IMG_GFX_GAME_BUTTON_PANEL_SOUND_SIMPLE, &game.button.panel_sound_simple, + SOUND_CTRL_ID_PANEL_SIMPLE, &setup.sound_simple, + FALSE, "normal sounds on/off" } }; -void CreateGameButtons() +void CreateGameButtons(void) { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) { - struct GraphicInfo *gfx = &graphic_info[gamebutton_info[i].graphic]; + int graphic = gamebutton_info[i].graphic; + struct GraphicInfo *gfx = &graphic_info[graphic]; struct XY *pos = gamebutton_info[i].pos; struct GadgetInfo *gi; int button_type; boolean checked; unsigned int event_mask; - int base_x = (tape.show_game_buttons ? VX : DX); - int base_y = (tape.show_game_buttons ? VY : DY); + boolean allowed_on_tape = gamebutton_info[i].allowed_on_tape; + boolean on_tape = (tape.show_game_buttons && allowed_on_tape); + int base_x = (on_tape ? VX : DX); + int base_y = (on_tape ? VY : DY); int gd_x = gfx->src_x; int gd_y = gfx->src_y; int gd_xp = gfx->src_x + gfx->pressed_xoffset; @@ -15240,7 +15535,9 @@ void CreateGameButtons() } if (id == GAME_CTRL_ID_STOP || + id == GAME_CTRL_ID_PANEL_STOP || id == GAME_CTRL_ID_PLAY || + id == GAME_CTRL_ID_PANEL_PLAY || id == GAME_CTRL_ID_SAVE || id == GAME_CTRL_ID_LOAD) { @@ -15258,14 +15555,13 @@ void CreateGameButtons() else { button_type = GD_TYPE_CHECK_BUTTON; - checked = - ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) || - (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) || - (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE); + checked = (gamebutton_info[i].setup_value != NULL ? + *gamebutton_info[i].setup_value : FALSE); event_mask = GD_EVENT_PRESSED; } gi = CreateGadget(GDI_CUSTOM_ID, id, + GDI_IMAGE_ID, graphic, GDI_INFO_TEXT, gamebutton_info[i].infotext, GDI_X, base_x + GDI_ACTIVE_POS(pos->x), GDI_Y, base_y + GDI_ACTIVE_POS(pos->y), @@ -15290,7 +15586,7 @@ void CreateGameButtons() } } -void FreeGameButtons() +void FreeGameButtons(void) { int i; @@ -15309,7 +15605,7 @@ static void UnmapGameButtonsAtSamePosition(int id) UnmapGadget(game_gadget[i]); } -static void UnmapGameButtonsAtSamePosition_All() +static void UnmapGameButtonsAtSamePosition_All(void) { if (setup.show_snapshot_buttons) { @@ -15322,6 +15618,10 @@ static void UnmapGameButtonsAtSamePosition_All() UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_STOP); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PAUSE); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PLAY); + + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PANEL_STOP); + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PANEL_PAUSE); + UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PANEL_PLAY); } } @@ -15338,7 +15638,7 @@ static void MapGameButtonsAtSamePosition(int id) UnmapGameButtonsAtSamePosition_All(); } -void MapUndoRedoButtons() +void MapUndoRedoButtons(void) { UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO); @@ -15349,7 +15649,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]); @@ -15360,12 +15660,13 @@ void UnmapUndoRedoButtons() ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, FALSE, GDI_END); } -void MapGameButtons() +static void MapGameButtonsExt(boolean on_tape) { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) - if (i != GAME_CTRL_ID_UNDO && + if ((!on_tape || gamebutton_info[i].allowed_on_tape) && + i != GAME_CTRL_ID_UNDO && i != GAME_CTRL_ID_REDO) MapGadget(game_gadget[i]); @@ -15374,26 +15675,80 @@ void MapGameButtons() RedrawGameButtons(); } -void UnmapGameButtons() +static void UnmapGameButtonsExt(boolean on_tape) { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) - UnmapGadget(game_gadget[i]); + if (!on_tape || gamebutton_info[i].allowed_on_tape) + UnmapGadget(game_gadget[i]); } -void RedrawGameButtons() +static void RedrawGameButtonsExt(boolean on_tape) { int i; for (i = 0; i < NUM_GAME_BUTTONS; i++) - RedrawGadget(game_gadget[i]); + if (!on_tape || gamebutton_info[i].allowed_on_tape) + RedrawGadget(game_gadget[i]); // RedrawGadget() may have set REDRAW_ALL if buttons are defined off-area redraw_mask &= ~REDRAW_ALL; } -void GameUndoRedoExt() +static void SetGadgetState(struct GadgetInfo *gi, boolean state) +{ + if (gi == NULL) + return; + + gi->checked = state; +} + +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 : + id == SOUND_CTRL_ID_SIMPLE ? SOUND_CTRL_ID_PANEL_SIMPLE : + id == SOUND_CTRL_ID_PANEL_MUSIC ? SOUND_CTRL_ID_MUSIC : + id == SOUND_CTRL_ID_PANEL_LOOPS ? SOUND_CTRL_ID_LOOPS : + id == SOUND_CTRL_ID_PANEL_SIMPLE ? SOUND_CTRL_ID_SIMPLE : + id); + + SetGadgetState(game_gadget[id2], *gamebutton_info[id2].setup_value); + RedrawGadget(game_gadget[id2]); +} + +void MapGameButtons(void) +{ + MapGameButtonsExt(FALSE); +} + +void UnmapGameButtons(void) +{ + UnmapGameButtonsExt(FALSE); +} + +void RedrawGameButtons(void) +{ + RedrawGameButtonsExt(FALSE); +} + +void MapGameButtonsOnTape(void) +{ + MapGameButtonsExt(TRUE); +} + +void UnmapGameButtonsOnTape(void) +{ + UnmapGameButtonsExt(TRUE); +} + +void RedrawGameButtonsOnTape(void) +{ + RedrawGameButtonsExt(TRUE); +} + +static void GameUndoRedoExt(void) { ClearPlayerAction(); @@ -15410,7 +15765,7 @@ void GameUndoRedoExt() BackToFront(); } -void GameUndo(int steps) +static void GameUndo(int steps) { if (!CheckEngineSnapshotList()) return; @@ -15420,7 +15775,7 @@ void GameUndo(int steps) GameUndoRedoExt(); } -void GameRedo(int steps) +static void GameRedo(int steps) { if (!CheckEngineSnapshotList()) return; @@ -15444,6 +15799,7 @@ static void HandleGameButtonsExt(int id, int button) switch (id) { case GAME_CTRL_ID_STOP: + case GAME_CTRL_ID_PANEL_STOP: if (game_status == GAME_MODE_MAIN) break; @@ -15456,14 +15812,13 @@ static void HandleGameButtonsExt(int id, int button) case GAME_CTRL_ID_PAUSE: case GAME_CTRL_ID_PAUSE2: - if (options.network && game_status == GAME_MODE_PLAYING) + case GAME_CTRL_ID_PANEL_PAUSE: + if (network.enabled && game_status == GAME_MODE_PLAYING) { -#if defined(NETWORK_AVALIABLE) if (tape.pausing) SendToServer_ContinuePlaying(); else SendToServer_PausePlaying(); -#endif } else TapeTogglePause(TAPE_TOGGLE_MANUAL); @@ -15473,17 +15828,16 @@ static void HandleGameButtonsExt(int id, int button) break; case GAME_CTRL_ID_PLAY: + case GAME_CTRL_ID_PANEL_PLAY: if (game_status == GAME_MODE_MAIN) { - StartGameActions(options.network, setup.autorecord, level.random_seed); + StartGameActions(network.enabled, setup.autorecord, level.random_seed); } else if (tape.pausing) { -#if defined(NETWORK_AVALIABLE) - if (options.network) + if (network.enabled) SendToServer_ContinuePlaying(); else -#endif TapeTogglePause(TAPE_TOGGLE_MANUAL | TAPE_TOGGLE_PLAY_PAUSE); } break; @@ -15516,6 +15870,7 @@ static void HandleGameButtonsExt(int id, int button) break; case SOUND_CTRL_ID_MUSIC: + case SOUND_CTRL_ID_PANEL_MUSIC: if (setup.sound_music) { setup.sound_music = FALSE; @@ -15528,11 +15883,16 @@ static void HandleGameButtonsExt(int id, int button) SetAudioMode(setup.sound); - PlayLevelMusic(); + if (game_status == GAME_MODE_PLAYING) + PlayLevelMusic(); } + + RedrawSoundButtonGadget(id); + break; case SOUND_CTRL_ID_LOOPS: + case SOUND_CTRL_ID_PANEL_LOOPS: if (setup.sound_loops) setup.sound_loops = FALSE; else if (audio.loops_available) @@ -15541,9 +15901,13 @@ static void HandleGameButtonsExt(int id, int button) SetAudioMode(setup.sound); } + + RedrawSoundButtonGadget(id); + break; case SOUND_CTRL_ID_SIMPLE: + case SOUND_CTRL_ID_PANEL_SIMPLE: if (setup.sound_simple) setup.sound_simple = FALSE; else if (audio.sound_available) @@ -15552,6 +15916,9 @@ static void HandleGameButtonsExt(int id, int button) SetAudioMode(setup.sound); } + + RedrawSoundButtonGadget(id); + break; default: @@ -15566,7 +15933,6 @@ static void HandleGameButtons(struct GadgetInfo *gi) void HandleSoundButtonKeys(Key key) { - if (key == setup.shortcut.sound_simple) ClickOnGadget(game_gadget[SOUND_CTRL_ID_SIMPLE], MB_LEFTBUTTON); else if (key == setup.shortcut.sound_loops)