rnd-20050525-1-src
[rocksndiamonds.git] / src / game.c
index 5466f2d82ac30d6be5e764d730bc7485d895c2ba..bac83725cb81b334bd9511d71ef56a865744b23d 100644 (file)
 #define USE_NEW_AMOEBA_CODE    FALSE
 
 /* EXPERIMENTAL STUFF */
-#define USE_NEW_STUFF          TRUE                            * 1
+#define USE_NEW_STUFF          (TRUE                           * 1)
 
-#define USE_NEW_MOVE_STYLE     TRUE    * USE_NEW_STUFF         * 1
-#define USE_NEW_MOVE_DELAY     TRUE    * USE_NEW_STUFF         * 1
-#define USE_NEW_PUSH_DELAY     TRUE    * USE_NEW_STUFF         * 1
-#define USE_NEW_BLOCK_STYLE    TRUE    * USE_NEW_STUFF         * 1 * 1
-#define USE_NEW_SP_SLIPPERY    TRUE    * USE_NEW_STUFF         * 1
-#define USE_NEW_RANDOMIZE      TRUE    * USE_NEW_STUFF         * 1
+#define USE_NEW_MOVE_STYLE     (TRUE   * USE_NEW_STUFF         * 1)
+#define USE_NEW_MOVE_DELAY     (TRUE   * USE_NEW_STUFF         * 1)
+#define USE_NEW_PUSH_DELAY     (TRUE   * USE_NEW_STUFF         * 1)
+#define USE_NEW_BLOCK_STYLE    (TRUE   * USE_NEW_STUFF         * 1)
+#define USE_NEW_SP_SLIPPERY    (TRUE   * USE_NEW_STUFF         * 1)
+#define USE_NEW_RANDOMIZE      (TRUE   * USE_NEW_STUFF         * 1)
+
+#define USE_PUSH_BUGFIX                (TRUE   * USE_NEW_STUFF         * 1)
+
+#define USE_CAN_MOVE_NOT_MOVING        (TRUE   * USE_NEW_STUFF         * 1)
+#define USE_PREVIOUS_MOVE_DIR  (TRUE   * USE_NEW_STUFF         * 1)
 
-#define USE_PUSH_BUGFIX                TRUE    * USE_NEW_STUFF         * 1
 
 /* for DigField() */
 #define DF_NO_PUSH             0
@@ -1062,11 +1066,12 @@ inline void DrawGameValue_Dynamite(int value)
   DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2);
 }
 
