rnd-20010715-1-src
[rocksndiamonds.git] / src / game.c
index da36f241121571eb6a7a16494c5bdd776209cf15..37608e5d5152f84946ad85f2d1c5e92a344d5606 100644 (file)
@@ -1,23 +1,22 @@
 /***********************************************************
-*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
 *----------------------------------------------------------*
-*  (c) 1995-98 Artsoft Entertainment                       *
-*              Holger Schemel                              *
-*              Oststrasse 11a                              *
-*              33604 Bielefeld                             *
-*              phone: ++49 +521 290471                     *
-*              email: aeglos@valinor.owl.de                *
+* (c) 1995-2001 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
 *----------------------------------------------------------*
-*  game.c                                                  *
+* game.c                                                   *
 ***********************************************************/
 
+#include "libgame/libgame.h"
+
 #include "game.h"
-#include "misc.h"
 #include "tools.h"
 #include "screens.h"
-#include "sound.h"
 #include "init.h"
-#include "buttons.h"
 #include "files.h"
 #include "tape.h"
 #include "joystick.h"
 
 /* for Explode() */
 #define EX_PHASE_START         0
-#define EX_NORMAL              0
-#define EX_CENTER              1
-#define EX_BORDER              2
+#define EX_NO_EXPLOSION                0
+#define EX_NORMAL              1
+#define EX_CENTER              2
+#define EX_BORDER              3
 
 /* special positions in the game control window (relative to control window) */
 #define XX_LEVEL               37
 /* forward declaration for internal use */
 static void CloseAllOpenTimegates(void);
 static void CheckGravityMovement(struct PlayerInfo *);
-static void KillHeroUnlessShield(struct PlayerInfo *);
+static void KillHeroUnlessProtected(int, int);
 
 static void MapGameButtons();
 static void HandleGameButtons(struct GadgetInfo *);
@@ -167,17 +167,21 @@ static unsigned int getStateCheckSum(int counter)
 
 void GetPlayerConfig()
 {
-  if (sound_status == SOUND_OFF)
+  if (!audio.sound_available)
     setup.sound = FALSE;
 
-  if (!sound_loops_allowed)
+  if (!audio.loops_available)
   {
     setup.sound_loops = FALSE;
     setup.sound_music = FALSE;
   }
 
+  if (!video.fullscreen_available)
+    setup.fullscreen = FALSE;
+
   setup.sound_simple = setup.sound;
 
+  SetAudioMode(setup.sound);
   InitJoysticks();
 }
 
@@ -229,8 +233,17 @@ static void InitField(int x, int y, boolean init_game)
 {
   switch (Feld[x][y])
   {
-    case EL_SPIELFIGUR:
     case EL_SP_MURPHY:
+      if (init_game)
+      {
+       if (stored_player[0].present)
+       {
+         Feld[x][y] = EL_SP_MURPHY_CLONE;
+         break;
+       }
+      }
+      /* no break! */
+    case EL_SPIELFIGUR:
       if (init_game)
        Feld[x][y] = EL_SPIELER1;
       /* no break! */
@@ -493,7 +506,7 @@ void InitGame()
 
   network_player_action_received = FALSE;
 
-#ifndef MSDOS
+#if defined(PLATFORM_UNIX)
   /* initial null action */
   if (network_playing)
     SendToServer_MovePlayer(MV_NO_MOVING);
@@ -501,7 +514,6 @@ void InitGame()
 
   ZX = ZY = -1;
 
-  game.yam_content_nr = 0;
   FrameCounter = 0;
   TimeFrames = 0;
   TimePlayed = 0;
@@ -514,12 +526,15 @@ void InitGame()
   ScrollStepSize = 0;  /* will be correctly initialized by ScrollScreen() */
 
   AllPlayersGone = FALSE;
+
+  game.yam_content_nr = 0;
   game.magic_wall_active = FALSE;
   game.magic_wall_time_left = 0;
   game.light_time_left = 0;
   game.timegate_time_left = 0;
   game.switchgate_pos = 0;
   game.balloon_dir = MV_NO_MOVING;
+  game.explosions_delayed = TRUE;
 
   for (i=0; i<4; i++)
   {
@@ -541,6 +556,7 @@ void InitGame()
       AmoebaNr[x][y] = 0;
       JustStopped[x][y] = 0;
       Stop[x][y] = FALSE;
+      ExplodeField[x][y] = EX_NO_EXPLOSION;
     }
   }
 
@@ -658,10 +674,33 @@ void InitGame()
     }
   }
 
