X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=a67f9def973370667b5e45266cbfd76c70ecb4fd;hb=ad15815ec04f42779d0717a6d291f93b8e847d39;hp=91694d2d7ea0e2ab2fd617081c89a046c14e5105;hpb=1ed02c282e3b4bd73c5d26244e4df30d731cc6c8;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 91694d2d..a67f9def 100644 --- a/src/game.c +++ b/src/game.c @@ -169,7 +169,9 @@ static void KillHeroUnlessProtected(int, int); static void TestIfPlayerTouchesCustomElement(int, int); static void TestIfElementTouchesCustomElement(int, int); +static boolean CheckTriggeredElementSideChange(int, int, int, int, int); static boolean CheckTriggeredElementChange(int, int, int, int); +static boolean CheckElementSideChange(int, int, int, int, int, int); static boolean CheckElementChange(int, int, int, int); static void PlaySoundLevel(int, int, int); @@ -241,6 +243,30 @@ static struct ChangingElementInfo change_delay_list[] = NULL, NULL }, + { + EL_EXIT_CLOSING, + EL_EXIT_CLOSED, + 29, + NULL, + NULL, + NULL + }, + { + EL_SP_EXIT_OPENING, + EL_SP_EXIT_OPEN, + 29, + NULL, + NULL, + NULL + }, + { + EL_SP_EXIT_CLOSING, + EL_SP_EXIT_CLOSED, + 29, + NULL, + NULL, + NULL + }, { EL_SWITCHGATE_OPENING, EL_SWITCHGATE_OPEN, @@ -648,10 +674,13 @@ static void InitField(int x, int y, boolean init_game) MovDir[x][y] = 1 << RND(4); break; +#if 0 case EL_SP_EMPTY: Feld[x][y] = EL_EMPTY; break; +#endif +#if 0 case EL_EM_KEY_1_FILE: Feld[x][y] = EL_EM_KEY_1; break; @@ -664,6 +693,7 @@ static void InitField(int x, int y, boolean init_game) case EL_EM_KEY_4_FILE: Feld[x][y] = EL_EM_KEY_4; break; +#endif case EL_CONVEYOR_BELT_1_SWITCH_LEFT: case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE: @@ -792,7 +822,7 @@ static void InitGameEngine() ei->change_events = CE_BITMASK_DEFAULT; for (j=0; j < NUM_CHANGE_EVENTS; j++) { - ei->event_page_num[j] = 0; + ei->event_page_nr[j] = 0; ei->event_page[j] = &ei->change_page[0]; } } @@ -831,7 +861,7 @@ static void InitGameEngine() !(ei->change_events & CH_EVENT_BIT(k))) { ei->change_events |= CH_EVENT_BIT(k); - ei->event_page_num[k] = j; + ei->event_page_nr[k] = j; ei->event_page[k] = &ei->change_page[j]; } } @@ -1002,6 +1032,9 @@ void InitGame() player->Frame = 0; player->StepFrame = 0; + player->switch_x = -1; + player->switch_y = -1; + player->use_murphy_graphic = FALSE; player->use_disk_red_graphic = FALSE; @@ -1014,6 +1047,8 @@ void InitGame() player->is_digging = FALSE; player->is_collecting = FALSE; + player->show_envelope = 0; + player->move_delay = game.initial_move_delay; player->move_delay_value = game.initial_move_delay_value; @@ -1067,8 +1102,11 @@ void InitGame() game.timegate_time_left = 0; game.switchgate_pos = 0; game.balloon_dir = MV_NO_MOVING; + game.gravity = level.initial_gravity; game.explosions_delayed = TRUE; + game.envelope_active = FALSE; + for (i=0; i<4; i++) { game.belt_dir[i] = MV_NO_MOVING; @@ -1090,7 +1128,10 @@ void InitGame() JustStopped[x][y] = 0; Stop[x][y] = FALSE; Pushed[x][y] = FALSE; - Changed[x][y] = FALSE; + + Changed[x][y] = CE_BITMASK_DEFAULT; + ChangeEvent[x][y] = CE_BITMASK_DEFAULT; + ExplodePhase[x][y] = 0; ExplodeField[x][y] = EX_NO_EXPLOSION; @@ -1646,6 +1687,18 @@ void GameWon() StopSound(SND_GAME_LEVELTIME_BONUS); } + /* close exit door after last player */ + if ((Feld[ExitX][ExitY] == EL_EXIT_OPEN || + Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN) && AllPlayersGone) + { + int element = Feld[ExitX][ExitY]; + + Feld[ExitX][ExitY] = (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING : + EL_SP_EXIT_CLOSING); + + PlaySoundLevelElementAction(ExitX, ExitY, element, ACTION_CLOSING); + } + /* Hero disappears */ DrawLevelField(ExitX, ExitY); BackToFront(); @@ -2285,6 +2338,24 @@ void Explode(int ex, int ey, int phase, int mode) ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0); +#ifdef DEBUG + + /* activate this even in non-DEBUG version until cause for crash in + getGraphicAnimationFrame() (see below) is found and eliminated */ +#endif +#if 1 + + if (GfxElement[x][y] == EL_UNDEFINED) + { + printf("\n\n"); + printf("Explode(): x = %d, y = %d: GfxElement == EL_UNDEFINED\n", x, y); + printf("Explode(): This should never happen!\n"); + printf("\n\n"); + + GfxElement[x][y] = EL_EMPTY; + } +#endif + if (phase == first_phase_after_start) { int element = Store2[x][y]; @@ -2330,7 +2401,9 @@ void Explode(int ex, int ey, int phase, int mode) InitMovDir(x, y); DrawLevelField(x, y); - if (CAN_BE_CRUMBLED(element)) + TestIfElementTouchesCustomElement(x, y); + + if (GFX_CRUMBLED(element)) DrawLevelFieldCrumbledSandNeighbours(x, y); if (IS_PLAYER(x, y) && !PLAYERINFO(x,y)->present) @@ -2430,7 +2503,11 @@ void Bang(int x, int y) int element = Feld[x][y]; #endif +#if 1 + if (IS_PLAYER(x, y) && !PLAYER_PROTECTED(x, y)) +#else if (IS_PLAYER(x, y)) +#endif { struct PlayerInfo *player = PLAYERINFO(x, y); @@ -3042,6 +3119,11 @@ void Impact(int x, int y) else { CheckElementChange(x, y + 1, smashed, CE_SMASHED); + + CheckTriggeredElementSideChange(x, y + 1, smashed, CH_SIDE_TOP, + CE_OTHER_IS_SWITCHING); + CheckElementSideChange(x, y + 1, smashed, CH_SIDE_TOP, + CE_SWITCHED, -1); } } else @@ -3600,6 +3682,13 @@ void TurnRound(int x, int y) MovDir[x][y] = old_move_dir; } } + else if (element_info[element].move_pattern == MV_WHEN_PUSHED) + { + if (!IN_LEV_FIELD_AND_IS_FREE(move_x, move_y)) + MovDir[x][y] = MV_NO_MOVING; + + MovDelay[x][y] = 0; + } } static boolean JustBeingPushed(int x, int y) @@ -3781,6 +3870,15 @@ void StartMoving(int x, int y) #endif } #if 1 + +#if 0 + /* TEST: bug where player gets not killed by falling rock ... */ + else if (CAN_SMASH(element) && + (Feld[x][y + 1] == EL_BLOCKED || + IS_PLAYER(x, y + 1)) && + JustStopped[x][y] && !Pushed[x][y + 1]) + +#else #if 1 else if (game.engine_version < RELEASE_IDENT(2,2,0,7) && CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED && @@ -3789,6 +3887,8 @@ void StartMoving(int x, int y) else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED && JustStopped[x][y]) #endif +#endif + { /* calling "Impact()" here is not only completely unneccessary (because it already gets called from "ContinueMoving()" in @@ -3899,11 +3999,16 @@ void StartMoving(int x, int y) { int newx, newy; +#if 1 + if (IS_PUSHABLE(element) && JustBeingPushed(x, y)) + return; +#else if ((element == EL_SATELLITE || element == EL_BALLOON || element == EL_SPRING) && JustBeingPushed(x, y)) return; +#endif #if 0 #if 0 @@ -4152,6 +4257,11 @@ void StartMoving(int x, int y) element1 != EL_DRAGON && element2 != EL_DRAGON && element1 != EL_FLAMES && element2 != EL_FLAMES) { +#if 1 + ResetGfxAnimation(x, y); + GfxAction[x][y] = ACTION_ATTACKING; +#endif + if (IS_PLAYER(x, y)) DrawPlayerField(x, y); else @@ -4165,6 +4275,7 @@ void StartMoving(int x, int y) Feld[newx1][newy1] = EL_FLAMES; if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY) Feld[newx2][newy2] = EL_FLAMES; + return; } } @@ -4375,6 +4486,12 @@ void ContinueMoving(int x, int y) /* copy element change control values to new field */ ChangeDelay[newx][newy] = ChangeDelay[x][y]; + Changed[newx][newy] = Changed[x][y]; + ChangeEvent[newx][newy] = ChangeEvent[x][y]; + + ChangeDelay[x][y] = 0; + Changed[x][y] = CE_BITMASK_DEFAULT; + ChangeEvent[x][y] = CE_BITMASK_DEFAULT; /* copy animation control values to new field */ GfxFrame[newx][newy] = GfxFrame[x][y]; @@ -4413,6 +4530,12 @@ void ContinueMoving(int x, int y) Stop[newx][newy] = TRUE; /* ignore this element until the next frame */ + /* prevent pushed element from moving on in pushed direction */ + if (pushed && CAN_MOVE(element) && + element_info[element].move_pattern & MV_ANY_DIRECTION && + !(element_info[element].move_pattern & MovDir[newx][newy])) + TurnRound(newx, newy); + if (!pushed) /* special case: moving object pushed by player */ JustStopped[newx][newy] = 3; @@ -4430,7 +4553,11 @@ void ContinueMoving(int x, int y) Impact(x, newy); if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty)) - CheckElementChange(newx, newy, element, CE_COLLISION); + CheckElementSideChange(newx, newy, element, direction, CE_COLLISION, -1); + +#if 1 + TestIfElementTouchesCustomElement(x, y); /* for empty space */ +#endif TestIfPlayerTouchesCustomElement(newx, newy); TestIfElementTouchesCustomElement(newx, newy); @@ -4973,6 +5100,9 @@ void CheckExit(int x, int y) return; } + if (AllPlayersGone) /* do not re-open exit door closed after last player */ + return; + Feld[x][y] = EL_EXIT_OPENING; PlaySoundLevelNearest(x, y, SND_CLASS_EXIT_OPENING); @@ -4991,7 +5121,10 @@ void CheckExitSP(int x, int y) return; } - Feld[x][y] = EL_SP_EXIT_OPEN; + if (AllPlayersGone) /* do not re-open exit door closed after last player */ + return; + + Feld[x][y] = EL_SP_EXIT_OPENING; PlaySoundLevelNearest(x, y, SND_CLASS_SP_EXIT_OPENING); } @@ -5342,7 +5475,7 @@ static void ChangeElementNowExt(int x, int y, int target_element) RemoveField(x, y); Feld[x][y] = target_element; - Changed[x][y] = TRUE; /* no more changes in this frame */ + Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */ ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); @@ -5353,7 +5486,7 @@ static void ChangeElementNowExt(int x, int y, int target_element) DrawLevelField(x, y); - if (CAN_BE_CRUMBLED(Feld[x][y])) + if (GFX_CRUMBLED(Feld[x][y])) DrawLevelFieldCrumbledSandNeighbours(x, y); TestIfBadThingTouchesHero(x, y); @@ -5364,18 +5497,32 @@ static void ChangeElementNowExt(int x, int y, int target_element) RelocatePlayer(x, y, target_element); } -static void ChangeElementNow(int x, int y, int element, int page) +static boolean ChangeElementNow(int x, int y, int element, int page) { struct ElementChangeInfo *change = &element_info[element].change_page[page]; - Changed[x][y] = TRUE; /* no more changes in this frame */ + /* always use default change event to prevent running into a loop */ + if (ChangeEvent[x][y] == CE_BITMASK_DEFAULT) + ChangeEvent[x][y] = CH_EVENT_BIT(CE_DELAY); + + /* do not change already changed elements with same change event */ +#if 0 + if (Changed[x][y] & ChangeEvent[x][y]) + return FALSE; +#else + if (Changed[x][y]) + return FALSE; +#endif + + Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */ CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING); if (change->explode) { Bang(x, y); - return; + + return TRUE; } if (change->use_content) @@ -5433,7 +5580,7 @@ static void ChangeElementNow(int x, int y, int element, int page) if (change->only_complete && change->use_random_change && RND(100) < change->random) - return; + return FALSE; for (yy = 0; yy < 3; yy++) for(xx = 0; xx < 3 ; xx++) { @@ -5446,6 +5593,8 @@ static void ChangeElementNow(int x, int y, int element, int page) if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey)) RemoveMovingField(ex, ey); + ChangeEvent[ex][ey] = ChangeEvent[x][y]; + ChangeElementNowExt(ex, ey, change->content[xx][yy]); something_has_changed = TRUE; @@ -5466,6 +5615,8 @@ static void ChangeElementNow(int x, int y, int element, int page) PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING); } + + return TRUE; } static void ChangeElement(int x, int y, int page) @@ -5473,6 +5624,19 @@ static void ChangeElement(int x, int y, int page) int element = MovingOrBlocked2Element(x, y); struct ElementChangeInfo *change = &element_info[element].change_page[page]; +#if 0 +#ifdef DEBUG + if (!CAN_CHANGE(element)) + { + printf("\n\n"); + printf("ChangeElement(): %d,%d: element = %d ('%s')\n", + x, y, element, element_info[element].token_name); + printf("ChangeElement(): This should never happen!\n"); + printf("\n\n"); + } +#endif +#endif + if (ChangeDelay[x][y] == 0) /* initialize element change */ { ChangeDelay[x][y] = ( change->delay_fixed * change->delay_frames + @@ -5506,43 +5670,40 @@ static void ChangeElement(int x, int y, int page) return; } - ChangeElementNow(x, y, element, page); - - if (change->post_change_function) - change->post_change_function(x, y); + if (ChangeElementNow(x, y, element, page)) + { + if (change->post_change_function) + change->post_change_function(x, y); + } } } -static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element, - int trigger_event) +static boolean CheckTriggeredElementSideChange(int lx, int ly, + int trigger_element, + int trigger_side, + int trigger_event) { int i, j, x, y; if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event))) return FALSE; -#if 0 - /* prevent this function from running into a loop */ - if (trigger_event == CE_OTHER_IS_CHANGING) - Changed[lx][ly] = TRUE; -#endif - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; -#if 1 boolean change_element = FALSE; - int page; + int page = 0; - if (!CAN_CHANGE(element) || - !HAS_ANY_CHANGE_EVENT(element, trigger_event)) + if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event)) continue; for (j=0; j < element_info[element].num_change_pages; j++) { - if (element_info[element].change_page[j].trigger_element == - trigger_element) + struct ElementChangeInfo *change = &element_info[element].change_page[j]; + + if (change->sides & trigger_side && + change->trigger_element == trigger_element) { change_element = TRUE; page = j; @@ -5554,52 +5715,52 @@ static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element, if (!change_element) continue; -#else - if (!CAN_CHANGE(element) || - !HAS_ANY_CHANGE_EVENT(element, trigger_event) || - element_info[element].change->trigger_element != trigger_element) - continue; -#endif - for (y=0; y 0) @@ -5877,7 +6037,7 @@ void GameActions() /* this may take place after moving, so 'element' may have changed */ if (IS_CHANGING(x, y)) { - ChangeElement(x, y, element_info[element].event_page_num[CE_DELAY]); + ChangeElement(x, y, element_info[element].event_page_nr[CE_DELAY]); element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]); } @@ -6128,7 +6288,7 @@ void GameActions() } } - if (TimeFrames >= (1000 / GameFrameDelay)) + if (TimeFrames >= FRAMES_PER_SECOND) { TimeFrames = 0; TimePlayed++; @@ -6213,6 +6373,15 @@ void GameActions() stored_player[i].StepFrame += move_frames; } #endif + +#if 1 + if (local_player->show_envelope != 0 && local_player->MovPos == 0) + { + ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1); + + local_player->show_envelope = 0; + } +#endif } static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y) @@ -6286,7 +6455,7 @@ void ScrollLevel(int dx, int dy) static void CheckGravityMovement(struct PlayerInfo *player) { - if (level.gravity && !player->programmed_action) + if (game.gravity && !player->programmed_action) { int move_dir_vertical = player->action & (MV_UP | MV_DOWN); int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT); @@ -6323,8 +6492,22 @@ static void CheckGravityMovement(struct PlayerInfo *player) boolean MoveFigureOneStep(struct PlayerInfo *player, int dx, int dy, int real_dx, int real_dy) { + static int change_sides[4][2] = + { + /* enter side leave side */ + { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* moving left */ + { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* moving right */ + { CH_SIDE_BOTTOM, CH_SIDE_TOP }, /* moving up */ + { CH_SIDE_TOP, CH_SIDE_BOTTOM } /* moving down */ + }; + int move_direction = (dx == -1 ? MV_LEFT : + dx == +1 ? MV_RIGHT : + dy == -1 ? MV_UP : + dy == +1 ? MV_DOWN : MV_NO_MOVING); + int enter_side = change_sides[MV_DIR_BIT(move_direction)][0]; + int leave_side = change_sides[MV_DIR_BIT(move_direction)][1]; int jx = player->jx, jy = player->jy; - int new_jx = jx+dx, new_jy = jy+dy; + int new_jx = jx + dx, new_jy = jy + dy; int element; int can_move; @@ -6376,15 +6559,33 @@ boolean MoveFigureOneStep(struct PlayerInfo *player, StorePlayer[jx][jy] = 0; player->last_jx = jx; player->last_jy = jy; - jx = player->jx = new_jx; - jy = player->jy = new_jy; - StorePlayer[jx][jy] = player->element_nr; + player->jx = new_jx; + player->jy = new_jy; + StorePlayer[new_jx][new_jy] = player->element_nr; player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value); ScrollFigure(player, SCROLL_INIT); +#if 1 + if (IS_CUSTOM_ELEMENT(Feld[jx][jy])) + { + CheckTriggeredElementSideChange(jx, jy, Feld[jx][jy], leave_side, + CE_OTHER_GETS_LEFT); + CheckElementSideChange(jx, jy, Feld[jx][jy], leave_side, + CE_LEFT_BY_PLAYER, -1); + } + + if (IS_CUSTOM_ELEMENT(Feld[new_jx][new_jy])) + { + CheckTriggeredElementSideChange(new_jx, new_jy, Feld[new_jx][new_jy], + enter_side, CE_OTHER_GETS_ENTERED); + CheckElementSideChange(new_jx, new_jy, Feld[new_jx][new_jy], enter_side, + CE_ENTERED_BY_PLAYER, -1); + } +#endif + return MF_MOVING; } @@ -6545,6 +6746,10 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy) #if 1 player->snapped = FALSE; #endif + +#if 1 + player->Switching = FALSE; +#endif } else { @@ -6604,7 +6809,7 @@ void ScrollFigure(struct PlayerInfo *player, int mode) DrawPlayer(player); /* needed here only to cleanup last field */ #endif - if (player->MovPos == 0) + if (player->MovPos == 0) /* player reached destination field */ { if (IS_PASSABLE(Feld[last_jx][last_jy])) { @@ -6619,13 +6824,14 @@ void ScrollFigure(struct PlayerInfo *player, int mode) player->last_jy = jy; if (Feld[jx][jy] == EL_EXIT_OPEN || - Feld[jx][jy] == EL_SP_EXIT_OPEN) + 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 */ RemoveHero(player); if (local_player->friends_still_needed == 0 || - Feld[jx][jy] == EL_SP_EXIT_OPEN) + IS_SP_ELEMENT(Feld[jx][jy])) player->LevelSolved = player->GameOver = TRUE; } @@ -6675,6 +6881,14 @@ void TestIfPlayerTouchesCustomElement(int x, int y) { +1, 0 }, { 0, +1 } }; + static int change_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 */ + }; int i; #if 0 @@ -6688,10 +6902,30 @@ void TestIfPlayerTouchesCustomElement(int x, int y) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; + int center_side = change_sides[i][0]; + int border_side = change_sides[i][1]; if (!IN_LEV_FIELD(xx, yy)) continue; +#if 1 + if (IS_PLAYER(x, y)) + { + CheckTriggeredElementSideChange(xx, yy, Feld[xx][yy], border_side, + CE_OTHER_GETS_TOUCHED); + CheckElementSideChange(xx, yy, Feld[xx][yy], border_side, + CE_TOUCHED_BY_PLAYER, -1); + } + else if (IS_PLAYER(xx, yy)) + { + CheckTriggeredElementSideChange(x, y, Feld[x][y], center_side, + CE_OTHER_GETS_TOUCHED); + CheckElementSideChange(x, y, Feld[x][y], center_side, + CE_TOUCHED_BY_PLAYER, -1); + + break; + } +#else if (IS_PLAYER(x, y)) { CheckTriggeredElementChange(xx, yy, Feld[xx][yy], CE_OTHER_GETS_TOUCHED); @@ -6704,6 +6938,7 @@ void TestIfPlayerTouchesCustomElement(int x, int y) break; } +#endif } #if 0 @@ -6723,6 +6958,14 @@ void TestIfElementTouchesCustomElement(int x, int y) { +1, 0 }, { 0, +1 } }; + static int change_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 */ + }; boolean change_center_element = FALSE; int center_element_change_page = 0; int center_element = Feld[x][y]; @@ -6739,6 +6982,8 @@ void TestIfElementTouchesCustomElement(int x, int y) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; + int center_side = change_sides[i][0]; + int border_side = change_sides[i][1]; int border_element; if (!IN_LEV_FIELD(xx, yy)) @@ -6757,6 +7002,7 @@ void TestIfElementTouchesCustomElement(int x, int y) &element_info[center_element].change_page[j]; if (change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) && + change->sides & border_side && change->trigger_element == border_element) { change_center_element = TRUE; @@ -6777,9 +7023,11 @@ void TestIfElementTouchesCustomElement(int x, int y) &element_info[border_element].change_page[j]; if (change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) && + change->sides & center_side && change->trigger_element == center_element) { - CheckElementChangeExt(xx,yy, border_element,CE_OTHER_IS_TOUCHING, j); + CheckElementSideChange(xx, yy, border_element, CH_SIDE_ANY, + CE_OTHER_IS_TOUCHING, j); break; } } @@ -6787,8 +7035,8 @@ void TestIfElementTouchesCustomElement(int x, int y) } if (change_center_element) - CheckElementChangeExt(x, y, center_element, CE_OTHER_IS_TOUCHING, - center_element_change_page); + CheckElementSideChange(x, y, center_element, CH_SIDE_ANY, + CE_OTHER_IS_TOUCHING, center_element_change_page); #if 0 check_changing = FALSE; @@ -7124,6 +7372,13 @@ static boolean checkDiagonalPushing(struct PlayerInfo *player, int DigField(struct PlayerInfo *player, int x, int y, int real_dx, int real_dy, int mode) { + static int change_sides[4] = + { + CH_SIDE_RIGHT, /* moving left */ + CH_SIDE_LEFT, /* moving right */ + CH_SIDE_BOTTOM, /* moving up */ + CH_SIDE_TOP, /* moving down */ + }; boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0)); int jx = player->jx, jy = player->jy; int dx = x - jx, dy = y - jy; @@ -7132,6 +7387,7 @@ int DigField(struct PlayerInfo *player, dx == +1 ? MV_RIGHT : dy == -1 ? MV_UP : dy == +1 ? MV_DOWN : MV_NO_MOVING); + int dig_side = change_sides[MV_DIR_BIT(move_direction)]; int element; if (player->MovPos == 0) @@ -7198,6 +7454,7 @@ int DigField(struct PlayerInfo *player, switch (element) { +#if 0 case EL_ROBOT_WHEEL: Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE; ZX = x; @@ -7206,7 +7463,9 @@ int DigField(struct PlayerInfo *player, PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVATING); return MF_ACTION; break; +#endif +#if 0 case EL_SP_TERMINAL: { int xx, yy; @@ -7227,7 +7486,9 @@ int DigField(struct PlayerInfo *player, return MF_ACTION; } break; +#endif +#if 0 case EL_CONVEYOR_BELT_1_SWITCH_LEFT: case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE: case EL_CONVEYOR_BELT_1_SWITCH_RIGHT: @@ -7240,31 +7501,56 @@ int DigField(struct PlayerInfo *player, case EL_CONVEYOR_BELT_4_SWITCH_LEFT: case EL_CONVEYOR_BELT_4_SWITCH_MIDDLE: case EL_CONVEYOR_BELT_4_SWITCH_RIGHT: +#if 1 + if (!PLAYER_SWITCHING(player, x, y)) +#else if (!player->Switching) +#endif { player->Switching = TRUE; + player->switch_x = x; + player->switch_y = y; + ToggleBeltSwitch(x, y); PlaySoundLevel(x, y, SND_CLASS_CONVEYOR_BELT_SWITCH_ACTIVATING); } return MF_ACTION; break; +#endif +#if 0 case EL_SWITCHGATE_SWITCH_UP: case EL_SWITCHGATE_SWITCH_DOWN: +#if 1 + if (!PLAYER_SWITCHING(player, x, y)) +#else if (!player->Switching) +#endif { player->Switching = TRUE; + player->switch_x = x; + player->switch_y = y; + ToggleSwitchgateSwitch(x, y); PlaySoundLevel(x, y, SND_CLASS_SWITCHGATE_SWITCH_ACTIVATING); } return MF_ACTION; break; +#endif +#if 0 case EL_LIGHT_SWITCH: case EL_LIGHT_SWITCH_ACTIVE: +#if 1 + if (!PLAYER_SWITCHING(player, x, y)) +#else if (!player->Switching) +#endif { player->Switching = TRUE; + player->switch_x = x; + player->switch_y = y; + ToggleLightSwitch(x, y); PlaySoundLevel(x, y, element == EL_LIGHT_SWITCH ? SND_LIGHT_SWITCH_ACTIVATING : @@ -7272,14 +7558,18 @@ int DigField(struct PlayerInfo *player, } return MF_ACTION; break; +#endif +#if 0 case EL_TIMEGATE_SWITCH: ActivateTimegateSwitch(x, y); PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVATING); return MF_ACTION; break; +#endif +#if 0 case EL_BALLOON_SWITCH_LEFT: case EL_BALLOON_SWITCH_RIGHT: case EL_BALLOON_SWITCH_UP: @@ -7297,6 +7587,7 @@ int DigField(struct PlayerInfo *player, return MF_ACTION; break; +#endif case EL_SP_PORT_LEFT: case EL_SP_PORT_RIGHT: @@ -7337,7 +7628,7 @@ int DigField(struct PlayerInfo *player, element == EL_SP_GRAVITY_PORT_RIGHT || element == EL_SP_GRAVITY_PORT_UP || element == EL_SP_GRAVITY_PORT_DOWN) - level.gravity = !level.gravity; + game.gravity = !game.gravity; /* automatically move to the next field with double speed */ player->programmed_action = move_direction; @@ -7389,6 +7680,7 @@ int DigField(struct PlayerInfo *player, } break; +#if 0 case EL_LAMP: Feld[x][y] = EL_LAMP_ACTIVE; local_player->lights_still_needed--; @@ -7396,7 +7688,9 @@ int DigField(struct PlayerInfo *player, PlaySoundLevel(x, y, SND_LAMP_ACTIVATING); return MF_ACTION; break; +#endif +#if 0 case EL_TIME_ORB_FULL: Feld[x][y] = EL_TIME_ORB_EMPTY; TimeLeft += 10; @@ -7405,6 +7699,7 @@ int DigField(struct PlayerInfo *player, PlaySoundStereo(SND_TIME_ORB_FULL_COLLECTING, SOUND_MIDDLE); return MF_ACTION; break; +#endif default: @@ -7422,7 +7717,9 @@ int DigField(struct PlayerInfo *player, if (!player->key[element - EL_GATE_1_GRAY]) return MF_NO_ACTION; } - else if (element == EL_EXIT_OPEN || element == EL_SP_EXIT_OPEN) + else if (element == EL_EXIT_OPEN || + element == EL_SP_EXIT_OPEN || + element == EL_SP_EXIT_OPENING) { sound_action = ACTION_PASSING; /* player is passing exit */ } @@ -7444,6 +7741,11 @@ int DigField(struct PlayerInfo *player, if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty)) return MF_NO_ACTION; +#if 1 + if (CAN_MOVE(element)) /* only fixed elements can be passed! */ + return MF_NO_ACTION; +#endif + if (element >= EL_EM_GATE_1 && element <= EL_EM_GATE_4) { if (!player->key[element - EL_EM_GATE_1]) @@ -7473,7 +7775,7 @@ int DigField(struct PlayerInfo *player, GfxElement[x][y] = GFX_ELEMENT(element); #else GfxElement[x][y] = - (CAN_BE_CRUMBLED(element) ? EL_SAND : GFX_ELEMENT(element)); + (GFX_CRUMBLED(element) ? EL_SAND : GFX_ELEMENT(element)); #endif player->is_digging = TRUE; } @@ -7482,7 +7784,7 @@ int DigField(struct PlayerInfo *player, CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_DIGGED); - TestIfElementTouchesCustomElement(x, y); + TestIfElementTouchesCustomElement(x, y); /* for empty space */ break; } @@ -7544,9 +7846,13 @@ int DigField(struct PlayerInfo *player, el2edimg(EL_KEY_1 + key_nr)); redraw_mask |= REDRAW_DOOR_1; } - else if (element == EL_ENVELOPE) + else if (IS_ENVELOPE(element)) { - ShowEnvelope(); +#if 1 + player->show_envelope = element; +#else + ShowEnvelope(element - EL_ENVELOPE_1); +#endif } else if (IS_DROPPABLE(element)) /* can be collected and dropped */ { @@ -7575,7 +7881,7 @@ int DigField(struct PlayerInfo *player, CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_COLLECTED); - TestIfElementTouchesCustomElement(x, y); + TestIfElementTouchesCustomElement(x, y); /* for empty space */ break; } @@ -7591,9 +7897,15 @@ int DigField(struct PlayerInfo *player, !(element == EL_SPRING && use_spring_bug)) return MF_NO_ACTION; +#if 1 + /* do not push elements already moving away faster than player */ + if (CAN_MOVE(element) && MovDir[x][y] == move_direction && + ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL) + return MF_NO_ACTION; +#else if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING) return MF_NO_ACTION; - +#endif if (!player->Pushing && game.engine_version >= RELEASE_IDENT(2,2,0,7)) player->push_delay_value = GET_NEW_PUSH_DELAY(element); @@ -7666,15 +7978,187 @@ int DigField(struct PlayerInfo *player, if (game.engine_version < RELEASE_IDENT(2,2,0,7)) player->push_delay_value = GET_NEW_PUSH_DELAY(element); +#if 1 + CheckTriggeredElementSideChange(x, y, element, dig_side, + CE_OTHER_GETS_PUSHED); + CheckElementSideChange(x, y, element, dig_side, + CE_PUSHED_BY_PLAYER, -1); +#else CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_PUSHED); CheckElementChange(x, y, element, CE_PUSHED_BY_PLAYER); +#endif break; } + else if (IS_SWITCHABLE(element)) + { + if (PLAYER_SWITCHING(player, x, y)) + return MF_ACTION; + +#if 1 + PlaySoundLevelElementAction(x, y, element, ACTION_ACTIVATING); +#endif + + if (element == EL_ROBOT_WHEEL) + { + Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE; + ZX = x; + ZY = y; + + DrawLevelField(x, y); + +#if 0 + PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVATING); +#endif + } + else if (element == EL_SP_TERMINAL) + { + int xx, yy; + +#if 0 + PlaySoundLevel(x, y, SND_SP_TERMINAL_ACTIVATING); +#endif + + for (yy=0; yySwitching = TRUE; + player->switch_x = x; + player->switch_y = y; + + ToggleBeltSwitch(x, y); + +#if 0 + PlaySoundLevel(x, y, SND_CLASS_CONVEYOR_BELT_SWITCH_ACTIVATING); +#endif + } + } + else if (element == EL_SWITCHGATE_SWITCH_UP || + element == EL_SWITCHGATE_SWITCH_DOWN) + { +#if 0 + if (!PLAYER_SWITCHING(player, x, y)) +#endif + { + player->Switching = TRUE; + player->switch_x = x; + player->switch_y = y; + + ToggleSwitchgateSwitch(x, y); + +#if 0 + PlaySoundLevel(x, y, SND_CLASS_SWITCHGATE_SWITCH_ACTIVATING); +#endif + } + } + else if (element == EL_LIGHT_SWITCH || + element == EL_LIGHT_SWITCH_ACTIVE) + { +#if 0 + if (!PLAYER_SWITCHING(player, x, y)) +#endif + { + player->Switching = TRUE; + player->switch_x = x; + player->switch_y = y; + + ToggleLightSwitch(x, y); + +#if 0 + PlaySoundLevel(x, y, element == EL_LIGHT_SWITCH ? + SND_LIGHT_SWITCH_ACTIVATING : + SND_LIGHT_SWITCH_DEACTIVATING); +#endif + } + } + else if (element == EL_TIMEGATE_SWITCH) + { + ActivateTimegateSwitch(x, y); + +#if 0 + PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVATING); +#endif + } + else if (element == EL_BALLOON_SWITCH_LEFT || + element == EL_BALLOON_SWITCH_RIGHT || + element == EL_BALLOON_SWITCH_UP || + element == EL_BALLOON_SWITCH_DOWN || + element == EL_BALLOON_SWITCH_ANY) + { + if (element == EL_BALLOON_SWITCH_ANY) + game.balloon_dir = move_direction; + else + game.balloon_dir = (element == EL_BALLOON_SWITCH_LEFT ? MV_LEFT : + element == EL_BALLOON_SWITCH_RIGHT ? MV_RIGHT : + element == EL_BALLOON_SWITCH_UP ? MV_UP : + element == EL_BALLOON_SWITCH_DOWN ? MV_DOWN : + MV_NO_MOVING); + +#if 0 + PlaySoundLevel(x, y, SND_CLASS_BALLOON_SWITCH_ACTIVATING); +#endif + } + else if (element == EL_LAMP) + { + Feld[x][y] = EL_LAMP_ACTIVE; + local_player->lights_still_needed--; + + DrawLevelField(x, y); + +#if 0 + PlaySoundLevel(x, y, SND_LAMP_ACTIVATING); +#endif + } + else if (element == EL_TIME_ORB_FULL) + { + Feld[x][y] = EL_TIME_ORB_EMPTY; + TimeLeft += 10; + DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2); + + DrawLevelField(x, y); + +#if 0 + PlaySoundStereo(SND_TIME_ORB_FULL_COLLECTING, SOUND_MIDDLE); +#endif + } + + return MF_ACTION; + } else { - CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_PRESSED); - CheckElementChange(x, y, element, CE_PRESSED_BY_PLAYER); +#if 1 + if (!PLAYER_SWITCHING(player, x, y)) +#else + if (!player->Switching) +#endif + { + player->Switching = TRUE; + player->switch_x = x; + player->switch_y = y; + + CheckTriggeredElementSideChange(x, y, element, dig_side, + CE_OTHER_IS_SWITCHING); + CheckElementSideChange(x, y, element, dig_side, CE_SWITCHED, -1); + } + + CheckTriggeredElementSideChange(x, y, element, dig_side, + CE_OTHER_GETS_PRESSED); + CheckElementSideChange(x, y, element, dig_side, + CE_PRESSED_BY_PLAYER, -1); } return MF_NO_ACTION;