rnd-19981204-1
[rocksndiamonds.git] / src / game.c
index a48ad78bad3944432795406b1fae03677445dbe4..26cc84cc2a8a61d0e95a9cd347f74368a549ebff 100644 (file)
 #include "joystick.h"
 #include "network.h"
 
-#ifdef DEBUG
-static unsigned int getStateCheckSum(int counter)
-{
-  int x, y;
-  unsigned int mult = 1;
-  unsigned int checksum = 0;
-  static short lastFeld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-  static boolean first_game = TRUE;
-
-  for (y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
-  {
-    /*
-    if (counter == 3)
-    {
-      if (first_game)
-       lastFeld[x][y] = Feld[x][y];
-      else if (lastFeld[x][y] != Feld[x][y])
-       printf("DIFF: [%d][%d]: lastFeld == %d != %d == Feld\n",
-              x, y, lastFeld[x][y], Feld[x][y]);
-    }
-    */
-
-    checksum += mult++ * Ur[x][y];
-    checksum += mult++ * Feld[x][y];
-
-    /*
-    checksum += mult++ * MovPos[x][y];
-    checksum += mult++ * MovDir[x][y];
-    checksum += mult++ * MovDelay[x][y];
-    checksum += mult++ * Store[x][y];
-    checksum += mult++ * Store2[x][y];
-    checksum += mult++ * StorePlayer[x][y];
-    checksum += mult++ * Frame[x][y];
-    checksum += mult++ * AmoebaNr[x][y];
-    checksum += mult++ * JustHit[x][y];
-    checksum += mult++ * Stop[x][y];
-    */
-  }
-
-  if (counter == 3 && first_game)
-    first_game = FALSE;
-
-  return checksum;
-}
-#endif
+/* for DigField() */
+#define DF_NO_PUSH             0
+#define DF_DIG                 1
+#define DF_SNAP                        2
+
+/* for MoveFigure() */
+#define MF_NO_ACTION           0
+#define MF_MOVING              1
+#define MF_ACTION              2
+
+/* for ScrollFigure() */
+#define SCROLL_INIT            0
+#define SCROLL_GO_ON           1
+
+/* for Explode() */
+#define EX_PHASE_START         0
+#define EX_NORMAL              0
+#define EX_CENTER              1
+#define EX_BORDER              2
+
+/* special positions in the game control window (relative to control window) */
+#define XX_LEVEL               37
+#define YY_LEVEL               20
+#define XX_EMERALDS            29
+#define YY_EMERALDS            54
+#define XX_DYNAMITE            29
+#define YY_DYNAMITE            89
+#define XX_KEYS                        18
+#define YY_KEYS                        123
+#define XX_SCORE               15
+#define YY_SCORE               159
+#define XX_TIME                        29
+#define YY_TIME                        194
+
+/* special positions in the game control window (relative to main window) */
+#define DX_LEVEL               (DX + XX_LEVEL)
+#define DY_LEVEL               (DY + YY_LEVEL)
+#define DX_EMERALDS            (DX + XX_EMERALDS)
+#define DY_EMERALDS            (DY + YY_EMERALDS)
+#define DX_DYNAMITE            (DX + XX_DYNAMITE)
+#define DY_DYNAMITE            (DY + YY_DYNAMITE)
+#define DX_KEYS                        (DX + XX_KEYS)
+#define DY_KEYS                        (DY + YY_KEYS)
+#define DX_SCORE               (DX + XX_SCORE)
+#define DY_SCORE               (DY + YY_SCORE)
+#define DX_TIME                        (DX + XX_TIME)
+#define DY_TIME                        (DY + YY_TIME)
+
+#define IS_LOOP_SOUND(s)       ((s)==SND_KLAPPER || (s)==SND_ROEHR ||  \
+                                (s)==SND_NJAM || (s)==SND_MIEP)
+#define IS_MUSIC_SOUND(s)      ((s)==SND_ALCHEMY || (s)==SND_CHASE || \
+                                (s)==SND_NETWORK || (s)==SND_CZARDASZ || \
+                                (s)==SND_TYGER || (s)==SND_VOYAGER || \
+                                (s)==SND_TWILIGHT)
+
+/* score for elements */
+#define SC_EDELSTEIN           0
+#define SC_DIAMANT             1
+#define SC_KAEFER              2
+#define SC_FLIEGER             3
+#define SC_MAMPFER             4
+#define SC_ROBOT               5
+#define SC_PACMAN              6
+#define SC_KOKOSNUSS           7
+#define SC_DYNAMIT             8
+#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;
 
 void GetPlayerConfig()
 {
@@ -154,9 +184,11 @@ void InitGame()
 
   network_player_action_received = FALSE;
 
+#ifndef MSDOS
   /* initial null action */
   if (network_playing)
     SendToServer_MovePlayer(MV_NO_MOVING);
+#endif
 
   ZX = ZY = -1;
 
@@ -224,10 +256,13 @@ void InitGame()
 
          StorePlayer[x][y] = Feld[x][y];
 
-         printf("Player %d activated.\n", player->element_nr);
-         printf("[Local player is %d and currently %s.]\n",
-                local_player->element_nr,
-                local_player->active ? "active" : "not active");
+         if (options.verbose)
+         {
+           printf("Player %d activated.\n", player->element_nr);
+           printf("[Local player is %d and currently %s.]\n",
+                  local_player->element_nr,
+                  local_player->active ? "active" : "not active");
+         }
        }
 
        Feld[x][y] = EL_LEERRAUM;
@@ -340,20 +375,38 @@ void InitGame()
     }
   }
 
-  /* when in single player mode, eliminate all but the first active player */
-  if (!options.network && !setup.team_mode)
+  if (tape.playing)
+  {
+    /* when playing a tape, eliminate all players who do not participate */
+
+    for (i=0; i<MAX_PLAYERS; i++)
+    {
+      if (stored_player[i].active && !tape.player_participates[i])
+      {
+       struct PlayerInfo *player = &stored_player[i];
+       int jx = player->jx, jy = player->jy;
+
+       player->active = FALSE;
+       StorePlayer[jx][jy] = 0;
+       Feld[jx][jy] = EL_LEERRAUM;
+      }
+    }
+  }
+  else if (!options.network && !setup.team_mode)       /* && !tape.playing */
   {
+    /* when in single player mode, eliminate all but the first active player */
+
     for (i=0; i<MAX_PLAYERS; i++)
     {
       if (stored_player[i].active)
       {
        for (j=i+1; j<MAX_PLAYERS; j++)
        {
-         struct PlayerInfo *player = &stored_player[j];
-         int jx = player->jx, jy = player->jy;
-
-         if (player->active)
+         if (stored_player[j].active)
          {
+           struct PlayerInfo *player = &stored_player[j];
+           int jx = player->jx, jy = player->jy;
+
            player->active = FALSE;
            StorePlayer[jx][jy] = 0;
            Feld[jx][jy] = EL_LEERRAUM;
@@ -363,19 +416,29 @@ void InitGame()
     }
   }
 
-  for (i=0; i<MAX_PLAYERS; i++)
+  /* when recording the game, store which players take part in the game */
+  if (tape.recording)
   {
-    struct PlayerInfo *player = &stored_player[i];
-
-    printf("Player %d: present == %d, connected == %d, active == %d.\n",
-          i+1,
-          player->present,
-          player->connected,
-          player->active);
-    if (local_player == player)
-      printf("Player %d is local player.\n", i+1);
+    for (i=0; i<MAX_PLAYERS; i++)
+      if (stored_player[i].active)
+       tape.player_participates[i] = TRUE;
   }
 
+  if (options.verbose)
+  {
+    for (i=0; i<MAX_PLAYERS; i++)
+    {
+      struct PlayerInfo *player = &stored_player[i];
+
+      printf("Player %d: present == %d, connected == %d, active == %d.\n",
+            i+1,
+            player->present,
+            player->connected,
+            player->active);
+      if (local_player == player)
+       printf("Player  %d is local player.\n", i+1);
+    }
+  }
 
   game_emulation = (emulate_bd ? EMU_BOULDERDASH :
                    emulate_sb ? EMU_SOKOBAN : EMU_NONE);
@@ -434,11 +497,12 @@ void InitGame()
 
   XAutoRepeatOff(display);
 
-
-  for (i=0; i<4; i++)
-    printf("Spieler %d %saktiv.\n",
-          i+1, (stored_player[i].active ? "" : "nicht "));
-
+  if (options.verbose)
+  {
+    for (i=0; i<4; i++)
+      printf("Spieler %d %saktiv.\n",
+            i+1, (stored_player[i].active ? "" : "nicht "));
+  }
 }
 
 void InitMovDir(int x, int y)
@@ -623,15 +687,15 @@ boolean NewHiScore()
 
   LoadScore(level_nr);
 
-  if (!strcmp(setup.player_name, EMPTY_ALIAS) ||
-      local_player->score < highscore[MAX_SCORE_ENTRIES-1].Score) 
+  if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 ||
+      local_player->score < highscore[MAX_SCORE_ENTRIES - 1].Score) 
     return -1;
 
   for (k=0; k<MAX_SCORE_ENTRIES; k++) 
   {
     if (local_player->score > highscore[k].Score)
     {
-      /* Spieler kommt in Highscore-Liste */
+      /* player has made it to the hall of fame */
 
       if (k < MAX_SCORE_ENTRIES - 1)
       {
@@ -641,7 +705,7 @@ boolean NewHiScore()
        for (l=k; l<MAX_SCORE_ENTRIES; l++)
          if (!strcmp(setup.player_name, highscore[l].Name))
            m = l;
-       if (m == k)     /* Spieler überschreibt seine alte Position */
+       if (m == k)     /* player's new highscore overwrites his old one */
          goto put_into_list;
 #endif
 
@@ -664,7 +728,7 @@ boolean NewHiScore()
 
 #ifdef ONE_PER_NAME
     else if (!strncmp(setup.player_name, highscore[k].Name, MAX_NAMELEN - 1))
-      break;   /* Spieler schon mit besserer Punktzahl in der Liste */
+      break;   /* player already there with a higher score */
 #endif
 
   }
@@ -808,7 +872,7 @@ void DrawDynamite(int x, int y)
 
 void CheckDynamite(int x, int y)
 {
-  if (MovDelay[x][y])          /* neues Dynamit / in Wartezustand */
+  if (MovDelay[x][y])          /* dynamite is still waiting to explode */
   {
     MovDelay[x][y]--;
     if (MovDelay[x][y])
@@ -836,7 +900,7 @@ void Explode(int ex, int ey, int phase, int mode)
   int last_phase = num_phase * delay;
   int half_phase = (num_phase / 2) * delay;
 
-  if (phase == 0)                      /* Feld 'Store' initialisieren */
+  if (phase == EX_PHASE_START)         /* initialize 'Store[][]' field */
   {
     int center_element = Feld[ex][ey];
 
@@ -996,7 +1060,7 @@ void DynaExplode(int ex, int ey)
 
   Store2[ex][ey] = 0;  /* delete player information */
 
-  Explode(ex, ey, 0, EX_CENTER);
+  Explode(ex, ey, EX_PHASE_START, EX_CENTER);
 
   for (i=0; i<4; i++)
   {
@@ -1010,7 +1074,7 @@ void DynaExplode(int ex, int ey)
        break;
 
       element = Feld[x][y];
-      Explode(x, y, 0, EX_BORDER);
+      Explode(x, y, EX_PHASE_START, EX_BORDER);
 
       if (element != EL_LEERRAUM &&
          element != EL_ERDREICH &&
@@ -1029,6 +1093,9 @@ void Bang(int x, int y)
 
   PlaySoundLevel(x, y, SND_ROAAAR);
 
+  if (IS_PLAYER(x, y)) /* remove objects that might cause smaller explosion */
+    element = EL_LEERRAUM;
+
   switch(element)
   {
     case EL_KAEFER:
@@ -1040,7 +1107,7 @@ void Bang(int x, int y)
     case EL_ROBOT:
     case EL_PACMAN:
       RaiseScoreElement(element);
-      Explode(x, y, 0, EX_NORMAL);
+      Explode(x, y, EX_PHASE_START, EX_NORMAL);
       break;
     case EL_DYNABOMB:
     case EL_DYNABOMB_NR:
@@ -1048,12 +1115,14 @@ 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, 0, EX_CENTER);
+      Explode(x, y, EX_PHASE_START, EX_CENTER);
       break;
     default:
-      Explode(x, y, 0, EX_NORMAL);
+      Explode(x, y, EX_PHASE_START, EX_NORMAL);
       break;
   }
 }
@@ -1062,7 +1131,7 @@ void Blurb(int x, int y)
 {
   int element = Feld[x][y];
 
-  if (element!=EL_BLURB_LEFT && element!=EL_BLURB_RIGHT) /* Anfang */
+  if (element != EL_BLURB_LEFT && element != EL_BLURB_RIGHT)   /* start */
   {
     PlaySoundLevel(x, y, SND_BLURB);
     if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) &&
@@ -1078,14 +1147,14 @@ void Blurb(int x, int y)
       Feld[x+1][y] = EL_BLURB_RIGHT;
     }
   }
-  else                                                  /* Blubbern */
+  else                                                         /* go on */
   {
     int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
 
-    if (!MovDelay[x][y])       /* neue Phase / noch nicht gewartet */
+    if (!MovDelay[x][y])       /* initialize animation counter */
       MovDelay[x][y] = 9;
 
-    if (MovDelay[x][y])                /* neue Phase / in Wartezustand */
+    if (MovDelay[x][y])                /* continue animation */
     {
       MovDelay[x][y]--;
       if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
@@ -1107,8 +1176,7 @@ void Impact(int x, int y)
   int element = Feld[x][y];
   int smashed = 0;
 
-  /* Element darunter berührt? */
-  if (!lastline)
+  if (!lastline)       /* check if element below was hit */
   {
     if (Feld[x][y+1] == EL_PLAYER_IS_LEAVING)
       return;
@@ -1120,22 +1188,19 @@ void Impact(int x, int y)
       smashed = MovingOrBlocked2Element(x, y+1);
   }
 
-  /* Auftreffendes Element fällt in Salzsäure */
-  if (!lastline && smashed == EL_SALZSAEURE)
+  if (!lastline && smashed == EL_SALZSAEURE)   /* element falls into acid */
   {
     Blurb(x, y);
     return;
   }
 
-  /* Auftreffendes Element ist Bombe */
-  if (element == EL_BOMBE && (lastline || object_hit))
+  if (element == EL_BOMBE && (lastline || object_hit)) /* element is bomb */
   {
     Bang(x, y);
     return;
   }
 
-  /* Auftreffendes Element ist Säuretropfen */
-  if (element == EL_TROPFEN && (lastline || object_hit))
+  if (element == EL_TROPFEN && (lastline || object_hit))       /* acid drop */
   {
     if (object_hit && IS_PLAYER(x, y+1))
       KillHero(PLAYERINFO(x, y+1));
@@ -1149,8 +1214,7 @@ void Impact(int x, int y)
     return;
   }
 
-  /* Welches Element kriegt was auf die Rübe? */
-  if (!lastline && object_hit)
+  if (!lastline && object_hit)         /* check which object was hit */
   {
     if (CAN_CHANGE(element) && 
        (smashed == EL_SIEB_LEER || smashed == EL_SIEB2_LEER) && !SiebAktiv)
@@ -1206,7 +1270,7 @@ void Impact(int x, int y)
     }
   }
 
-  /* Geräusch beim Durchqueren des Siebes */
+  /* play sound of magic wall / mill */
   if (!lastline &&
       (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
   {
@@ -1214,7 +1278,7 @@ void Impact(int x, int y)
     return;
   }
 
-  /* Geräusch beim Auftreffen */
+  /* play sound of object that hits the ground */
   if (lastline || object_hit)
   {
     int sound;
@@ -1797,11 +1861,10 @@ void StartMoving(int x, int y)
     if (element == EL_SONDE && JustBeingPushed(x, y))
       return;
 
-    if (!MovDelay[x][y])       /* neuer Schritt / noch nicht gewartet */
+    if (!MovDelay[x][y])       /* start new movement phase */
     {
-      /* Alle Figuren, die nach jeden Schritt die Richtung wechseln können.
-       * (MAMPFER, MAMPFER2 und PACMAN laufen bis zur nächsten Wand.)
-       */
+      /* all objects that can change their move direction after each step */
+      /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall  */
 
       if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
       {
@@ -1811,7 +1874,7 @@ void StartMoving(int x, int y)
       }
     }
 
-    if (MovDelay[x][y])                /* neuer Schritt / in Wartezustand */
+    if (MovDelay[x][y])                /* wait some time before next movement */
     {
       MovDelay[x][y]--;
 
@@ -1886,13 +1949,13 @@ void StartMoving(int x, int y)
       PlaySoundLevel(x, y, SND_ROEHR);
     }
 
-    /* neuer Schritt / Wartezustand beendet */
+    /* now make next step */
 
-    Moving2Blocked(x, y, &newx, &newy);        /* wohin soll's gehen? */
+    Moving2Blocked(x, y, &newx, &newy);        /* get next screen position */
 
     if (IS_ENEMY(element) && IS_PLAYER(newx, newy))
     {
-      /* Spieler erwischt */
+      /* enemy got the player */
       MovDir[x][y] = 0;
       KillHero(PLAYERINFO(newx, newy));
       return;
@@ -2046,7 +2109,9 @@ void StartMoving(int x, int y)
       DrawLevelField(newx, newy);
     }
     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
-    {                                  /* gegen Wand gelaufen */
+    {
+      /* object was running against a wall */
+
       TurnRound(x, y);
 
       if (element == EL_KAEFER || element == EL_FLIEGER)
@@ -2088,7 +2153,7 @@ void ContinueMoving(int x, int y)
 
   MovPos[x][y] += step;
 
-  if (ABS(MovPos[x][y])>=TILEX)                /* Zielfeld erreicht */
+  if (ABS(MovPos[x][y])>=TILEX)                /* object reached its destination */
   {
     Feld[x][y] = EL_LEERRAUM;
     Feld[newx][newy] = element;
@@ -2148,7 +2213,7 @@ void ContinueMoving(int x, int y)
     Stop[newx][newy] = TRUE;
     JustHit[x][newy] = 3;
 
-    if (DONT_TOUCH(element))   /* Käfer oder Flieger */
+    if (DONT_TOUCH(element))   /* object may be nasty to player or others */
     {
       TestIfBadThingHitsHero(newx, newy);
       TestIfBadThingHitsFriend(newx, newy);
@@ -2161,7 +2226,7 @@ void ContinueMoving(int x, int y)
        (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
       Impact(x, newy);
   }
-  else                         /* noch in Bewegung */
+  else                         /* still moving on */
     DrawLevelField(x, y);
 }
 
@@ -2302,10 +2367,10 @@ void AmoebeUmwandeln2(int ax, int ay, int new_element)
 
 void AmoebeWaechst(int x, int y)
 {
-  static long sound_delay = 0;
-  static int sound_delay_value = 0;
+  static unsigned long sound_delay = 0;
+  static unsigned long sound_delay_value = 0;
 
-  if (!MovDelay[x][y])         /* neue Phase / noch nicht gewartet */
+  if (!MovDelay[x][y])         /* start new growing cycle */
   {
     MovDelay[x][y] = 7;
 
@@ -2316,7 +2381,7 @@ void AmoebeWaechst(int x, int y)
     }
   }
 
-  if (MovDelay[x][y])          /* neue Phase / in Wartezustand */
+  if (MovDelay[x][y])          /* wait some time before growing bigger */
   {
     MovDelay[x][y]--;
     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
@@ -2351,17 +2416,17 @@ void AmoebeAbleger(int ax, int ay)
     return;
   }
 
-  if (!MovDelay[ax][ay])       /* neue Amoebe / noch nicht gewartet */
+  if (!MovDelay[ax][ay])       /* start making new amoeba field */
     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25/(1+level.tempo_amoebe));
 
-  if (MovDelay[ax][ay])                /* neue Amoebe / in Wartezustand */
+  if (MovDelay[ax][ay])                /* wait some time before making new amoeba */
   {
     MovDelay[ax][ay]--;
     if (MovDelay[ax][ay])
       return;
   }
 
-  if (element == EL_AMOEBE_NASS)       /* tropfende Amöbe */
+  if (element == EL_AMOEBE_NASS)       /* object is an acid / amoeba drop */
   {
     int start = RND(4);
     int x = ax+xy[start][0];
@@ -2380,7 +2445,7 @@ void AmoebeAbleger(int ax, int ay)
     if (newax == ax && neway == ay)
       return;
   }
-  else                         /* normale oder "gefüllte" Amöbe */
+  else                         /* normal or "filled" amoeba */
   {
     int start = RND(4);
     boolean waiting_for_player = FALSE;
@@ -2413,7 +2478,7 @@ void AmoebeAbleger(int ax, int ay)
        DrawLevelField(ax, ay);
        AmoebaCnt[AmoebaNr[ax][ay]]--;
 
-       if (AmoebaCnt[AmoebaNr[ax][ay]]<=0)     /* Amöbe vollständig tot */
+       if (AmoebaCnt[AmoebaNr[ax][ay]]<=0)     /* amoeba is completely dead */
        {
          if (element == EL_AMOEBE_VOLL)
            AmoebeUmwandeln(ax, ay);
@@ -2463,17 +2528,17 @@ void AmoebeAbleger(int ax, int ay)
 void Life(int ax, int ay)
 {
   int x1, y1, x2, y2;
-  static int life[4] = { 2, 3, 3, 3 }; /* "Life"-Parameter */
+  static int life[4] = { 2, 3, 3, 3 }; /* parameters for "game of life" */
   int life_time = 40;
   int element = Feld[ax][ay];
 
   if (Stop[ax][ay])
     return;
 
-  if (!MovDelay[ax][ay])       /* neue Phase / noch nicht gewartet */
+  if (!MovDelay[ax][ay])       /* start new "game of life" cycle */
     MovDelay[ax][ay] = life_time;
 
-  if (MovDelay[ax][ay])                /* neue Phase / in Wartezustand */
+  if (MovDelay[ax][ay])                /* wait some time before next cycle */
   {
     MovDelay[ax][ay]--;
     if (MovDelay[ax][ay])
@@ -2502,7 +2567,7 @@ void Life(int ax, int ay)
        nachbarn++;
     }
 
-    if (xx == ax && yy == ay)          /* mittleres Feld mit Amoebe */
+    if (xx == ax && yy == ay)          /* field in the middle */
     {
       if (nachbarn<life[0] || nachbarn>life[1])
       {
@@ -2513,7 +2578,7 @@ void Life(int ax, int ay)
       }
     }
     else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
-    {                                  /* Randfeld ohne Amoebe */
+    {                                  /* free border field */
       if (nachbarn>=life[2] && nachbarn<=life[3])
       {
        Feld[xx][yy] = element;
@@ -2528,10 +2593,10 @@ void Life(int ax, int ay)
 
 void Ablenk(int x, int y)
 {
-  if (!MovDelay[x][y])         /* neue Phase / noch nicht gewartet */
+  if (!MovDelay[x][y])         /* next animation frame */
     MovDelay[x][y] = level.dauer_ablenk * FRAMES_PER_SECOND;
 
-  if (MovDelay[x][y])          /* neue Phase / in Wartezustand */
+  if (MovDelay[x][y])          /* wait some time before next frame */
   {
     MovDelay[x][y]--;
     if (MovDelay[x][y])
@@ -2552,10 +2617,10 @@ void Ablenk(int x, int y)
 
 void Birne(int x, int y)
 {
-  if (!MovDelay[x][y])         /* neue Phase / noch nicht gewartet */
+  if (!MovDelay[x][y])         /* next animation frame */
     MovDelay[x][y] = 800;
 
-  if (MovDelay[x][y])          /* neue Phase / in Wartezustand */
+  if (MovDelay[x][y])          /* wait some time before next frame */
   {
     MovDelay[x][y]--;
     if (MovDelay[x][y])
@@ -2589,10 +2654,10 @@ void Blubber(int x, int y)
 
 void NussKnacken(int x, int y)
 {
-  if (!MovDelay[x][y])         /* neue Phase / noch nicht gewartet */
+  if (!MovDelay[x][y])         /* next animation frame */
     MovDelay[x][y] = 7;
 
-  if (MovDelay[x][y])          /* neue Phase / in Wartezustand */
+  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)))
@@ -2634,10 +2699,10 @@ void AusgangstuerOeffnen(int x, int y)
 {
   int delay = 6;
 
-  if (!MovDelay[x][y])         /* neue Phase / noch nicht gewartet */
+  if (!MovDelay[x][y])         /* next animation frame */
     MovDelay[x][y] = 5*delay;
 
-  if (MovDelay[x][y])          /* neue Phase / in Wartezustand */
+  if (MovDelay[x][y])          /* wait some time before next frame */
   {
     int tuer;
 
@@ -2668,10 +2733,10 @@ void EdelsteinFunkeln(int x, int y)
     DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
   else
   {
-    if (!MovDelay[x][y])       /* neue Phase / noch nicht gewartet */
+    if (!MovDelay[x][y])       /* next animation frame */
       MovDelay[x][y] = 11 * !SimpleRND(500);
 
-    if (MovDelay[x][y])                /* neue Phase / in Wartezustand */
+    if (MovDelay[x][y])                /* wait some time before next frame */
     {
       MovDelay[x][y]--;
 
@@ -2709,10 +2774,10 @@ void MauerWaechst(int x, int y)
 {
   int delay = 6;
 
-  if (!MovDelay[x][y])         /* neue Phase / noch nicht gewartet */
+  if (!MovDelay[x][y])         /* next animation frame */
     MovDelay[x][y] = 3*delay;
 
-  if (MovDelay[x][y])          /* neue Phase / in Wartezustand */
+  if (MovDelay[x][y])          /* wait some time before next frame */
   {
     int phase;
 
@@ -2764,10 +2829,10 @@ void MauerAbleger(int ax, int ay)
   boolean oben_massiv = FALSE, unten_massiv = FALSE;
   boolean links_massiv = FALSE, rechts_massiv = FALSE;
 
-  if (!MovDelay[ax][ay])       /* neue Mauer / noch nicht gewartet */
+  if (!MovDelay[ax][ay])       /* start building new wall */
     MovDelay[ax][ay] = 6;
 
-  if (MovDelay[ax][ay])                /* neue Mauer / in Wartezustand */
+  if (MovDelay[ax][ay])                /* wait some time before building new wall */
   {
     MovDelay[ax][ay]--;
     if (MovDelay[ax][ay])
@@ -2992,8 +3057,8 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
 
 void GameActions()
 {
-  static long action_delay = 0;
-  long action_delay_value;
+  static unsigned long action_delay = 0;
+  unsigned long action_delay_value;
   int sieb_x = 0, sieb_y = 0;
   int i, x, y, element;
   byte *recorded_player_action;
@@ -3005,8 +3070,40 @@ void GameActions()
   action_delay_value =
     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
 
+  /*
+  if (tape.playing && tape.fast_forward)
+  {
+    char buf[100];
+
+    sprintf(buf, "FFWD: %ld ms", action_delay_value);
+    print_debug(buf);
+  }
+  */
+
+
   /* main game synchronization point */
+
+
+
+
+#if 1
   WaitUntilDelayReached(&action_delay, action_delay_value);
+#else
+
+  while (!DelayReached(&action_delay, action_delay_value))
+  {
+    char buf[100];
+
+    sprintf(buf, "%ld %ld %ld",
+           Counter(), action_delay, action_delay_value);
+    print_debug(buf);
+  }
+  print_debug("done");
+
+#endif
+
+
+
 
   if (network_playing && !network_player_action_received)
   {
@@ -3016,8 +3113,10 @@ void GameActions()
 #endif
     */
 
+#ifndef MSDOS
     /* last chance to get network player actions without main loop delay */
     HandleNetworking();
+#endif
 
     if (game_status != PLAYING)
       return;
@@ -3059,8 +3158,10 @@ void GameActions()
       stored_player[i].effective_action = stored_player[i].action;
   }
 
+#ifndef MSDOS
   if (network_playing)
     SendToServer_MovePlayer(summarized_player_action);
+#endif
 
   if (!options.network && !setup.team_mode)
     local_player->effective_action = summarized_player_action;
@@ -3093,6 +3194,7 @@ void GameActions()
 
 
 #ifdef DEBUG
+  /*
   if (TimeFrames == 0 && !local_player->gone)
   {
     extern unsigned int last_RND();
@@ -3102,13 +3204,16 @@ void GameActions()
           last_RND(),
           getStateCheckSum(level.time - TimeLeft));
   }
+  */
 #endif
 
 
 
 #ifdef DEBUG
+  /*
   if (GameFrameDelay >= 500)
     printf("FrameCounter == %d\n", FrameCounter);
+  */
 #endif
 
 
@@ -3405,11 +3510,11 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
 
   if (player->MovPos)
   {
-    /* should only happen if pre-1.0 tape recordings are played */
+    /* should only happen if pre-1.2 tape recordings are played */
     /* this is only for backward compatibility */
 
 #if DEBUG
-    printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.0 LEVEL TAPES.\n");
+    printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
 #endif
 
     while (player->MovPos)
@@ -3517,7 +3622,7 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
     else if (old_jx == jx && old_jy != jy)
       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
 
-    DrawLevelField(jx, jy);    /* für "ErdreichAnbroeckeln()" */
+    DrawLevelField(jx, jy);    /* for "ErdreichAnbroeckeln()" */
 
     player->last_move_dir = player->MovDir;
   }
@@ -3579,7 +3684,7 @@ void ScrollFigure(struct PlayerInfo *player, int mode)
 
 void ScrollScreen(struct PlayerInfo *player, int mode)
 {
-  static long screen_frame_counter = 0;
+  static unsigned long screen_frame_counter = 0;
 
   if (mode == SCROLL_INIT)
   {
@@ -3970,7 +4075,7 @@ int DigField(struct PlayerInfo *player,
 
     case EL_AUSGANG_ZU:
     case EL_AUSGANG_ACT:
-      /* Tür ist (noch) nicht offen! */
+      /* door is not (yet) open */
       return MF_NO_ACTION;
       break;