rnd-19990829-1-src
[rocksndiamonds.git] / src / game.c
index fc0d64767d09631bef0d1fb55345d7ab2c7b26f2..d7fb2368f8536f59501a5dc05cbe86eb6309eda9 100644 (file)
 
 /* forward declaration for internal use */
 static void CheckGravityMovement(struct PlayerInfo *);
+static void KillHeroUnlessForceField(struct PlayerInfo *);
 
 static void MapGameButtons();
 static void HandleGameButtons(struct GadgetInfo *);
@@ -188,19 +189,19 @@ static int getBeltNrFromElement(int element)
 
 static int getBeltNrFromSwitchElement(int element)
 {
-  return (element < EL_BELT2_SWITCH_L ? 0 :
-         element < EL_BELT3_SWITCH_L ? 1 :
-         element < EL_BELT4_SWITCH_L ? 2 : 3);
+  return (element < EL_BELT2_SWITCH_LEFT ? 0 :
+         element < EL_BELT3_SWITCH_LEFT ? 1 :
+         element < EL_BELT4_SWITCH_LEFT ? 2 : 3);
 }
 
 static int getBeltDirNrFromSwitchElement(int element)
 {
   static int belt_base_element[4] =
   {
-    EL_BELT1_SWITCH_L,
-    EL_BELT2_SWITCH_L,
-    EL_BELT3_SWITCH_L,
-    EL_BELT4_SWITCH_L
+    EL_BELT1_SWITCH_LEFT,
+    EL_BELT2_SWITCH_LEFT,
+    EL_BELT3_SWITCH_LEFT,
+    EL_BELT4_SWITCH_LEFT
   };
 
   int belt_nr = getBeltNrFromSwitchElement(element);
@@ -281,36 +282,41 @@ static void InitField(int x, int y, boolean init_game)
        Feld[x][y] = EL_BADEWANNE5;
       break;
 
-    case EL_KAEFER_R:
-    case EL_KAEFER_O:
-    case EL_KAEFER_L:
-    case EL_KAEFER_U:
+    case EL_KAEFER_RIGHT:
+    case EL_KAEFER_UP:
+    case EL_KAEFER_LEFT:
+    case EL_KAEFER_DOWN:
     case EL_KAEFER:
-    case EL_FLIEGER_R:
-    case EL_FLIEGER_O:
-    case EL_FLIEGER_L:
-    case EL_FLIEGER_U:
+    case EL_FLIEGER_RIGHT:
+    case EL_FLIEGER_UP:
+    case EL_FLIEGER_LEFT:
+    case EL_FLIEGER_DOWN:
     case EL_FLIEGER:
-    case EL_BUTTERFLY_R:
-    case EL_BUTTERFLY_O:
-    case EL_BUTTERFLY_L:
-    case EL_BUTTERFLY_U:
+    case EL_BUTTERFLY_RIGHT:
+    case EL_BUTTERFLY_UP:
+    case EL_BUTTERFLY_LEFT:
+    case EL_BUTTERFLY_DOWN:
     case EL_BUTTERFLY:
-    case EL_FIREFLY_R:
-    case EL_FIREFLY_O:
-    case EL_FIREFLY_L:
-    case EL_FIREFLY_U:
+    case EL_FIREFLY_RIGHT:
+    case EL_FIREFLY_UP:
+    case EL_FIREFLY_LEFT:
+    case EL_FIREFLY_DOWN:
     case EL_FIREFLY:
-    case EL_PACMAN_R:
-    case EL_PACMAN_O:
-    case EL_PACMAN_L:
-    case EL_PACMAN_U:
+    case EL_PACMAN_RIGHT:
+    case EL_PACMAN_UP:
+    case EL_PACMAN_LEFT:
+    case EL_PACMAN_DOWN:
     case EL_MAMPFER:
     case EL_MAMPFER2:
     case EL_ROBOT:
     case EL_PACMAN:
     case EL_SP_SNIKSNAK:
     case EL_SP_ELECTRON:
+    case EL_MOLE_LEFT:
+    case EL_MOLE_RIGHT:
+    case EL_MOLE_UP:
+    case EL_MOLE_DOWN:
+    case EL_MOLE:
       InitMovDir(x, y);
       break;
 
@@ -339,7 +345,6 @@ static void InitField(int x, int y, boolean init_game)
       local_player->sokobanfields_still_needed++;
       break;
 
-    case EL_MAULWURF:
     case EL_PINGUIN:
       local_player->friends_still_needed++;
       break;
@@ -366,18 +371,18 @@ static void InitField(int x, int y, boolean init_game)
       Feld[x][y] = EL_EM_KEY_4;
       break;
 
-    case EL_BELT1_SWITCH_L:
-    case EL_BELT1_SWITCH_M:
-    case EL_BELT1_SWITCH_R:
-    case EL_BELT2_SWITCH_L:
-    case EL_BELT2_SWITCH_M:
-    case EL_BELT2_SWITCH_R:
-    case EL_BELT3_SWITCH_L:
-    case EL_BELT3_SWITCH_M:
-    case EL_BELT3_SWITCH_R:
-    case EL_BELT4_SWITCH_L:
-    case EL_BELT4_SWITCH_M:
-    case EL_BELT4_SWITCH_R:
+    case EL_BELT1_SWITCH_LEFT:
+    case EL_BELT1_SWITCH_MIDDLE:
+    case EL_BELT1_SWITCH_RIGHT:
+    case EL_BELT2_SWITCH_LEFT:
+    case EL_BELT2_SWITCH_MIDDLE:
+    case EL_BELT2_SWITCH_RIGHT:
+    case EL_BELT3_SWITCH_LEFT:
+    case EL_BELT3_SWITCH_MIDDLE:
+    case EL_BELT3_SWITCH_RIGHT:
+    case EL_BELT4_SWITCH_LEFT:
+    case EL_BELT4_SWITCH_MIDDLE:
+    case EL_BELT4_SWITCH_RIGHT:
       if (init_game)
       {
        int belt_nr = getBeltNrFromSwitchElement(Feld[x][y]);
@@ -475,6 +480,9 @@ void InitGame()
     player->last_jx = player->last_jy = 0;
     player->jx = player->jy = 0;
 
+    player->force_field_passive_time_left = 0;
+    player->force_field_active_time_left = 0;
+
     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
     SnapField(player, 0, 0);
 
@@ -756,52 +764,53 @@ void InitMovDir(int x, int y)
     {  0, -1 },
     { -1,  0 }
   };
-  static int direction[2][4] =
+  static int direction[3][4] =
   {
     { MV_RIGHT, MV_UP,   MV_LEFT,  MV_DOWN },
-    { MV_LEFT,  MV_DOWN, MV_RIGHT, MV_UP }
+    { MV_LEFT,  MV_DOWN, MV_RIGHT, MV_UP },
+    { MV_LEFT,  MV_RIGHT, MV_UP, MV_DOWN }
   };
 
   switch(element)
   {
-    case EL_KAEFER_R:
-    case EL_KAEFER_O:
-    case EL_KAEFER_L:
-    case EL_KAEFER_U:
+    case EL_KAEFER_RIGHT:
+    case EL_KAEFER_UP:
+    case EL_KAEFER_LEFT:
+    case EL_KAEFER_DOWN:
       Feld[x][y] = EL_KAEFER;
-      MovDir[x][y] = direction[0][element - EL_KAEFER_R];
+      MovDir[x][y] = direction[0][element - EL_KAEFER_RIGHT];
       break;
 
-    case EL_FLIEGER_R:
-    case EL_FLIEGER_O:
-    case EL_FLIEGER_L:
-    case EL_FLIEGER_U:
+    case EL_FLIEGER_RIGHT:
+    case EL_FLIEGER_UP:
+    case EL_FLIEGER_LEFT:
+    case EL_FLIEGER_DOWN:
       Feld[x][y] = EL_FLIEGER;
-      MovDir[x][y] = direction[0][element - EL_FLIEGER_R];
+      MovDir[x][y] = direction[0][element - EL_FLIEGER_RIGHT];
       break;
 
-    case EL_BUTTERFLY_R:
-    case EL_BUTTERFLY_O:
-    case EL_BUTTERFLY_L:
-    case EL_BUTTERFLY_U:
+    case EL_BUTTERFLY_RIGHT:
+    case EL_BUTTERFLY_UP:
+    case EL_BUTTERFLY_LEFT:
+    case EL_BUTTERFLY_DOWN:
       Feld[x][y] = EL_BUTTERFLY;
-      MovDir[x][y] = direction[0][element - EL_BUTTERFLY_R];
+      MovDir[x][y] = direction[0][element - EL_BUTTERFLY_RIGHT];
       break;
 
-    case EL_FIREFLY_R:
-    case EL_FIREFLY_O:
-    case EL_FIREFLY_L:
-    case EL_FIREFLY_U:
+    case EL_FIREFLY_RIGHT:
+    case EL_FIREFLY_UP:
+    case EL_FIREFLY_LEFT:
+    case EL_FIREFLY_DOWN:
       Feld[x][y] = EL_FIREFLY;
-      MovDir[x][y] = direction[0][element - EL_FIREFLY_R];
+      MovDir[x][y] = direction[0][element - EL_FIREFLY_RIGHT];
       break;
 
-    case EL_PACMAN_R:
-    case EL_PACMAN_O:
-    case EL_PACMAN_L:
-    case EL_PACMAN_U:
+    case EL_PACMAN_RIGHT:
+    case EL_PACMAN_UP:
+    case EL_PACMAN_LEFT:
+    case EL_PACMAN_DOWN:
       Feld[x][y] = EL_PACMAN;
-      MovDir[x][y] = direction[0][element - EL_PACMAN_R];
+      MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT];
       break;
 
     case EL_SP_SNIKSNAK:
@@ -812,6 +821,14 @@ void InitMovDir(int x, int y)
       MovDir[x][y] = MV_LEFT;
       break;
 
+    case EL_MOLE_LEFT:
+    case EL_MOLE_RIGHT:
+    case EL_MOLE_UP:
+    case EL_MOLE_DOWN:
+      Feld[x][y] = EL_MOLE;
+      MovDir[x][y] = direction[2][element - EL_MOLE_LEFT];
+      break;
+
     default:
       MovDir[x][y] = 1 << RND(4);
       if (element != EL_KAEFER &&
@@ -1240,10 +1257,22 @@ void Explode(int ex, int ey, int phase, int mode)
       if (IS_MASSIVE(element) || element == EL_BURNING)
        continue;
 
+      if (IS_PLAYER(x, y) && FORCE_FIELD_ON(PLAYERINFO(x, y)))
+      {
+       if (IS_ACTIVE_BOMB(element))
+       {
+         /* re-activate things under the bomb like gate or penguin */
+         Feld[x][y] = (Store[x][y] ? Store[x][y] : EL_LEERRAUM);
+         Store[x][y] = 0;
+       }
+
+       continue;
+      }
+
       if (element == EL_EXPLODING)
        element = Store2[x][y];
 
-      if (IS_PLAYER(ex, ey))
+      if (IS_PLAYER(ex, ey) && !FORCE_FIELD_ON(PLAYERINFO(ex, ey)))
       {
        switch(StorePlayer[ex][ey])
        {
@@ -1265,7 +1294,7 @@ void Explode(int ex, int ey, int phase, int mode)
        if (game.emulation == EMU_SUPAPLEX)
          Store[x][y] = EL_LEERRAUM;
       }
-      else if (center_element == EL_MAULWURF)
+      else if (center_element == EL_MOLE)
        Store[x][y] = EL_EDELSTEIN_ROT;
       else if (center_element == EL_PINGUIN)
        Store[x][y] = EL_EDELSTEIN_LILA;
@@ -1344,7 +1373,7 @@ void Explode(int ex, int ey, int phase, int mode)
     int element = Store2[x][y];
 
     if (IS_PLAYER(x, y))
-      KillHero(PLAYERINFO(x, y));
+      KillHeroUnlessForceField(PLAYERINFO(x, y));
     else if (IS_EXPLOSIVE(element))
     {
       Feld[x][y] = Store2[x][y];
@@ -1444,8 +1473,10 @@ void Bang(int x, int y)
   else
     PlaySoundLevel(x, y, SND_ROAAAR);
 
+#if 0
   if (IS_PLAYER(x, y)) /* remove objects that might cause smaller explosion */
     element = EL_LEERRAUM;
+#endif
 
   switch(element)
   {
@@ -1457,6 +1488,7 @@ void Bang(int x, int y)
     case EL_MAMPFER2:
     case EL_ROBOT:
     case EL_PACMAN:
+    case EL_MOLE:
       RaiseScoreElement(element);
       Explode(x, y, EX_PHASE_START, EX_NORMAL);
       break;
@@ -1469,11 +1501,13 @@ void Bang(int x, int y)
     case EL_DYNABOMB_XL:
       DynaExplode(x, y);
       break;
-    case EL_MAULWURF:
     case EL_PINGUIN:
     case EL_BIRNE_AUS:
     case EL_BIRNE_EIN:
-      Explode(x, y, EX_PHASE_START, EX_CENTER);
+      if (IS_PLAYER(x, y))
+       Explode(x, y, EX_PHASE_START, EX_NORMAL);
+      else
+       Explode(x, y, EX_PHASE_START, EX_CENTER);
       break;
     default:
       Explode(x, y, EX_PHASE_START, EX_NORMAL);
@@ -1527,10 +1561,10 @@ static void ToggleBeltSwitch(int x, int y)
 {
   static int belt_base_element[4] =
   {
-    EL_BELT1_SWITCH_L,
-    EL_BELT2_SWITCH_L,
-    EL_BELT3_SWITCH_L,
-    EL_BELT4_SWITCH_L
+    EL_BELT1_SWITCH_LEFT,
+    EL_BELT2_SWITCH_LEFT,
+    EL_BELT3_SWITCH_LEFT,
+    EL_BELT4_SWITCH_LEFT
   };
   static int belt_move_dir[4] =
   {
@@ -1686,8 +1720,8 @@ void Impact(int x, int y)
   if (element == EL_TROPFEN && (lastline || object_hit))       /* acid drop */
   {
     if (object_hit && IS_PLAYER(x, y+1))
-      KillHero(PLAYERINFO(x, y+1));
-    else if (object_hit && (smashed == EL_MAULWURF || smashed == EL_PINGUIN))
+      KillHeroUnlessForceField(PLAYERINFO(x, y+1));
+    else if (object_hit && smashed == EL_PINGUIN)
       Bang(x, y+1);
     else
     {
@@ -1719,10 +1753,10 @@ void Impact(int x, int y)
 
     if (IS_PLAYER(x, y+1))
     {
-      KillHero(PLAYERINFO(x, y+1));
+      KillHeroUnlessForceField(PLAYERINFO(x, y+1));
       return;
     }
-    else if (smashed == EL_MAULWURF || smashed == EL_PINGUIN)
+    else if (smashed == EL_PINGUIN)
     {
       Bang(x, y+1);
       return;
@@ -1739,7 +1773,8 @@ void Impact(int x, int y)
     {
       if (IS_ENEMY(smashed) ||
          smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE ||
-         smashed == EL_SONDE || smashed == EL_SCHWEIN || smashed == EL_DRACHE)
+         smashed == EL_SONDE || smashed == EL_SCHWEIN ||
+         smashed == EL_DRACHE || smashed == EL_MOLE)
       {
        Bang(x, y+1);
        return;
@@ -1889,10 +1924,10 @@ void TurnRound(int x, int y)
     TestIfBadThingHitsOtherBadThing(x, y);
 
     if (IN_LEV_FIELD(right_x, right_y) &&
-       IS_FREE_OR_PLAYER(right_x, right_y))
+       IS_FREE(right_x, right_y))
       MovDir[x][y] = right_dir;
     else if (!IN_LEV_FIELD(move_x, move_y) ||
-            !IS_FREE_OR_PLAYER(move_x, move_y))
+            !IS_FREE(move_x, move_y))
       MovDir[x][y] = left_dir;
 
     if (element == EL_KAEFER && MovDir[x][y] != old_move_dir)
@@ -1906,10 +1941,10 @@ void TurnRound(int x, int y)
     TestIfBadThingHitsOtherBadThing(x, y);
 
     if (IN_LEV_FIELD(left_x, left_y) &&
-       IS_FREE_OR_PLAYER(left_x, left_y))
+       IS_FREE(left_x, left_y))
       MovDir[x][y] = left_dir;
     else if (!IN_LEV_FIELD(move_x, move_y) ||
-            !IS_FREE_OR_PLAYER(move_x, move_y))
+            !IS_FREE(move_x, move_y))
       MovDir[x][y] = right_dir;
 
     if ((element == EL_FLIEGER ||
@@ -2092,8 +2127,36 @@ void TurnRound(int x, int y)
 
     MovDelay[x][y] = 0;
   }
-  else if (element == EL_ROBOT || element == EL_SONDE ||
-          element == EL_MAULWURF || element == EL_PINGUIN)
+  else if (element == EL_MOLE)
+  {
+    boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
+
+    if (IN_LEV_FIELD(move_x, move_y) &&
+       (IS_FREE(move_x, move_y) || IS_AMOEBOID(Feld[move_x][move_y]) ||
+        Feld[move_x][move_y] == EL_DEAMOEBING))
+      can_move_on = TRUE;
+
+    if (!can_move_on)
+    {
+      if (IN_LEV_FIELD(left_x, left_y) &&
+         (IS_FREE(left_x, left_y) || IS_AMOEBOID(Feld[left_x][left_y])))
+       can_turn_left = TRUE;
+      if (IN_LEV_FIELD(right_x, right_y) &&
+         (IS_FREE(right_x, right_y) || IS_AMOEBOID(Feld[right_x][right_y])))
+       can_turn_right = TRUE;
+
+      if (can_turn_left && can_turn_right)
+       MovDir[x][y] = (RND(2) ? left_dir : right_dir);
+      else if (can_turn_left)
+       MovDir[x][y] = left_dir;
+      else
+       MovDir[x][y] = right_dir;
+    }
+
+    if (MovDir[x][y] != old_move_dir)
+      MovDelay[x][y] = 9;
+  }
+  else if (element == EL_ROBOT || element == EL_SONDE || element == EL_PINGUIN)
   {
     int attr_x = -1, attr_y = -1;
 
@@ -2128,7 +2191,7 @@ void TurnRound(int x, int y)
       attr_y = ZY;
     }
 
-    if (element == EL_MAULWURF || element == EL_PINGUIN)
+    if (element == EL_PINGUIN)
     {
       int i;
       static int xy[4][2] =
@@ -2194,7 +2257,7 @@ void TurnRound(int x, int y)
        if (IN_LEV_FIELD(newx, newy) &&
            (IS_FREE(newx, newy) ||
             Feld[newx][newy] == EL_SALZSAEURE ||
-            ((element == EL_MAULWURF || element == EL_PINGUIN) &&
+            (element == EL_PINGUIN &&
              (Feld[newx][newy] == EL_AUSGANG_AUF ||
               IS_MAMPF3(Feld[newx][newy])))))
          return;
@@ -2206,7 +2269,7 @@ void TurnRound(int x, int y)
        if (IN_LEV_FIELD(newx, newy) &&
            (IS_FREE(newx, newy) ||
             Feld[newx][newy] == EL_SALZSAEURE ||
-            ((element == EL_MAULWURF || element == EL_PINGUIN) &&
+            (element == EL_PINGUIN &&
              (Feld[newx][newy] == EL_AUSGANG_AUF ||
               IS_MAMPF3(Feld[newx][newy])))))
          return;
@@ -2408,9 +2471,11 @@ void StartMoving(int x, int y)
       if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
       {
        TurnRound(x, y);
-       if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER ||
+       if (MovDelay[x][y] && (element == EL_KAEFER ||
+                              element == EL_FLIEGER ||
                               element == EL_SP_SNIKSNAK ||
-                              element == EL_SP_ELECTRON))
+                              element == EL_SP_ELECTRON ||
+                              element == EL_MOLE))
          DrawLevelField(x, y);
       }
     }
@@ -2496,14 +2561,22 @@ void StartMoving(int x, int y)
 
     Moving2Blocked(x, y, &newx, &newy);        /* get next screen position */
 
-    if (IS_ENEMY(element) && IS_PLAYER(newx, newy))
+    if (IS_ENEMY(element) && IS_PLAYER(newx, newy) &&
+       !FORCE_FIELD_ON(PLAYERINFO(newx, newy)))
     {
+
+#if 1
+      TestIfBadThingHitsHero(x, y);
+      return;
+#else
       /* enemy got the player */
       MovDir[x][y] = 0;
       KillHero(PLAYERINFO(newx, newy));
       return;
+#endif
+
     }
-    else if ((element == EL_MAULWURF || element == EL_PINGUIN ||
+    else if ((element == EL_PINGUIN ||
              element == EL_ROBOT || element == EL_SONDE) &&
             IN_LEV_FIELD(newx, newy) &&
             MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE)
@@ -2511,8 +2584,7 @@ void StartMoving(int x, int y)
       Blurb(x, y);
       Store[x][y] = EL_SALZSAEURE;
     }
-    else if ((element == EL_MAULWURF || element == EL_PINGUIN) &&
-            IN_LEV_FIELD(newx, newy))
+    else if (element == EL_PINGUIN && IN_LEV_FIELD(newx, newy))
     {
       if (Feld[newx][newy] == EL_AUSGANG_AUF)
       {
@@ -2637,8 +2709,8 @@ void StartMoving(int x, int y)
        DrawLevelField(newx, newy);
       }
     }
-    else if (element == EL_PACMAN && IN_LEV_FIELD(newx, newy) &&
-            IS_AMOEBOID(Feld[newx][newy]))
+    else if ((element == EL_PACMAN || element == EL_MOLE)
+            && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy]))
     {
       if (AmoebaNr[newx][newy])
       {
@@ -2648,8 +2720,24 @@ void StartMoving(int x, int y)
          AmoebaCnt[AmoebaNr[newx][newy]]--;
       }
 
-      Feld[newx][newy] = EL_LEERRAUM;
-      DrawLevelField(newx, newy);
+      if (element == EL_MOLE)
+      {
+       Feld[newx][newy] = EL_DEAMOEBING;
+       MovDelay[newx][newy] = 0;       /* start amoeba shrinking delay */
+       return;                         /* wait for shrinking amoeba */
+      }
+      else     /* element == EL_PACMAN */
+      {
+       Feld[newx][newy] = EL_LEERRAUM;
+       DrawLevelField(newx, newy);
+      }
+    }
+    else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) &&
+            (Feld[newx][newy] == EL_DEAMOEBING ||
+             (Feld[newx][newy] == EL_LEERRAUM && Stop[newx][newy])))
+    {
+      /* wait for shrinking amoeba to completely disappear */
+      return;
     }
     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
     {
@@ -2658,7 +2746,7 @@ void StartMoving(int x, int y)
       TurnRound(x, y);
 
       if (element == EL_KAEFER || element == EL_FLIEGER ||
-         element == EL_SP_SNIKSNAK)
+         element == EL_SP_SNIKSNAK || element == EL_MOLE)
        DrawLevelField(x, y);
       else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
        DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
@@ -2710,6 +2798,32 @@ void ContinueMoving(int x, int y)
     Feld[x][y] = EL_LEERRAUM;
     Feld[newx][newy] = element;
 
+    if (element == EL_MOLE)
+    {
+      int i;
+      static int xy[4][2] =
+      {
+       { 0, -1 },
+       { -1, 0 },
+       { +1, 0 },
+       { 0, +1 }
+      };
+
+      Feld[x][y] = EL_ERDREICH;
+      DrawLevelField(x, y);
+
+      for(i=0; i<4; i++)
+      {
+       int xx, yy;
+
+       xx = x + xy[i][0];
+       yy = y + xy[i][1];
+
+       if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_ERDREICH)
+         DrawLevelField(xx, yy);       /* for "ErdreichAnbroeckeln()" */
+      }
+    }
+
     if (Store[x][y] == EL_MORAST_VOLL)
     {
       Store[x][y] = 0;
@@ -2985,6 +3099,40 @@ void AmoebeWaechst(int x, int y)
   }
 }
 
+void AmoebeSchrumpft(int x, int y)
+{
+  static unsigned long sound_delay = 0;
+  static unsigned long sound_delay_value = 0;
+
+  if (!MovDelay[x][y])         /* start new shrinking cycle */
+  {
+    MovDelay[x][y] = 7;
+
+    if (DelayReached(&sound_delay, sound_delay_value))
+    {
+      PlaySoundLevel(x, y, SND_BLURB);
+      sound_delay_value = 30;
+    }
+  }
+
+  if (MovDelay[x][y])          /* wait some time before shrinking */
+  {
+    MovDelay[x][y]--;
+    if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+      DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + MovDelay[x][y]/2);
+
+    if (!MovDelay[x][y])
+    {
+      Feld[x][y] = EL_LEERRAUM;
+      DrawLevelField(x, y);
+
+      /* don't let mole enter this field in this cycle;
+        (give priority to objects falling to this field from above) */
+      Stop[x][y] = TRUE;
+    }
+  }
+}
+
 void AmoebeAbleger(int ax, int ay)
 {
   int i;
@@ -3936,6 +4084,8 @@ void GameActions()
       Explode(x, y, Frame[x][y], EX_NORMAL);
     else if (element == EL_AMOEBING)
       AmoebeWaechst(x, y);
+    else if (element == EL_DEAMOEBING)
+      AmoebeSchrumpft(x, y);
     else if (IS_AMOEBALIVE(element))
       AmoebeAbleger(x, y);
     else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
@@ -3977,8 +4127,10 @@ void GameActions()
       CloseSwitchgate(x, y);
     else if (element == EL_EXTRA_TIME)
       DrawGraphicAnimation(x, y, GFX_EXTRA_TIME, 6, 4, ANIM_NORMAL);
-    else if (element == EL_FORCE_FIELD)
-      DrawGraphicAnimation(x, y, GFX_FORCE_FIELD, 6, 4, ANIM_NORMAL);
+    else if (element == EL_FORCE_FIELD_PASSIVE)
+      DrawGraphicAnimation(x, y, GFX_FORCE_FIELD_PASSIVE, 6, 4, ANIM_NORMAL);
+    else if (element == EL_FORCE_FIELD_ACTIVE)
+      DrawGraphicAnimation(x, y, GFX_FORCE_FIELD_ACTIVE, 6, 4, ANIM_NORMAL);
 
     if (game.magic_wall_active)
     {
@@ -4061,11 +4213,22 @@ void GameActions()
     }
   }
 
-  if (TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing)
+  if (TimeFrames >= (1000 / GameFrameDelay))
   {
     TimeFrames = 0;
     TimePlayed++;
 
+    for (i=0; i<MAX_PLAYERS; i++)
+    {
+      if (FORCE_FIELD_ON(&stored_player[i]))
+      {
+       stored_player[i].force_field_passive_time_left--;
+
+       if (stored_player[i].force_field_active_time_left > 0)
+         stored_player[i].force_field_active_time_left--;
+      }
+    }
+
     if (tape.recording || tape.playing)
       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
 
@@ -4223,7 +4386,14 @@ boolean MoveFigureOneStep(struct PlayerInfo *player,
       BuryHero(player);
     }
     else
-      KillHero(player);
+    {
+#if 1
+      TestIfBadThingHitsHero(new_jx, new_jy);
+#else
+      if (player->force_field_time_left == 0)
+       KillHero(player);
+#endif
+    }
 
     return MF_MOVING;
   }
@@ -4537,7 +4707,14 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody)
   if (killx != goodx || killy != goody)
   {
     if (IS_PLAYER(goodx, goody))
-      KillHero(PLAYERINFO(goodx, goody));
+    {
+      struct PlayerInfo *player = PLAYERINFO(goodx, goody);
+
+      if (player->force_field_active_time_left > 0)
+       Bang(killx, killy);
+      else if (player->force_field_passive_time_left == 0)
+       KillHero(player);
+    }
     else
       Bang(goodx, goody);
   }
@@ -4592,7 +4769,14 @@ void TestIfBadThingHitsGoodThing(int badx, int bady)
   if (killx != badx || killy != bady)
   {
     if (IS_PLAYER(killx, killy))
-      KillHero(PLAYERINFO(killx, killy));
+    {
+      struct PlayerInfo *player = PLAYERINFO(killx, killy);
+
+      if (player->force_field_active_time_left > 0)
+       Bang(badx, bady);
+      else if (player->force_field_passive_time_left == 0)
+       KillHero(player);
+    }
     else
       Bang(killx, killy);
   }
@@ -4662,10 +4846,20 @@ void KillHero(struct PlayerInfo *player)
   if (IS_PFORTE(Feld[jx][jy]))
     Feld[jx][jy] = EL_LEERRAUM;
 
+  /* deactivate force field (else Bang()/Explode() would not work right) */
+  player->force_field_passive_time_left = 0;
+  player->force_field_active_time_left = 0;
+
   Bang(jx, jy);
   BuryHero(player);
 }
 
+static void KillHeroUnlessForceField(struct PlayerInfo *player)
+{
+  if (!FORCE_FIELD_ON(player))
+    KillHero(player);
+}
+
 void BuryHero(struct PlayerInfo *player)
 {
   int jx = player->jx, jy = player->jy;
@@ -4787,8 +4981,16 @@ int DigField(struct PlayerInfo *player,
       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
       break;
 
-    case EL_FORCE_FIELD:
+    case EL_FORCE_FIELD_PASSIVE:
+      RemoveField(x, y);
+      player->force_field_passive_time_left += 10;
+      PlaySoundLevel(x, y, SND_PONG);
+      break;
+
+    case EL_FORCE_FIELD_ACTIVE:
       RemoveField(x, y);
+      player->force_field_passive_time_left += 10;
+      player->force_field_active_time_left += 10;
       PlaySoundLevel(x, y, SND_PONG);
       break;
 
@@ -4895,18 +5097,18 @@ int DigField(struct PlayerInfo *player,
       }
       break;
 
-    case EL_BELT1_SWITCH_L:
-    case EL_BELT1_SWITCH_M:
-    case EL_BELT1_SWITCH_R:
-    case EL_BELT2_SWITCH_L:
-    case EL_BELT2_SWITCH_M:
-    case EL_BELT2_SWITCH_R:
-    case EL_BELT3_SWITCH_L:
-    case EL_BELT3_SWITCH_M:
-    case EL_BELT3_SWITCH_R:
-    case EL_BELT4_SWITCH_L:
-    case EL_BELT4_SWITCH_M:
-    case EL_BELT4_SWITCH_R:
+    case EL_BELT1_SWITCH_LEFT:
+    case EL_BELT1_SWITCH_MIDDLE:
+    case EL_BELT1_SWITCH_RIGHT:
+    case EL_BELT2_SWITCH_LEFT:
+    case EL_BELT2_SWITCH_MIDDLE:
+    case EL_BELT2_SWITCH_RIGHT:
+    case EL_BELT3_SWITCH_LEFT:
+    case EL_BELT3_SWITCH_MIDDLE:
+    case EL_BELT3_SWITCH_RIGHT:
+    case EL_BELT4_SWITCH_LEFT:
+    case EL_BELT4_SWITCH_MIDDLE:
+    case EL_BELT4_SWITCH_RIGHT:
       if (!player->Switching)
       {
        player->Switching = TRUE;
@@ -5198,7 +5400,6 @@ int DigField(struct PlayerInfo *player,
 
       break;
 
-    case EL_MAULWURF:
     case EL_PINGUIN:
     case EL_SCHWEIN:
     case EL_DRACHE: