X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=92a181bbc49ddeea03a43289e0991947c09a04dd;hb=3e71d06e9a97be7bb8c50c76717d08e5c46e0cc8;hp=8cbcc8ee4e3873a8011decd0c3b72f185d70e72d;hpb=c5d03f36989babf47697957101ecebe9b7b9cbe8;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 8cbcc8ee..92a181bb 100644 --- a/src/game.c +++ b/src/game.c @@ -38,6 +38,8 @@ #define USE_ONE_MORE_CHANGE_PER_FRAME (USE_NEW_STUFF * 1) #define USE_FIXED_DONT_RUN_INTO (USE_NEW_STUFF * 1) #define USE_NEW_SPRING_BUMPER (USE_NEW_STUFF * 1) +#define USE_STOP_CHANGED_ELEMENTS (USE_NEW_STUFF * 1) +#define USE_ELEMENT_TOUCHING_BUGFIX (USE_NEW_STUFF * 1) #define USE_QUICKSAND_IMPACT_BUGFIX (USE_NEW_STUFF * 0) @@ -141,9 +143,18 @@ #define GET_CE_DELAY_VALUE(c) ( ((c)->delay_fixed) + \ RND((c)->delay_random)) +#if 1 +#define GET_VALID_RUNTIME_ELEMENT(e) \ + ((e) >= NUM_RUNTIME_ELEMENTS ? EL_UNKNOWN : (e)) +#else +#define GET_VALID_FILE_ELEMENT(e) \ + ((e) >= NUM_FILE_ELEMENTS ? EL_UNKNOWN : (e)) +#endif + #define GET_TARGET_ELEMENT(e, ch) \ - ((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \ - (e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : (e)) + ((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)) #define CAN_GROW_INTO(e) \ ((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable)) @@ -182,6 +193,10 @@ #define ANDROID_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, Feld[x][y] == EL_EMC_PLANT) +#define ANDROID_CAN_CLONE_FIELD(x, y) \ + (IN_LEV_FIELD(x, y) && (CAN_BE_CLONED_BY_ANDROID(Feld[x][y]) || \ + CAN_BE_CLONED_BY_ANDROID(EL_TRIGGER_ELEMENT))) + #define ENEMY_CAN_ENTER_FIELD(e, x, y) \ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) @@ -213,13 +228,16 @@ (IN_LEV_FIELD(x, y) && (Feld[x][y] == EL_EMC_SPRING_BUMPER || \ Feld[x][y] == EL_EMC_SPRING_BUMPER_ACTIVE)) +#if 0 #define GROUP_NR(e) ((e) - EL_GROUP_START) -#define MOVE_ENTER_EL(e) (element_info[e].move_enter_element) #define IS_IN_GROUP(e, nr) (element_info[e].in_group[nr] == TRUE) #define IS_IN_GROUP_EL(e, ge) (IS_IN_GROUP(e, (ge) - EL_GROUP_START)) #define IS_EQUAL_OR_IN_GROUP(e, ge) \ (IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge)) +#endif + +#define MOVE_ENTER_EL(e) (element_info[e].move_enter_element) #define CE_ENTER_FIELD_COND(e, x, y) \ (!IS_PLAYER(x, y) && \ @@ -276,6 +294,8 @@ static void TestIfElementSmashesCustomElement(int, int, int); #endif static void HandleElementChange(int, int, int); +static void ExecuteCustomElementAction(int, int, int, int); +static boolean ChangeElement(int, int, int, int); static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int); #define CheckTriggeredElementChange(x, y, e, ev) \ @@ -333,7 +353,7 @@ static void RunTimegateWheel(int, int); static void InitMagicBallDelay(int, int); static void ActivateMagicBall(int, int); -static void InitAndroid(int, int); +static void InitDiagonalMovingElement(int, int); struct ChangingElementInfo { @@ -517,20 +537,20 @@ static struct ChangingElementInfo change_delay_list[] = NULL }, { - EL_EMC_ANDROID_SHRINKING, - EL_EMPTY, - 8, + EL_DIAGONAL_SHRINKING, + EL_UNDEFINED, + 0, NULL, NULL, NULL }, { - EL_EMC_ANDROID_GROWING, - EL_EMC_ANDROID, - 8, + EL_DIAGONAL_GROWING, + EL_UNDEFINED, + 0, NULL, NULL, - InitAndroid + InitDiagonalMovingElement }, { @@ -812,6 +832,9 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) else { stored_player[0].use_murphy = TRUE; + + if (!level.use_artwork_element[0]) + stored_player[0].artwork_element = EL_SP_MURPHY; } Feld[x][y] = EL_PLAYER_1; @@ -967,6 +990,10 @@ static void InitField(int x, int y, boolean init_game) MovDelay[x][y] = 96; break; + case EL_EM_DYNAMITE_ACTIVE: + MovDelay[x][y] = 32; + break; + case EL_LAMP: local_player->lights_still_needed++; break; @@ -1227,6 +1254,7 @@ void DrawGameDoorValues() DrawGameValue_Keys(stored_player[i].key); } +#if 0 static void resolve_group_element(int group_element, int recursion_depth) { static int group_nr; @@ -1270,7 +1298,7 @@ static void resolve_group_element(int group_element, int recursion_depth) } } } - +#endif /* ============================================================================= @@ -1402,6 +1430,7 @@ static void InitGameEngine() printf(" => game.engine_version == %06d\n", game.engine_version); #endif +#if 0 /* ---------- recursively resolve group elements ------------------------- */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) @@ -1410,6 +1439,7 @@ static void InitGameEngine() for (i = 0; i < NUM_GROUP_ELEMENTS; i++) resolve_group_element(EL_GROUP_START + i, 0); +#endif /* ---------- initialize player's initial move delay --------------------- */ @@ -1906,6 +1936,8 @@ void InitGame() game.envelope_active = FALSE; + game.centered_player_nr = game.centered_player_nr_next = -1; /* focus all */ + for (i = 0; i < NUM_BELTS; i++) { game.belt_dir[i] = MV_NONE; @@ -2070,7 +2102,7 @@ void InitGame() if (tape.playing) { - /* when playing a tape, eliminate all players which do not participate */ + /* when playing a tape, eliminate all players who do not participate */ for (i = 0; i < MAX_PLAYERS; i++) { @@ -2634,6 +2666,13 @@ void GameWon() BackToFront(); +#if 0 + if (tape.playing) + printf("::: TAPE PLAYING -> DO NOT SAVE SCORE\n"); + else + printf("::: NO TAPE PLAYING -> SAVING SCORE\n"); +#endif + if (tape.playing) return; @@ -2794,14 +2833,33 @@ static void ResetRandomAnimationValue(int x, int y) static void ResetGfxAnimation(int x, int y) { +#if 0 + int element, graphic; +#endif + GfxFrame[x][y] = 0; GfxAction[x][y] = ACTION_DEFAULT; GfxDir[x][y] = MovDir[x][y]; + +#if 0 + element = Feld[x][y]; + graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); + + if (graphic_info[graphic].anim_global_sync) + GfxFrame[x][y] = FrameCounter; + else if (ANIM_MODE(graphic) == ANIM_CE_VALUE) + GfxFrame[x][y] = CustomValue[x][y]; + else if (ANIM_MODE(graphic) == ANIM_CE_SCORE) + GfxFrame[x][y] = element_info[element].collect_score; +#endif } void InitMovingField(int x, int y, int direction) { int element = Feld[x][y]; +#if 0 + int graphic; +#endif int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); int newx = x + dx; @@ -2815,6 +2873,17 @@ void InitMovingField(int x, int y, int direction) GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ? ACTION_FALLING : ACTION_MOVING); +#if 0 + graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); + + if (graphic_info[graphic].anim_global_sync) + GfxFrame[x][y] = FrameCounter; + else if (ANIM_MODE(graphic) == ANIM_CE_VALUE) + GfxFrame[x][y] = CustomValue[x][y]; + else if (ANIM_MODE(graphic) == ANIM_CE_SCORE) + GfxFrame[x][y] = element_info[element].collect_score; +#endif + /* this is needed for CEs with property "can move" / "not moving" */ if (getElementMoveStepsize(x, y) != 0) /* moving or being moved */ @@ -3031,7 +3100,7 @@ void CheckDynamite(int x, int y) Bang(x, y); } -void DrawRelocatePlayer(struct PlayerInfo *player) +void DrawRelocatePlayer(struct PlayerInfo *player, boolean quick_relocation) { boolean ffwd_delay = (tape.playing && tape.fast_forward); boolean no_delay = (tape.warp_forward); @@ -3040,19 +3109,19 @@ void DrawRelocatePlayer(struct PlayerInfo *player) int jx = player->jx; int jy = player->jy; - if (level.instant_relocation) + if (quick_relocation) { int offset = (setup.scroll_delay ? 3 : 0); if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy))) { - scroll_x = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left : - local_player->jx > SBX_Right + MIDPOSX ? SBX_Right : - local_player->jx - MIDPOSX); + scroll_x = (player->jx < SBX_Left + MIDPOSX ? SBX_Left : + player->jx > SBX_Right + MIDPOSX ? SBX_Right : + player->jx - MIDPOSX); - scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper : - local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower : - local_player->jy - MIDPOSY); + scroll_y = (player->jy < SBY_Upper + MIDPOSY ? SBY_Upper : + player->jy > SBY_Lower + MIDPOSY ? SBY_Lower : + player->jy - MIDPOSY); } else { @@ -3077,23 +3146,21 @@ void DrawRelocatePlayer(struct PlayerInfo *player) } else { - int scroll_xx = -999, scroll_yy = -999; + int scroll_xx = (player->jx < SBX_Left + MIDPOSX ? SBX_Left : + player->jx > SBX_Right + MIDPOSX ? SBX_Right : + player->jx - MIDPOSX); + + int scroll_yy = (player->jy < SBY_Upper + MIDPOSY ? SBY_Upper : + player->jy > SBY_Lower + MIDPOSY ? SBY_Lower : + player->jy - MIDPOSY); ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */ - while (scroll_xx != scroll_x || scroll_yy != scroll_y) + while (scroll_x != scroll_xx || scroll_y != scroll_yy) { int dx = 0, dy = 0; int fx = FX, fy = FY; - scroll_xx = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left : - local_player->jx > SBX_Right + MIDPOSX ? SBX_Right : - local_player->jx - MIDPOSX); - - scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper : - local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower : - local_player->jy - MIDPOSY); - dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0); dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0); @@ -3200,8 +3267,14 @@ void RelocatePlayer(int jx, int jy, int el_player_raw) InitField(jx, jy, FALSE); } +#if 1 + /* only visually relocate centered player */ + if (player->index_nr == game.centered_player_nr) + DrawRelocatePlayer(player, level.instant_relocation); +#else if (player == local_player) /* only visually relocate local player */ - DrawRelocatePlayer(player); + DrawRelocatePlayer(player, level.instant_relocation); +#endif TestIfPlayerTouchesBadThing(jx, jy); TestIfPlayerTouchesCustomElement(jx, jy); @@ -3458,6 +3531,11 @@ void Explode(int ex, int ey, int phase, int mode) Feld[x][y] = EL_EXPLOSION; GfxElement[x][y] = artwork_element; +#if 0 + printf(":: setting gfx(%d,%d) to %d ['%s']\n", + x, y, artwork_element, EL_NAME(artwork_element)); +#endif + ExplodePhase[x][y] = 1; ExplodeDelay[x][y] = last_phase; @@ -3492,6 +3570,11 @@ void Explode(int ex, int ey, int phase, int mode) #endif #if 1 +#if 1 + /* this can happen if the player leaves an explosion just in time */ + if (GfxElement[x][y] == EL_UNDEFINED) + GfxElement[x][y] = EL_EMPTY; +#else if (GfxElement[x][y] == EL_UNDEFINED) { printf("\n\n"); @@ -3501,6 +3584,8 @@ void Explode(int ex, int ey, int phase, int mode) GfxElement[x][y] = EL_EMPTY; } +#endif + #endif border_element = Store2[x][y]; @@ -4901,31 +4986,105 @@ inline static void TurnRoundExt(int x, int y) { -1, +1, MV_LEFT | MV_DOWN }, { -1, 0, MV_LEFT }, }; - int check_order = (RND(2) ? -1 : +1); - int start_pos = check_pos[MovDir[x][y] & 0x0f]; + int start_pos, check_order; + boolean can_clone = FALSE; int i; - MovDelay[x][y] = level.android_move_time * 8 + 1; + /* check if there is any free field around current position */ + for (i = 0; i < 8; i++) + { + int newx = x + check_xy[i].dx; + int newy = y + check_xy[i].dy; + + if (IN_LEV_FIELD_AND_IS_FREE(newx, newy)) + { + can_clone = TRUE; + + break; + } + } + + if (can_clone) /* randomly find an element to clone */ + { + can_clone = FALSE; + + start_pos = check_pos[RND(8)]; + check_order = (RND(2) ? -1 : +1); + + for (i = 0; i < 8; i++) + { + int pos_raw = start_pos + i * check_order; + int pos = (pos_raw + 8) % 8; + int newx = x + check_xy[pos].dx; + int newy = y + check_xy[pos].dy; + + if (ANDROID_CAN_CLONE_FIELD(newx, newy)) + { + element_info[element].move_leave_type = LEAVE_TYPE_LIMITED; + element_info[element].move_leave_element = EL_TRIGGER_ELEMENT; + + Store[x][y] = Feld[newx][newy]; - if (start_pos < 0) /* (should never happen) */ + can_clone = TRUE; + + break; + } + } + } + + if (can_clone) /* randomly find a direction to move */ + { + can_clone = FALSE; + + start_pos = check_pos[RND(8)]; + check_order = (RND(2) ? -1 : +1); + + for (i = 0; i < 8; i++) + { + int pos_raw = start_pos + i * check_order; + int pos = (pos_raw + 8) % 8; + int newx = x + check_xy[pos].dx; + int newy = y + check_xy[pos].dy; + int new_move_dir = check_xy[pos].dir; + + if (IN_LEV_FIELD_AND_IS_FREE(newx, newy)) + { + MovDir[x][y] = new_move_dir; + MovDelay[x][y] = level.android_clone_time * 8 + 1; + + can_clone = TRUE; + + break; + } + } + } + + if (can_clone) /* cloning and moving successful */ return; + /* cannot clone -- try to move towards player */ + + start_pos = check_pos[MovDir[x][y] & 0x0f]; + check_order = (RND(2) ? -1 : +1); + for (i = 0; i < 3; i++) { - int pos_raw = start_pos + (i == 0 ? 0 : i == 1 ? 1 : -1) * check_order; + /* first check start_pos, then previous/next or (next/previous) pos */ + int pos_raw = start_pos + (i < 2 ? i : -1) * check_order; int pos = (pos_raw + 8) % 8; int newx = x + check_xy[pos].dx; int newy = y + check_xy[pos].dy; int new_move_dir = check_xy[pos].dir; if (IS_PLAYER(newx, newy)) - return; + break; if (ANDROID_CAN_ENTER_FIELD(element, newx, newy)) { MovDir[x][y] = new_move_dir; + MovDelay[x][y] = level.android_move_time * 8 + 1; - return; + break; } } } @@ -5168,6 +5327,9 @@ inline static void TurnRoundExt(int x, int y) static void TurnRound(int x, int y) { int direction = MovDir[x][y]; +#if 1 + int element, graphic; +#endif TurnRoundExt(x, y); @@ -5178,6 +5340,18 @@ static void TurnRound(int x, int y) if (MovDelay[x][y]) GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_TO_BIT(direction); + +#if 1 + element = Feld[x][y]; + graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); + + if (graphic_info[graphic].anim_global_sync) + GfxFrame[x][y] = FrameCounter; + else if (ANIM_MODE(graphic) == ANIM_CE_VALUE) + GfxFrame[x][y] = CustomValue[x][y]; + else if (ANIM_MODE(graphic) == ANIM_CE_SCORE) + GfxFrame[x][y] = element_info[element].collect_score; +#endif } static boolean JustBeingPushed(int x, int y) @@ -5676,6 +5850,7 @@ void StartMoving(int x, int y) else if (CAN_MOVE_INTO_ACID(element) && IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID && + !IS_MV_DIAGONAL(MovDir[x][y]) && (MovDir[x][y] == MV_DOWN || game.engine_version >= VERSION_IDENT(3,1,0,0))) { @@ -5745,33 +5920,82 @@ void StartMoving(int x, int y) } else if (element == EL_EMC_ANDROID && IN_LEV_FIELD(newx, newy)) { - if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL && - ANDROID_CAN_ENTER_FIELD(element, newx, newy)) + if (Store[x][y] != EL_EMPTY) { - /* android is moving diagonally */ + boolean can_clone = FALSE; + int xx, yy; - CreateField(x, y, EL_EMC_ANDROID_SHRINKING); + /* check if element to clone is still there */ + for (yy = y - 1; yy <= y + 1; yy++) for (xx = x - 1; xx <= x + 1; xx++) + { + if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == Store[x][y]) + { + can_clone = TRUE; -#if 0 - CheckTriggeredElementChangeBySide(x, y, element, - CE_MOVE_OF_X, new_move_dir); + break; + } + } - TestIfElementTouchesCustomElement(x, y); /* empty or new element */ + /* cannot clone or target field not free anymore -- do not clone */ + if (!can_clone || !ANDROID_CAN_ENTER_FIELD(element, newx, newy)) + Store[x][y] = EL_EMPTY; + } - TestIfElementHitsCustomElement(newx, newy, new_move_dir); - TestIfElementTouchesCustomElement(newx, newy); -#endif + if (ANDROID_CAN_ENTER_FIELD(element, newx, newy)) + { + if (IS_MV_DIAGONAL(MovDir[x][y])) + { + int diagonal_move_dir = MovDir[x][y]; + int stored = Store[x][y]; + int change_delay = 8; + int graphic; - CreateField(newx, newy, EL_EMC_ANDROID_GROWING); + /* android is moving diagonally */ - return; - } - else if (ANDROID_CAN_ENTER_FIELD(element, newx, newy)) - { - Feld[newx][newy] = EL_EMPTY; - DrawLevelField(newx, newy); + CreateField(x, y, EL_DIAGONAL_SHRINKING); + + Store[x][y] = (stored == EL_ACID ? EL_EMPTY : stored); + GfxElement[x][y] = EL_EMC_ANDROID; + GfxAction[x][y] = ACTION_SHRINKING; + GfxDir[x][y] = diagonal_move_dir; + ChangeDelay[x][y] = change_delay; + + graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y], + GfxDir[x][y]); + + DrawLevelGraphicAnimation(x, y, graphic); + PlayLevelSoundAction(x, y, ACTION_SHRINKING); + + if (Feld[newx][newy] == EL_ACID) + { + SplashAcid(newx, newy); + + return; + } - PlayLevelSoundAction(x, y, ACTION_DIGGING); + CreateField(newx, newy, EL_DIAGONAL_GROWING); + + Store[newx][newy] = EL_EMC_ANDROID; + GfxElement[newx][newy] = EL_EMC_ANDROID; + GfxAction[newx][newy] = ACTION_GROWING; + GfxDir[newx][newy] = diagonal_move_dir; + ChangeDelay[newx][newy] = change_delay; + + graphic = el_act_dir2img(GfxElement[newx][newy], + GfxAction[newx][newy], GfxDir[newx][newy]); + + DrawLevelGraphicAnimation(newx, newy, graphic); + PlayLevelSoundAction(newx, newy, ACTION_GROWING); + + return; + } + else + { + Feld[newx][newy] = EL_EMPTY; + DrawLevelField(newx, newy); + + PlayLevelSoundAction(x, y, ACTION_DIGGING); + } } else if (!IS_FREE(newx, newy)) { @@ -6186,16 +6410,28 @@ void ContinueMoving(int x, int y) Pushed[x][y] = Pushed[newx][newy] = FALSE; /* some elements can leave other elements behind after moving */ +#if 1 + if (ei->move_leave_element != EL_EMPTY && + (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) && + (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element))) +#else if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY && (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) && (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element))) +#endif { int move_leave_element = ei->move_leave_element; +#if 1 #if 1 + /* this makes it possible to leave the removed element again */ + if (ei->move_leave_element == EL_TRIGGER_ELEMENT) + move_leave_element = (stored == EL_ACID ? EL_EMPTY : stored); +#else /* this makes it possible to leave the removed element again */ if (ei->move_leave_element == EL_TRIGGER_ELEMENT) move_leave_element = stored; +#endif #else /* this makes it possible to leave the removed element again */ if (ei->move_leave_type == LEAVE_TYPE_LIMITED && @@ -6293,6 +6529,28 @@ void ContinueMoving(int x, int y) TestIfElementTouchesCustomElement(x, y); /* empty or new element */ +#if 0 + if (ChangePage[newx][newy] != -1) /* delayed change */ + { + int page = ChangePage[newx][newy]; + struct ElementChangeInfo *change = &ei->change_page[page]; + + ChangePage[newx][newy] = -1; + + if (change->can_change) + { + if (ChangeElement(newx, newy, element, page)) + { + if (change->post_change_function) + change->post_change_function(newx, newy); + } + } + + if (change->has_action) + ExecuteCustomElementAction(newx, newy, element, page); + } +#endif + TestIfElementHitsCustomElement(newx, newy, direction); TestIfPlayerTouchesCustomElement(newx, newy); TestIfElementTouchesCustomElement(newx, newy); @@ -6863,9 +7121,11 @@ static void ActivateMagicBall(int bx, int by) game.ball_content_nr = (game.ball_content_nr + 1) % level.num_ball_contents; } -static void InitAndroid(int x, int y) +static void InitDiagonalMovingElement(int x, int y) { +#if 0 MovDelay[x][y] = level.android_move_time; +#endif } void CheckExit(int x, int y) @@ -7208,9 +7468,10 @@ static void WarnBuggyBase(int x, int y) for (i = 0; i < NUM_DIRECTIONS; i++) { - int xx = x + xy[i][0], yy = y + xy[i][1]; + int xx = x + xy[i][0]; + int yy = y + xy[i][1]; - if (IS_PLAYER(xx, yy)) + if (IN_LEV_FIELD(xx, yy) && IS_PLAYER(xx, yy)) { PlayLevelSound(x, y, SND_SP_BUGGY_BASE_ACTIVE); @@ -7338,8 +7599,10 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_arg == CA_ARG_NUMBER_LEVEL_TIME ? level_time_value : action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? local_player->gems_still_needed : action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score : - action_arg == CA_ARG_ELEMENT_TARGET ? GET_NEW_CUSTOM_VALUE(change->target_element) : - action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_ce_value : + action_arg == CA_ARG_ELEMENT_CV_TARGET ? GET_NEW_CUSTOM_VALUE(change->target_element) : + action_arg == CA_ARG_ELEMENT_CV_TRIGGER ? change->actual_trigger_ce_value: + action_arg == CA_ARG_ELEMENT_NR_TARGET ? change->target_element : + action_arg == CA_ARG_ELEMENT_NR_TRIGGER ? change->actual_trigger_element : -1); int action_arg_number_old = @@ -7630,6 +7893,10 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO); CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X); + +#if 0 + printf("::: RESULT: %d, %d\n", Feld[x][y], ChangePage[x][y]); +#endif } #endif @@ -7716,6 +7983,21 @@ static void CreateField(int x, int y, int element) static void CreateElementFromChange(int x, int y, int element) { + element = GET_VALID_RUNTIME_ELEMENT(element); + +#if USE_STOP_CHANGED_ELEMENTS + if (game.engine_version >= VERSION_IDENT(3,2,0,7)) + { + int old_element = Feld[x][y]; + + /* prevent changed element from moving in same engine frame + unless both old and new element can either fall or move */ + if ((!CAN_FALL(old_element) || !CAN_FALL(element)) && + (!CAN_MOVE(old_element) || !CAN_MOVE(element))) + Stop[x][y] = TRUE; + } +#endif + CreateFieldExt(x, y, element, TRUE); } @@ -7863,6 +8145,14 @@ static boolean ChangeElement(int x, int y, int element, int page) { target_element = GET_TARGET_ELEMENT(change->target_element, change); + if (element == EL_DIAGONAL_GROWING || + element == EL_DIAGONAL_SHRINKING) + { + target_element = Store[x][y]; + + Store[x][y] = EL_EMPTY; + } + CreateElementFromChange(x, y, target_element); PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING); @@ -8156,8 +8446,20 @@ static boolean CheckElementChangeExt(int x, int y, element = Feld[x][y]; } - if (Feld[x][y] != element) /* check if element has already changed */ +#if 0 + /* check if element has already changed */ + if (Feld[x][y] != element) return FALSE; +#else + /* check if element has already changed or is about to change after moving */ + if ((game.engine_version < VERSION_IDENT(3,2,0,7) && + Feld[x][y] != element) || + + (game.engine_version >= VERSION_IDENT(3,2,0,7) && + (ChangeCount[x][y] >= game.max_num_changes_per_frame || + ChangePage[x][y] != -1))) + return FALSE; +#endif for (p = 0; p < element_info[element].num_change_pages; p++) { @@ -8526,6 +8828,27 @@ void GameActions() InitPlayfieldScanModeVars(); + if (ScreenMovPos == 0) /* screen currently aligned at tile position */ + { + struct PlayerInfo *player; + int player_nr = game.centered_player_nr_next; + + if (game.centered_player_nr_next == -1) + player_nr = local_player->index_nr; + + player = &stored_player[player_nr]; + + if (!player->active) + game.centered_player_nr_next = game.centered_player_nr; + + if (game.centered_player_nr != game.centered_player_nr_next) + { + DrawRelocatePlayer(player, setup.quick_switch); + + game.centered_player_nr = game.centered_player_nr_next; + } + } + #if USE_ONE_MORE_CHANGE_PER_FRAME if (game.engine_version >= VERSION_IDENT(3,2,0,7)) { @@ -8887,7 +9210,9 @@ void GameActions() CheckForDragon(x, y); else if (element == EL_EXPLOSION) ; /* drawing of correct explosion animation is handled separately */ - else if (element == EL_ELEMENT_SNAPPING) + else if (element == EL_ELEMENT_SNAPPING || + element == EL_DIAGONAL_SHRINKING || + element == EL_DIAGONAL_GROWING) { #if 1 graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],GfxDir[x][y]); @@ -9352,8 +9677,14 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, #endif } +#if 1 + if (!options.network && game.centered_player_nr == -1 && + !AllPlayersInSight(player, new_jx, new_jy)) + return MP_NO_ACTION; +#else if (!options.network && !AllPlayersInSight(player, new_jx, new_jy)) return MP_NO_ACTION; +#endif #if !USE_FIXED_DONT_RUN_INTO element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy); @@ -9496,8 +9827,14 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) jx = player->jx; jy = player->jy; +#if 1 + if (moved & MP_MOVING && !ScreenMovPos && + (player->index_nr == game.centered_player_nr || + game.centered_player_nr == -1)) +#else if (moved & MP_MOVING && !ScreenMovPos && (player == local_player || !options.network)) +#endif { int old_scroll_x = scroll_x, old_scroll_y = scroll_y; int offset = (setup.scroll_delay ? 3 : 0); @@ -9552,12 +9889,22 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy) if (scroll_x != old_scroll_x || scroll_y != old_scroll_y) { +#if 1 + if (!options.network && game.centered_player_nr == -1 && + !AllPlayersInVisibleScreen()) + { + scroll_x = old_scroll_x; + scroll_y = old_scroll_y; + } + else +#else if (!options.network && !AllPlayersInVisibleScreen()) { scroll_x = old_scroll_x; scroll_y = old_scroll_y; } else +#endif { ScrollScreen(player, SCROLL_INIT); ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y); @@ -9906,7 +10253,94 @@ void TestIfPlayerTouchesCustomElement(int x, int y) } } +#if USE_ELEMENT_TOUCHING_BUGFIX + void TestIfElementTouchesCustomElement(int x, int y) +{ + static int xy[4][2] = + { + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } + }; + static int trigger_sides[4][2] = + { + /* center side border side */ + { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */ + { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */ + { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */ + { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */ + }; + static int touch_dir[4] = + { + MV_LEFT | MV_RIGHT, + MV_UP | MV_DOWN, + MV_UP | MV_DOWN, + MV_LEFT | MV_RIGHT + }; + boolean change_center_element = FALSE; + int center_element = Feld[x][y]; /* should always be non-moving! */ + int border_element_old[NUM_DIRECTIONS]; + int i; + + for (i = 0; i < NUM_DIRECTIONS; i++) + { + int xx = x + xy[i][0]; + int yy = y + xy[i][1]; + int border_element; + + border_element_old[i] = -1; + + if (!IN_LEV_FIELD(xx, yy)) + continue; + + if (game.engine_version < VERSION_IDENT(3,0,7,0)) + border_element = Feld[xx][yy]; /* may be moving! */ + else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy)) + border_element = Feld[xx][yy]; + else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */ + border_element = MovingOrBlocked2Element(xx, yy); + else + continue; /* center and border element do not touch */ + + border_element_old[i] = border_element; + } + + for (i = 0; i < NUM_DIRECTIONS; i++) + { + int xx = x + xy[i][0]; + int yy = y + xy[i][1]; + int center_side = trigger_sides[i][0]; + int border_element = border_element_old[i]; + + if (border_element == -1) + continue; + + /* check for change of border element */ + CheckElementChangeBySide(xx, yy, border_element, center_element, + CE_TOUCHING_X, center_side); + } + + for (i = 0; i < NUM_DIRECTIONS; i++) + { + int border_side = trigger_sides[i][1]; + int border_element = border_element_old[i]; + + if (border_element == -1) + continue; + + /* check for change of center element (but change it only once) */ + if (!change_center_element) + change_center_element = + CheckElementChangeBySide(x, y, center_element, border_element, + CE_TOUCHING_X, border_side); + } +} + +#else + +void TestIfElementTouchesCustomElement_OLD(int x, int y) { static int xy[4][2] = { @@ -9966,6 +10400,8 @@ void TestIfElementTouchesCustomElement(int x, int y) } } +#endif + void TestIfElementHitsCustomElement(int x, int y, int direction) { int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); @@ -10739,7 +11175,9 @@ int DigField(struct PlayerInfo *player, if (element == EL_SHIELD_DEADLY) player->shield_deadly_time_left += level.shield_deadly_time; } - else if (element == EL_DYNAMITE || element == EL_SP_DISK_RED) + else if (element == EL_DYNAMITE || + element == EL_EM_DYNAMITE || + element == EL_SP_DISK_RED) { if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; @@ -11268,6 +11706,8 @@ boolean DropElement(struct PlayerInfo *player) if (new_element == EL_DYNAMITE) new_element = EL_DYNAMITE_ACTIVE; + else if (new_element == EL_EM_DYNAMITE) + new_element = EL_EM_DYNAMITE_ACTIVE; else if (new_element == EL_SP_DISK_RED) new_element = EL_SP_DISK_RED_ACTIVE; } @@ -11499,7 +11939,7 @@ void PlayLevelSound_EM(int x, int y, int element_em, int sample) break; case SAMPLE_slurp: - PlayLevelSoundElementAction(x, y, element, ACTION_SLURPED_BY_SPRING); + PlayLevelSoundElementAction(x, y, element, ACTION_EATING); break; case SAMPLE_eater: @@ -11661,6 +12101,7 @@ void RaiseScoreElement(int element) RaiseScore(level.score[SC_NUT]); break; case EL_DYNAMITE: + case EL_EM_DYNAMITE: case EL_SP_DISK_RED: case EL_DYNABOMB_INCREASE_NUMBER: case EL_DYNABOMB_INCREASE_SIZE: