rnd-19990107-1
[rocksndiamonds.git] / src / game.c
index a250fc9da64528bed70d668aaee52d0c6a6f046f..02448c8bbb1ae3ab56a1f2ae1d0440dec51a666c 100644 (file)
 #define SC_SCHLUESSEL          9
 #define SC_ZEITBONUS           10
 
-/* values for game_emulation */
-#define EMU_NONE               0
-#define EMU_BOULDERDASH                1
-#define EMU_SOKOBAN            2
-
-/* to control special behaviour of certain game elements */
-int game_emulation = EMU_NONE;
-
 
 
 
@@ -315,6 +307,7 @@ void InitGame()
   int i, j, x, y;
   boolean emulate_bd = TRUE;   /* unless non-BOULDERDASH elements found */
   boolean emulate_sb = TRUE;   /* unless non-SOKOBAN     elements found */
+  boolean emulate_sp = TRUE;   /* unless non-SUPAPLEX    elements found */
 
   /* don't play tapes over network */
   network_playing = (options.network && !tape.playing);
@@ -390,6 +383,7 @@ void InitGame()
   MampferNr = 0;
   FrameCounter = 0;
   TimeFrames = 0;
+  TimePlayed = 0;
   TimeLeft = level.time;
 
   ScreenMovDir = MV_NO_MOVING;
@@ -428,14 +422,19 @@ void InitGame()
     }
   }
 
-  for(y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
+  for(y=0; y<lev_fieldy; y++)
   {
-    if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
-      emulate_bd = FALSE;
-    if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
-      emulate_sb = FALSE;
-
-    InitField(x, y, TRUE);
+    for(x=0; x<lev_fieldx; x++)
+    {
+      if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
+       emulate_bd = FALSE;
+      if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
+       emulate_sb = FALSE;
+      if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
+       emulate_sp = FALSE;
+
+      InitField(x, y, TRUE);
+    }
   }
 
   /* check if any connected player was not found in playfield */
@@ -533,8 +532,56 @@ void InitGame()
   }
 
   game_emulation = (emulate_bd ? EMU_BOULDERDASH :
-                   emulate_sb ? EMU_SOKOBAN : EMU_NONE);
+                   emulate_sb ? EMU_SOKOBAN :
+                   emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
+
+  if (BorderElement == EL_LEERRAUM)
+  {
+    SBX_Left = 0;
+    SBX_Right = lev_fieldx - SCR_FIELDX;
+    SBY_Upper = 0;
+    SBY_Lower = lev_fieldy - SCR_FIELDY;
+  }
+  else
+  {
+    SBX_Left = -1;
+    SBX_Right = lev_fieldx - SCR_FIELDX + 1;
+    SBY_Upper = -1;
+    SBY_Lower = lev_fieldy - SCR_FIELDY + 1;
+  }
+
+  if (lev_fieldx < SCR_FIELDX)
+  {
+    SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2;
+
+    /*
+    SBX_Left  -= (SCR_FIELDX - lev_fieldx) / 2;
+    SBX_Right -= (SCR_FIELDX - lev_fieldx) / 2;
+    */
+  }
+
+  if (lev_fieldy < SCR_FIELDY)
+  {
+    SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2;
+
+    /*
+    SBY_Upper -= (SCR_FIELDY - lev_fieldy) / 2;
+    SBY_Lower -= (SCR_FIELDY - lev_fieldy) / 2;
+    */
+  }
 
+#if 1
+  scroll_x = SBX_Left;
+  scroll_y = SBY_Upper;
+  if (local_player->jx >= SBX_Left + MIDPOSX)
+    scroll_x = (local_player->jx <= SBX_Right + MIDPOSX ?
+               local_player->jx - MIDPOSX :
+               SBX_Right);
+  if (local_player->jy >= SBY_Upper + MIDPOSY)
+    scroll_y = (local_player->jy <= SBY_Lower + MIDPOSY ?
+               local_player->jy - MIDPOSY :
+               SBY_Lower);
+#else
   scroll_x = scroll_y = -1;
   if (local_player->jx >= MIDPOSX-1)
     scroll_x = (local_player->jx <= lev_fieldx-MIDPOSX ?
@@ -544,6 +591,7 @@ void InitGame()
     scroll_y = (local_player->jy <= lev_fieldy-MIDPOSY ?
                local_player->jy - MIDPOSY :
                lev_fieldy - SCR_FIELDY + 1);
+#endif
 
   CloseDoor(DOOR_CLOSE_1);
 
@@ -622,6 +670,7 @@ void InitMovDir(int x, int y)
       Feld[x][y] = EL_KAEFER;
       MovDir[x][y] = direction[0][element - EL_KAEFER_R];
       break;
+
     case EL_FLIEGER_R:
     case EL_FLIEGER_O:
     case EL_FLIEGER_L:
@@ -629,6 +678,7 @@ void InitMovDir(int x, int y)
       Feld[x][y] = EL_FLIEGER;
       MovDir[x][y] = direction[0][element - EL_FLIEGER_R];
       break;
+
     case EL_BUTTERFLY_R:
     case EL_BUTTERFLY_O:
     case EL_BUTTERFLY_L:
@@ -636,6 +686,7 @@ void InitMovDir(int x, int y)
       Feld[x][y] = EL_BUTTERFLY;
       MovDir[x][y] = direction[0][element - EL_BUTTERFLY_R];
       break;
+
     case EL_FIREFLY_R:
     case EL_FIREFLY_O:
     case EL_FIREFLY_L:
@@ -643,6 +694,7 @@ void InitMovDir(int x, int y)
       Feld[x][y] = EL_FIREFLY;
       MovDir[x][y] = direction[0][element - EL_FIREFLY_R];
       break;
+
     case EL_PACMAN_R:
     case EL_PACMAN_O:
     case EL_PACMAN_L:
@@ -650,14 +702,21 @@ void InitMovDir(int x, int y)
       Feld[x][y] = EL_PACMAN;
       MovDir[x][y] = direction[0][element - EL_PACMAN_R];
       break;
+
+    case EL_SP_SNIKSNAK:
+      MovDir[x][y] = MV_UP;
+      break;
+
+    case EL_SP_ELECTRON:
+      MovDir[x][y] = MV_LEFT;
+      break;
+
     default:
       MovDir[x][y] = 1 << RND(4);
       if (element != EL_KAEFER &&
          element != EL_FLIEGER &&
          element != EL_BUTTERFLY &&
-         element != EL_FIREFLY &&
-         element != EL_SP_SNIKSNAK &&
-         element != EL_SP_ELECTRON)
+         element != EL_FIREFLY)
        break;
 
       for (i=0; i<4; i++)
@@ -725,7 +784,7 @@ void GameWon()
     {
       if (!setup.sound_loops)
        PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
-      if (TimeLeft && !(TimeLeft % 10))
+      if (TimeLeft > 0 && !(TimeLeft % 10))
        RaiseScore(level.score[SC_ZEITBONUS]);
       if (TimeLeft > 100 && !(TimeLeft % 10))
        TimeLeft -= 10;
@@ -739,6 +798,29 @@ void GameWon()
     if (setup.sound_loops)
       StopSound(SND_SIRR);
   }
+  else if (level.time == 0)            /* level without time limit */
+  {
+    if (setup.sound_loops)
+      PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
+
+    while(TimePlayed < 999)
+    {
+      if (!setup.sound_loops)
+       PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
+      if (TimePlayed < 999 && !(TimePlayed % 10))
+       RaiseScore(level.score[SC_ZEITBONUS]);
+      if (TimePlayed < 900 && !(TimePlayed % 10))
+       TimePlayed += 10;
+      else
+       TimePlayed++;
+      DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
+      BackToFront();
+      Delay(10);
+    }
+
+    if (setup.sound_loops)
+      StopSound(SND_SIRR);
+  }
 
   FadeSounds();
 
@@ -775,7 +857,7 @@ void GameWon()
   BackToFront();
 }
 
-boolean NewHiScore()
+int NewHiScore()
 {
   int k, l;
   int position = -1;
@@ -959,7 +1041,9 @@ void DrawDynamite(int x, int y)
       phase = 7 - phase;
   }
 
-  if (Store[x][y])
+  if (game_emulation == EMU_SUPAPLEX)
+    DrawGraphic(sx, sy, GFX_SP_DISK_RED);
+  else if (Store[x][y])
     DrawGraphicThruMask(sx, sy, graphic + phase);
   else
     DrawGraphic(sx, sy, graphic + phase);
@@ -1015,7 +1099,7 @@ void Explode(int ex, int ey, int phase, int mode)
        RemoveMovingField(x, y);
       }
 
-      if (!IN_LEV_FIELD(x, y) || IS_MASSIV(element) || element == EL_BURNING)
+      if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(element) || element == EL_BURNING)
        continue;
 
       if ((mode!=EX_NORMAL || center_element == EL_AMOEBA2DIAM) &&
@@ -1043,6 +1127,9 @@ void Explode(int ex, int ey, int phase, int mode)
            Store[x][y] = EL_EDELSTEIN_GELB;
            break;
        }
+
+       if (game_emulation == EMU_SUPAPLEX)
+         Store[x][y] = EL_LEERRAUM;
       }
       else if (center_element == EL_MAULWURF)
        Store[x][y] = EL_EDELSTEIN_ROT;
@@ -1052,6 +1139,8 @@ void Explode(int ex, int ey, int phase, int mode)
        Store[x][y] = ((x == ex && y == ey) ? EL_DIAMANT : EL_EDELSTEIN);
       else if (center_element == EL_BUTTERFLY)
        Store[x][y] = EL_EDELSTEIN_BD;
+      else if (center_element == EL_SP_ELECTRON)
+       Store[x][y] = EL_SP_INFOTRON;
       else if (center_element == EL_MAMPFER)
        Store[x][y] = level.mampfer_inhalt[MampferNr][x-ex+1][y-ey+1];
       else if (center_element == EL_AMOEBA2DIAM)
@@ -1133,12 +1222,19 @@ void Explode(int ex, int ey, int phase, int mode)
       InitMovDir(x, y);
     DrawLevelField(x, y);
   }
-  else if (!(phase%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+  else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
   {
+    int graphic = GFX_EXPLOSION;
+
+    if (game_emulation == EMU_SUPAPLEX)
+      graphic = (Store[x][y] == EL_SP_INFOTRON ?
+                GFX_SP_EXPLODE_INFOTRON :
+                GFX_SP_EXPLODE_EMPTY);
+
     if (phase == delay)
       ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
 
-    DrawGraphic(SCREENX(x), SCREENY(y), GFX_EXPLOSION+(phase/delay-1));
+    DrawGraphic(SCREENX(x), SCREENY(y), graphic + (phase / delay - 1));
   }
 }
 
@@ -1166,7 +1262,7 @@ void DynaExplode(int ex, int ey)
       int y = ey+j*xy[i%4][1];
       int element;
 
-      if (!IN_LEV_FIELD(x, y) || IS_MASSIV(Feld[x][y]))
+      if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(Feld[x][y]))
        break;
 
       element = Feld[x][y];
@@ -1187,7 +1283,10 @@ void Bang(int x, int y)
 {
   int element = Feld[x][y];
 
-  PlaySoundLevel(x, y, SND_ROAAAR);
+  if (game_emulation == EMU_SUPAPLEX)
+    PlaySoundLevel(x, y, SND_SP_BOOOM);
+  else
+    PlaySoundLevel(x, y, SND_ROAAAR);
 
   if (IS_PLAYER(x, y)) /* remove objects that might cause smaller explosion */
     element = EL_LEERRAUM;
@@ -1349,7 +1448,7 @@ void Impact(int x, int y)
        return;
       }
     }
-    else if (element == EL_FELSBROCKEN)
+    else if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
     {
       if (IS_ENEMY(smashed) ||
          smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE ||
@@ -1403,6 +1502,7 @@ void Impact(int x, int y)
       case EL_EDELSTEIN_ROT:
       case EL_EDELSTEIN_LILA:
       case EL_DIAMANT:
+      case EL_SP_INFOTRON:
         sound = SND_PLING;
        break;
       case EL_KOKOSNUSS:
@@ -1411,6 +1511,9 @@ void Impact(int x, int y)
       case EL_FELSBROCKEN:
        sound = SND_KLOPF;
        break;
+      case EL_SP_ZONK:
+       sound = SND_SP_ZONKDOWN;
+       break;
       case EL_SCHLUESSEL:
       case EL_SCHLUESSEL1:
       case EL_SCHLUESSEL2:
@@ -1995,8 +2098,8 @@ void StartMoving(int x, int y)
     {
       MovDelay[x][y]--;
 
-      if (element == EL_ROBOT || element == EL_MAMPFER ||
-         element == EL_MAMPFER2)
+      if (element == EL_ROBOT ||
+         element == EL_MAMPFER || element == EL_MAMPFER2)
       {
        int phase = MovDelay[x][y] % 8;
 
@@ -2010,6 +2113,8 @@ void StartMoving(int x, int y)
            && MovDelay[x][y]%4 == 3)
          PlaySoundLevel(x, y, SND_NJAM);
       }
+      else if (element == EL_SP_ELECTRON)
+       DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
       else if (element == EL_DRACHE)
       {
        int i;
@@ -2232,12 +2337,14 @@ void StartMoving(int x, int y)
       TurnRound(x, y);
 
       if (element == EL_KAEFER || element == EL_FLIEGER ||
-         element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
+         element == EL_SP_SNIKSNAK)
        DrawLevelField(x, y);
       else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
        DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
       else if (element == EL_SONDE)
        DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
+      else if (element == EL_SP_ELECTRON)
+       DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
 
       return;
     }
@@ -3122,6 +3229,68 @@ void CheckForDragon(int x, int y)
   }
 }
 
+static void CheckBuggyBase(int x, int y)
+{
+  int element = Feld[x][y];
+
+  if (element == EL_SP_BUG)
+  {
+    if (!MovDelay[x][y])       /* start activating buggy base */
+      MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
+
+    if (MovDelay[x][y])                /* wait some time before activating base */
+    {
+      MovDelay[x][y]--;
+      if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+       DrawGraphic(SCREENX(x), SCREENY(y), GFX_SP_BUG_WARNING);
+      if (MovDelay[x][y])
+       return;
+
+      Feld[x][y] = EL_SP_BUG_ACTIVE;
+    }
+  }
+  else if (element == EL_SP_BUG_ACTIVE)
+  {
+    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 */
+    {
+      MovDelay[x][y]--;
+      if (MovDelay[x][y])
+      {
+       int i;
+       static int xy[4][2] =
+       {
+         { 0, -1 },
+         { -1, 0 },
+         { +1, 0 },
+         { 0, +1 }
+       };
+
+       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+         DrawGraphic(SCREENX(x),SCREENY(y), GFX_SP_BUG_ACTIVE + SimpleRND(4));
+
+       for (i=0; i<4; i++)
+       {
+         int xx = x + xy[i][0], yy = y + xy[i][1];
+
+         if (IS_PLAYER(xx, yy))
+         {
+           PlaySoundLevel(x, y, SND_SP_BUG);
+           break;
+         }
+       }
+
+       return;
+      }
+
+      Feld[x][y] = EL_SP_BUG;
+      DrawLevelField(x, y);
+    }
+  }
+}
+
 static void PlayerActions(struct PlayerInfo *player, byte player_action)
 {
   static byte stored_player_action[MAX_PLAYERS];
@@ -3365,9 +3534,9 @@ void GameActions()
     extern unsigned int last_RND();
 
     printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
-          level.time - TimeLeft,
+          TimePlayed,
           last_RND(),
-          getStateCheckSum(level.time - TimeLeft));
+          getStateCheckSum(TimePlayed));
   }
   */
 #endif
@@ -3460,6 +3629,12 @@ void GameActions()
       MauerAbleger(x, y);
     else if (element == EL_BURNING)
       CheckForDragon(x, y);
+    else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE)
+      CheckBuggyBase(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)
+      DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL_ACTIVE, 7, 4, ANIM_NORMAL);
 
     if (SiebAktiv)
     {
@@ -3518,22 +3693,29 @@ void GameActions()
     }
   }
 
-  if (TimeLeft > 0 && TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing)
+  if (TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing)
   {
     TimeFrames = 0;
-    TimeLeft--;
+    TimePlayed++;
 
     if (tape.recording || tape.playing)
-      DrawVideoDisplay(VIDEO_STATE_TIME_ON, level.time-TimeLeft);
+      DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
 
-    if (TimeLeft<=10)
-      PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
+    if (TimeLeft > 0)
+    {
+      TimeLeft--;
 
-    DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
+      if (TimeLeft <= 10)
+       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
 
-    if (!TimeLeft)
-      for (i=0; i<MAX_PLAYERS; i++)
-       KillHero(&stored_player[i]);
+      DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
+
+      if (!TimeLeft)
+       for (i=0; i<MAX_PLAYERS; i++)
+         KillHero(&stored_player[i]);
+    }
+    else if (level.time == 0)          /* level without time limit */
+      DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
   }
 
   DrawAllPlayers();
@@ -3741,9 +3923,15 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
            (player->MovDir == MV_RIGHT && scroll_x < jx-MIDPOSX-offset))
          scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
 
+#if 1
+       /* don't scroll over playfield boundaries */
+       if (scroll_x < SBX_Left || scroll_x > SBX_Right)
+         scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
+#else
        /* don't scroll over playfield boundaries */
        if (scroll_x < -1 || scroll_x > lev_fieldx - SCR_FIELDX + 1)
          scroll_x = (scroll_x < -1 ? -1 : lev_fieldx - SCR_FIELDX + 1);
+#endif
 
        /* don't scroll more than one field at a time */
        scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
@@ -3759,9 +3947,15 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
            (player->MovDir == MV_DOWN && scroll_y < jy-MIDPOSY-offset))
          scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
 
+#if 1
+       /* don't scroll over playfield boundaries */
+       if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
+         scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
+#else
        /* don't scroll over playfield boundaries */
        if (scroll_y < -1 || scroll_y > lev_fieldy - SCR_FIELDY + 1)
          scroll_y = (scroll_y < -1 ? -1 : lev_fieldy - SCR_FIELDY + 1);
+#endif
 
        /* don't scroll more than one field at a time */
        scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
@@ -4114,10 +4308,18 @@ int DigField(struct PlayerInfo *player,
   switch(element)
   {
     case EL_LEERRAUM:
+      PlaySoundLevel(x, y, SND_EMPTY);
       break;
 
     case EL_ERDREICH:
       Feld[x][y] = EL_LEERRAUM;
+      PlaySoundLevel(x, y, SND_SCHLURF);
+      break;
+
+    case EL_SP_BASE:
+    case EL_SP_BUG:
+      Feld[x][y] = EL_LEERRAUM;
+      PlaySoundLevel(x, y, SND_SP_BASE);
       break;
 
     case EL_EDELSTEIN:
@@ -4135,7 +4337,10 @@ int DigField(struct PlayerInfo *player,
       DrawText(DX_EMERALDS, DY_EMERALDS,
               int2str(local_player->gems_still_needed, 3),
               FS_SMALL, FC_YELLOW);
-      PlaySoundLevel(x, y, SND_PONG);
+      if (element == EL_SP_INFOTRON)
+       PlaySoundLevel(x, y, SND_SP_INFOTRON);
+      else
+       PlaySoundLevel(x, y, SND_PONG);
       break;
 
     case EL_SPEED_PILL:
@@ -4153,7 +4358,10 @@ int DigField(struct PlayerInfo *player,
       DrawText(DX_DYNAMITE, DY_DYNAMITE,
               int2str(local_player->dynamite, 3),
               FS_SMALL, FC_YELLOW);
-      PlaySoundLevel(x, y, SND_PONG);
+      if (element == EL_SP_DISK_RED)
+       PlaySoundLevel(x, y, SND_SP_INFOTRON);
+      else
+       PlaySoundLevel(x, y, SND_PONG);
       break;
 
     case EL_DYNABOMB_NR:
@@ -4211,12 +4419,16 @@ int DigField(struct PlayerInfo *player,
        int xx, yy;
 
        for (yy=0; yy<lev_fieldy; yy++)
+       {
          for (xx=0; xx<lev_fieldx; xx++)
+         {
            if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
              Bang(xx, yy);
+           else if (Feld[xx][yy] == EL_SP_TERMINAL)
+             Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
+         }
+       }
 
-       Feld[x][y] = EL_SP_TERMINAL_ACTIVE;
-       DrawLevelField(x, y);
        return MF_ACTION;
       }
       break;
@@ -4226,7 +4438,7 @@ int DigField(struct PlayerInfo *player,
        return MF_NO_ACTION;
 
       player->LevelSolved = player->GameOver = TRUE;
-      PlaySoundLevel(x, y, SND_BUING);
+      PlaySoundStereo(SND_SP_EXIT, PSND_MAX_RIGHT);
       break;
 
     case EL_FELSBROCKEN:
@@ -4235,7 +4447,6 @@ int DigField(struct PlayerInfo *player,
     case EL_ZEIT_LEER:
     case EL_SP_ZONK:
     case EL_SP_DISK_ORANGE:
-    case EL_SP_DISK_YELLOW:
       if (dy || mode == DF_SNAP)
        return MF_NO_ACTION;
 
@@ -4266,6 +4477,8 @@ int DigField(struct PlayerInfo *player,
        PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
       else if (element == EL_KOKOSNUSS)
        PlaySoundLevel(x+dx, y+dy, SND_KNURK);
+      else if (IS_SP_ELEMENT(element))
+       PlaySoundLevel(x+dx, y+dy, SND_SP_ZONKPUSH);
       else
        PlaySoundLevel(x+dx, y+dy, SND_KLOPF);
       break;
@@ -4286,6 +4499,42 @@ int DigField(struct PlayerInfo *player,
        return MF_NO_ACTION;
       break;
 
+    case EL_SP_PORT1_LEFT:
+    case EL_SP_PORT2_LEFT:
+    case EL_SP_PORT1_RIGHT:
+    case EL_SP_PORT2_RIGHT:
+    case EL_SP_PORT1_UP:
+    case EL_SP_PORT2_UP:
+    case EL_SP_PORT1_DOWN:
+    case EL_SP_PORT2_DOWN:
+    case EL_SP_PORT_X:
+    case EL_SP_PORT_Y:
+    case EL_SP_PORT_XY:
+      if ((dx == -1 &&
+          element != EL_SP_PORT1_LEFT &&
+          element != EL_SP_PORT2_LEFT &&
+          element != EL_SP_PORT_X &&
+          element != EL_SP_PORT_XY) ||
+         (dx == +1 &&
+          element != EL_SP_PORT1_RIGHT &&
+          element != EL_SP_PORT2_RIGHT &&
+          element != EL_SP_PORT_X &&
+          element != EL_SP_PORT_XY) ||
+         (dy == -1 &&
+          element != EL_SP_PORT1_UP &&
+          element != EL_SP_PORT2_UP &&
+          element != EL_SP_PORT_Y &&
+          element != EL_SP_PORT_XY) ||
+         (dy == +1 &&
+          element != EL_SP_PORT1_DOWN &&
+          element != EL_SP_PORT2_DOWN &&
+          element != EL_SP_PORT_Y &&
+          element != EL_SP_PORT_XY) ||
+         !IN_LEV_FIELD(x + dx, y + dy) ||
+         !IS_FREE(x + dx, y + dy))
+       return MF_NO_ACTION;
+      break;
+
     case EL_AUSGANG_ZU:
     case EL_AUSGANG_ACT:
       /* door is not (yet) open */
@@ -4331,6 +4580,7 @@ int DigField(struct PlayerInfo *player,
     case EL_SOKOBAN_FELD_VOLL:
     case EL_SOKOBAN_OBJEKT:
     case EL_SONDE:
+    case EL_SP_DISK_YELLOW:
       if (mode == DF_SNAP)
        return MF_NO_ACTION;
 
@@ -4408,12 +4658,7 @@ int DigField(struct PlayerInfo *player,
       break;
 
     default:
-      if (IS_EATABLE(element))         /* other kinds of 'dirt' */
-       Feld[x][y] = EL_LEERRAUM;
-      else
-       return MF_NO_ACTION;
-
-      break;
+      return MF_NO_ACTION;
   }
 
   player->push_delay = 0;
@@ -4482,7 +4727,12 @@ boolean PlaceBomb(struct PlayerInfo *player)
     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
             FS_SMALL, FC_YELLOW);
     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
-      DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
+    {
+      if (game_emulation == EMU_SUPAPLEX)
+       DrawGraphic(SCREENX(jx), SCREENY(jy), GFX_SP_DISK_RED);
+      else
+       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
+    }
   }
   else
   {