X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=207be5f457a86e581b913aa095390bc803cc2381;hb=6e9374af7b69e20dbab5b8b3e06a8d4e2ffb1ddd;hp=0659bd04c273b6c7dab7c7405c6870004c92b20f;hpb=b1f42b6eb7bfa63765e34366a2fd51ed9dd0be86;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 0659bd04..207be5f4 100644 --- a/src/game.c +++ b/src/game.c @@ -59,6 +59,8 @@ #define USE_FIX_KILLED_BY_NON_WALKABLE (USE_NEW_STUFF * 1) #define USE_FIX_IMPACT_COLLISION (USE_NEW_STUFF * 1) +#define USE_GFX_RESET_WHEN_NOT_MOVING (USE_NEW_STUFF * 1) + /* for DigField() */ #define DF_NO_PUSH 0 @@ -86,7 +88,8 @@ #define EX_TYPE_SINGLE_TILE (EX_TYPE_CENTER | EX_TYPE_BORDER) #if 1 -#define PANEL_DEACTIVATED(p) ((p)->x < 0 || (p)->y < 0) +#define PANEL_OFF() (local_player->LevelSolved_PanelOff) +#define PANEL_DEACTIVATED(p) ((p)->x < 0 || (p)->y < 0 || PANEL_OFF()) #define PANEL_XPOS(p) (DX + ALIGNED_MENU_XPOS(p)) #define PANEL_YPOS(p) (DY + ALIGNED_MENU_YPOS(p)) #else @@ -939,58 +942,7 @@ void GetPlayerConfig() InitJoysticks(); } -static int getBeltNrFromBeltElement(int element) -{ - return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 : - element < EL_CONVEYOR_BELT_3_LEFT ? 1 : - element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3); -} - -static int getBeltNrFromBeltActiveElement(int element) -{ - return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 : - element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 : - element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3); -} - -static int getBeltNrFromBeltSwitchElement(int element) -{ - return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 : - element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 : - element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3); -} - -static int getBeltDirNrFromBeltSwitchElement(int element) -{ - static int belt_base_element[4] = - { - EL_CONVEYOR_BELT_1_SWITCH_LEFT, - EL_CONVEYOR_BELT_2_SWITCH_LEFT, - EL_CONVEYOR_BELT_3_SWITCH_LEFT, - EL_CONVEYOR_BELT_4_SWITCH_LEFT - }; - - int belt_nr = getBeltNrFromBeltSwitchElement(element); - int belt_dir_nr = element - belt_base_element[belt_nr]; - - return (belt_dir_nr % 3); -} - -static int getBeltDirFromBeltSwitchElement(int element) -{ - static int belt_move_dir[3] = - { - MV_LEFT, - MV_NONE, - MV_RIGHT - }; - - int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element); - - return belt_move_dir[belt_dir_nr]; -} - -static int get_element_from_group_element(int element) +int GetElementFromGroupElement(int element) { if (IS_GROUP_ELEMENT(element)) { @@ -1288,7 +1240,7 @@ static void InitField(int x, int y, boolean init_game) } else if (IS_GROUP_ELEMENT(element)) { - Feld[x][y] = get_element_from_group_element(element); + Feld[x][y] = GetElementFromGroupElement(element); InitField(x, y, init_game); } @@ -1338,14 +1290,14 @@ void DrawGameValue_Emeralds(int value) struct TextPosInfo *pos = &game.panel.gems; int font_nr = FONT_TEXT_2; int font_width = getFontWidth(font_nr); - int digits = pos->chars; + int chars = pos->chars; if (PANEL_DEACTIVATED(pos)) return; - pos->width = digits * font_width; + pos->width = chars * font_width; - DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, digits), font_nr); + DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); } void DrawGameValue_Dynamite(int value) @@ -1353,14 +1305,14 @@ void DrawGameValue_Dynamite(int value) struct TextPosInfo *pos = &game.panel.inventory; int font_nr = FONT_TEXT_2; int font_width = getFontWidth(font_nr); - int digits = pos->chars; + int chars = pos->chars; if (PANEL_DEACTIVATED(pos)) return; - pos->width = digits * font_width; + pos->width = chars * font_width; - DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, digits), font_nr); + DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); } void DrawGameValue_Score(int value) @@ -1368,42 +1320,42 @@ void DrawGameValue_Score(int value) struct TextPosInfo *pos = &game.panel.score; int font_nr = FONT_TEXT_2; int font_width = getFontWidth(font_nr); - int digits = pos->chars; + int chars = pos->chars; if (PANEL_DEACTIVATED(pos)) return; - pos->width = digits * font_width; + pos->width = chars * font_width; - DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, digits), font_nr); + DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); } void DrawGameValue_Time(int value) { struct TextPosInfo *pos = &game.panel.time; static int last_value = -1; - int digits1 = 3; - int digits2 = 4; - int digits = pos->chars; + int chars1 = 3; + int chars2 = 4; + int chars = pos->chars; int font1_nr = FONT_TEXT_2; int font2_nr = FONT_TEXT_1; int font_nr = font1_nr; - boolean use_dynamic_digits = (digits == -1 ? TRUE : FALSE); + boolean use_dynamic_chars = (chars == -1 ? TRUE : FALSE); if (PANEL_DEACTIVATED(pos)) return; - if (use_dynamic_digits) /* use dynamic number of digits */ + if (use_dynamic_chars) /* use dynamic number of chars */ { - digits = (value < 1000 ? digits1 : digits2); + chars = (value < 1000 ? chars1 : chars2); font_nr = (value < 1000 ? font1_nr : font2_nr); } - /* clear background if value just changed its size (dynamic digits only) */ - if (use_dynamic_digits && (last_value < 1000) != (value < 1000)) + /* clear background if value just changed its size (dynamic chars only) */ + if (use_dynamic_chars && (last_value < 1000) != (value < 1000)) { - int width1 = digits1 * getFontWidth(font1_nr); - int width2 = digits2 * getFontWidth(font2_nr); + int width1 = chars1 * getFontWidth(font1_nr); + int width2 = chars2 * getFontWidth(font2_nr); int max_width = MAX(width1, width2); int max_height = MAX(getFontHeight(font1_nr), getFontHeight(font2_nr)); @@ -1413,9 +1365,9 @@ void DrawGameValue_Time(int value) max_width, max_height); } - pos->width = digits * getFontWidth(font_nr); + pos->width = chars * getFontWidth(font_nr); - DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, digits), font_nr); + DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); last_value = value; } @@ -1423,26 +1375,26 @@ void DrawGameValue_Time(int value) void DrawGameValue_Level(int value) { struct TextPosInfo *pos = &game.panel.level; - int digits1 = 2; - int digits2 = 3; - int digits = pos->chars; + int chars1 = 2; + int chars2 = 3; + int chars = pos->chars; int font1_nr = FONT_TEXT_2; int font2_nr = FONT_TEXT_1; int font_nr = font1_nr; - boolean use_dynamic_digits = (digits == -1 ? TRUE : FALSE); + boolean use_dynamic_chars = (chars == -1 ? TRUE : FALSE); if (PANEL_DEACTIVATED(pos)) return; - if (use_dynamic_digits) /* use dynamic number of digits */ + if (use_dynamic_chars) /* use dynamic number of chars */ { - digits = (level_nr < 100 ? digits1 : digits2); + chars = (level_nr < 100 ? chars1 : chars2); font_nr = (level_nr < 100 ? font1_nr : font2_nr); } - pos->width = digits * getFontWidth(font_nr); + pos->width = chars * getFontWidth(font_nr); - DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, digits), font_nr); + DrawText(PANEL_XPOS(pos), PANEL_YPOS(pos), int2str(value, chars), font_nr); } void DrawGameValue_Keys(int key[MAX_NUM_KEYS]) @@ -2242,7 +2194,9 @@ void InitGame() 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; } @@ -2974,10 +2928,12 @@ void GameWon() { static int time, time_final; static int score, score_final; - static int game_over_delay = 0; - int game_over_delay_value = 50; + static int game_over_delay_1 = 0; + static int game_over_delay_2 = 0; + int game_over_delay_value_1 = 50; + int game_over_delay_value_2 = 50; - if (!local_player->LevelSolved_GameEnd) + if (!local_player->LevelSolved_GameWon) { int i; @@ -2985,7 +2941,7 @@ void GameWon() if (local_player->MovPos) return; - local_player->LevelSolved_GameEnd = TRUE; + local_player->LevelSolved_GameWon = TRUE; local_player->LevelSolved_SaveTape = tape.recording; local_player->LevelSolved_SaveScore = !tape.playing; @@ -2996,7 +2952,8 @@ void GameWon() TapeStop(); #endif - game_over_delay = game_over_delay_value; + game_over_delay_1 = game_over_delay_value_1; + game_over_delay_2 = game_over_delay_value_2; time = time_final = (level.time == 0 ? TimePlayed : TimeLeft); score = score_final = local_player->score_final; @@ -3078,9 +3035,9 @@ void GameWon() PlaySound(SND_GAME_WINNING); } - if (game_over_delay > 0) + if (game_over_delay_1 > 0) { - game_over_delay--; + game_over_delay_1--; return; } @@ -3103,7 +3060,22 @@ void GameWon() PlaySoundLoop(SND_GAME_LEVELTIME_BONUS); else PlaySound(SND_GAME_LEVELTIME_BONUS); + + return; } + + local_player->LevelSolved_PanelOff = TRUE; + + if (game_over_delay_2 > 0) + { + game_over_delay_2--; + + return; + } + +#if 1 + GameEnd(); +#endif } void GameEnd() @@ -3111,6 +3083,8 @@ void GameEnd() int hi_pos; boolean raise_level = FALSE; + local_player->LevelSolved_GameEnd = TRUE; + CloseDoor(DOOR_CLOSE_1); if (local_player->LevelSolved_SaveTape) @@ -3337,7 +3311,12 @@ void InitMovingField(int x, int y, int direction) /* check if element was/is moving or being moved before/after mode change */ #if 1 +#if 1 + is_moving_before = (WasJustMoving[x][y] != 0); +#else + /* (!!! this does not work -- WasJustMoving is NOT a boolean value !!!) */ is_moving_before = WasJustMoving[x][y]; +#endif #else is_moving_before = (getElementMoveStepsizeExt(x, y, MovDir[x][y]) != 0); #endif @@ -6882,6 +6861,17 @@ void ContinueMoving(int x, int y) if (ABS(MovPos[x][y]) < TILEX) { +#if 0 + int ee = Feld[x][y]; + int gg = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); + int ff = getGraphicAnimationFrame(gg, GfxFrame[x][y]); + + printf("::: %d.%d: moving %d ... [%d, %d, %d] [%d, %d, %d]\n", + x, y, ABS(MovPos[x][y]), + ee, gg, ff, + GfxAction[x][y], GfxDir[x][y], GfxFrame[x][y]); +#endif + DrawLevelField(x, y); return; /* element is still moving */ @@ -8742,7 +8732,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) static void CreateFieldExt(int x, int y, int element, boolean is_change) { int old_element = Feld[x][y]; - int new_element = get_element_from_group_element(element); + int new_element = GetElementFromGroupElement(element); int previous_move_direction = MovDir[x][y]; #if USE_NEW_CUSTOM_VALUE int last_ce_value = CustomValue[x][y]; @@ -9074,8 +9064,19 @@ static void HandleElementChange(int x, int y, int page) if (change->can_change) { - ResetGfxAnimation(x, y); - ResetRandomAnimationValue(x, y); +#if 1 + /* !!! not clear why graphic animation should be reset at all here !!! */ + /* !!! UPDATE: but is needed for correct Snake Bite tail animation !!! */ +#if USE_GFX_RESET_WHEN_NOT_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 (!IS_MOVING(x, y)) +#endif + { + ResetGfxAnimation(x, y); + ResetRandomAnimationValue(x, y); + } +#endif if (change->pre_change_function) change->pre_change_function(x, y); @@ -9870,7 +9871,7 @@ void GameActions() AllPlayersGone = TRUE; } - if (local_player->LevelSolved) + if (local_player->LevelSolved && !local_player->LevelSolved_GameEnd) GameWon(); if (AllPlayersGone && !TAPE_IS_STOPPED(tape)) @@ -10107,13 +10108,15 @@ void GameActions_RND() /* continue moving after pushing (this is actually a bug) */ if (!IS_MOVING(x, y)) - { Stop[x][y] = FALSE; - } } } } +#if 0 + debug_print_timestamp(0, "start main loop profiling"); +#endif + SCAN_PLAYFIELD(x, y) { ChangeCount[x][y] = 0; @@ -10188,6 +10191,63 @@ void GameActions_RND() #endif } +#if 0 + debug_print_timestamp(0, "- time for pre-main loop:"); +#endif + +#if 0 // -------------------- !!! TEST ONLY !!! -------------------- + SCAN_PLAYFIELD(x, y) + { + element = Feld[x][y]; + graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); + +#if 1 + { +#if 1 + int element2 = element; + int graphic2 = graphic; +#else + int element2 = Feld[x][y]; + int graphic2 = el_act_dir2img(element2, GfxAction[x][y], GfxDir[x][y]); +#endif + int last_gfx_frame = GfxFrame[x][y]; + + if (graphic_info[graphic2].anim_global_sync) + GfxFrame[x][y] = FrameCounter; + else if (ANIM_MODE(graphic2) == ANIM_CE_VALUE) + GfxFrame[x][y] = CustomValue[x][y]; + else if (ANIM_MODE(graphic2) == ANIM_CE_SCORE) + GfxFrame[x][y] = element_info[element2].collect_score; + else if (ANIM_MODE(graphic2) == ANIM_CE_DELAY) + GfxFrame[x][y] = ChangeDelay[x][y]; + + if (redraw && GfxFrame[x][y] != last_gfx_frame) + DrawLevelGraphicAnimation(x, y, graphic2); + } +#else + ResetGfxFrame(x, y, TRUE); +#endif + +#if 1 + if (ANIM_MODE(graphic) == ANIM_RANDOM && + IS_NEXT_FRAME(GfxFrame[x][y], graphic)) + ResetRandomAnimationValue(x, y); +#endif + +#if 1 + SetRandomAnimationValue(x, y); +#endif + +#if 1 + PlayLevelSoundActionIfLoop(x, y, GfxAction[x][y]); +#endif + } +#endif // -------------------- !!! TEST ONLY !!! -------------------- + +#if 0 + debug_print_timestamp(0, "- time for TEST loop: -->"); +#endif + SCAN_PLAYFIELD(x, y) { element = Feld[x][y]; @@ -10231,6 +10291,143 @@ void GameActions_RND() graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); } +#if 0 // --------------------------------------------------------------------- + + if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element))) + { + StartMoving(x, y); + + element = Feld[x][y]; + graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); + + if (IS_ANIMATED(graphic) && + !IS_MOVING(x, y) && + !Stop[x][y]) + DrawLevelGraphicAnimationIfNeeded(x, y, graphic); + + if (IS_GEM(element) || element == EL_SP_INFOTRON) + DrawTwinkleOnField(x, y); + } + else if (IS_MOVING(x, y)) + ContinueMoving(x, y); + else + { + switch (element) + { + case EL_ACID: + case EL_EXIT_OPEN: + case EL_EM_EXIT_OPEN: + case EL_SP_EXIT_OPEN: + case EL_STEEL_EXIT_OPEN: + case EL_EM_STEEL_EXIT_OPEN: + case EL_SP_TERMINAL: + case EL_SP_TERMINAL_ACTIVE: + case EL_EXTRA_TIME: + case EL_SHIELD_NORMAL: + case EL_SHIELD_DEADLY: + if (IS_ANIMATED(graphic)) + DrawLevelGraphicAnimationIfNeeded(x, y, graphic); + break; + + case EL_DYNAMITE_ACTIVE: + case EL_EM_DYNAMITE_ACTIVE: + case EL_DYNABOMB_PLAYER_1_ACTIVE: + case EL_DYNABOMB_PLAYER_2_ACTIVE: + case EL_DYNABOMB_PLAYER_3_ACTIVE: + case EL_DYNABOMB_PLAYER_4_ACTIVE: + case EL_SP_DISK_RED_ACTIVE: + CheckDynamite(x, y); + break; + + case EL_AMOEBA_GROWING: + AmoebeWaechst(x, y); + break; + + case EL_AMOEBA_SHRINKING: + AmoebaDisappearing(x, y); + break; + +#if !USE_NEW_AMOEBA_CODE + case EL_AMOEBA_WET: + case EL_AMOEBA_DRY: + case EL_AMOEBA_FULL: + case EL_BD_AMOEBA: + case EL_EMC_DRIPPER: + AmoebeAbleger(x, y); + break; +#endif + + case EL_GAME_OF_LIFE: + case EL_BIOMAZE: + Life(x, y); + break; + + case EL_EXIT_CLOSED: + CheckExit(x, y); + break; + + case EL_EM_EXIT_CLOSED: + CheckExitEM(x, y); + break; + + case EL_STEEL_EXIT_CLOSED: + CheckExitSteel(x, y); + break; + + case EL_EM_STEEL_EXIT_CLOSED: + CheckExitSteelEM(x, y); + break; + + case EL_SP_EXIT_CLOSED: + CheckExitSP(x, y); + break; + + case EL_EXPANDABLE_WALL_GROWING: + case EL_EXPANDABLE_STEELWALL_GROWING: + MauerWaechst(x, y); + break; + + case EL_EXPANDABLE_WALL: + case EL_EXPANDABLE_WALL_HORIZONTAL: + case EL_EXPANDABLE_WALL_VERTICAL: + case EL_EXPANDABLE_WALL_ANY: + case EL_BD_EXPANDABLE_WALL: + MauerAbleger(x, y); + break; + + case EL_EXPANDABLE_STEELWALL_HORIZONTAL: + case EL_EXPANDABLE_STEELWALL_VERTICAL: + case EL_EXPANDABLE_STEELWALL_ANY: + MauerAblegerStahl(x, y); + break; + + case EL_FLAMES: + CheckForDragon(x, y); + break; + + case EL_EXPLOSION: + break; + + case EL_ELEMENT_SNAPPING: + case EL_DIAGONAL_SHRINKING: + case EL_DIAGONAL_GROWING: + { + graphic = + el_act_dir2img(GfxElement[x][y], GfxAction[x][y],GfxDir[x][y]); + + DrawLevelGraphicAnimationIfNeeded(x, y, graphic); + break; + } + + default: + if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y)) + DrawLevelGraphicAnimationIfNeeded(x, y, graphic); + break; + } + } + +#else // --------------------------------------------------------------------- + if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element))) { StartMoving(x, y); @@ -10313,6 +10510,8 @@ void GameActions_RND() else if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); +#endif // --------------------------------------------------------------------- + if (IS_BELT_ACTIVE(element)) PlayLevelSoundAction(x, y, ACTION_ACTIVE); @@ -10338,6 +10537,10 @@ void GameActions_RND() } } +#if 0 + debug_print_timestamp(0, "- time for MAIN loop: -->"); +#endif + #if USE_NEW_AMOEBA_CODE /* new experimental amoeba growth stuff */ if (!(FrameCounter % 8)) @@ -10521,6 +10724,11 @@ void GameActions_RND() local_player->show_envelope = 0; } +#if 0 + debug_print_timestamp(0, "stop main loop profiling "); + printf("----------------------------------------------------------\n"); +#endif + /* use random number generator in every frame to make it less predictable */ if (game.engine_version >= VERSION_IDENT(3,1,1,0)) RND(1); @@ -10575,14 +10783,19 @@ void ScrollLevel(int dx, int dy) int i, x, y; #endif +#if 0 + /* !!! THIS IS APPARENTLY WRONG FOR PLAYER RELOCATION !!! */ /* only horizontal XOR vertical scroll direction allowed */ if ((dx == 0 && dy == 0) || (dx != 0 && dy != 0)) return; +#endif #if 1 if (bitmap_db_field2 == NULL) bitmap_db_field2 = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH); + /* needed when blitting directly to same bitmap -- should not be needed with + recent SDL libraries, but apparently does not work in 1.2.11 directly */ BlitBitmap(drawto_field, bitmap_db_field2, FX + TILEX * (dx == -1) - softscroll_offset, FY + TILEY * (dy == -1) - softscroll_offset, @@ -10601,6 +10814,7 @@ void ScrollLevel(int dx, int dy) #else #if 1 + /* !!! DOES NOT WORK FOR DIAGONAL PLAYER RELOCATION !!! */ int xsize = (BX2 - BX1 + 1); int ysize = (BY2 - BY1 + 1); int start = (dx != 0 ? (dx == -1 ? BX1 : BX2) : (dy == -1 ? BY1 : BY2)); @@ -13536,9 +13750,9 @@ static void LoadEngineSnapshotValues_RND() if (game.num_random_calls != num_random_calls) { - Error(ERR_RETURN, "number of random calls out of sync"); - Error(ERR_RETURN, "number of random calls should be %d", num_random_calls); - Error(ERR_RETURN, "number of random calls is %d", game.num_random_calls); + Error(ERR_INFO, "number of random calls out of sync"); + Error(ERR_INFO, "number of random calls should be %d", num_random_calls); + Error(ERR_INFO, "number of random calls is %d", game.num_random_calls); Error(ERR_EXIT, "this should not happen -- please debug"); } }