rnd-20040322-B-src
[rocksndiamonds.git] / src / game.c
index ac8eced7871f3c3f5c04b49ea4a199d2a8b063f0..6fc7f7bdc7dbd196ecfd616c94935a282f716466 100644 (file)
 
 /* for Explode() */
 #define EX_PHASE_START         0
-#define EX_NO_EXPLOSION                0
-#define EX_NORMAL              1
-#define EX_CENTER              2
-#define EX_BORDER              3
+#define EX_TYPE_NONE           0
+#define EX_TYPE_NORMAL         (1 << 0)
+#define EX_TYPE_CENTER         (1 << 1)
+#define EX_TYPE_BORDER         (1 << 2)
+#define EX_TYPE_CROSS          (1 << 3)
+#define EX_TYPE_SINGLE_TILE    (EX_TYPE_CENTER | EX_TYPE_BORDER)
 
 /* special positions in the game control window (relative to control window) */
 #define XX_LEVEL               37
 
 #define GET_NEW_PUSH_DELAY(e)  (   (element_info[e].push_delay_fixed) + \
                                 RND(element_info[e].push_delay_random))
+#define GET_NEW_DROP_DELAY(e)  (   (element_info[e].drop_delay_fixed) + \
+                                RND(element_info[e].drop_delay_random))
 #define GET_NEW_MOVE_DELAY(e)  (   (element_info[e].move_delay_fixed) + \
                                 RND(element_info[e].move_delay_random))
 #define GET_MAX_MOVE_DELAY(e)  (   (element_info[e].move_delay_fixed) + \
@@ -1349,6 +1353,7 @@ static void InitGameEngine()
     element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize;
   }
 
+#if 0
   /* ---------- initialize move dig/leave ---------------------------------- */
 
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
@@ -1356,6 +1361,7 @@ static void InitGameEngine()
     element_info[i].can_leave_element = FALSE;
     element_info[i].can_leave_element_last = FALSE;
   }
+#endif
 
   /* ---------- initialize gem count --------------------------------------- */
 
@@ -1613,7 +1619,7 @@ void InitGame()
 
       ExplodePhase[x][y] = 0;
       ExplodeDelay[x][y] = 0;
-      ExplodeField[x][y] = EX_NO_EXPLOSION;
+      ExplodeField[x][y] = EX_TYPE_NONE;
 
       RunnerVisit[x][y] = 0;
       PlayerVisit[x][y] = 0;
@@ -2088,6 +2094,11 @@ void InitMovDir(int x, int y)
 
              break;
            }
+
+#if 1
+           if (MovDir[x][y] == MV_NO_MOVING)   /* no start direction found */
+             MovDir[x][y] = 1 << RND(4);       /* => use random direction */
+#endif
          }
        }                
       }
@@ -2614,7 +2625,7 @@ void RelocatePlayer(int x, int y, int element_raw)
   int element = (element_raw == EL_SP_MURPHY ? EL_PLAYER_1 : element_raw);
   struct PlayerInfo *player = &stored_player[element - EL_PLAYER_1];
   boolean ffwd_delay = (tape.playing && tape.fast_forward);
-  boolean no_delay = (tape.index_search);
+  boolean no_delay = (tape.warp_forward);
   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
   int wait_delay_value = (no_delay ? 0 : frame_delay_value);
   int old_jx, old_jy;
@@ -2846,11 +2857,12 @@ void Explode(int ex, int ey, int phase, int mode)
     /* --- This is only really needed (and now handled) in "Impact()". --- */
     /* do not explode moving elements that left the explode field in time */
     if (game.engine_version >= VERSION_IDENT(2,2,0,7) &&
-       center_element == EL_EMPTY && (mode == EX_NORMAL || mode == EX_CENTER))
+       center_element == EL_EMPTY &&
+       (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER))
       return;
 #endif
 
-    if (mode == EX_NORMAL || mode == EX_CENTER)
+    if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER)
       PlayLevelSoundAction(ex, ey, ACTION_EXPLODING);
 
     /* remove things displayed in background while burning dynamite */
@@ -2885,11 +2897,20 @@ void Explode(int ex, int ey, int phase, int mode)
       int element;
 
 #if 1
-      if (!IN_LEV_FIELD(x, y) || (mode != EX_NORMAL && (x != ex || y != ey)))
+#if 1
+      if (!IN_LEV_FIELD(x, y) ||
+         (mode & EX_TYPE_SINGLE_TILE && (x != ex || y != ey)) ||
+         (mode == EX_TYPE_CROSS      && (x != ex && y != ey)))
        continue;
 #else
       if (!IN_LEV_FIELD(x, y) ||
-         ((mode != EX_NORMAL || center_element == EL_AMOEBA_TO_DIAMOND) &&
+         (mode != EX_TYPE_NORMAL && (x != ex || y != ey)))
+       continue;
+#endif
+#else
+      if (!IN_LEV_FIELD(x, y) ||
+         ((mode != EX_TYPE_NORMAL ||
+           center_element == EL_AMOEBA_TO_DIAMOND) &&
           (x != ex || y != ey)))
        continue;
 #endif
@@ -3028,7 +3049,7 @@ void Explode(int ex, int ey, int phase, int mode)
        Store[x][y] = EL_EMPTY;
 
       if (x != ex || y != ey ||
-         center_element == EL_AMOEBA_TO_DIAMOND || mode == EX_BORDER)
+         center_element == EL_AMOEBA_TO_DIAMOND || mode == EX_TYPE_BORDER)
        Store2[x][y] = element;
 
 #if 0
@@ -3355,7 +3376,7 @@ void DynaExplode(int ex, int ey)
     player->dynabombs_left++;
   }
 
-  Explode(ex, ey, EX_PHASE_START, EX_CENTER);
+  Explode(ex, ey, EX_PHASE_START, EX_TYPE_CENTER);
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
@@ -3374,7 +3395,7 @@ void DynaExplode(int ex, int ey)
       if (element == EL_EXPLOSION && IS_ACTIVE_BOMB(Store2[x][y]))
        continue;
 
-      Explode(x, y, EX_PHASE_START, EX_BORDER);
+      Explode(x, y, EX_PHASE_START, EX_TYPE_BORDER);
 
       /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
       if (element != EL_EMPTY &&
@@ -3434,7 +3455,7 @@ void Bang(int x, int y)
     case EL_PACMAN:
     case EL_MOLE:
       RaiseScoreElement(element);
-      Explode(x, y, EX_PHASE_START, EX_NORMAL);
+      Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
       break;
     case EL_DYNABOMB_PLAYER_1_ACTIVE:
     case EL_DYNABOMB_PLAYER_2_ACTIVE:
@@ -3452,17 +3473,21 @@ void Bang(int x, int y)
     case EL_AMOEBA_TO_DIAMOND:
 #endif
       if (IS_PLAYER(x, y))
-       Explode(x, y, EX_PHASE_START, EX_NORMAL);
+       Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
       else
-       Explode(x, y, EX_PHASE_START, EX_CENTER);
+       Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER);
       break;
     default:
-      if (CAN_EXPLODE_DYNA(element))
+      if (CAN_EXPLODE_CROSS(element))
+#if 1
+       Explode(x, y, EX_PHASE_START, EX_TYPE_CROSS);
+#else
        DynaExplode(x, y);
+#endif
       else if (CAN_EXPLODE_1X1(element))
-       Explode(x, y, EX_PHASE_START, EX_CENTER);
+       Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER);
       else
-       Explode(x, y, EX_PHASE_START, EX_NORMAL);
+       Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
       break;
   }
 
@@ -5317,11 +5342,30 @@ void StartMoving(int x, int y)
          {
            int flamed = MovingOrBlocked2Element(xx, yy);
 
+           /* !!! */
+#if 0
+           if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed))
+             Bang(xx, yy);
+           else if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy))
+             RemoveMovingField(xx, yy);
+           else
+             RemoveField(xx, yy);
+#else
            if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed))
              Bang(xx, yy);
            else
              RemoveMovingField(xx, yy);
+#endif
 
+#if 0
+           if (ChangeDelay[xx][yy])
+             printf("::: !!! [%d]\n", (IS_MOVING(xx, yy) ||
+                                       Feld[xx][yy] == EL_BLOCKED));
+#endif
+
+#if 1
+           ChangeDelay[xx][yy] = 0;
+#endif
            Feld[xx][yy] = EL_FLAMES;
            if (IN_SCR_FIELD(sx, sy))
            {
@@ -5521,8 +5565,21 @@ void StartMoving(int x, int y)
        PlayLevelSoundAction(x, y, action);
       }
 
+#if 1
+#if 1
+      Store[newx][newy] = EL_EMPTY;
+      if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
+       Store[newx][newy] = element_info[element].move_leave_element;
+#else
+      Store[newx][newy] = EL_EMPTY;
+      if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)) ||
+         element_info[element].move_leave_type == LEAVE_TYPE_UNLIMITED)
+       Store[newx][newy] = element_info[element].move_leave_element;
+#endif
+#else
       if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
        element_info[element].can_leave_element = TRUE;
+#endif
 
       if (move_pattern & MV_MAZE_RUNNER_STYLE)
       {
@@ -5575,11 +5632,25 @@ void StartMoving(int x, int y)
 
          MovDelay[x][y] = 50;
 
+         /* !!! */
+#if 0
+         RemoveField(newx, newy);
+#endif
          Feld[newx][newy] = EL_FLAMES;
          if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_EMPTY)
+         {
+#if 0
+           RemoveField(newx1, newy1);
+#endif
            Feld[newx1][newy1] = EL_FLAMES;
+         }
          if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY)
+         {
+#if 0
+           RemoveField(newx2, newy2);
+#endif
            Feld[newx2][newy2] = EL_FLAMES;
+         }
 
          return;
        }
@@ -5815,8 +5886,23 @@ void ContinueMoving(int x, int y)
   {
     element = Feld[newx][newy] = EL_ACID;
   }
+#if 1
+  else if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) &&
+          ei->move_leave_element != EL_EMPTY &&
+          (ei->move_leave_type == LEAVE_TYPE_UNLIMITED ||
+           Store[x][y] != EL_EMPTY))
+  {
+    /* some elements can leave other elements behind after moving */
+
+    Feld[x][y] = ei->move_leave_element;
+    InitField(x, y, FALSE);
+
+    if (GFX_CRUMBLED(Feld[x][y]))
+      DrawLevelFieldCrumbledSandNeighbours(x, y);
+  }
+#endif
 
-  Store[x][y] = 0;
+  Store[x][y] = EL_EMPTY;
   MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
   MovDelay[newx][newy] = 0;
 
@@ -5844,7 +5930,7 @@ void ContinueMoving(int x, int y)
 
   ResetGfxAnimation(x, y);     /* reset animation values for old field */
 
-#if 1
+#if 0
   /* some elements can leave other elements behind after moving */
   if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) &&
       ei->move_leave_element != EL_EMPTY &&
@@ -7717,7 +7803,7 @@ void GameActions()
   action_delay_value =
     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
 
-  if (tape.playing && tape.index_search && !tape.pausing)
+  if (tape.playing && tape.warp_forward && !tape.pausing)
     action_delay_value = 0;
 
   /* ---------- main game synchronization point ---------- */
@@ -8101,7 +8187,7 @@ void GameActions()
       CheckDynamite(x, y);
 #if 0
     else if (element == EL_EXPLOSION && !game.explosions_delayed)
-      Explode(x, y, ExplodePhase[x][y], EX_NORMAL);
+      Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL);
 #endif
     else if (element == EL_AMOEBA_GROWING)
       AmoebeWaechst(x, y);
@@ -8217,9 +8303,9 @@ void GameActions()
       if (ExplodeField[x][y])
        Explode(x, y, EX_PHASE_START, ExplodeField[x][y]);
       else if (element == EL_EXPLOSION)
-       Explode(x, y, ExplodePhase[x][y], EX_NORMAL);
+       Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL);
 
-      ExplodeField[x][y] = EX_NO_EXPLOSION;
+      ExplodeField[x][y] = EX_TYPE_NONE;
     }
 
     game.explosions_delayed = TRUE;
@@ -8686,7 +8772,9 @@ boolean MovePlayerOneStep(struct PlayerInfo *player,
 
   player->step_counter++;
 
+#if 0
   player->drop_delay = 0;
+#endif
 
   PlayerVisit[jx][jy] = FrameCounter;
 
@@ -8919,24 +9007,22 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
       int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1];
 
 #if 1
+      CheckTriggeredElementChangePlayer(old_jx, old_jy, Feld[old_jx][old_jy],
+                                       CE_OTHER_GETS_LEFT,
+                                       player->index_bit, leave_side);
+
       if (IS_CUSTOM_ELEMENT(Feld[old_jx][old_jy]))
-      {
-       CheckTriggeredElementChangePlayer(old_jx, old_jy, Feld[old_jx][old_jy],
-                                         CE_OTHER_GETS_LEFT,
-                                         player->index_bit, leave_side);
        CheckElementChangePlayer(old_jx, old_jy, Feld[old_jx][old_jy],
                                 CE_LEFT_BY_PLAYER,
                                 player->index_bit, leave_side);
-      }
+
+      CheckTriggeredElementChangePlayer(jx, jy, Feld[jx][jy],
+                                       CE_OTHER_GETS_ENTERED,
+                                       player->index_bit, enter_side);
 
       if (IS_CUSTOM_ELEMENT(Feld[jx][jy]))
-      {
-       CheckTriggeredElementChangePlayer(jx, jy, Feld[jx][jy],
-                                         CE_OTHER_GETS_ENTERED,
-                                         player->index_bit, enter_side);
        CheckElementChangePlayer(jx, jy, Feld[jx][jy], CE_ENTERED_BY_PLAYER,
                                 player->index_bit, enter_side);
-      }
 #endif
 
     }
@@ -9072,24 +9158,22 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
       int old_jy = last_jy;
 
 #if 1
+      CheckTriggeredElementChangePlayer(old_jx, old_jy, Feld[old_jx][old_jy],
+                                       CE_OTHER_GETS_LEFT,
+                                       player->index_bit, leave_side);
+
       if (IS_CUSTOM_ELEMENT(Feld[old_jx][old_jy]))
-      {
-       CheckTriggeredElementChangePlayer(old_jx, old_jy, Feld[old_jx][old_jy],
-                                         CE_OTHER_GETS_LEFT,
-                                         player->index_bit, leave_side);
        CheckElementChangePlayer(old_jx, old_jy, Feld[old_jx][old_jy],
                                 CE_LEFT_BY_PLAYER,
                                 player->index_bit, leave_side);
-      }
+
+      CheckTriggeredElementChangePlayer(jx, jy, Feld[jx][jy],
+                                       CE_OTHER_GETS_ENTERED,
+                                       player->index_bit, enter_side);
 
       if (IS_CUSTOM_ELEMENT(Feld[jx][jy]))
-      {
-       CheckTriggeredElementChangePlayer(jx, jy, Feld[jx][jy],
-                                         CE_OTHER_GETS_ENTERED,
-                                         player->index_bit, enter_side);
        CheckElementChangePlayer(jx, jy, Feld[jx][jy], CE_ENTERED_BY_PLAYER,
                                 player->index_bit, enter_side);
-      }
 #endif
 
     }
@@ -10233,7 +10317,7 @@ int DigField(struct PlayerInfo *player,
        PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
 
        CheckTriggeredElementChangePlayer(x, y, element, CE_OTHER_GETS_DIGGED,
-                                         player->index_bit, CH_SIDE_ANY);
+                                         player->index_bit, dig_side);
 
 #if 1
        if (mode == DF_SNAP)
@@ -10333,7 +10417,7 @@ int DigField(struct PlayerInfo *player,
 
        CheckTriggeredElementChangePlayer(x, y, element,
                                          CE_OTHER_GETS_COLLECTED,
-                                         player->index_bit, CH_SIDE_ANY);
+                                         player->index_bit, dig_side);
 
 #if 1
        if (mode == DF_SNAP)
@@ -10698,15 +10782,25 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy)
 
 boolean DropElement(struct PlayerInfo *player)
 {
+  static int trigger_sides[4] =
+  {
+    CH_SIDE_LEFT,      /* dropping left  */
+    CH_SIDE_RIGHT,     /* dropping right */
+    CH_SIDE_TOP,       /* dropping up    */
+    CH_SIDE_BOTTOM,    /* dropping down  */
+  };
   int jx = player->jx, jy = player->jy;
+  int drop_direction = player->MovDir;
+  int drop_side = trigger_sides[MV_DIR_BIT(drop_direction)];
   int old_element = Feld[jx][jy];
-  int new_element = (player->inventory_size > 0 ?
-                    player->inventory_element[player->inventory_size - 1] :
-                    player->inventory_infinite_element != EL_UNDEFINED ?
-                    player->inventory_infinite_element :
-                    player->dynabombs_left > 0 ?
-                    EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr :
-                    EL_UNDEFINED);
+  int drop_element = (player->inventory_size > 0 ?
+                     player->inventory_element[player->inventory_size - 1] :
+                     player->inventory_infinite_element != EL_UNDEFINED ?
+                     player->inventory_infinite_element :
+                     player->dynabombs_left > 0 ?
+                     EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr :
+                     EL_UNDEFINED);
+  int new_element = drop_element;      /* default: element does not change */
 
   /* check if player is active, not moving and ready to drop */
   if (!player->active || player->MovPos || player->drop_delay > 0)
@@ -10777,9 +10871,9 @@ boolean DropElement(struct PlayerInfo *player)
 
     CheckTriggeredElementChangePlayer(jx, jy, new_element,
                                      CE_OTHER_GETS_DROPPED,
-                                     player->index_bit, CH_SIDE_ANY);
+                                     player->index_bit, drop_side);
     CheckElementChangePlayer(jx, jy, new_element, CE_DROPPED_BY_PLAYER,
-                            player->index_bit, CH_SIDE_ANY);
+                            player->index_bit, drop_side);
 
     TestIfElementTouchesCustomElement(jx, jy);
   }
@@ -10814,12 +10908,14 @@ boolean DropElement(struct PlayerInfo *player)
 #endif
   }
 
-  new_element = Feld[jx][jy];
+  new_element = Feld[jx][jy];          /* element might have changed */
 
   if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) &&
       element_info[new_element].move_pattern == MV_WHEN_DROPPED)
   {
+#if 0
     int move_stepsize = element_info[new_element].move_stepsize;
+#endif
     int direction, dx, dy, nextx, nexty;
 
     if (element_info[new_element].move_direction_initial == MV_START_AUTOMATIC)
@@ -10852,13 +10948,19 @@ boolean DropElement(struct PlayerInfo *player)
 #endif
     }
 
+#if 0
     player->drop_delay = 2 * TILEX / move_stepsize + 1;
+#endif
   }
 
 #if 0
   player->drop_delay = 8 + 8 + 8;
 #endif
 
+#if 1
+  player->drop_delay = GET_NEW_DROP_DELAY(drop_element);
+#endif
+
 #endif
 
   player->is_dropping = TRUE;
@@ -11084,21 +11186,15 @@ void RequestQuitGame(boolean ask_if_really_quit)
   {
 
 #if 1
-    if (tape.playing && tape.index_search)
-    {
-      SetDrawDeactivationMask(REDRAW_NONE);
-      audio.sound_deactivated = FALSE;
-    }
+    if (tape.playing && tape.deactivate_display)
+      TapeDeactivateDisplayOff(TRUE);
 #endif
 
     OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
 
 #if 1
-    if (tape.playing && tape.index_search)
-    {
-      SetDrawDeactivationMask(REDRAW_FIELD);
-      audio.sound_deactivated = TRUE;
-    }
+    if (tape.playing && tape.deactivate_display)
+      TapeDeactivateDisplayOn();
 #endif
 
   }