-inline void DrawGameValue_Keys(int key[4])
+inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS])
 {
   int i;
 
-  for (i = 0; i < MAX_KEYS; i++)
+  /* currently only 4 of 8 possible keys are displayed */
+  for (i = 0; i < STD_NUM_KEYS; i++)
     if (key[i])
       DrawMiniGraphicExt(drawto, DX_KEYS + i * MINI_TILEX, DY_KEYS,
                         el2edimg(EL_KEY_1 + i));
@@ -1112,12 +1117,14 @@ inline void DrawGameValue_Level(int value)
 void DrawAllGameValues(int emeralds, int dynamite, int score, int time,
                       int key_bits)
 {
-  int key[4];
+  int key[MAX_NUM_KEYS];
   int i;
 
-  for (i = 0; i < MAX_KEYS; i++)
+  for (i = 0; i < MAX_NUM_KEYS; i++)
     key[i] = key_bits & (1 << i);
 
+  DrawGameValue_Level(level_nr);
+
   DrawGameValue_Emeralds(emeralds);
   DrawGameValue_Dynamite(dynamite);
   DrawGameValue_Score(score);
@@ -1584,7 +1591,7 @@ void InitGame()
     player->lights_still_needed = 0;
     player->friends_still_needed = 0;
 
-    for (j = 0; j < MAX_KEYS; j++)
+    for (j = 0; j < MAX_NUM_KEYS; j++)
       player->key[j] = FALSE;
 
     player->dynabomb_count = 0;
@@ -2541,6 +2548,37 @@ int NewHiScore()
   return position;
 }
 
+inline static int getElementMoveStepsize(int x, int y)
+{
+  int element = Feld[x][y];
+  int direction = MovDir[x][y];
+  int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
+  int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
+  int horiz_move = (dx != 0);
+  int sign = (horiz_move ? dx : dy);
+  int step = sign * element_info[element].move_stepsize;
+
+  /* special values for move stepsize for spring and things on conveyor belt */
+  if (horiz_move)
+  {
+#if 0
+    if (element == EL_SPRING)
+      step = sign * MOVE_STEPSIZE_NORMAL * 2;
+    else if (CAN_FALL(element) && !CAN_MOVE(element) &&
+            y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
+      step = sign * MOVE_STEPSIZE_NORMAL / 2;
+#else
+    if (CAN_FALL(element) &&
+       y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
+      step = sign * MOVE_STEPSIZE_NORMAL / 2;
+    else if (element == EL_SPRING)
+      step = sign * MOVE_STEPSIZE_NORMAL * 2;
+#endif
+  }
+
+  return step;
+}
+
 void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir)
 {
   if (player->GfxAction != action || player->GfxDir != dir)
@@ -2580,6 +2618,27 @@ void InitMovingField(int x, int y, int direction)
   if (!WasJustMoving[x][y] || direction != MovDir[x][y])
     ResetGfxAnimation(x, y);
 
+#if USE_CAN_MOVE_NOT_MOVING
+
+  MovDir[x][y] = direction;
+  GfxDir[x][y] = direction;
+  GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ?
+                    ACTION_FALLING : ACTION_MOVING);
+
+  if (getElementMoveStepsize(x, y) != 0)       /* moving or being moved */
+  {
+    if (Feld[newx][newy] == EL_EMPTY)
+      Feld[newx][newy] = EL_BLOCKED;
+
+    MovDir[newx][newy] = MovDir[x][y];
+    GfxFrame[newx][newy] = GfxFrame[x][y];
+    GfxRandom[newx][newy] = GfxRandom[x][y];
+    GfxAction[newx][newy] = GfxAction[x][y];
+    GfxDir[newx][newy] = GfxDir[x][y];
+  }
+
+#else
+
   MovDir[newx][newy] = MovDir[x][y] = direction;
   GfxDir[x][y] = direction;
 
@@ -2595,6 +2654,7 @@ void InitMovingField(int x, int y, int direction)
   GfxRandom[newx][newy] = GfxRandom[x][y];
   GfxAction[newx][newy] = GfxAction[x][y];
   GfxDir[newx][newy] = GfxDir[x][y];
+#endif
 }
 
 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
@@ -4168,6 +4228,10 @@ static void RedrawAllLightSwitchesAndInvisibleElements()
          Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
 
        DrawLevelField(x, y);
+
+       /* uncrumble neighbour fields, if needed */
+       if (element == EL_INVISIBLE_SAND)
+         DrawLevelFieldCrumbledSandNeighbours(x, y);
       }
       else if (element == EL_INVISIBLE_STEELWALL_ACTIVE ||
               element == EL_INVISIBLE_WALL_ACTIVE ||
@@ -4177,6 +4241,10 @@ static void RedrawAllLightSwitchesAndInvisibleElements()
          Feld[x][y] = getInvisibleFromInvisibleActiveElement(element);
 
        DrawLevelField(x, y);
+
+       /* re-crumble neighbour fields, if needed */
+       if (element == EL_INVISIBLE_SAND)
+         DrawLevelFieldCrumbledSandNeighbours(x, y);
       }
     }
   }
@@ -4226,37 +4294,6 @@ static void ActivateTimegateSwitch(int x, int y)
   Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE;
 }
 
-inline static int getElementMoveStepsize(int x, int y)
-{
-  int element = Feld[x][y];
-  int direction = MovDir[x][y];
-  int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
-  int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
-  int horiz_move = (dx != 0);
-  int sign = (horiz_move ? dx : dy);
-  int step = sign * element_info[element].move_stepsize;
-
-  /* special values for move stepsize for spring and things on conveyor belt */
-  if (horiz_move)
-  {
-#if 0
-    if (element == EL_SPRING)
-      step = sign * MOVE_STEPSIZE_NORMAL * 2;
-    else if (CAN_FALL(element) && !CAN_MOVE(element) &&
-            y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
-      step = sign * MOVE_STEPSIZE_NORMAL / 2;
-#else
-    if (CAN_FALL(element) &&
-       y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
-      step = sign * MOVE_STEPSIZE_NORMAL / 2;
-    else if (element == EL_SPRING)
-      step = sign * MOVE_STEPSIZE_NORMAL * 2;
-#endif
-  }
-
-  return step;
-}
-
 void Impact(int x, int y)
 {
   boolean lastline = (y == lev_fieldy-1);
@@ -4995,6 +5032,11 @@ inline static void TurnRoundExt(int x, int y)
     boolean can_turn_right =
       CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
 
+#if USE_CAN_MOVE_NOT_MOVING
+    if (element_info[element].move_stepsize == 0)      /* not moving */
+      return;
+#endif
+
     if (move_pattern == MV_TURNING_LEFT)
       MovDir[x][y] = left_dir;
     else if (move_pattern == MV_TURNING_RIGHT)
@@ -5105,6 +5147,16 @@ inline static void TurnRoundExt(int x, int y)
       boolean first_horiz = RND(2);
       int new_move_dir = MovDir[x][y];
 
+#if USE_CAN_MOVE_NOT_MOVING
+      if (element_info[element].move_stepsize == 0)    /* not moving */
+      {
+       first_horiz = (ABS(attr_x - x) >= ABS(attr_y - y));
+       MovDir[x][y] &= (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+
+       return;
+      }
+#endif
+
       MovDir[x][y] =
        new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
       Moving2Blocked(x, y, &newx, &newy);
@@ -6411,7 +6463,9 @@ void ContinueMoving(int x, int y)
 #endif
 
   Store[x][y] = EL_EMPTY;
-  MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
+  MovPos[x][y] = 0;
+  MovDir[x][y] = 0;
+  MovDelay[x][y] = 0;
   MovDelay[newx][newy] = 0;
 
   if (CAN_CHANGE(element))
@@ -6436,7 +6490,10 @@ void ContinueMoving(int x, int y)
 
   Pushed[x][y] = Pushed[newx][newy] = FALSE;
 
+#if 0
+  /* do this after checking for left-behind element */
   ResetGfxAnimation(x, y);     /* reset animation values for old field */
+#endif
 
 #if 1
   /* some elements can leave other elements behind after moving */
@@ -6453,6 +6510,12 @@ void ContinueMoving(int x, int y)
     int move_leave_element = ei->move_leave_element;
 
     Feld[x][y] = move_leave_element;
+
+#if USE_PREVIOUS_MOVE_DIR
+    if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
+      MovDir[x][y] = direction;
+#endif
+
     InitField(x, y, FALSE);
 
     if (GFX_CRUMBLED(Feld[x][y]))
@@ -6481,6 +6544,11 @@ void ContinueMoving(int x, int y)
   ei->can_leave_element = FALSE;
 #endif
 
+#if 1
+  /* do this after checking for left-behind element */
+  ResetGfxAnimation(x, y);     /* reset animation values for old field */
+#endif
+
 #if 0
   /* 2.1.1 (does not work correctly for spring) */
   if (!CAN_MOVE(element))
@@ -9416,6 +9484,9 @@ static boolean canFallDown(struct PlayerInfo *player)
 
   return (IN_LEV_FIELD(jx, jy + 1) &&
          (IS_FREE(jx, jy + 1) ||
+#if USE_NEW_BLOCK_STYLE
+          Feld[jx][jy + 1] == EL_PLAYER_IS_LEAVING ||
+#endif
           (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)) &&
          IS_WALKABLE_FROM(Feld[jx][jy], MV_DOWN) &&
          !IS_WALKABLE_INSIDE(Feld[jx][jy]));
@@ -11358,14 +11429,14 @@ int DigField(struct PlayerInfo *player,
          return MF_NO_ACTION;  /* player cannot walk here due to gravity */
 #endif
 
-       if (IS_GATE(element))
+       if (IS_RND_GATE(element))
        {
-         if (!player->key[element - EL_GATE_1])
+         if (!player->key[RND_GATE_NR(element)])
            return MF_NO_ACTION;
        }
-       else if (IS_GATE_GRAY(element))
+       else if (IS_RND_GATE_GRAY(element))
        {
-         if (!player->key[element - EL_GATE_1_GRAY])
+         if (!player->key[RND_GATE_GRAY_NR(element)])
            return MF_NO_ACTION;
        }
        else if (element == EL_EXIT_OPEN ||
@@ -11428,12 +11499,12 @@ int DigField(struct PlayerInfo *player,
 
        if (IS_EM_GATE(element))
        {
-         if (!player->key[element - EL_EM_GATE_1])
+         if (!player->key[EM_GATE_NR(element)])
            return MF_NO_ACTION;
        }
        else if (IS_EM_GATE_GRAY(element))
        {
-         if (!player->key[element - EL_EM_GATE_1_GRAY])
+         if (!player->key[EM_GATE_GRAY_NR(element)])
            return MF_NO_ACTION;
        }
        else if (IS_SP_PORT(element))
@@ -11544,13 +11615,9 @@ int DigField(struct PlayerInfo *player,
        {
          player->dynabomb_xl = TRUE;
        }
-       else if ((element >= EL_KEY_1 && element <= EL_KEY_4) ||
-                (element >= EL_EM_KEY_1 && element <= EL_EM_KEY_4))
+       else if (IS_KEY(element))
        {
-         int key_nr = (element >= EL_KEY_1 && element <= EL_KEY_4 ?
-                       element - EL_KEY_1 : element - EL_EM_KEY_1);
-
-         player->key[key_nr] = TRUE;
+         player->key[KEY_NR(element)] = TRUE;
 
          DrawGameValue_Keys(player->key);
 
@@ -12462,17 +12529,21 @@ void PlayLevelSound_EM(int x, int y, int element_em, int sample)
       break;
 
     case SAMPLE_bug:
-      PlayLevelSoundElementAction(x, y, EL_BUG, ACTION_MOVING);
+      PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
       break;
 
     case SAMPLE_tank:
-      PlayLevelSoundElementAction(x, y, EL_SPACESHIP, ACTION_MOVING);
+      PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
       break;
 
-    case SAMPLE_android:
+    case SAMPLE_android_clone:
       PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
       break;
 
+    case SAMPLE_android_move:
+      PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
+      break;
+
     case SAMPLE_spring:
       PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
       break;
@@ -12482,7 +12553,11 @@ void PlayLevelSound_EM(int x, int y, int element_em, int sample)
       break;
 
     case SAMPLE_eater:
-      PlayLevelSoundElementAction(x, y, EL_YAMYAM, ACTION_WAITING);
+      PlayLevelSoundElementAction(x, y, element, ACTION_WAITING);
+      break;
+
+    case SAMPLE_eater_eat:
+      PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
       break;
 
     case SAMPLE_alien:
@@ -12498,11 +12573,16 @@ void PlayLevelSound_EM(int x, int y, int element_em, int sample)
       break;
 
     case SAMPLE_squash:
+      /* !!! CHECK THIS !!! */
+#if 1
+      PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING);
+#else
       PlayLevelSoundElementAction(x, y, element, ACTION_SMASHED_BY_ROCK);
+#endif
       break;
 
     case SAMPLE_wonderfall:
-      PlayLevelSoundElementAction(x, y, EL_MAGIC_WALL, ACTION_FILLING);
+      PlayLevelSoundElementAction(x, y, element, ACTION_FILLING);
       break;
 
     case SAMPLE_drip:
@@ -12518,7 +12598,7 @@ void PlayLevelSound_EM(int x, int y, int element_em, int sample)
       break;
 
     case SAMPLE_acid:
-      PlayLevelSound(x, y, SND_ACID_SPLASHING);
+      PlayLevelSoundElementAction(x, y, element, ACTION_SPLASHING);
       break;
 
     case SAMPLE_ball:
@@ -12537,7 +12617,11 @@ void PlayLevelSound_EM(int x, int y, int element_em, int sample)
       PlayLevelSoundElementAction(x, y, element, ACTION_PASSING);
       break;
 
-    case SAMPLE_exit:
+    case SAMPLE_exit_open:
+      PlayLevelSoundElementAction(x, y, element, ACTION_OPENING);
+      break;
+
+    case SAMPLE_exit_leave:
       PlayLevelSoundElementAction(x, y, element, ACTION_PASSING);
       break;
 
@@ -12554,21 +12638,21 @@ void PlayLevelSound_EM(int x, int y, int element_em, int sample)
       break;
 
     case SAMPLE_wheel:
-      PlayLevelSound(x, y, SND_ROBOT_WHEEL_ACTIVE);
+      PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
       break;
 
     case SAMPLE_boom:
       PlayLevelSoundElementAction(x, y, element, ACTION_EXPLODING);
       break;
 
-    case SAMPLE_time:
-      PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
-      break;
-
     case SAMPLE_die:
       PlayLevelSoundElementAction(x, y, element, ACTION_DYING);
       break;
 
+    case SAMPLE_time:
+      PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
+      break;
+
     default:
       PlayLevelSoundElementAction(x, y, element, ACTION_DEFAULT);
       break;
@@ -12644,6 +12728,14 @@ void RaiseScoreElement(int element)
     case EL_KEY_2:
     case EL_KEY_3:
     case EL_KEY_4:
+    case EL_EM_KEY_1:
+    case EL_EM_KEY_2:
+    case EL_EM_KEY_3:
+    case EL_EM_KEY_4:
+    case EL_EMC_KEY_5:
+    case EL_EMC_KEY_6:
+    case EL_EMC_KEY_7:
+    case EL_EMC_KEY_8:
       RaiseScore(level.score[SC_KEY]);
       break;
     default: