X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame.c;h=c51b7ece8e596108139c1ebc94670c66497faa6a;hp=de844f4298ca0351fcaceab4ce88082c9c8402c7;hb=6687b5314f1e08eb7364c0c5d753b96db18f6089;hpb=457e98ec0803cd9005a522018e7c255454d1e915 diff --git a/src/game.c b/src/game.c index de844f42..c51b7ece 100644 --- a/src/game.c +++ b/src/game.c @@ -1002,6 +1002,8 @@ 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)) +#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 @@ -1011,11 +1013,17 @@ 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 */ @@ -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,6 +1112,7 @@ void TestIfGoodThingGetsHitByBadThing(int, int, int); void KillPlayer(struct PlayerInfo *); void BuryPlayer(struct PlayerInfo *); void RemovePlayer(struct PlayerInfo *); +void RemovePlayerWithCleanup(struct PlayerInfo *); static int getInvisibleActiveFromInvisibleElement(int); static int getInvisibleFromInvisibleActiveElement(int); @@ -1723,7 +1732,7 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) 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; @@ -2205,8 +2214,11 @@ void UpdateGameControlValues() local_player->gems_still_needed > 0 || local_player->sokobanfields_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 = (local_player->LevelSolved ? + local_player->LevelSolved_CountingHealth : + level.game_engine_type == GAME_ENGINE_TYPE_MM ? + MM_HEALTH(game_mm.laser_overload_value) : + local_player->health); UpdatePlayfieldElementCount(); @@ -2297,7 +2309,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; @@ -3262,6 +3274,36 @@ int get_num_special_action(int element, int action_first, int action_last) ============================================================================= */ +#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() { int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0); @@ -3287,29 +3329,30 @@ void InitGame() else FadeSetEnterScreen(); - if (CheckIfGlobalBorderHasChanged()) + if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged()) fade_mask = REDRAW_ALL; FadeLevelSoundsAndMusic(); ExpireSoundLoops(TRUE); - FadeOut(fade_mask); + if (!level_editor_test_game) + FadeOut(fade_mask); /* needed if different viewport properties defined for playing */ 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); + network_playing = (network.enabled && !tape.playing); for (i = 0; i < MAX_PLAYERS; i++) { @@ -3333,10 +3376,19 @@ 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->lights_still_needed = 0; @@ -3472,19 +3524,19 @@ void InitGame() player->LevelSolved_PanelOff = FALSE; player->LevelSolved_SaveTape = FALSE; player->LevelSolved_SaveScore = FALSE; + player->LevelSolved_CountingTime = 0; player->LevelSolved_CountingScore = 0; + player->LevelSolved_CountingHealth = 0; map_player_action[i] = i; } network_player_action_received = FALSE; -#if defined(NETWORK_AVALIABLE) /* initial null action */ if (network_playing) SendToServer_MovePlayer(MV_NONE); -#endif ZX = ZY = -1; ExitX = ExitY = -1; @@ -3522,18 +3574,6 @@ void InitGame() 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; - - 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; - } - for (i = 0; i < NUM_BELTS; i++) { game.belt_dir[i] = MV_NONE; @@ -3544,10 +3584,7 @@ void InitGame() 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) @@ -3661,22 +3698,33 @@ void InitGame() 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) + { + /* add team mode players connected over the network (needed for correct + assignment of player figures from level to locally playing players) */ + + for (i = 0; i < MAX_PLAYERS; i++) + if (stored_player[i].connected_network) + stored_player[i].connected = TRUE; + } + else if (game.team_mode) { /* try to guess locally connected team mode players (needed for correct assignment of player figures from level to locally playing players) */ @@ -3688,26 +3736,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, active == %d", - i + 1, - player->present, - player->connected, - player->active); - - if (local_player == player) - printf(" (local player)"); - - printf("\n"); - } - } + DebugPrintPlayerStatus("Player status after level initialization"); #endif #if DEBUG_INIT_PLAYER @@ -3794,26 +3823,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, 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 @@ -3861,6 +3871,18 @@ 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 */ @@ -3906,28 +3928,23 @@ 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; } } } @@ -3947,26 +3964,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) @@ -4155,10 +4153,6 @@ 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(); @@ -4167,34 +4161,10 @@ void InitGame() 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,11 +4181,20 @@ void InitGame() } game.restart_level = FALSE; + game.restart_game_message = NULL; 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, @@ -4446,20 +4425,28 @@ static void PlayerWins(struct PlayerInfo *player) level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.score : player->score); + player->health_final = (level.game_engine_type == GAME_ENGINE_TYPE_MM ? + MM_HEALTH(game_mm.laser_overload_value) : + player->health); player->LevelSolved_CountingTime = (game.no_time_limit ? TimePlayed : TimeLeft); player->LevelSolved_CountingScore = player->score_final; + player->LevelSolved_CountingHealth = player->health_final; } void GameWon() { + 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) { @@ -4485,24 +4472,42 @@ void GameWon() 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); - local_player->score_final = score_final; + game_over_delay_1 = game_over_delay_value_1; + + 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) { @@ -4574,7 +4579,9 @@ 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]; @@ -4597,8 +4604,6 @@ void GameWon() return; } - local_player->LevelSolved_PanelOff = TRUE; - if (game_over_delay_2 > 0) { game_over_delay_2--; @@ -4606,24 +4611,60 @@ 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]; + + local_player->LevelSolved_CountingHealth = health; + local_player->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; + } + + local_player->LevelSolved_PanelOff = TRUE; + + if (game_over_delay_3 > 0) + { + game_over_delay_3--; + + return; + } + GameEnd(); } void GameEnd() { int hi_pos; - boolean raise_level = FALSE; + int last_level_nr = level_nr; local_player->LevelSolved_GameEnd = TRUE; - if (!global.use_envelope_request) - CloseDoor(DOOR_CLOSE_1); - if (local_player->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) @@ -4653,35 +4694,39 @@ void GameEnd() if (setup.increment_levels && level_nr < leveldir_current->last_level) - raise_level = TRUE; /* advance to next level */ - - if ((hi_pos = NewHiScore()) >= 0) { - 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(); } } - else + + hi_pos = NewHiScore(last_level_nr); + + if (hi_pos >= 0 && !setup.skip_scores_after_game) { - SetGameStatus(GAME_MODE_MAIN); + SetGameStatus(GAME_MODE_SCORES); - if (raise_level) - { - level_nr++; - TapeErase(); - } + DrawHallOfFame(last_level_nr, hi_pos); + } + else if (!setup.auto_play_next_level || !setup.increment_levels) + { + SetGameStatus(GAME_MODE_MAIN); DrawMainMenu(); } + else + { + StartGameActions(network.enabled, setup.autorecord, level.random_seed); + } } -int NewHiScore() +int NewHiScore(int level_nr) { int k, l; int position = -1; @@ -9731,7 +9776,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]); + RemovePlayerWithCleanup(&stored_player[i]); + + if (AllPlayersGone) + PlayerWins(local_player); break; } @@ -10977,6 +11025,9 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) static void SetMouseActionFromTapeAction(struct MouseActionInfo *mouse_action, byte *tape_action) { + 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]; @@ -10985,6 +11036,9 @@ static void SetMouseActionFromTapeAction(struct MouseActionInfo *mouse_action, 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; @@ -11162,14 +11216,12 @@ 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_StartPlaying(); return; } -#endif InitGame(); } @@ -11205,7 +11257,7 @@ void GameActionsExt() } if (game.restart_level) - StartGameActions(options.network, setup.autorecord, level.random_seed); + StartGameActions(network.enabled, setup.autorecord, level.random_seed); /* !!! SAME CODE AS IN "CheckLevelTime()" -- FIX THIS !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) @@ -11292,10 +11344,8 @@ void GameActionsExt() { /* try to get network player actions in time */ -#if defined(NETWORK_AVALIABLE) /* last chance to get network player actions without main loop delay */ HandleNetworking(); -#endif /* game was quit by network peer */ if (game_status != GAME_MODE_PLAYING) @@ -11317,8 +11367,10 @@ void GameActionsExt() /* when playing tape, read previously recorded player input from tape data */ recorded_player_action = (tape.playing ? TapePlayAction() : NULL); + local_player->effective_mouse_action = local_player->mouse_action; + if (recorded_player_action != NULL) - SetMouseActionFromTapeAction(&local_player->mouse_action, + SetMouseActionFromTapeAction(&local_player->effective_mouse_action, recorded_player_action); /* TapePlayAction() may return NULL when toggling to "pause before death" */ @@ -11339,14 +11391,12 @@ void GameActionsExt() stored_player[i].effective_action = stored_player[i].action; } -#if defined(NETWORK_AVALIABLE) if (network_playing) 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; @@ -11377,7 +11427,8 @@ void GameActionsExt() tape.player_participates[i] = TRUE; } - SetTapeActionFromMouseAction(tape_action, &local_player->mouse_action); + SetTapeActionFromMouseAction(tape_action, + &local_player->effective_mouse_action); /* only record actions from input devices, but not programmed actions */ if (tape.recording) @@ -11537,7 +11588,7 @@ void GameActions_MM_Main() { 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() @@ -12255,7 +12306,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; @@ -12442,7 +12493,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; @@ -12594,12 +12645,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); + RemovePlayerWithCleanup(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 */ @@ -13355,6 +13406,12 @@ void RemovePlayer(struct PlayerInfo *player) ExitY = ZY = jy; } +void RemovePlayerWithCleanup(struct PlayerInfo *player) +{ + DrawPlayer(player); /* needed here only to cleanup last field */ + RemovePlayer(player); +} + static void setFieldForSnapping(int x, int y, int element, int direction) { struct ElementInfo *ei = &element_info[element]; @@ -14703,6 +14760,9 @@ void PlayLevelSound_MM(int xx, int yy, int element_mm, int action_mm) int x = xx - offset; int y = yy - offset; + if (!IS_MM_ELEMENT(element)) + element = EL_MM_DEFAULT; + PlayLevelSoundElementAction(x, y, element, action); } @@ -14833,11 +14893,9 @@ void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message) 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(); @@ -14868,6 +14926,22 @@ void RequestQuitGame(boolean ask_if_really_quit) "Do you really want to quit the game?"); } +void RequestRestartGame(char *message) +{ + game.restart_game_message = NULL; + + if (Request(message, REQ_ASK | REQ_STAY_CLOSED)) + { + StartGameActions(network.enabled, setup.autorecord, level.random_seed); + } + else + { + SetGameStatus(GAME_MODE_MAIN); + + DrawMainMenu(); + } +} + /* ------------------------------------------------------------------------- */ /* random generator functions */ @@ -15178,7 +15252,7 @@ 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(); } @@ -15222,52 +15296,95 @@ 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" } }; @@ -15277,14 +15394,17 @@ void CreateGameButtons() 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; @@ -15303,7 +15423,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) { @@ -15321,14 +15443,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), @@ -15385,6 +15506,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); } } @@ -15423,12 +15548,13 @@ void UnmapUndoRedoButtons() ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, FALSE, GDI_END); } -void MapGameButtons() +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]); @@ -15437,25 +15563,79 @@ void MapGameButtons() RedrawGameButtons(); } -void UnmapGameButtons() +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() +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 SetGadgetState(struct GadgetInfo *gi, boolean state) +{ + if (gi == NULL) + return; + + gi->checked = state; +} + +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() +{ + MapGameButtonsExt(FALSE); +} + +void UnmapGameButtons() +{ + UnmapGameButtonsExt(FALSE); +} + +void RedrawGameButtons() +{ + RedrawGameButtonsExt(FALSE); +} + +void MapGameButtonsOnTape() +{ + MapGameButtonsExt(TRUE); +} + +void UnmapGameButtonsOnTape() +{ + UnmapGameButtonsExt(TRUE); +} + +void RedrawGameButtonsOnTape() +{ + RedrawGameButtonsExt(TRUE); +} + void GameUndoRedoExt() { ClearPlayerAction(); @@ -15507,6 +15687,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; @@ -15519,14 +15700,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); @@ -15536,17 +15716,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; @@ -15579,6 +15758,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; @@ -15591,11 +15771,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) @@ -15604,9 +15789,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) @@ -15615,6 +15804,9 @@ static void HandleGameButtonsExt(int id, int button) SetAudioMode(setup.sound); } + + RedrawSoundButtonGadget(id); + break; default: @@ -15629,7 +15821,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)