+  game.version = (tape.playing ? tape.game_version : level.game_version);
   game.emulation = (emulate_bd ? EMU_BOULDERDASH :
                    emulate_sb ? EMU_SOKOBAN :
                    emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
 
+  /* dynamically adjust element properties according to game engine version */
+  {
+    static int ep_slippery[] =
+    {
+      EL_BETON,
+      EL_MAUERWERK,
+      EL_MAUER_LEBT,
+      EL_MAUER_X,
+      EL_MAUER_Y,
+      EL_MAUER_XY
+    };
+    static int ep_slippery_num = sizeof(ep_slippery)/sizeof(int);
+
+    for (i=0; i<ep_slippery_num; i++)
+    {
+      if (game.version >= GAME_VERSION_2_0)
+       Elementeigenschaften2[ep_slippery[i]] |= EP_BIT_SLIPPERY_GEMS;
+      else
+       Elementeigenschaften2[ep_slippery[i]] &= ~EP_BIT_SLIPPERY_GEMS;
+    }
+  }
+
   if (BorderElement == EL_LEERRAUM)
   {
     SBX_Left = 0;
@@ -700,32 +739,30 @@ void InitGame()
   DrawAllPlayers();
   FadeToFront();
 
-  /* after drawing the level, corect some elements */
-
+  /* after drawing the level, correct some elements */
   if (game.timegate_time_left == 0)
     CloseAllOpenTimegates();
 
   if (setup.soft_scrolling)
-    XCopyArea(display, fieldbuffer, backbuffer, gc,
-             FX, FY, SXSIZE, SYSIZE, SX, SY);
+    BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
 
   redraw_mask |= REDRAW_FROM_BACKBUFFER;
 
   /* copy default game door content to main double buffer */
-  XCopyArea(display, pix[PIX_DOOR], drawto, gc,
-           DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
+  BlitBitmap(pix[PIX_DOOR], drawto,
+            DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
 
   if (level_nr < 100)
     DrawText(DX + XX_LEVEL, DY + YY_LEVEL,
             int2str(level_nr, 2), FS_SMALL, FC_YELLOW);
   else
   {
-    DrawTextExt(drawto, gc, DX + XX_EMERALDS, DY + YY_EMERALDS,
+    DrawTextExt(drawto, DX + XX_EMERALDS, DY + YY_EMERALDS,
                int2str(level_nr, 3), FS_SMALL, FC_SPECIAL3);
-    XCopyArea(display, drawto, drawto, gc,
-             DX + XX_EMERALDS, DY + YY_EMERALDS + 1,
-             FONT5_XSIZE * 3, FONT5_YSIZE - 1,
-             DX + XX_LEVEL - 1, DY + YY_LEVEL + 1);
+    BlitBitmap(drawto, drawto,
+              DX + XX_EMERALDS, DY + YY_EMERALDS + 1,
+              FONT5_XSIZE * 3, FONT5_YSIZE - 1,
+              DX + XX_LEVEL - 1, DY + YY_LEVEL + 1);
   }
 
   DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
@@ -745,15 +782,15 @@ void InitGame()
   MapTapeButtons();
 
   /* copy actual game door content to door double buffer for OpenDoor() */
-  XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
-           DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
+  BlitBitmap(drawto, pix[PIX_DB_DOOR],
+            DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
 
   OpenDoor(DOOR_OPEN_ALL);
 
-  if (setup.sound_music)
-    PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
+  if (setup.sound_music && num_bg_loops)
+    PlayMusic(level_nr % num_bg_loops);
 
-  XAutoRepeatOff(display);
+  KeyboardAutoRepeatOff();
 
   if (options.verbose)
   {
@@ -949,7 +986,9 @@ void GameWon()
       StopSound(SND_SIRR);
   }
 
+#if 0
   FadeSounds();
+#endif
 
   /* Hero disappears */
   DrawLevelField(ExitX, ExitY);
@@ -970,11 +1009,13 @@ void GameWon()
   {
     leveldir_current->handicap_level++;
     SaveLevelSetup_SeriesInfo();
-
-    if (level_nr < leveldir_current->last_level)
-      raise_level = TRUE;
   }
 
+  if (level_editor_test_game)
+    local_player->score = -1;  /* no highscore when playing from editor */
+  else if (level_nr < leveldir_current->last_level)
+    raise_level = TRUE;                /* advance to next level */
+
   if ((hi_pos = NewHiScore()) >= 0) 
   {
     game_status = HALLOFFAME;
@@ -1159,17 +1200,16 @@ void RemoveMovingField(int x, int y)
   }
 
   if (Feld[x][y] == EL_BLOCKED &&
-      (Store[oldx][oldy] == EL_MORAST_LEER ||
-       Store[oldx][oldy] == EL_SIEB_LEER ||
-       Store[oldx][oldy] == EL_SIEB2_LEER ||
-       Store[oldx][oldy] == EL_AMOEBE_NASS))
-  {
-    Feld[oldx][oldy] = Store[oldx][oldy];
-    Store[oldx][oldy] = Store2[oldx][oldy] = 0;
-  }
+      (Feld[oldx][oldy] == EL_QUICKSAND_EMPTYING ||
+       Feld[oldx][oldy] == EL_MAGIC_WALL_EMPTYING ||
+       Feld[oldx][oldy] == EL_MAGIC_WALL_BD_EMPTYING ||
+       Feld[oldx][oldy] == EL_AMOEBA_DRIPPING))
+    Feld[oldx][oldy] = get_next_element(Feld[oldx][oldy]);
   else
     Feld[oldx][oldy] = EL_LEERRAUM;
 
+  Store[oldx][oldy] = Store2[oldx][oldy] = 0;
+
   Feld[newx][newy] = EL_LEERRAUM;
   MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
   MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
@@ -1238,11 +1278,17 @@ void CheckDynamite(int x, int y)
 void Explode(int ex, int ey, int phase, int mode)
 {
   int x, y;
-  int num_phase = 9, delay = 2;
+  int num_phase = 9, delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
   int last_phase = num_phase * delay;
   int half_phase = (num_phase / 2) * delay;
   int first_phase_after_start = EX_PHASE_START + 1;
 
+  if (game.explosions_delayed)
+  {
+    ExplodeField[ex][ey] = mode;
+    return;
+  }
+
   if (phase == EX_PHASE_START)         /* initialize 'Store[][]' field */
   {
     int center_element = Feld[ex][ey];
@@ -1290,7 +1336,7 @@ void Explode(int ex, int ey, int phase, int mode)
       if (element == EL_EXPLODING)
        element = Store2[x][y];
 
-      if (IS_PLAYER(ex, ey) && !SHIELD_ON(PLAYERINFO(ex, ey)))
+      if (IS_PLAYER(ex, ey) && !PLAYER_PROTECTED(ex, ey))
       {
        switch(StorePlayer[ex][ey])
        {
@@ -1338,6 +1384,10 @@ void Explode(int ex, int ey, int phase, int mode)
        Store[x][y] = EL_EDELSTEIN_ROT;
       else if (element == EL_ERZ_EDEL_LILA)
        Store[x][y] = EL_EDELSTEIN_LILA;
+      else if (element == EL_WALL_PEARL)
+       Store[x][y] = EL_PEARL;
+      else if (element == EL_WALL_CRYSTAL)
+       Store[x][y] = EL_CRYSTAL;
       else if (!IS_PFORTE(Store[x][y]))
        Store[x][y] = EL_LEERRAUM;
 
@@ -1391,7 +1441,7 @@ void Explode(int ex, int ey, int phase, int mode)
     int element = Store2[x][y];
 
     if (IS_PLAYER(x, y))
-      KillHeroUnlessShield(PLAYERINFO(x, y));
+      KillHeroUnlessProtected(x, y);
     else if (IS_EXPLOSIVE(element))
     {
       Feld[x][y] = Store2[x][y];
@@ -1413,6 +1463,9 @@ void Explode(int ex, int ey, int phase, int mode)
     if (CAN_MOVE(element) || COULD_MOVE(element))
       InitMovDir(x, y);
     DrawLevelField(x, y);
+
+    if (IS_PLAYER(x, y) && !PLAYERINFO(x,y)->present)
+      StorePlayer[x][y] = 0;
   }
   else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
   {
@@ -1426,7 +1479,15 @@ void Explode(int ex, int ey, int phase, int mode)
     if (phase == delay)
       ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
 
-    DrawGraphic(SCREENX(x), SCREENY(y), graphic + (phase / delay - 1));
+    graphic += (phase / delay - 1);
+
+    if (IS_PFORTE(Store[x][y]))
+    {
+      DrawLevelElement(x, y, Store[x][y]);
+      DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic);
+    }
+    else
+      DrawGraphic(SCREENX(x), SCREENY(y), graphic);
   }
 }
 
@@ -1768,17 +1829,25 @@ void Impact(int x, int y)
     return;
   }
 
-  if ((element == EL_BOMBE || element == EL_SP_DISK_ORANGE) &&
+  if ((element == EL_BOMBE ||
+       element == EL_SP_DISK_ORANGE ||
+       element == EL_DX_SUPABOMB) &&
       (lastline || object_hit))        /* element is bomb */
   {
     Bang(x, y);
     return;
   }
+  else if (element == EL_PEARL)
+  {
+    Feld[x][y] = EL_PEARL_BREAKING;
+    PlaySoundLevel(x, y, SND_KNACK);
+    return;
+  }
 
   if (element == EL_TROPFEN && (lastline || object_hit))       /* acid drop */
   {
     if (object_hit && IS_PLAYER(x, y+1))
-      KillHeroUnlessShield(PLAYERINFO(x, y+1));
+      KillHeroUnlessProtected(x, y+1);
     else if (object_hit && smashed == EL_PINGUIN)
       Bang(x, y+1);
     else
@@ -1792,11 +1861,12 @@ void Impact(int x, int y)
   if (!lastline && object_hit)         /* check which object was hit */
   {
     if (CAN_CHANGE(element) && 
-       (smashed == EL_SIEB_INAKTIV || smashed == EL_SIEB2_INAKTIV))
+       (smashed == EL_MAGIC_WALL_OFF || smashed == EL_MAGIC_WALL_BD_OFF))
     {
       int x, y;
       int activated_magic_wall =
-       (smashed == EL_SIEB_INAKTIV ? EL_SIEB_LEER : EL_SIEB2_LEER);
+       (smashed == EL_MAGIC_WALL_OFF ? EL_MAGIC_WALL_EMPTY :
+        EL_MAGIC_WALL_BD_EMPTY);
 
       /* activate magic wall / mill */
 
@@ -1811,7 +1881,7 @@ void Impact(int x, int y)
 
     if (IS_PLAYER(x, y+1))
     {
-      KillHeroUnlessShield(PLAYERINFO(x, y+1));
+      KillHeroUnlessProtected(x, y+1);
       return;
     }
     else if (smashed == EL_PINGUIN)
@@ -1827,10 +1897,20 @@ void Impact(int x, int y)
        return;
       }
     }
-    else if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
+    else if ((element == EL_SP_INFOTRON || element == EL_SP_ZONK) &&
+            (smashed == EL_SP_SNIKSNAK || smashed == EL_SP_ELECTRON ||
+             smashed == EL_SP_DISK_ORANGE))
+    {
+      Bang(x, y+1);
+      return;
+    }
+    else if (element == EL_FELSBROCKEN ||
+            element == EL_SP_ZONK ||
+            element == EL_BD_ROCK)
     {
       if (IS_ENEMY(smashed) ||
          smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE ||
+         smashed == EL_DX_SUPABOMB ||
          smashed == EL_SONDE || smashed == EL_SCHWEIN ||
          smashed == EL_DRACHE || smashed == EL_MOLE)
       {
@@ -1851,6 +1931,12 @@ void Impact(int x, int y)
          RaiseScoreElement(EL_KOKOSNUSS);
          return;
        }
+       else if (smashed == EL_PEARL)
+       {
+         Feld[x][y+1] = EL_PEARL_BREAKING;
+         PlaySoundLevel(x, y, SND_KNACK);
+         return;
+       }
        else if (smashed == EL_DIAMANT)
        {
          Feld[x][y+1] = EL_LEERRAUM;
@@ -1877,7 +1963,8 @@ void Impact(int x, int y)
 
   /* play sound of magic wall / mill */
   if (!lastline &&
-      (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
+      (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY ||
+       Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY))
   {
     PlaySoundLevel(x, y, SND_QUIRK);
     return;
@@ -1903,6 +1990,7 @@ void Impact(int x, int y)
        sound = SND_KLUMPF;
        break;
       case EL_FELSBROCKEN:
+      case EL_BD_ROCK:
        sound = SND_KLOPF;
        break;
       case EL_SP_ZONK:
@@ -1979,7 +2067,7 @@ void TurnRound(int x, int y)
 
   if (element == EL_KAEFER || element == EL_BUTTERFLY)
   {
-    TestIfBadThingHitsOtherBadThing(x, y);
+    TestIfBadThingTouchesOtherBadThing(x, y);
 
     if (IN_LEV_FIELD(right_x, right_y) &&
        IS_FREE(right_x, right_y))
@@ -1996,7 +2084,7 @@ void TurnRound(int x, int y)
   else if (element == EL_FLIEGER || element == EL_FIREFLY ||
           element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
   {
-    TestIfBadThingHitsOtherBadThing(x, y);
+    TestIfBadThingTouchesOtherBadThing(x, y);
 
     if (IN_LEV_FIELD(left_x, left_y) &&
        IS_FREE(left_x, left_y))
@@ -2219,6 +2307,16 @@ void TurnRound(int x, int y)
     MovDir[x][y] = game.balloon_dir;
     MovDelay[x][y] = 0;
   }
+  else if (element == EL_SPRING_MOVING)
+  {
+    if (!IN_LEV_FIELD(move_x, move_y) || !IS_FREE(move_x, move_y) ||
+       (IN_LEV_FIELD(x, y+1) && IS_FREE(x, y+1)))
+    {
+      Feld[x][y] = EL_SPRING;
+      MovDir[x][y] = MV_NO_MOVING;
+    }
+    MovDelay[x][y] = 0;
+  }
   else if (element == EL_ROBOT || element == EL_SONDE || element == EL_PINGUIN)
   {
     int attr_x = -1, attr_y = -1;
@@ -2383,8 +2481,8 @@ void StartMoving(int x, int y)
       if (IS_FREE(x, y+1))
       {
        InitMovingField(x, y, MV_DOWN);
-       Feld[x][y] = EL_FELSBROCKEN;
-       Store[x][y] = EL_MORAST_LEER;
+       Feld[x][y] = EL_QUICKSAND_EMPTYING;
+       Store[x][y] = EL_FELSBROCKEN;
       }
       else if (Feld[x][y+1] == EL_MORAST_LEER)
       {
@@ -2400,22 +2498,26 @@ void StartMoving(int x, int y)
 
        Feld[x][y] = EL_MORAST_LEER;
        Feld[x][y+1] = EL_MORAST_VOLL;
+       Store[x][y+1] = Store[x][y];
+       Store[x][y] = 0;
       }
     }
-    else if (element == EL_FELSBROCKEN && Feld[x][y+1] == EL_MORAST_LEER)
+    else if ((element == EL_FELSBROCKEN || element == EL_BD_ROCK) &&
+            Feld[x][y+1] == EL_MORAST_LEER)
     {
       InitMovingField(x, y, MV_DOWN);
-      Store[x][y] = EL_MORAST_VOLL;
+      Feld[x][y] = EL_QUICKSAND_FILLING;
+      Store[x][y] = element;
     }
-    else if (element == EL_SIEB_VOLL)
+    else if (element == EL_MAGIC_WALL_FULL)
     {
       if (IS_FREE(x, y+1))
       {
        InitMovingField(x, y, MV_DOWN);
-       Feld[x][y] = EL_CHANGED(Store2[x][y]);
-       Store[x][y] = EL_SIEB_LEER;
+       Feld[x][y] = EL_MAGIC_WALL_EMPTYING;
+       Store[x][y] = EL_CHANGED(Store[x][y]);
       }
-      else if (Feld[x][y+1] == EL_SIEB_LEER)
+      else if (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY)
       {
        if (!MovDelay[x][y])
          MovDelay[x][y] = TILEY/4 + 1;
@@ -2427,21 +2529,21 @@ void StartMoving(int x, int y)
            return;
        }
 
-       Feld[x][y] = EL_SIEB_LEER;
-       Feld[x][y+1] = EL_SIEB_VOLL;
-       Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
-       Store2[x][y] = 0;
+       Feld[x][y] = EL_MAGIC_WALL_EMPTY;
+       Feld[x][y+1] = EL_MAGIC_WALL_FULL;
+       Store[x][y+1] = EL_CHANGED(Store[x][y]);
+       Store[x][y] = 0;
       }
     }
-    else if (element == EL_SIEB2_VOLL)
+    else if (element == EL_MAGIC_WALL_BD_FULL)
     {
       if (IS_FREE(x, y+1))
       {
        InitMovingField(x, y, MV_DOWN);
-       Feld[x][y] = EL_CHANGED2(Store2[x][y]);
-       Store[x][y] = EL_SIEB2_LEER;
+       Feld[x][y] = EL_MAGIC_WALL_BD_EMPTYING;
+       Store[x][y] = EL_CHANGED2(Store[x][y]);
       }
-      else if (Feld[x][y+1] == EL_SIEB2_LEER)
+      else if (Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY)
       {
        if (!MovDelay[x][y])
          MovDelay[x][y] = TILEY/4 + 1;
@@ -2453,19 +2555,21 @@ void StartMoving(int x, int y)
            return;
        }
 
-       Feld[x][y] = EL_SIEB2_LEER;
-       Feld[x][y+1] = EL_SIEB2_VOLL;
-       Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
-       Store2[x][y] = 0;
+       Feld[x][y] = EL_MAGIC_WALL_BD_EMPTY;
+       Feld[x][y+1] = EL_MAGIC_WALL_BD_FULL;
+       Store[x][y+1] = EL_CHANGED2(Store[x][y]);
+       Store[x][y] = 0;
       }
     }
     else if (CAN_CHANGE(element) &&
-            (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
+            (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY ||
+             Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY))
     {
       InitMovingField(x, y, MV_DOWN);
-      Store[x][y] =
-       (Feld[x][y+1] == EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL);
-      Store2[x][y+1] = element;
+      Feld[x][y] =
+       (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY ? EL_MAGIC_WALL_FILLING :
+        EL_MAGIC_WALL_BD_FILLING);
+      Store[x][y] = element;
     }
     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_SALZSAEURE)
     {
@@ -2487,11 +2591,22 @@ void StartMoving(int x, int y)
       Feld[x][y] = EL_AMOEBING;
       Store[x][y] = EL_AMOEBE_NASS;
     }
+    /* Store[x][y+1] must be zero, because:
+       (EL_MORAST_VOLL -> EL_FELSBROCKEN): Store[x][y+1] == EL_MORAST_LEER
+    */
+#if 0
 #if OLD_GAME_BEHAVIOUR
     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
 #else
     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1] &&
-            !IS_FALLING(x, y+1) && !JustStopped[x][y+1])
+            !IS_FALLING(x, y+1) && !JustStopped[x][y+1] &&
+            element != EL_DX_SUPABOMB)
+#endif
+#else
+    else if ((IS_SLIPPERY(Feld[x][y+1]) ||
+             (IS_SLIPPERY_GEMS(Feld[x][y+1]) && IS_GEM(element))) &&
+            !IS_FALLING(x, y+1) && !JustStopped[x][y+1] &&
+            element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE)
 #endif
     {
       boolean left  = (x>0 && IS_FREE(x-1, y) &&
@@ -2501,7 +2616,9 @@ void StartMoving(int x, int y)
 
       if (left || right)
       {
-       if (left && right && game.emulation != EMU_BOULDERDASH)
+       if (left && right &&
+           (game.emulation != EMU_BOULDERDASH &&
+            element != EL_BD_ROCK && element != EL_EDELSTEIN_BD))
          left = !(right = RND(2));
 
        InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
@@ -2523,7 +2640,8 @@ void StartMoving(int x, int y)
   {
     int newx, newy;
 
-    if ((element == EL_SONDE || element == EL_BALLOON)
+    if ((element == EL_SONDE || element == EL_BALLOON ||
+        element == EL_SPRING_MOVING)
        && JustBeingPushed(x, y))
       return;
 
@@ -2626,11 +2744,11 @@ void StartMoving(int x, int y)
     Moving2Blocked(x, y, &newx, &newy);        /* get next screen position */
 
     if (IS_ENEMY(element) && IS_PLAYER(newx, newy) &&
-       !SHIELD_ON(PLAYERINFO(newx, newy)))
+       !PLAYER_PROTECTED(newx, newy))
     {
 
 #if 1
-      TestIfBadThingHitsHero(x, y);
+      TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]);
       return;
 #else
       /* enemy got the player */
@@ -2820,7 +2938,7 @@ void StartMoving(int x, int y)
        DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
 
       if (DONT_TOUCH(element))
-       TestIfBadThingHitsHero(x, y);
+       TestIfBadThingTouchesHero(x, y);
 
       return;
     }
@@ -2845,13 +2963,21 @@ void ContinueMoving(int x, int y)
   int newx = x + dx, newy = y + dy;
   int step = (horiz_move ? dx : dy) * TILEX / 8;
 
-  if (element == EL_TROPFEN)
+  if (element == EL_TROPFEN || element == EL_AMOEBA_DRIPPING)
     step /= 2;
-  else if (Store[x][y] == EL_MORAST_VOLL || Store[x][y] == EL_MORAST_LEER)
+  else if (element == EL_QUICKSAND_FILLING ||
+          element == EL_QUICKSAND_EMPTYING)
     step /= 4;
+  else if (element == EL_MAGIC_WALL_FILLING ||
+          element == EL_MAGIC_WALL_BD_FILLING ||
+          element == EL_MAGIC_WALL_EMPTYING ||
+          element == EL_MAGIC_WALL_BD_EMPTYING)
+    step /= 2;
   else if (CAN_FALL(element) && horiz_move &&
           y < lev_fieldy-1 && IS_BELT(Feld[x][y+1]))
     step /= 2;
+  else if (element == EL_SPRING_MOVING)
+    step*=2;
 
 #if OLD_GAME_BEHAVIOUR
   else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element))
@@ -2891,51 +3017,55 @@ void ContinueMoving(int x, int y)
       }
     }
 
-    if (Store[x][y] == EL_MORAST_VOLL)
+    if (element == EL_QUICKSAND_FILLING)
     {
-      Store[x][y] = 0;
-      Feld[newx][newy] = EL_MORAST_VOLL;
-      element = EL_MORAST_VOLL;
+      element = Feld[newx][newy] = get_next_element(element);
+      Store[newx][newy] = Store[x][y];
     }
-    else if (Store[x][y] == EL_MORAST_LEER)
+    else if (element == EL_QUICKSAND_EMPTYING)
     {
-      Store[x][y] = 0;
-      Feld[x][y] = EL_MORAST_LEER;
+      Feld[x][y] = get_next_element(element);
+      element = Feld[newx][newy] = Store[x][y];
     }
-    else if (Store[x][y] == EL_SIEB_VOLL)
+    else if (element == EL_MAGIC_WALL_FILLING)
     {
-      Store[x][y] = 0;
-      element = Feld[newx][newy] =
-       (game.magic_wall_active ? EL_SIEB_VOLL : EL_SIEB_TOT);
+      element = Feld[newx][newy] = get_next_element(element);
+      if (!game.magic_wall_active)
+       element = Feld[newx][newy] = EL_MAGIC_WALL_DEAD;
+      Store[newx][newy] = Store[x][y];
     }
-    else if (Store[x][y] == EL_SIEB_LEER)
+    else if (element == EL_MAGIC_WALL_EMPTYING)
     {
-      Store[x][y] = Store2[x][y] = 0;
-      Feld[x][y] = (game.magic_wall_active ? EL_SIEB_LEER : EL_SIEB_TOT);
+      Feld[x][y] = get_next_element(element);
+      if (!game.magic_wall_active)
+       Feld[x][y] = EL_MAGIC_WALL_DEAD;
+      element = Feld[newx][newy] = Store[x][y];
     }
-    else if (Store[x][y] == EL_SIEB2_VOLL)
+    else if (element == EL_MAGIC_WALL_BD_FILLING)
     {
-      Store[x][y] = 0;
-      element = Feld[newx][newy] =
-       (game.magic_wall_active ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
+      element = Feld[newx][newy] = get_next_element(element);
+      if (!game.magic_wall_active)
+       element = Feld[newx][newy] = EL_MAGIC_WALL_BD_DEAD;
+      Store[newx][newy] = Store[x][y];
     }
-    else if (Store[x][y] == EL_SIEB2_LEER)
+    else if (element == EL_MAGIC_WALL_BD_EMPTYING)
     {
-      Store[x][y] = Store2[x][y] = 0;
-      Feld[x][y] = (game.magic_wall_active ? EL_SIEB2_LEER : EL_SIEB2_TOT);
+      Feld[x][y] = get_next_element(element);
+      if (!game.magic_wall_active)
+       Feld[x][y] = EL_MAGIC_WALL_BD_DEAD;
+      element = Feld[newx][newy] = Store[x][y];
     }
-    else if (Store[x][y] == EL_SALZSAEURE)
+    else if (element == EL_AMOEBA_DRIPPING)
     {
-      Store[x][y] = 0;
-      Feld[newx][newy] = EL_SALZSAEURE;
-      element = EL_SALZSAEURE;
+      Feld[x][y] = get_next_element(element);
+      element = Feld[newx][newy] = Store[x][y];
     }
-    else if (Store[x][y] == EL_AMOEBE_NASS)
+    else if (Store[x][y] == EL_SALZSAEURE)
     {
-      Store[x][y] = 0;
-      Feld[x][y] = EL_AMOEBE_NASS;
+      element = Feld[newx][newy] = EL_SALZSAEURE;
     }
 
+    Store[x][y] = 0;
     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
     MovDelay[newx][newy] = 0;
 
@@ -2950,12 +3080,12 @@ void ContinueMoving(int x, int y)
 
     if (DONT_TOUCH(element))   /* object may be nasty to player or others */
     {
-      TestIfBadThingHitsHero(newx, newy);
-      TestIfBadThingHitsFriend(newx, newy);
-      TestIfBadThingHitsOtherBadThing(newx, newy);
+      TestIfBadThingTouchesHero(newx, newy);
+      TestIfBadThingTouchesFriend(newx, newy);
+      TestIfBadThingTouchesOtherBadThing(newx, newy);
     }
     else if (element == EL_PINGUIN)
-      TestIfFriendHitsBadThing(newx, newy);
+      TestIfFriendTouchesBadThing(newx, newy);
 
     if (CAN_SMASH(element) && direction == MV_DOWN &&
        (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
@@ -3132,7 +3262,7 @@ void AmoebeUmwandelnBD(int ax, int ay, int new_element)
 
   if (done)
     PlaySoundLevel(ax, ay,
-                  (new_element == EL_FELSBROCKEN ? SND_KLOPF : SND_PLING));
+                  (new_element == EL_BD_ROCK ? SND_KLOPF : SND_PLING));
 }
 
 void AmoebeWaechst(int x, int y)
@@ -3316,7 +3446,7 @@ void AmoebeAbleger(int ax, int ay)
 
       if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200)
       {
-       AmoebeUmwandelnBD(newax, neway, EL_FELSBROCKEN);
+       AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK);
        return;
       }
     }
@@ -3325,16 +3455,16 @@ void AmoebeAbleger(int ax, int ay)
   if (element != EL_AMOEBE_NASS || neway < ay || !IS_FREE(newax, neway) ||
       (neway == lev_fieldy - 1 && newax != ax))
   {
-    Feld[newax][neway] = EL_AMOEBING;
+    Feld[newax][neway] = EL_AMOEBING;  /* simple growth of new amoeba tile */
     Store[newax][neway] = element;
   }
   else if (neway == ay)
-    Feld[newax][neway] = EL_TROPFEN;
+    Feld[newax][neway] = EL_TROPFEN;   /* drop left or right from amoeba */
   else
   {
-    InitMovingField(ax, ay, MV_DOWN);
-    Feld[ax][ay] = EL_TROPFEN;
-    Store[ax][ay] = EL_AMOEBE_NASS;
+    InitMovingField(ax, ay, MV_DOWN);  /* drop dripping out of amoeba */
+    Feld[ax][ay] = EL_AMOEBA_DRIPPING;
+    Store[ax][ay] = EL_TROPFEN;
     ContinueMoving(ax, ay);
     return;
   }
@@ -3503,7 +3633,8 @@ void NussKnacken(int x, int y)
   {
     MovDelay[x][y]--;
     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      DrawGraphic(SCREENX(x), SCREENY(y), GFX_CRACKINGNUT+3-MovDelay[x][y]/2);
+      DrawGraphic(SCREENX(x), SCREENY(y),
+                 GFX_CRACKINGNUT + 3 - MovDelay[x][y]/2);
 
     if (!MovDelay[x][y])
     {
@@ -3513,9 +3644,29 @@ void NussKnacken(int x, int y)
   }
 }
 
+void BreakingPearl(int x, int y)
+{
+  if (!MovDelay[x][y])         /* next animation frame */
+    MovDelay[x][y] = 9;
+
+  if (MovDelay[x][y])          /* wait some time before next frame */
+  {
+    MovDelay[x][y]--;
+    if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+      DrawGraphic(SCREENX(x), SCREENY(y),
+                 GFX_PEARL_BREAKING + 4 - MovDelay[x][y]/2);
+
+    if (!MovDelay[x][y])
+    {
+      Feld[x][y] = EL_LEERRAUM;
+      DrawLevelField(x, y);
+    }
+  }
+}
+
 void SiebAktivieren(int x, int y, int typ)
 {
-  int graphic = (typ == 1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL) + 3;
+  int graphic = (typ == 1 ? GFX_MAGIC_WALL_FULL : GFX_MAGIC_WALL_BD_FULL) + 3;
 
   DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE);
 }
@@ -3717,8 +3868,8 @@ void EdelsteinFunkeln(int x, int y)
          dest_x = FX + SCREENX(x)*TILEX;
          dest_y = FY + SCREENY(y)*TILEY;
 
-         XCopyArea(display, drawto_field, window, gc,
-                   dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
+         BlitBitmap(drawto_field, window,
+                    dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
          SetDrawtoField(DRAW_DIRECT);
        }
       }
@@ -3919,10 +4070,10 @@ static void CheckBuggyBase(int x, int y)
 
   if (element == EL_SP_BUG)
   {
-    if (!MovDelay[x][y])       /* start activating buggy base */
+    if (!MovDelay[x][y])       /* wait some time before activating base */
       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
 
-    if (MovDelay[x][y])                /* wait some time before activating base */
+    if (MovDelay[x][y])
     {
       MovDelay[x][y]--;
       if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
@@ -3938,7 +4089,7 @@ static void CheckBuggyBase(int x, int y)
     if (!MovDelay[x][y])       /* start activating buggy base */
       MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND);
 
-    if (MovDelay[x][y])                /* wait some time before activating base */
+    if (MovDelay[x][y])
     {
       MovDelay[x][y]--;
       if (MovDelay[x][y])
@@ -3975,6 +4126,61 @@ static void CheckBuggyBase(int x, int y)
   }
 }
 
+static void CheckTrap(int x, int y)
+{
+  int element = Feld[x][y];
+
+  if (element == EL_TRAP_INACTIVE)
+  {
+    if (!MovDelay[x][y])       /* wait some time before activating trap */
+      MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
+
+    if (MovDelay[x][y])
+    {
+      MovDelay[x][y]--;
+      if (MovDelay[x][y])
+       return;
+
+      Feld[x][y] = EL_TRAP_ACTIVE;
+    }
+  }
+  else if (element == EL_TRAP_ACTIVE)
+  {
+    int delay = 4;
+    int num_frames = 8;
+
+    if (!MovDelay[x][y])       /* start activating trap */
+      MovDelay[x][y] = num_frames * delay;
+
+    if (MovDelay[x][y])
+    {
+      MovDelay[x][y]--;
+
+      if (MovDelay[x][y])
+      {
+       if (!(MovDelay[x][y] % delay))
+       {
+         int phase = MovDelay[x][y]/delay;
+
+         if (phase >= num_frames/2)
+           phase = num_frames - phase;
+
+         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+         {
+           DrawGraphic(SCREENX(x),SCREENY(y), GFX_TRAP_INACTIVE + phase - 1);
+           ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
+         }
+       }
+
+       return;
+      }
+
+      Feld[x][y] = EL_TRAP_INACTIVE;
+      DrawLevelField(x, y);
+    }
+  }
+}
+
 static void DrawBeltAnimation(int x, int y, int element)
 {
   int belt_nr = getBeltNrFromElement(element);
@@ -4044,6 +4250,9 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
     SnapField(player, 0, 0);
     CheckGravityMovement(player);
 
+    if (player->MovPos == 0)   /* needed for tape.playing */
+      player->last_move_dir = MV_NO_MOVING;
+
     if (++player->frame_reset_delay > player->move_delay_value)
       player->Frame = 0;
   }
@@ -4070,7 +4279,7 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
       {
        int el = Feld[jx+dx][jy];
        int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 :
-                         el == EL_BALLOON ? 0 : 10);
+                         (el == EL_BALLOON || el == EL_SPRING) ? 0 : 10);
 
        if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
        {
@@ -4083,6 +4292,51 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
   }
 }
 
+static void sleep_milliseconds_x(unsigned long milliseconds_delay)
+{
+  boolean do_busy_waiting = (milliseconds_delay < 5 ? TRUE : FALSE);
+
+#if defined(PLATFORM_MSDOS)
+  /* don't use select() to perform waiting operations under DOS/Windows
+     environment; always use a busy loop for waiting instead */
+  do_busy_waiting = TRUE;
+#endif
+
+
+
+  do_busy_waiting = TRUE;
+
+
+
+  if (do_busy_waiting)
+  {
+    /* we want to wait only a few ms -- if we assume that we have a
+       kernel timer resolution of 10 ms, we would wait far to long;
+       therefore it's better to do a short interval of busy waiting
+       to get our sleeping time more accurate */
+
+    unsigned long base_counter = Counter(), actual_counter = Counter();
+
+    while (actual_counter < base_counter + milliseconds_delay &&
+          actual_counter >= base_counter)
+      actual_counter = Counter();
+  }
+  else
+  {
+#if defined(TARGET_SDL)
+    SDL_Delay(milliseconds_delay);
+#else
+    struct timeval delay;
+
+    delay.tv_sec  = milliseconds_delay / 1000;
+    delay.tv_usec = 1000 * (milliseconds_delay % 1000);
+
+    if (select(0, NULL, NULL, NULL, &delay) != 0)
+      Error(ERR_WARN, "sleep_milliseconds(): select() failed");
+#endif
+  }
+}
+
 void GameActions()
 {
   static unsigned long action_delay = 0;
@@ -4100,7 +4354,45 @@ void GameActions()
 
   /* ---------- main game synchronization point ---------- */
 
-  WaitUntilDelayReached(&action_delay, action_delay_value);
+
+
+#if 1
+    WaitUntilDelayReached(&action_delay, action_delay_value);
+#else
+  {
+    unsigned long count1 = SDL_GetTicks(), count2, current_ms, test;
+
+    /*
+    WaitUntilDelayReached(&action_delay, action_delay_value);
+    */
+
+    /*
+    SDL_Delay(20);
+    */
+
+    /*
+    sleep_milliseconds_x(20);
+    */
+
+    current_ms = SDL_GetTicks();
+    test = -1;
+    while (current_ms < count1 + 20)
+    {
+      current_ms = SDL_GetTicks();             /* busy wait! */
+
+      if (test != current_ms)
+      {
+       Error(ERR_RETURN, "current_ms == %ld", current_ms);
+       test = current_ms;
+      }
+    }
+
+    count2 = SDL_GetTicks();
+    Error(ERR_RETURN, "delay == %ld", count2 - count1);
+  }
+#endif
+
+
 
   if (network_playing && !network_player_action_received)
   {
@@ -4110,7 +4402,7 @@ void GameActions()
 #endif
     */
 
-#ifndef MSDOS
+#if defined(PLATFORM_UNIX)
     /* last chance to get network player actions without main loop delay */
     HandleNetworking();
 #endif
@@ -4147,7 +4439,7 @@ void GameActions()
       stored_player[i].effective_action = stored_player[i].action;
   }
 
-#ifndef MSDOS
+#if defined(PLATFORM_UNIX)
   if (network_playing)
     SendToServer_MovePlayer(summarized_player_action);
 #endif
@@ -4233,21 +4525,25 @@ void GameActions()
     {
       StartMoving(x, y);
 
-      if (IS_GEM(element))
+      if (IS_GEM(element) || element == EL_SP_INFOTRON)
        EdelsteinFunkeln(x, y);
     }
     else if (IS_MOVING(x, y))
       ContinueMoving(x, y);
     else if (IS_ACTIVE_BOMB(element))
       CheckDynamite(x, y);
-    else if (element == EL_EXPLODING)
+#if 0
+    else if (element == EL_EXPLODING && !game.explosions_delayed)
       Explode(x, y, Frame[x][y], EX_NORMAL);
+#endif
     else if (element == EL_AMOEBING)
       AmoebeWaechst(x, y);
     else if (element == EL_DEAMOEBING)
       AmoebeSchrumpft(x, y);
+#if 0
     else if (IS_AMOEBALIVE(element))
       AmoebeAbleger(x, y);
+#endif
     else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
       Life(x, y);
     else if (element == EL_ABLENK_EIN)
@@ -4260,6 +4556,8 @@ void GameActions()
       Blurb(x, y);
     else if (element == EL_CRACKINGNUT)
       NussKnacken(x, y);
+    else if (element == EL_PEARL_BREAKING)
+      BreakingPearl(x, y);
     else if (element == EL_AUSGANG_ZU)
       AusgangstuerPruefen(x, y);
     else if (element == EL_AUSGANG_ACT)
@@ -4277,6 +4575,8 @@ void GameActions()
       CheckForDragon(x, y);
     else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE)
       CheckBuggyBase(x, y);
+    else if (element == EL_TRAP_INACTIVE || element == EL_TRAP_ACTIVE)
+      CheckTrap(x, y);
     else if (element == EL_SP_TERMINAL)
       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL);
     else if (element == EL_SP_TERMINAL_ACTIVE)
@@ -4303,14 +4603,16 @@ void GameActions()
       boolean sieb = FALSE;
       int jx = local_player->jx, jy = local_player->jy;
 
-      if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL ||
-         Store[x][y] == EL_SIEB_LEER)
+      if (element == EL_MAGIC_WALL_FULL ||
+         element == EL_MAGIC_WALL_EMPTY ||
+         element == EL_MAGIC_WALL_EMPTYING)
       {
        SiebAktivieren(x, y, 1);
        sieb = TRUE;
       }
-      else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL ||
-              Store[x][y] == EL_SIEB2_LEER)
+      else if (element == EL_MAGIC_WALL_BD_FULL ||
+              element == EL_MAGIC_WALL_BD_EMPTY ||
+              element == EL_MAGIC_WALL_BD_EMPTYING)
       {
        SiebAktivieren(x, y, 2);
        sieb = TRUE;
@@ -4325,6 +4627,65 @@ void GameActions()
     }
   }
 
+#if 1
+  /* new experimental amoeba growth stuff*/
+#if 1
+  if (!(FrameCounter % 8))
+#endif
+  {
+    static unsigned long random = 1684108901;
+
+    for (i = 0; i < level.amoeba_speed * 28 / 8; i++)
+    {
+#if 0
+      x = (random >> 10) % lev_fieldx;
+      y = (random >> 20) % lev_fieldy;
+#else
+      x = RND(lev_fieldx);
+      y = RND(lev_fieldy);
+#endif
+      element = Feld[x][y];
+
+      if (!IS_PLAYER(x,y) &&
+         (element == EL_LEERRAUM ||
+          element == EL_ERDREICH ||
+          element == EL_MORAST_LEER ||
+          element == EL_BLURB_LEFT ||
+          element == EL_BLURB_RIGHT))
+      {
+       if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBE_NASS) ||
+           (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBE_NASS) ||
+           (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBE_NASS) ||
+           (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBE_NASS))
+         Feld[x][y] = EL_TROPFEN;
+      }
+
+      random = random * 129 + 1;
+    }
+  }
+#endif
+
+#if 0
+  if (game.explosions_delayed)
+#endif
+  {
+    game.explosions_delayed = FALSE;
+
+    for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+    {
+      element = Feld[x][y];
+
+      if (ExplodeField[x][y])
+       Explode(x, y, EX_PHASE_START, ExplodeField[x][y]);
+      else if (element == EL_EXPLODING)
+       Explode(x, y, Frame[x][y], EX_NORMAL);
+
+      ExplodeField[x][y] = EX_NO_EXPLOSION;
+    }
+
+    game.explosions_delayed = TRUE;
+  }
+
   if (game.magic_wall_active)
   {
     if (!(game.magic_wall_time_left % 4))
@@ -4339,14 +4700,16 @@ void GameActions()
        {
          element = Feld[x][y];
 
-         if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL)
+         if (element == EL_MAGIC_WALL_EMPTY ||
+             element == EL_MAGIC_WALL_FULL)
          {
-           Feld[x][y] = EL_SIEB_TOT;
+           Feld[x][y] = EL_MAGIC_WALL_DEAD;
            DrawLevelField(x, y);
          }
-         else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL)
+         else if (element == EL_MAGIC_WALL_BD_EMPTY ||
+                  element == EL_MAGIC_WALL_BD_FULL)
          {
-           Feld[x][y] = EL_SIEB2_TOT;
+           Feld[x][y] = EL_MAGIC_WALL_BD_DEAD;
            DrawLevelField(x, y);
          }
        }
@@ -4424,6 +4787,25 @@ void GameActions()
   }
 
   DrawAllPlayers();
+
+  if (options.debug)                   /* calculate frames per second */
+  {
+    static unsigned long fps_counter = 0;
+    static int fps_frames = 0;
+    unsigned long fps_delay_ms = Counter() - fps_counter;
+
+    fps_frames++;
+
+    if (fps_delay_ms >= 500)   /* calculate fps every 0.5 seconds */
+    {
+      global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms;
+
+      fps_frames = 0;
+      fps_counter = Counter();
+    }
+
+    redraw_mask |= REDRAW_FPS;
+  }
 }
 
 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
@@ -4470,13 +4852,13 @@ void ScrollLevel(int dx, int dy)
   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
   int x, y;
 
-  XCopyArea(display, drawto_field, drawto_field, gc,
-           FX + TILEX*(dx == -1) - softscroll_offset,
-           FY + TILEY*(dy == -1) - softscroll_offset,
-           SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
-           SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
-           FX + TILEX*(dx == 1) - softscroll_offset,
-           FY + TILEY*(dy == 1) - softscroll_offset);
+  BlitBitmap(drawto_field, drawto_field,
+            FX + TILEX*(dx == -1) - softscroll_offset,
+            FY + TILEY*(dy == -1) - softscroll_offset,
+            SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
+            SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
+            FX + TILEX*(dx == 1) - softscroll_offset,
+            FY + TILEY*(dy == 1) - softscroll_offset);
 
   if (dx)
   {
@@ -4560,14 +4942,7 @@ boolean MoveFigureOneStep(struct PlayerInfo *player,
       BuryHero(player);
     }
     else
-    {
-#if 1
-      TestIfBadThingHitsHero(new_jx, new_jy);
-#else
-      if (player->shield_time_left == 0)
-       KillHero(player);
-#endif
-    }
+      TestIfHeroRunsIntoBadThing(jx, jy, player->MovDir);
 
     return MF_MOVING;
   }
@@ -4739,7 +5114,7 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
     player->last_move_dir = MV_NO_MOVING;
   }
 
-  TestIfHeroHitsBadThing(jx, jy);
+  TestIfHeroTouchesBadThing(jx, jy);
 
   if (!player->active)
     RemoveHero(player);
@@ -4834,7 +5209,7 @@ void ScrollScreen(struct PlayerInfo *player, int mode)
     ScreenMovDir = MV_NO_MOVING;
 }
 
-void TestIfGoodThingHitsBadThing(int goodx, int goody)
+void TestIfGoodThingHitsBadThing(int goodx, int goody, int move_dir)
 {
   int i, killx = goodx, killy = goody;
   static int xy[4][2] =
@@ -4844,7 +5219,7 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody)
     { +1, 0 },
     { 0, +1 }
   };
-  static int harmless[4] =
+  static int xy_dir[4] =
   {
     MV_UP,
     MV_LEFT,
@@ -4867,11 +5242,12 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody)
     element = MovingOrBlocked2ElementIfNotLeaving(x, y);
 #endif
 
-    if (DONT_TOUCH(element))
+    /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
+       2nd case: DONT_TOUCH style bad thing does not move away from good thing
+    */
+    if ((DONT_GO_TO(element) && move_dir == xy_dir[i]) ||
+       (DONT_TOUCH(element) && MovDir[x][y] != xy_dir[i]))
     {
-      if (MovDir[x][y] == harmless[i])
-       continue;
-
       killx = x;
       killy = y;
       break;
@@ -4886,7 +5262,7 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody)
 
       if (player->shield_active_time_left > 0)
        Bang(killx, killy);
-      else if (player->shield_passive_time_left == 0)
+      else if (!PLAYER_PROTECTED(goodx, goody))
        KillHero(player);
     }
     else
@@ -4894,9 +5270,10 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody)
   }
 }
 
-void TestIfBadThingHitsGoodThing(int badx, int bady)
+void TestIfBadThingHitsGoodThing(int badx, int bady, int move_dir)
 {
   int i, killx = badx, killy = bady;
+  int bad_element = Feld[badx][bady];
   static int xy[4][2] =
   {
     { 0, -1 },
@@ -4904,7 +5281,7 @@ void TestIfBadThingHitsGoodThing(int badx, int bady)
     { +1, 0 },
     { 0, +1 }
   };
-  static int harmless[4] =
+  static int xy_dir[4] =
   {
     MV_UP,
     MV_LEFT,
@@ -4912,7 +5289,7 @@ void TestIfBadThingHitsGoodThing(int badx, int bady)
     MV_DOWN
   };
 
-  if (Feld[badx][bady] == EL_EXPLODING)        /* skip just exploding bad things */
+  if (bad_element == EL_EXPLODING)     /* skip just exploding bad things */
     return;
 
   for (i=0; i<4; i++)
@@ -4926,20 +5303,31 @@ void TestIfBadThingHitsGoodThing(int badx, int bady)
 
     element = Feld[x][y];
 
-    if (IS_PLAYER(x, y))
-    {
-      killx = x;
-      killy = y;
-      break;
-    }
-    else if (element == EL_PINGUIN)
+    /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
+       2nd case: DONT_TOUCH style bad thing does not move away from good thing
+    */
+    if ((DONT_GO_TO(bad_element) && move_dir == xy_dir[i]) ||
+       (DONT_TOUCH(bad_element) && MovDir[x][y] != xy_dir[i]))
     {
-      if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y))
-       continue;
+      /* good thing is player or penguin that does not move away */
+      if (IS_PLAYER(x, y))
+      {
+       struct PlayerInfo *player = PLAYERINFO(x, y);
 
-      killx = x;
-      killy = y;
-      break;
+       if (bad_element == EL_ROBOT && player->last_move_dir)
+         continue;     /* robot does not kill player if he moves */
+
+       killx = x;
+       killy = y;
+       break;
+      }
+      else if (element == EL_PINGUIN &&
+              (MovDir[x][y] != xy_dir[i] || !IS_MOVING(x, y)))
+      {
+       killx = x;
+       killy = y;
+       break;
+      }
     }
   }
 
@@ -4949,9 +5337,27 @@ void TestIfBadThingHitsGoodThing(int badx, int bady)
     {
       struct PlayerInfo *player = PLAYERINFO(killx, killy);
 
+#if 0
+      int dir = player->MovDir;
+      int newx = player->jx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
+      int newy = player->jy + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
+
+      if (Feld[badx][bady] == EL_ROBOT && player->last_move_dir &&
+         newx != badx && newy != bady)
+       ;       /* robot does not kill player if he moves */
+      else
+       printf("-> %d\n", player->MovDir);
+
+      if (Feld[badx][bady] == EL_ROBOT && player->last_move_dir &&
+         newx != badx && newy != bady)
+       ;       /* robot does not kill player if he moves */
+      else
+       ;
+#endif
+
       if (player->shield_active_time_left > 0)
        Bang(badx, bady);
-      else if (player->shield_passive_time_left == 0)
+      else if (!PLAYER_PROTECTED(killx, killy))
        KillHero(player);
     }
     else
@@ -4959,27 +5365,37 @@ void TestIfBadThingHitsGoodThing(int badx, int bady)
   }
 }
 
-void TestIfHeroHitsBadThing(int x, int y)
+void TestIfHeroTouchesBadThing(int x, int y)
+{
+  TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
+}
+
+void TestIfHeroRunsIntoBadThing(int x, int y, int move_dir)
 {
-  TestIfGoodThingHitsBadThing(x, y);
+  TestIfGoodThingHitsBadThing(x, y, move_dir);
 }
 
-void TestIfBadThingHitsHero(int x, int y)
+void TestIfBadThingTouchesHero(int x, int y)
 {
-  TestIfBadThingHitsGoodThing(x, y);
+  TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
 }
 
-void TestIfFriendHitsBadThing(int x, int y)
+void TestIfBadThingRunsIntoHero(int x, int y, int move_dir)
 {
-  TestIfGoodThingHitsBadThing(x, y);
+  TestIfBadThingHitsGoodThing(x, y, move_dir);
 }
 
-void TestIfBadThingHitsFriend(int x, int y)
+void TestIfFriendTouchesBadThing(int x, int y)
 {
-  TestIfBadThingHitsGoodThing(x, y);
+  TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
 }
 
-void TestIfBadThingHitsOtherBadThing(int badx, int bady)
+void TestIfBadThingTouchesFriend(int x, int y)
+{
+  TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
+}
+
+void TestIfBadThingTouchesOtherBadThing(int badx, int bady)
 {
   int i, killx = badx, killy = bady;
   static int xy[4][2] =
@@ -5031,10 +5447,10 @@ void KillHero(struct PlayerInfo *player)
   BuryHero(player);
 }
 
-static void KillHeroUnlessShield(struct PlayerInfo *player)
+static void KillHeroUnlessProtected(int x, int y)
 {
-  if (!SHIELD_ON(player))
-    KillHero(player);
+  if (!PLAYER_PROTECTED(x, y))
+    KillHero(PLAYERINFO(x, y));
 }
 
 void BuryHero(struct PlayerInfo *player)
@@ -5059,7 +5475,8 @@ void RemoveHero(struct PlayerInfo *player)
   player->present = FALSE;
   player->active = FALSE;
 
-  StorePlayer[jx][jy] = 0;
+  if (!ExplodeField[jx][jy])
+    StorePlayer[jx][jy] = 0;
 
   for (i=0; i<MAX_PLAYERS; i++)
     if (stored_player[i].active)
@@ -5096,6 +5513,36 @@ int DigField(struct PlayerInfo *player,
   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
     return MF_NO_ACTION;
 
+  if (IS_TUBE(Feld[jx][jy]))
+  {
+    int i = 0;
+    int tube_leave_directions[][2] =
+    {
+      { EL_TUBE_CROSS,         MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
+      { EL_TUBE_VERTICAL,                           MV_UP | MV_DOWN },
+      { EL_TUBE_HORIZONTAL,    MV_LEFT | MV_RIGHT                   },
+      { EL_TUBE_VERT_LEFT,     MV_LEFT |            MV_UP | MV_DOWN },
+      { EL_TUBE_VERT_RIGHT,              MV_RIGHT | MV_UP | MV_DOWN },
+      { EL_TUBE_HORIZ_UP,      MV_LEFT | MV_RIGHT | MV_UP           },
+      { EL_TUBE_HORIZ_DOWN,    MV_LEFT | MV_RIGHT |         MV_DOWN },
+      { EL_TUBE_LEFT_UP,       MV_LEFT |            MV_UP           },
+      { EL_TUBE_LEFT_DOWN,     MV_LEFT |                    MV_DOWN },
+      { EL_TUBE_RIGHT_UP,                MV_RIGHT | MV_UP           },
+      { EL_TUBE_RIGHT_DOWN,              MV_RIGHT |         MV_DOWN },
+      { -1,                     MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }
+    };
+
+    while (tube_leave_directions[i][0] != Feld[jx][jy])
+    {
+      i++;
+      if (tube_leave_directions[i][0] == -1)   /* should not happen */
+       break;
+    }
+
+    if (!(tube_leave_directions[i][1] & move_direction))
+      return MF_NO_ACTION;     /* tube has no opening in this direction */
+  }
+
   element = Feld[x][y];
 
   switch (element)
@@ -5106,6 +5553,7 @@ int DigField(struct PlayerInfo *player,
 
     case EL_ERDREICH:
     case EL_SAND_INVISIBLE:
+    case EL_TRAP_INACTIVE:
       Feld[x][y] = EL_LEERRAUM;
       PlaySoundLevel(x, y, SND_SCHLURF);
       break;
@@ -5123,8 +5571,12 @@ int DigField(struct PlayerInfo *player,
     case EL_EDELSTEIN_LILA:
     case EL_DIAMANT:
     case EL_SP_INFOTRON:
+    case EL_PEARL:
+    case EL_CRYSTAL:
       RemoveField(x, y);
-      local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1);
+      local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 :
+                                         element == EL_PEARL ? 5 :
+                                         element == EL_CRYSTAL ? 8 : 1);
       if (local_player->gems_still_needed < 0)
        local_player->gems_still_needed = 0;
       RaiseScoreElement(element);
@@ -5217,12 +5669,10 @@ int DigField(struct PlayerInfo *player,
       RemoveField(x, y);
       player->key[key_nr] = TRUE;
       RaiseScoreElement(EL_SCHLUESSEL);
-      DrawMiniGraphicExt(drawto, gc,
-                        DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
-                        GFX_SCHLUESSEL1+key_nr);
-      DrawMiniGraphicExt(window, gc,
-                        DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
-                        GFX_SCHLUESSEL1+key_nr);
+      DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
+                        GFX_SCHLUESSEL1 + key_nr);
+      DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
+                        GFX_SCHLUESSEL1 + key_nr);
       PlaySoundLevel(x, y, SND_PONG);
       break;
     }
@@ -5237,12 +5687,10 @@ int DigField(struct PlayerInfo *player,
       RemoveField(x, y);
       player->key[key_nr] = TRUE;
       RaiseScoreElement(EL_SCHLUESSEL);
-      DrawMiniGraphicExt(drawto, gc,
-                        DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
-                        GFX_SCHLUESSEL1+key_nr);
-      DrawMiniGraphicExt(window, gc,
-                        DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
-                        GFX_SCHLUESSEL1+key_nr);
+      DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
+                        GFX_SCHLUESSEL1 + key_nr);
+      DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
+                        GFX_SCHLUESSEL1 + key_nr);
       PlaySoundLevel(x, y, SND_PONG);
       break;
     }
@@ -5346,11 +5794,14 @@ int DigField(struct PlayerInfo *player,
       break;
 
     case EL_FELSBROCKEN:
+    case EL_BD_ROCK:
     case EL_BOMBE:
+    case EL_DX_SUPABOMB:
     case EL_KOKOSNUSS:
     case EL_ZEIT_LEER:
     case EL_SP_ZONK:
     case EL_SP_DISK_ORANGE:
+    case EL_SPRING:
       if (dy || mode == DF_SNAP)
        return MF_NO_ACTION;
 
@@ -5368,16 +5819,22 @@ int DigField(struct PlayerInfo *player,
       if (player->push_delay == 0)
        player->push_delay = FrameCounter;
       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
-         !tape.playing)
+         !tape.playing && element != EL_SPRING)
        return MF_NO_ACTION;
 
       RemoveField(x, y);
       Feld[x+dx][y+dy] = element;
 
-      player->push_delay_value = 2+RND(8);
+      if (element == EL_SPRING)
+      {
+       Feld[x+dx][y+dy] = EL_SPRING_MOVING;
+       MovDir[x+dx][y+dy] = move_direction;
+      }
+
+      player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8));
 
       DrawLevelField(x+dx, y+dy);
-      if (element == EL_FELSBROCKEN)
+      if (element == EL_FELSBROCKEN || element == EL_BD_ROCK)
        PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
       else if (element == EL_KOKOSNUSS)
        PlaySoundLevel(x+dx, y+dy, SND_KNURK);
@@ -5490,7 +5947,47 @@ int DigField(struct PlayerInfo *player,
       DOUBLE_PLAYER_SPEED(player);
 
       PlaySoundLevel(x, y, SND_GATE);
+      break;
 
+    case EL_TUBE_CROSS:
+    case EL_TUBE_VERTICAL:
+    case EL_TUBE_HORIZONTAL:
+    case EL_TUBE_VERT_LEFT:
+    case EL_TUBE_VERT_RIGHT:
+    case EL_TUBE_HORIZ_UP:
+    case EL_TUBE_HORIZ_DOWN:
+    case EL_TUBE_LEFT_UP:
+    case EL_TUBE_LEFT_DOWN:
+    case EL_TUBE_RIGHT_UP:
+    case EL_TUBE_RIGHT_DOWN:
+      {
+       int i = 0;
+       int tube_enter_directions[][2] =
+       {
+         { EL_TUBE_CROSS,      MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
+         { EL_TUBE_VERTICAL,                        MV_UP | MV_DOWN },
+         { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT                   },
+         { EL_TUBE_VERT_LEFT,            MV_RIGHT | MV_UP | MV_DOWN },
+         { EL_TUBE_VERT_RIGHT, MV_LEFT            | MV_UP | MV_DOWN },
+         { EL_TUBE_HORIZ_UP,   MV_LEFT | MV_RIGHT |         MV_DOWN },
+         { EL_TUBE_HORIZ_DOWN, MV_LEFT | MV_RIGHT | MV_UP           },
+         { EL_TUBE_LEFT_UP,              MV_RIGHT |         MV_DOWN },
+         { EL_TUBE_LEFT_DOWN,            MV_RIGHT | MV_UP           },
+         { EL_TUBE_RIGHT_UP,   MV_LEFT |                    MV_DOWN },
+         { EL_TUBE_RIGHT_DOWN, MV_LEFT |            MV_UP           },
+         { -1,                 MV_NO_MOVING                         }
+       };
+
+       while (tube_enter_directions[i][0] != element)
+       {
+         i++;
+         if (tube_enter_directions[i][0] == -1)        /* should not happen */
+           break;
+       }
+
+       if (!(tube_enter_directions[i][1] & move_direction))
+         return MF_NO_ACTION;  /* tube has no opening in this direction */
+      }
       break;
 
     case EL_AUSGANG_ZU:
@@ -5715,7 +6212,7 @@ void PlaySoundLevel(int x, int y, int sound_nr)
 
   volume = PSND_MAX_VOLUME;
 
-#ifndef MSDOS
+#if !defined(PLATFORM_MSDOS)
   stereo = (sx - SCR_FIELDX/2) * 12;
 #else
   stereo = PSND_MIDDLE + (2 * sx - (SCR_FIELDX - 1)) * 5;
@@ -5851,7 +6348,7 @@ void CreateGameButtons()
 
   for (i=0; i<NUM_GAME_BUTTONS; i++)
   {
-    Pixmap gd_pixmap = pix[PIX_DOOR];
+    Bitmap *gd_bitmap = pix[PIX_DOOR];
     struct GadgetInfo *gi;
     int button_type;
     boolean checked;
@@ -5896,10 +6393,10 @@ void CreateGameButtons()
                      GDI_TYPE, button_type,
                      GDI_STATE, GD_BUTTON_UNPRESSED,
                      GDI_CHECKED, checked,
-                     GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
-                     GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
-                     GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
-                     GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
+                     GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
+                     GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
+                     GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
+                     GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_ACTION, HandleGameButtons,
                      GDI_END);
@@ -5949,7 +6446,7 @@ static void HandleGameButtons(struct GadgetInfo *gi)
          Request("Do you really want to quit the game ?",
                  REQ_ASK | REQ_STAY_CLOSED))
       { 
-#ifndef MSDOS
+#if defined(PLATFORM_UNIX)
        if (options.network)
          SendToServer_StopPlaying();
        else
@@ -5966,7 +6463,7 @@ static void HandleGameButtons(struct GadgetInfo *gi)
     case GAME_CTRL_ID_PAUSE:
       if (options.network)
       {
-#ifndef MSDOS
+#if defined(PLATFORM_UNIX)
        if (tape.pausing)
          SendToServer_ContinuePlaying();
        else
@@ -5980,7 +6477,7 @@ static void HandleGameButtons(struct GadgetInfo *gi)
     case GAME_CTRL_ID_PLAY:
       if (tape.pausing)
       {
-#ifndef MSDOS
+#if defined(PLATFORM_UNIX)
        if (options.network)
          SendToServer_ContinuePlaying();
        else
@@ -5996,26 +6493,27 @@ static void HandleGameButtons(struct GadgetInfo *gi)
       if (setup.sound_music)
       { 
        setup.sound_music = FALSE;
-       FadeSound(background_loop[level_nr % num_bg_loops]);
+       FadeMusic();
       }
-      else if (sound_loops_allowed)
+      else if (audio.loops_available)
       { 
        setup.sound = setup.sound_music = TRUE;
-       PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
+       if (num_bg_loops)
+         PlayMusic(level_nr % num_bg_loops);
       }
       break;
 
     case SOUND_CTRL_ID_LOOPS:
       if (setup.sound_loops)
        setup.sound_loops = FALSE;
-      else if (sound_loops_allowed)
+      else if (audio.loops_available)
        setup.sound = setup.sound_loops = TRUE;
       break;
 
     case SOUND_CTRL_ID_SIMPLE:
       if (setup.sound_simple)
        setup.sound_simple = FALSE;
-      else if (sound_status==SOUND_AVAILABLE)
+      else if (audio.sound_available)
        setup.sound = setup.sound_simple = TRUE;
       break;