X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame.c;h=5bfa71db14d69900b035c2d31a0e60df472027bd;hp=d37dee3a5f7c162ce69acdf33167a2d3b64f2233;hb=8cae2f011a23232a4233e808fd1092d2871603e6;hpb=7466541c01db2ed673eee2302cd3ede5a5fbdf5e diff --git a/src/game.c b/src/game.c index d37dee3a..5bfa71db 100644 --- a/src/game.c +++ b/src/game.c @@ -81,7 +81,7 @@ #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)) @@ -1085,8 +1085,8 @@ static void PlayLevelSoundElementAction(int, int, int, int); static void PlayLevelSoundElementActionIfLoop(int, int, int, int); static void PlayLevelSoundActionIfLoop(int, int, int); static void StopLevelSoundActionIfLoop(int, int, int); -static void PlayLevelMusic(); -static void FadeLevelSoundsAndMusic(); +static void PlayLevelMusic(void); +static void FadeLevelSoundsAndMusic(void); static void HandleGameButtons(struct GadgetInfo *); @@ -1096,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); @@ -1112,6 +1112,7 @@ 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); @@ -1561,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; @@ -1572,7 +1573,7 @@ void DEBUG_SetMaximumDynamite() } #endif -static void InitPlayfieldScanModeVars() +static void InitPlayfieldScanModeVars(void) { if (game.use_reverse_scan_direction) { @@ -1635,7 +1636,7 @@ static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize, } } -void GetPlayerConfig() +void GetPlayerConfig(void) { GameFrameDelay = setup.game_frame_delay; @@ -2102,7 +2103,7 @@ int getPlayerInventorySize(int player_nr) return stored_player[player_nr].inventory_size; } -void InitGameControlValues() +static void InitGameControlValues(void) { int i; @@ -2147,7 +2148,7 @@ void InitGameControlValues() sizeof(struct GamePanelOrderInfo), compareGamePanelOrderInfo); } -void UpdatePlayfieldElementCount() +static void UpdatePlayfieldElementCount(void) { boolean use_element_count = FALSE; int i, j, x, y; @@ -2175,7 +2176,7 @@ void UpdatePlayfieldElementCount() element_info[j].element_count; } -void UpdateGameControlValues() +static void UpdateGameControlValues(void) { int i, k; int time = (local_player->LevelSolved ? @@ -2223,7 +2224,8 @@ void UpdateGameControlValues() /* 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; @@ -2505,7 +2507,7 @@ void UpdateGameControlValues() } } -void DisplayGameControlValues() +static void DisplayGameControlValues(void) { boolean redraw_panel = FALSE; int i; @@ -2756,7 +2758,7 @@ void DisplayGameControlValues() SetGameStatus(GAME_MODE_PLAYING); } -void UpdateAndDisplayGameControlValues() +void UpdateAndDisplayGameControlValues(void) { if (tape.deactivate_display) return; @@ -2765,12 +2767,14 @@ void UpdateAndDisplayGameControlValues() DisplayGameControlValues(); } -void UpdateGameDoorValues() +#if 0 +static void UpdateGameDoorValues(void) { UpdateGameControlValues(); } +#endif -void DrawGameDoorValues() +void DrawGameDoorValues(void) { DisplayGameControlValues(); } @@ -2784,7 +2788,7 @@ void DrawGameDoorValues() ============================================================================= */ -static void InitGameEngine() +static void InitGameEngine(void) { int i, j, k, l, x, y; @@ -3241,7 +3245,8 @@ static void InitGameEngine() 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; @@ -3273,7 +3278,37 @@ int get_num_special_action(int element, int action_first, int action_last) ============================================================================= */ -void InitGame() +#if DEBUG_INIT_PLAYER +static void DebugPrintPlayerStatus(char *message) +{ + int i; + + if (!options.debug) + return; + + printf("%s:\n", message); + + 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); @@ -3305,8 +3340,7 @@ void InitGame() ExpireSoundLoops(TRUE); - if (!level_editor_test_game) - FadeOut(fade_mask); + FadeOut(fade_mask); /* needed if different viewport properties defined for playing */ ChangeViewportPropertiesIfNeeded(); @@ -3361,6 +3395,7 @@ void InitGame() player->gems_still_needed = level.gems_needed; player->sokobanfields_still_needed = 0; player->lights_still_needed = 0; + player->players_still_needed = 0; player->friends_still_needed = 0; for (j = 0; j < MAX_NUM_KEYS; j++) @@ -3490,7 +3525,6 @@ void InitGame() player->LevelSolved_GameWon = FALSE; player->LevelSolved_GameEnd = FALSE; - player->LevelSolved_PanelOff = FALSE; player->LevelSolved_SaveTape = FALSE; player->LevelSolved_SaveScore = FALSE; @@ -3524,6 +3558,8 @@ void InitGame() AllPlayersGone = FALSE; + game.panel.active = TRUE; + game.no_time_limit = (level.time == 0); game.yamyam_content_nr = 0; @@ -3541,6 +3577,8 @@ void InitGame() game.ball_state = level.ball_state_initial; game.ball_content_nr = 0; + game.explosions_delayed = TRUE; + game.envelope_active = FALSE; for (i = 0; i < NUM_BELTS; i++) @@ -3553,33 +3591,12 @@ void InitGame() AmoebaCnt[i] = AmoebaCnt2[i] = 0; #if DEBUG_INIT_PLAYER - if (options.debug) - { - printf("Player status at level initialization:\n"); - - 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"); - } - } + 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; @@ -3726,28 +3743,7 @@ void InitGame() } #if DEBUG_INIT_PLAYER - if (options.debug) - { - printf("Player status after level initialization:\n"); - - 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"); - } - } + DebugPrintPlayerStatus("Player status after level initialization"); #endif #if DEBUG_INIT_PLAYER @@ -3834,28 +3830,7 @@ 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 [%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"); - } - } + DebugPrintPlayerStatus("Player status after player assignment (first stage)"); #endif #else @@ -3981,6 +3956,13 @@ void InitGame() } } + 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) { @@ -3996,28 +3978,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 [%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"); - } - } + DebugPrintPlayerStatus("Player status after player assignment (final stage)"); #endif if (BorderElement == EL_EMPTY) @@ -4217,28 +4178,7 @@ void InitGame() 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 [%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"); - } - } + DebugPrintPlayerStatus("Player status (final)"); #endif } @@ -4256,6 +4196,7 @@ void InitGame() game.restart_level = FALSE; game.restart_game_message = NULL; + game.request_active = FALSE; if (level.game_engine_type == GAME_ENGINE_TYPE_MM) InitGameActions_MM(); @@ -4491,6 +4432,10 @@ void InitAmoebaNr(int x, int y) static void PlayerWins(struct PlayerInfo *player) { + if (level.game_engine_type == GAME_ENGINE_TYPE_RND && + local_player->players_still_needed > 0) + return; + player->LevelSolved = TRUE; player->GameOver = TRUE; @@ -4509,7 +4454,7 @@ static void PlayerWins(struct PlayerInfo *player) player->LevelSolved_CountingHealth = player->health_final; } -void GameWon() +void GameWon(void) { static int time_count_steps; static int time, time_final; @@ -4613,8 +4558,8 @@ 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); @@ -4710,7 +4655,7 @@ void GameWon() return; } - local_player->LevelSolved_PanelOff = TRUE; + game.panel.active = FALSE; if (game_over_delay_3 > 0) { @@ -4722,10 +4667,11 @@ void GameWon() GameEnd(); } -void GameEnd() +void GameEnd(void) { + /* used instead of "level_nr" (needed for network games) */ + int last_level_nr = levelset.level_nr; int hi_pos; - boolean raise_level = FALSE; local_player->LevelSolved_GameEnd = TRUE; @@ -4767,36 +4713,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); - - DrawHallOfFame(hi_pos); + level_nr++; /* advance to next level */ + TapeErase(); /* start with empty tape */ - 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; @@ -4927,7 +4880,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); @@ -5000,7 +4953,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]; @@ -5058,7 +5011,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]; @@ -5139,7 +5092,7 @@ 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 */ { @@ -5189,7 +5142,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; @@ -5209,8 +5162,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); @@ -5300,7 +5253,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); @@ -5405,7 +5358,7 @@ 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; @@ -5708,7 +5661,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]; @@ -5833,7 +5786,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) || @@ -5848,7 +5801,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] = { @@ -6082,7 +6035,7 @@ static int getInvisibleFromInvisibleActiveElement(int element) element); } -static void RedrawAllLightSwitchesAndInvisibleElements() +static void RedrawAllLightSwitchesAndInvisibleElements(void) { int x, y; @@ -6143,7 +6096,7 @@ static void RedrawAllLightSwitchesAndInvisibleElements() } } -static void RedrawAllInvisibleElementsForLenses() +static void RedrawAllInvisibleElementsForLenses(void) { int x, y; @@ -6192,7 +6145,7 @@ static void RedrawAllInvisibleElementsForLenses() } } -static void RedrawAllInvisibleElementsForMagnifier() +static void RedrawAllInvisibleElementsForMagnifier(void) { int x, y; @@ -6285,7 +6238,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; @@ -7389,7 +7342,7 @@ 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 */ int element = Feld[x][y]; @@ -8568,7 +8521,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]; @@ -8675,7 +8628,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]; @@ -8711,7 +8664,7 @@ 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; @@ -8747,7 +8700,7 @@ 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; @@ -8783,7 +8736,7 @@ void AmoebaDisappearing(int x, int y) } } -void AmoebeAbleger(int ax, int ay) +static void AmoebeAbleger(int ax, int ay) { int i; int element = Feld[ax][ay]; @@ -8938,7 +8891,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; @@ -8967,7 +8920,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; @@ -8979,33 +8933,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++; } + 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])) + else if (is_free || CAN_GROW_INTO(Feld[xx][yy])) { /* free border field */ - if (nachbarn >= life_parameter[2] && - nachbarn <= life_parameter[3]) + 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; @@ -9085,7 +9054,7 @@ 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 || @@ -9108,7 +9077,7 @@ 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 || @@ -9131,7 +9100,7 @@ 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 || @@ -9154,7 +9123,7 @@ 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 || @@ -9177,7 +9146,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) { @@ -9198,7 +9167,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; @@ -9215,7 +9184,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; @@ -9242,7 +9211,7 @@ void DrawTwinkleOnField(int x, int y) } } -void MauerWaechst(int x, int y) +static void MauerWaechst(int x, int y) { int delay = 6; @@ -9292,7 +9261,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); @@ -9400,7 +9369,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); @@ -9502,7 +9471,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; @@ -9846,7 +9815,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) + PlayerWins(local_player); break; } @@ -10830,7 +10802,7 @@ static void PlayPlayerSound(struct PlayerInfo *player) } } -static void PlayAllPlayersSound() +static void PlayAllPlayersSound(void) { int i; @@ -11111,11 +11083,8 @@ static void SetTapeActionFromMouseAction(byte *tape_action, tape_action[TAPE_ACTION_BUTTON] = mouse_action->button; } -static void CheckLevelTime() +static void CheckLevelSolved(void) { - int i; - - /* !!! SAME CODE AS IN "GameActions()" -- FIX THIS !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { if (level.native_em_level->lev->home == 0) /* all players at home */ @@ -11163,6 +11132,11 @@ static void CheckLevelTime() if (game_mm.game_over) /* game lost */ AllPlayersGone = TRUE; } +} + +static void CheckLevelTime(void) +{ + int i; if (TimeFrames >= FRAMES_PER_SECOND) { @@ -11285,6 +11259,7 @@ void StartGameActions(boolean init_network_game, boolean record_tape, if (init_network_game) { + SendToServer_LevelFile(); SendToServer_StartPlaying(); return; @@ -11293,7 +11268,7 @@ void StartGameActions(boolean init_network_game, boolean record_tape, InitGame(); } -void GameActionsExt() +static void GameActionsExt(void) { #if 0 static unsigned int game_frame_delay = 0; @@ -11326,54 +11301,7 @@ void GameActionsExt() if (game.restart_level) StartGameActions(network.enabled, setup.autorecord, level.random_seed); - /* !!! SAME CODE AS IN "CheckLevelTime()" -- FIX THIS !!! */ - if (level.game_engine_type == GAME_ENGINE_TYPE_EM) - { - if (level.native_em_level->lev->home == 0) /* all players at home */ - { - PlayerWins(local_player); - - AllPlayersGone = TRUE; - - level.native_em_level->lev->home = -1; - } - - if (level.native_em_level->ply[0]->alive == 0 && - level.native_em_level->ply[1]->alive == 0 && - level.native_em_level->ply[2]->alive == 0 && - level.native_em_level->ply[3]->alive == 0) /* all dead */ - AllPlayersGone = TRUE; - } - else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) - { - if (game_sp.LevelSolved && - !game_sp.GameOver) /* game won */ - { - PlayerWins(local_player); - - game_sp.GameOver = TRUE; - - AllPlayersGone = TRUE; - } - - if (game_sp.GameOver) /* game lost */ - AllPlayersGone = TRUE; - } - else if (level.game_engine_type == GAME_ENGINE_TYPE_MM) - { - if (game_mm.level_solved && - !game_mm.game_over) /* game won */ - { - PlayerWins(local_player); - - game_mm.game_over = TRUE; - - AllPlayersGone = TRUE; - } - - if (game_mm.game_over) /* game lost */ - AllPlayersGone = TRUE; - } + CheckLevelSolved(); if (local_player->LevelSolved && !local_player->LevelSolved_GameEnd) GameWon(); @@ -11572,6 +11500,7 @@ void GameActionsExt() BlitScreenToBitmap(backbuffer); + CheckLevelSolved(); CheckLevelTime(); AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */ @@ -11601,7 +11530,7 @@ void GameActionsExt() } } -static void GameActions_CheckSaveEngineSnapshot() +static void GameActions_CheckSaveEngineSnapshot(void) { if (!game.snapshot.save_snapshot) return; @@ -11612,14 +11541,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); @@ -11631,7 +11560,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); @@ -11651,19 +11580,19 @@ void GameActions_SP_Main() } } -void GameActions_MM_Main() +void GameActions_MM_Main(void) { boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing); GameActions_MM(local_player->effective_mouse_action, warp_mode); } -void GameActions_RND_Main() +void GameActions_RND_Main(void) { GameActions_RND(); } -void GameActions_RND() +void GameActions_RND(void) { int magic_wall_x = 0, magic_wall_y = 0; int i, x, y, element, graphic, last_gfx_frame; @@ -11779,6 +11708,8 @@ void GameActions_RND() SCAN_PLAYFIELD(x, y) { + Last[x][y] = Feld[x][y]; + ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; @@ -12206,7 +12137,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; @@ -12712,12 +12643,12 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) Feld[jx][jy] == EL_SP_EXIT_OPEN || 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) + PlayerWins(local_player); } /* this breaks one level: "machine", level 000 */ @@ -13473,6 +13404,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]; @@ -14018,6 +13962,8 @@ static int DigField(struct PlayerInfo *player, if (local_player->sokobanfields_still_needed == 0 && (game.emulation == EMU_SOKOBAN || level.auto_exit_sokoban)) { + local_player->players_still_needed = 0; + PlayerWins(player); PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING); @@ -14500,7 +14446,7 @@ static boolean DropElement(struct PlayerInfo *player) static int *loop_sound_frame = NULL; static int *loop_sound_volume = NULL; -void InitPlayLevelSound() +void InitPlayLevelSound(void) { int num_sounds = getSoundListSize(); @@ -14603,7 +14549,7 @@ 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 */ @@ -14611,12 +14557,12 @@ static int getLevelMusicNr() 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(); @@ -14626,20 +14572,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) @@ -15003,6 +14949,32 @@ void RequestRestartGame(char *message) } } +boolean checkGameSolved(void) +{ + /* set for all game engines if level was solved */ + return local_player->LevelSolved_GameEnd; +} + +boolean checkGameFailed(void) +{ + if (!AllPlayersGone) + return FALSE; + + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) + return (level.native_em_level->lev->home > 0); + else if (level.game_engine_type == GAME_ENGINE_TYPE_SP) + return (game_sp.GameOver && !game_sp.LevelSolved); + 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 && !local_player->LevelSolved); +} + +boolean checkGameEnded(void) +{ + return (checkGameSolved() || checkGameFailed()); +} + /* ------------------------------------------------------------------------- */ /* random generator functions */ @@ -15049,7 +15021,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] = { @@ -15088,7 +15060,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; @@ -15134,7 +15106,7 @@ static void LoadEngineSnapshotValues_RND() } } -void FreeEngineSnapshotSingle() +void FreeEngineSnapshotSingle(void) { FreeSnapshotSingle(); @@ -15142,12 +15114,12 @@ void FreeEngineSnapshotSingle() snapshot_level_nr = -1; } -void FreeEngineSnapshotList() +void FreeEngineSnapshotList(void) { FreeSnapshotList(); } -ListNode *SaveEngineSnapshotBuffers() +static ListNode *SaveEngineSnapshotBuffers(void) { ListNode *buffers = NULL; @@ -15256,7 +15228,7 @@ ListNode *SaveEngineSnapshotBuffers() return buffers; } -void SaveEngineSnapshotSingle() +void SaveEngineSnapshotSingle(void) { ListNode *buffers = SaveEngineSnapshotBuffers(); @@ -15268,7 +15240,7 @@ void SaveEngineSnapshotSingle() snapshot_level_nr = level_nr; } -boolean CheckSaveEngineSnapshotToList() +boolean CheckSaveEngineSnapshotToList(void) { boolean save_snapshot = ((game.snapshot.mode == SNAPSHOT_MODE_EVERY_STEP) || @@ -15284,7 +15256,7 @@ boolean CheckSaveEngineSnapshotToList() return save_snapshot; } -void SaveEngineSnapshotToList() +void SaveEngineSnapshotToList(void) { if (game.snapshot.mode == SNAPSHOT_MODE_OFF || tape.quick_resume) @@ -15296,14 +15268,14 @@ void SaveEngineSnapshotToList() SaveSnapshotToList(buffers); } -void SaveEngineSnapshotToListInitial() +void SaveEngineSnapshotToListInitial(void) { FreeEngineSnapshotList(); SaveEngineSnapshotToList(); } -void LoadEngineSnapshotValues() +static void LoadEngineSnapshotValues(void) { /* restore special values from snapshot structure */ @@ -15317,34 +15289,34 @@ void LoadEngineSnapshotValues() LoadEngineSnapshotValues_MM(); } -void LoadEngineSnapshotSingle() +void LoadEngineSnapshotSingle(void) { LoadSnapshotSingle(); LoadEngineSnapshotValues(); } -void LoadEngineSnapshot_Undo(int steps) +static void LoadEngineSnapshot_Undo(int steps) { LoadSnapshotFromList_Older(steps); LoadEngineSnapshotValues(); } -void LoadEngineSnapshot_Redo(int steps) +static void LoadEngineSnapshot_Redo(int steps) { LoadSnapshotFromList_Newer(steps); LoadEngineSnapshotValues(); } -boolean CheckEngineSnapshotSingle() +boolean CheckEngineSnapshotSingle(void) { return (strEqual(snapshot_level_identifier, leveldir_current->identifier) && snapshot_level_nr == level_nr); } -boolean CheckEngineSnapshotList() +boolean CheckEngineSnapshotList(void) { return CheckSnapshotList(); } @@ -15449,7 +15421,7 @@ static struct } }; -void CreateGameButtons() +void CreateGameButtons(void) { int i; @@ -15535,7 +15507,7 @@ void CreateGameButtons() } } -void FreeGameButtons() +void FreeGameButtons(void) { int i; @@ -15554,7 +15526,7 @@ static void UnmapGameButtonsAtSamePosition(int id) UnmapGadget(game_gadget[i]); } -static void UnmapGameButtonsAtSamePosition_All() +static void UnmapGameButtonsAtSamePosition_All(void) { if (setup.show_snapshot_buttons) { @@ -15587,7 +15559,7 @@ static void MapGameButtonsAtSamePosition(int id) UnmapGameButtonsAtSamePosition_All(); } -void MapUndoRedoButtons() +void MapUndoRedoButtons(void) { UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO); UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO); @@ -15598,7 +15570,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]); @@ -15609,7 +15581,7 @@ void UnmapUndoRedoButtons() ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, FALSE, GDI_END); } -void MapGameButtonsExt(boolean on_tape) +static void MapGameButtonsExt(boolean on_tape) { int i; @@ -15624,7 +15596,7 @@ void MapGameButtonsExt(boolean on_tape) RedrawGameButtons(); } -void UnmapGameButtonsExt(boolean on_tape) +static void UnmapGameButtonsExt(boolean on_tape) { int i; @@ -15633,7 +15605,7 @@ void UnmapGameButtonsExt(boolean on_tape) UnmapGadget(game_gadget[i]); } -void RedrawGameButtonsExt(boolean on_tape) +static void RedrawGameButtonsExt(boolean on_tape) { int i; @@ -15645,7 +15617,7 @@ void RedrawGameButtonsExt(boolean on_tape) redraw_mask &= ~REDRAW_ALL; } -void SetGadgetState(struct GadgetInfo *gi, boolean state) +static void SetGadgetState(struct GadgetInfo *gi, boolean state) { if (gi == NULL) return; @@ -15653,7 +15625,7 @@ void SetGadgetState(struct GadgetInfo *gi, boolean state) gi->checked = state; } -void RedrawSoundButtonGadget(int id) +static void RedrawSoundButtonGadget(int id) { int id2 = (id == SOUND_CTRL_ID_MUSIC ? SOUND_CTRL_ID_PANEL_MUSIC : id == SOUND_CTRL_ID_LOOPS ? SOUND_CTRL_ID_PANEL_LOOPS : @@ -15667,37 +15639,37 @@ void RedrawSoundButtonGadget(int id) RedrawGadget(game_gadget[id2]); } -void MapGameButtons() +void MapGameButtons(void) { MapGameButtonsExt(FALSE); } -void UnmapGameButtons() +void UnmapGameButtons(void) { UnmapGameButtonsExt(FALSE); } -void RedrawGameButtons() +void RedrawGameButtons(void) { RedrawGameButtonsExt(FALSE); } -void MapGameButtonsOnTape() +void MapGameButtonsOnTape(void) { MapGameButtonsExt(TRUE); } -void UnmapGameButtonsOnTape() +void UnmapGameButtonsOnTape(void) { UnmapGameButtonsExt(TRUE); } -void RedrawGameButtonsOnTape() +void RedrawGameButtonsOnTape(void) { RedrawGameButtonsExt(TRUE); } -void GameUndoRedoExt() +static void GameUndoRedoExt(void) { ClearPlayerAction(); @@ -15714,7 +15686,7 @@ void GameUndoRedoExt() BackToFront(); } -void GameUndo(int steps) +static void GameUndo(int steps) { if (!CheckEngineSnapshotList()) return; @@ -15724,7 +15696,7 @@ void GameUndo(int steps) GameUndoRedoExt(); } -void GameRedo(int steps) +static void GameRedo(int steps) { if (!CheckEngineSnapshotList()) return;