X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fgame.c;h=4e4c901c990286248b043614b2716d243a3d822e;hp=2b4c7c0d02b75cf1a5453c9d2c83c24057d7fa79;hb=c0c5862d9ee59c70412b1c35e558101b109a8ec9;hpb=6e392e90d99cc0b6d8af3a15fc334bf34f889994 diff --git a/src/game.c b/src/game.c index 2b4c7c0d..4e4c901c 100644 --- a/src/game.c +++ b/src/game.c @@ -49,6 +49,12 @@ #define USE_QUICKSAND_IMPACT_BUGFIX (USE_NEW_STUFF * 0) +#define USE_CODE_THAT_BREAKS_SNAKE_BITE (USE_NEW_STUFF * 1) + +#define USE_UFAST_PLAYER_EXIT_BUGFIX (USE_NEW_STUFF * 1) +#define USE_NEW_GAME_WON (USE_NEW_STUFF * 1) + + /* for DigField() */ #define DF_NO_PUSH 0 #define DF_DIG 1 @@ -74,6 +80,28 @@ #define EX_TYPE_DYNA (1 << 4) #define EX_TYPE_SINGLE_TILE (EX_TYPE_CENTER | EX_TYPE_BORDER) +#if 1 + +#define PANEL_DEACTIVATED(p) ((p).x < 0 || (p).y < 0) + +/* special positions in the game control window (relative to control window) */ +#define XX_LEVEL1 (game.panel.level.x) +#define XX_LEVEL2 (game.panel.level.x - 1) +#define YY_LEVEL (game.panel.level.y) +#define XX_EMERALDS (game.panel.gems.x) +#define YY_EMERALDS (game.panel.gems.y) +#define XX_DYNAMITE (game.panel.inventory.x) +#define YY_DYNAMITE (game.panel.inventory.y) +#define XX_KEYS (game.panel.keys.x) +#define YY_KEYS (game.panel.keys.y) +#define XX_SCORE (game.panel.score.x) +#define YY_SCORE (game.panel.score.y) +#define XX_TIME1 (game.panel.time.x) +#define XX_TIME2 (game.panel.time.x + 1) +#define YY_TIME (game.panel.time.y) + +#else + /* special positions in the game control window (relative to control window) */ #define XX_LEVEL 37 #define YY_LEVEL 20 @@ -89,8 +117,11 @@ #define XX_TIME2 30 #define YY_TIME 194 +#endif + /* special positions in the game control window (relative to main window) */ -#define DX_LEVEL (DX + XX_LEVEL) +#define DX_LEVEL1 (DX + XX_LEVEL1) +#define DX_LEVEL2 (DX + XX_LEVEL2) #define DY_LEVEL (DY + YY_LEVEL) #define DX_EMERALDS (DX + XX_EMERALDS) #define DY_EMERALDS (DY + YY_EMERALDS) @@ -164,13 +195,21 @@ ((e) >= NUM_FILE_ELEMENTS ? EL_UNKNOWN : (e)) #endif -#define GET_TARGET_ELEMENT(e, ch, cv, cs) \ +#define RESOLVED_REFERENCE_ELEMENT(be, e) \ + ((be) + (e) - EL_SELF < EL_CUSTOM_START ? EL_CUSTOM_START : \ + (be) + (e) - EL_SELF > EL_CUSTOM_END ? EL_CUSTOM_END : \ + (be) + (e) - EL_SELF) + +#define GET_TARGET_ELEMENT(be, e, ch, cv, cs) \ ((e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : \ (e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \ (e) == EL_TRIGGER_CE_VALUE ? (ch)->actual_trigger_ce_value : \ (e) == EL_TRIGGER_CE_SCORE ? (ch)->actual_trigger_ce_score : \ (e) == EL_CURRENT_CE_VALUE ? (cv) : \ - (e) == EL_CURRENT_CE_SCORE ? (cs) : (e)) + (e) == EL_CURRENT_CE_SCORE ? (cs) : \ + (e) >= EL_LAST_CE_8 && (e) <= EL_NEXT_CE_8 ? \ + RESOLVED_REFERENCE_ELEMENT(be, e) : \ + (e)) #define CAN_GROW_INTO(e) \ ((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable)) @@ -1198,6 +1237,7 @@ static void InitField(int x, int y, boolean init_game) InitField(x, y, init_game); #endif } + break; } @@ -1256,6 +1296,9 @@ inline void DrawGameValue_Emeralds(int value) { int xpos = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2; + if (PANEL_DEACTIVATED(game.panel.gems)) + return; + DrawText(DX_EMERALDS + xpos, DY_EMERALDS, int2str(value, 3), FONT_TEXT_2); } @@ -1263,6 +1306,9 @@ inline void DrawGameValue_Dynamite(int value) { int xpos = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2; + if (PANEL_DEACTIVATED(game.panel.inventory)) + return; + DrawText(DX_DYNAMITE + xpos, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2); } @@ -1271,19 +1317,23 @@ inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) int base_key_graphic = EL_KEY_1; int i; + if (PANEL_DEACTIVATED(game.panel.keys)) + return; + if (level.game_engine_type == GAME_ENGINE_TYPE_EM) base_key_graphic = EL_EM_KEY_1; /* currently only 4 of 8 possible keys are displayed */ for (i = 0; i < STD_NUM_KEYS; i++) { + int x = XX_KEYS + i * MINI_TILEX; + int y = YY_KEYS; + if (key[i]) - DrawMiniGraphicExt(drawto, DX_KEYS + i * MINI_TILEX, DY_KEYS, - el2edimg(base_key_graphic + i)); + DrawMiniGraphicExt(drawto, DX + x,DY + y, el2edimg(base_key_graphic + i)); else BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, - DOOR_GFX_PAGEX5 + XX_KEYS + i * MINI_TILEX, YY_KEYS, - MINI_TILEX, MINI_TILEY, DX_KEYS + i * MINI_TILEX, DY_KEYS); + DOOR_GFX_PAGEX5 + x, y, MINI_TILEX, MINI_TILEY, DX + x,DY + y); } } @@ -1291,6 +1341,9 @@ inline void DrawGameValue_Score(int value) { int xpos = (5 * 14 - 5 * getFontWidth(FONT_TEXT_2)) / 2; + if (PANEL_DEACTIVATED(game.panel.score)) + return; + DrawText(DX_SCORE + xpos, DY_SCORE, int2str(value, 5), FONT_TEXT_2); } @@ -1299,9 +1352,12 @@ inline void DrawGameValue_Time(int value) int xpos3 = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2; int xpos4 = (4 * 10 - 4 * getFontWidth(FONT_LEVEL_NUMBER)) / 2; + if (PANEL_DEACTIVATED(game.panel.time)) + return; + /* clear background if value just changed its size */ if (value == 999 || value == 1000) - ClearRectangle(drawto, DX_TIME1, DY_TIME, 14 * 3, 14); + ClearRectangleOnBackground(drawto, DX_TIME1, DY_TIME, 14 * 3, 14); if (value < 1000) DrawText(DX_TIME1 + xpos3, DY_TIME, int2str(value, 3), FONT_TEXT_2); @@ -1311,9 +1367,15 @@ inline void DrawGameValue_Time(int value) inline void DrawGameValue_Level(int value) { + if (PANEL_DEACTIVATED(game.panel.level)) + return; + if (level_nr < 100) - DrawText(DX_LEVEL, DY_LEVEL, int2str(value, 2), FONT_TEXT_2); + DrawText(DX_LEVEL1, DY_LEVEL, int2str(value, 2), FONT_TEXT_2); else +#if 1 + DrawText(DX_LEVEL2, DY_LEVEL, int2str(value, 3), FONT_LEVEL_NUMBER); +#else { /* misuse area for displaying emeralds to draw bigger level number */ DrawTextExt(drawto, DX_EMERALDS, DY_EMERALDS, @@ -1331,6 +1393,7 @@ inline void DrawGameValue_Level(int value) /* yes, this is all really ugly :-) */ } +#endif } void DrawAllGameValues(int emeralds, int dynamite, int score, int time, @@ -1354,6 +1417,7 @@ void DrawAllGameValues(int emeralds, int dynamite, int score, int time, void DrawGameDoorValues() { + int time_value = (level.time == 0 ? TimePlayed : TimeLeft); int dynamite_state = 0; int key_bits = 0; int i, j; @@ -1402,7 +1466,7 @@ void DrawGameDoorValues() } DrawAllGameValues(local_player->gems_still_needed, dynamite_state, - local_player->score, TimeLeft, key_bits); + local_player->score, time_value, key_bits); #endif } @@ -1452,6 +1516,18 @@ static void resolve_group_element(int group_element, int recursion_depth) } #endif +#if 0 +static void replace_reference_element(int base_element, int *element) +{ + if (*element >= EL_LAST_CE_8 && *element <= EL_NEXT_CE_8) + { + *element = base_element + *element - EL_SELF; + *element = (*element < EL_CUSTOM_START ? EL_CUSTOM_START : + *element > EL_CUSTOM_END ? EL_CUSTOM_END : *element); + } +} +#endif + /* ============================================================================= InitGameEngine() @@ -1754,6 +1830,11 @@ static void InitGameEngine() for (l = 0; l < group->num_elements_resolved; l++) trigger_events[group->element_resolved[l]][k] = TRUE; } +#if 1 + else if (trigger_element == EL_ANY_ELEMENT) + for (l = 0; l < MAX_NUM_ELEMENTS; l++) + trigger_events[l][k] = TRUE; +#endif else trigger_events[trigger_element][k] = TRUE; } @@ -1891,6 +1972,29 @@ static void InitGameEngine() EL_EMPTY); } } + +#if 0 + /* ---------- initialize reference elements ------------------------------- */ + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + struct ElementInfo *ei = &element_info[element]; + + for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) + replace_reference_element(element, &ei->content.e[x][y]); + + for (j = 0; j < ei->num_change_pages; j++) + { + struct ElementChangeInfo *change = &ei->change_page[j]; + + replace_reference_element(element, &change->target_element); + replace_reference_element(element, &change->trigger_element); + + for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) + replace_reference_element(element, &change->target_content.e[x][y]); + } + } +#endif } int get_num_special_action(int element, int action_first, int action_last) @@ -1933,8 +2037,11 @@ void InitGame() 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 do_fading = (game_status == GAME_MODE_MAIN); int i, j, x, y; + game_status = GAME_MODE_PLAYING; + InitGameEngine(); /* don't play tapes over network */ @@ -2076,6 +2183,10 @@ void InitGame() player->LevelSolved = FALSE; player->GameOver = FALSE; + + player->LevelSolved_GameEnd = FALSE; + player->LevelSolved_SaveTape = FALSE; + player->LevelSolved_SaveScore = FALSE; } network_player_action_received = FALSE; @@ -2521,9 +2632,14 @@ void InitGame() local_player->jy - MIDPOSY); } + StopAnimation(); + if (!game.restart_level) CloseDoor(DOOR_CLOSE_1); + if (do_fading) + FadeOut(REDRAW_FIELD); + /* !!! FIX THIS (START) !!! */ if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { @@ -2542,10 +2658,16 @@ void InitGame() BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY); redraw_mask |= REDRAW_FROM_BACKBUFFER; + +#if 0 FadeToFront(); +#endif } /* !!! FIX THIS (END) !!! */ + if (do_fading) + FadeIn(REDRAW_FIELD); + if (!game.restart_level) { /* copy default game door content to main double buffer */ @@ -2553,6 +2675,11 @@ void InitGame() DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); } +#if 1 + SetPanelBackground(); + SetDrawBackgroundMask(REDRAW_DOOR_1); +#endif + DrawGameDoorValues(); if (!game.restart_level) @@ -2796,6 +2923,194 @@ void InitAmoebaNr(int x, int y) AmoebaCnt2[group_nr]++; } +#if USE_NEW_GAME_WON + +void GameWon() +{ + static boolean score_done = FALSE; + static boolean player_done = FALSE; + static int game_over_delay = 0; + int game_over_delay_value = 50; + + /* do not start end game actions before the player stops moving (to exit) */ + if (local_player->MovPos) + return; + + if (tape.auto_play) /* tape might already be stopped here */ + tape.auto_play_level_solved = TRUE; + + if (!local_player->LevelSolved_GameEnd) + { + local_player->LevelSolved_GameEnd = TRUE; + local_player->LevelSolved_SaveTape = tape.recording; + local_player->LevelSolved_SaveScore = !tape.playing; + + score_done = FALSE; + player_done = FALSE; + game_over_delay = 0; + } + + PlaySoundStereo(SND_GAME_WINNING, SOUND_MIDDLE); + + if (TimeLeft > 0) + { + if (!tape.playing) + { + if (setup.sound_loops) + PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MIDDLE, + SND_CTRL_PLAY_LOOP); + else + PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MIDDLE); + } + + if (TimeLeft > 100 && TimeLeft % 10 == 0) + { + TimeLeft -= 10; + RaiseScore(level.score[SC_TIME_BONUS] * 10); + } + else + { + TimeLeft--; + RaiseScore(level.score[SC_TIME_BONUS]); + } + + DrawGameValue_Time(TimeLeft); + +#if 0 + if (!tape.playing) + Delay(10); +#endif + + if (TimeLeft <= 0 && !tape.playing && setup.sound_loops) + StopSound(SND_GAME_LEVELTIME_BONUS); + } + else if (level.time == 0 && TimePlayed < 999) /* level without time limit */ + { + if (!tape.playing) + { + if (setup.sound_loops) + PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MIDDLE, + SND_CTRL_PLAY_LOOP); + else + PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MIDDLE); + } + + if (TimePlayed < 900 && TimePlayed % 10 == 0) + { + TimePlayed += 10; + RaiseScore(level.score[SC_TIME_BONUS] * 10); + } + else + { + TimePlayed++; + RaiseScore(level.score[SC_TIME_BONUS]); + } + + DrawGameValue_Time(TimePlayed); + + if (TimePlayed >= 999 && !tape.playing && setup.sound_loops) + StopSound(SND_GAME_LEVELTIME_BONUS); + } + else + { + score_done = TRUE; + } + + /* close exit door after last player */ + if (AllPlayersGone && ExitX >= 0 && ExitY >= 0 && + (Feld[ExitX][ExitY] == EL_EXIT_OPEN || + Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN)) + { + int element = Feld[ExitX][ExitY]; + + Feld[ExitX][ExitY] = (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING : + EL_SP_EXIT_CLOSING); + + PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING); + } + + /* player disappears */ + if (ExitX >= 0 && ExitY >= 0 && !player_done) + { + DrawLevelField(ExitX, ExitY); + + player_done = TRUE; + } + + game_over_delay++; + + if (game_over_delay < game_over_delay_value || !score_done) + return; +} + +void GameEnd() +{ + int hi_pos; + boolean raise_level = FALSE; + + CloseDoor(DOOR_CLOSE_1); + + if (local_player->LevelSolved_SaveTape) + { + TapeStop(); + + SaveTape(tape.level_nr); /* Ask to save tape */ + } + + if (!local_player->LevelSolved_SaveScore) + { + FadeOut(REDRAW_FIELD); + + game_status = GAME_MODE_MAIN; + + DrawAndFadeInMainMenu(REDRAW_FIELD); + + return; + } + + if (level_nr == leveldir_current->handicap_level) + { + leveldir_current->handicap_level++; + SaveLevelSetup_SeriesInfo(); + } + + if (level_editor_test_game) + local_player->score = -1; /* no highscore when playing from editor */ + else if (level_nr < leveldir_current->last_level) + raise_level = TRUE; /* advance to next level */ + + if ((hi_pos = NewHiScore()) >= 0) + { + game_status = GAME_MODE_SCORES; + + DrawHallOfFame(hi_pos); + + if (raise_level) + { + level_nr++; + TapeErase(); + } + } + else + { + FadeOut(REDRAW_FIELD); + + game_status = GAME_MODE_MAIN; + + if (raise_level) + { + level_nr++; + TapeErase(); + } + + DrawAndFadeInMainMenu(REDRAW_FIELD); + } + + local_player->LevelSolved_SaveScore = FALSE; +} + +#else + void GameWon() { int hi_pos; @@ -2950,6 +3265,8 @@ void GameWon() BackToFront(); } +#endif + int NewHiScore() { int k, l; @@ -8484,7 +8801,12 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change) #endif boolean new_element_is_player = ELEM_IS_PLAYER(new_element); boolean add_player_onto_element = (new_element_is_player && +#if USE_CODE_THAT_BREAKS_SNAKE_BITE + /* this breaks SnakeBite when a snake is + halfway through a door that closes */ + /* NOW FIXED AT LEVEL INIT IN files.c */ new_element != EL_SOKOBAN_FIELD_PLAYER && +#endif IS_WALKABLE(old_element)); #if 0 @@ -8711,7 +9033,7 @@ static boolean ChangeElement(int x, int y, int element, int page) ChangeEvent[ex][ey] = ChangeEvent[x][y]; content_element = change->target_content.e[xx][yy]; - target_element = GET_TARGET_ELEMENT(content_element, change, + target_element = GET_TARGET_ELEMENT(element, content_element, change, ce_value, ce_score); CreateElementFromChange(ex, ey, target_element); @@ -8733,7 +9055,7 @@ static boolean ChangeElement(int x, int y, int element, int page) } else { - target_element = GET_TARGET_ELEMENT(change->target_element, change, + target_element = GET_TARGET_ELEMENT(element, change->target_element, change, ce_value, ce_score); if (element == EL_DIAGONAL_GROWING || @@ -9523,10 +9845,6 @@ void StartGameActions(boolean init_network_game, boolean record_tape, } #endif - StopAnimation(); - - game_status = GAME_MODE_PLAYING; - InitGame(); } @@ -10401,7 +10719,7 @@ static void CheckGravityMovement(struct PlayerInfo *player) { int move_dir_horizontal = player->effective_action & MV_HORIZONTAL; int move_dir_vertical = player->effective_action & MV_VERTICAL; - boolean player_is_snapping = player->effective_action & JOY_BUTTON_1; + boolean player_is_snapping = (player->effective_action & JOY_BUTTON_1); int jx = player->jx, jy = player->jy; boolean player_is_moving_to_valid_field = (!player_is_snapping && @@ -10556,7 +10874,14 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, PlayerVisit[jx][jy] = FrameCounter; +#if USE_UFAST_PLAYER_EXIT_BUGFIX + player->is_moving = TRUE; +#endif + +#if 1 + /* should better be called in MovePlayer(), but this breaks some tapes */ ScrollPlayer(player, SCROLL_INIT); +#endif return MP_MOVING; } @@ -10754,6 +11079,11 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) player->is_dropping = FALSE; player->is_dropping_pressed = FALSE; player->drop_pressed_delay = 0; + +#if 0 + /* should better be called here than above, but this breaks some tapes */ + ScrollPlayer(player, SCROLL_INIT); +#endif } else { @@ -13096,8 +13426,20 @@ void RequestQuitGame(boolean ask_if_really_quit) else #endif { - game_status = GAME_MODE_MAIN; - DrawMainMenu(); + if (!ask_if_really_quit || level_editor_test_game) + { + game_status = GAME_MODE_MAIN; + + DrawMainMenu(); + } + else + { + FadeOut(REDRAW_FIELD); + + game_status = GAME_MODE_MAIN; + + DrawAndFadeInMainMenu(REDRAW_FIELD); + } } } else