rnd-19990317-1-src
[rocksndiamonds.git] / src / game.c
index fcaedf73e391e6c0882991de5811ecfc1e1968c7..d4860369384bee8c3a33cf2f685e70d89d1429c4 100644 (file)
@@ -280,7 +280,7 @@ static void InitField(int x, int y, boolean init_game)
       }
       break;
 
-    case EL_DYNAMIT:
+    case EL_DYNAMITE_ACTIVE:
       MovDelay[x][y] = 96;
       break;
 
@@ -359,7 +359,7 @@ void InitGame()
 
     player->dynamite = 0;
     player->dynabomb_count = 0;
-    player->dynabomb_size = 0;
+    player->dynabomb_size = 1;
     player->dynabombs_left = 0;
     player->dynabomb_xl = FALSE;
 
@@ -550,9 +550,6 @@ void InitGame()
                    emulate_sb ? EMU_SOKOBAN :
                    emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
 
-  /* determine border element for this level */
-  SetBorderElement();
-
   if (BorderElement == EL_LEERRAUM)
   {
     SBX_Left = 0;
@@ -591,14 +588,31 @@ void InitGame()
   DrawAllPlayers();
   FadeToFront();
 
+  if (setup.soft_scrolling)
+    XCopyArea(display, fieldbuffer, backbuffer, gc,
+             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);
 
-  DrawText(DX + XX_LEVEL, DY + YY_LEVEL,
-          int2str(level_nr, 2), FS_SMALL, FC_YELLOW);
+  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,
+               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);
+  }
+
   DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
-          int2str(local_player->gems_still_needed,3), FS_SMALL, FC_YELLOW);
+          int2str(local_player->gems_still_needed, 3), FS_SMALL, FC_YELLOW);
   DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE,
           int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW);
   DrawText(DX + XX_SCORE, DY + YY_SCORE,
@@ -883,15 +897,16 @@ int NewHiScore()
 #ifdef ONE_PER_NAME
       put_into_list:
 #endif
-      strncpy(highscore[k].Name, setup.player_name, MAX_NAMELEN - 1);
-      highscore[k].Name[MAX_NAMELEN - 1] = '\0';
+      strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN);
+      highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0';
       highscore[k].Score = local_player->score; 
       position = k;
       break;
     }
 
 #ifdef ONE_PER_NAME
-    else if (!strncmp(setup.player_name, highscore[k].Name, MAX_NAMELEN - 1))
+    else if (!strncmp(setup.player_name, highscore[k].Name,
+                     MAX_PLAYER_NAME_LEN))
       break;   /* player already there with a higher score */
 #endif
 
@@ -1040,7 +1055,7 @@ void DrawDynamite(int x, int y)
   if (Store[x][y])
     DrawGraphic(sx, sy, el2gfx(Store[x][y]));
 
-  if (Feld[x][y] == EL_DYNAMIT)
+  if (Feld[x][y] == EL_DYNAMITE_ACTIVE)
   {
     if ((phase = (96 - MovDelay[x][y]) / 12) > 6)
       phase = 6;
@@ -1069,10 +1084,13 @@ void CheckDynamite(int x, int y)
       if (!(MovDelay[x][y] % 12))
        PlaySoundLevel(x, y, SND_ZISCH);
 
-      if (Feld[x][y] == EL_DYNAMIT && !(MovDelay[x][y] % 12))
-       DrawDynamite(x, y);
-      else if (Feld[x][y] == EL_DYNABOMB && !(MovDelay[x][y] % 6))
-       DrawDynamite(x, y);
+      if (IS_ACTIVE_BOMB(Feld[x][y]))
+      {
+       int delay = (Feld[x][y] == EL_DYNAMITE_ACTIVE ? 12 : 6);
+
+       if (!(MovDelay[x][y] % delay))
+         DrawDynamite(x, y);
+      }
 
       return;
     }
@@ -1096,13 +1114,22 @@ void Explode(int ex, int ey, int phase, int mode)
 
     if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
     {
+      /* put moving element to center field (and let it explode there) */
       center_element = MovingOrBlocked2Element(ex, ey);
       RemoveMovingField(ex, ey);
+      Feld[ex][ey] = center_element;
     }
 
-    for (y=ey-1; y<ey+2; y++) for(x=ex-1; x<ex+2; x++)
+    for (y=ey-1; y<=ey+1; y++) for(x=ex-1; x<=ex+1; x++)
     {
-      int element = Feld[x][y];
+      int element;
+
+      if (!IN_LEV_FIELD(x, y) ||
+         ((mode != EX_NORMAL || center_element == EL_AMOEBA2DIAM) &&
+          (x != ex || y != ey)))
+       continue;
+
+      element = Feld[x][y];
 
       if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
       {
@@ -1110,11 +1137,7 @@ void Explode(int ex, int ey, int phase, int mode)
        RemoveMovingField(x, y);
       }
 
-      if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(element) || element == EL_BURNING)
-       continue;
-
-      if ((mode!=EX_NORMAL || center_element == EL_AMOEBA2DIAM) &&
-         (x!=ex || y!=ey))
+      if (IS_MASSIVE(element) || element == EL_BURNING)
        continue;
 
       if (element == EL_EXPLODING)
@@ -1263,7 +1286,9 @@ void Explode(int ex, int ey, int phase, int mode)
 void DynaExplode(int ex, int ey)
 {
   int i, j;
-  struct PlayerInfo *player = &stored_player[Store2[ex][ey] - EL_SPIELER1];
+  int dynabomb_size = 1;
+  boolean dynabomb_xl = FALSE;
+  struct PlayerInfo *player;
   static int xy[4][2] =
   {
     { 0, -1 },
@@ -1272,33 +1297,42 @@ void DynaExplode(int ex, int ey)
     { 0, +1 }
   };
 
-  Store2[ex][ey] = 0;  /* delete player information */
+  if (IS_ACTIVE_BOMB(Feld[ex][ey]))
+  {
+    player = &stored_player[Feld[ex][ey] - EL_DYNABOMB_ACTIVE_1];
+    dynabomb_size = player->dynabomb_size;
+    dynabomb_xl = player->dynabomb_xl;
+    player->dynabombs_left++;
+  }
 
   Explode(ex, ey, EX_PHASE_START, EX_CENTER);
 
   for (i=0; i<4; i++)
   {
-    for (j=1; j<=player->dynabomb_size; j++)
+    for (j=1; j<=dynabomb_size; j++)
     {
-      int x = ex+j*xy[i%4][0];
-      int y = ey+j*xy[i%4][1];
+      int x = ex + j * xy[i % 4][0];
+      int y = ey + j * xy[i % 4][1];
       int element;
 
       if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(Feld[x][y]))
        break;
 
       element = Feld[x][y];
+
+      /* do not restart explosions of fields with active bombs */
+      if (element == EL_EXPLODING && IS_ACTIVE_BOMB(Store2[x][y]))
+       continue;
+
       Explode(x, y, EX_PHASE_START, EX_BORDER);
 
       if (element != EL_LEERRAUM &&
          element != EL_ERDREICH &&
          element != EL_EXPLODING &&
-         !player->dynabomb_xl)
+         !dynabomb_xl)
        break;
     }
   }
-
-  player->dynabombs_left++;
 }
 
 void Bang(int x, int y)
@@ -1326,7 +1360,10 @@ void Bang(int x, int y)
       RaiseScoreElement(element);
       Explode(x, y, EX_PHASE_START, EX_NORMAL);
       break;
-    case EL_DYNABOMB:
+    case EL_DYNABOMB_ACTIVE_1:
+    case EL_DYNABOMB_ACTIVE_2:
+    case EL_DYNABOMB_ACTIVE_3:
+    case EL_DYNABOMB_ACTIVE_4:
     case EL_DYNABOMB_NR:
     case EL_DYNABOMB_SZ:
     case EL_DYNABOMB_XL:
@@ -3565,7 +3602,7 @@ void GameActions()
     }
     else if (IS_MOVING(x, y))
       ContinueMoving(x, y);
-    else if (element == EL_DYNAMIT || element == EL_DYNABOMB)
+    else if (IS_ACTIVE_BOMB(element))
       CheckDynamite(x, y);
     else if (element == EL_EXPLODING)
       Explode(x, y, Frame[x][y], EX_NORMAL);
@@ -4371,11 +4408,11 @@ int DigField(struct PlayerInfo *player,
       PlaySoundLevel(x, y, SND_PONG);
       break;
 
-    case EL_DYNAMIT_AUS:
+    case EL_DYNAMITE_INACTIVE:
     case EL_SP_DISK_RED:
       RemoveField(x, y);
       player->dynamite++;
-      RaiseScoreElement(EL_DYNAMIT);
+      RaiseScoreElement(EL_DYNAMITE_INACTIVE);
       DrawText(DX_DYNAMITE, DY_DYNAMITE,
               int2str(local_player->dynamite, 3),
               FS_SMALL, FC_YELLOW);
@@ -4389,21 +4426,21 @@ int DigField(struct PlayerInfo *player,
       RemoveField(x, y);
       player->dynabomb_count++;
       player->dynabombs_left++;
-      RaiseScoreElement(EL_DYNAMIT);
+      RaiseScoreElement(EL_DYNAMITE_INACTIVE);
       PlaySoundLevel(x, y, SND_PONG);
       break;
 
     case EL_DYNABOMB_SZ:
       RemoveField(x, y);
       player->dynabomb_size++;
-      RaiseScoreElement(EL_DYNAMIT);
+      RaiseScoreElement(EL_DYNAMITE_INACTIVE);
       PlaySoundLevel(x, y, SND_PONG);
       break;
 
     case EL_DYNABOMB_XL:
       RemoveField(x, y);
       player->dynabomb_xl = TRUE;
-      RaiseScoreElement(EL_DYNAMIT);
+      RaiseScoreElement(EL_DYNAMITE_INACTIVE);
       PlaySoundLevel(x, y, SND_PONG);
       break;
 
@@ -4553,6 +4590,8 @@ int DigField(struct PlayerInfo *player,
       player->programmed_action = move_direction;
       DOUBLE_PLAYER_SPEED(player);
 
+      PlaySoundLevel(x, y, SND_GATE);
+
       break;
 
     case EL_EM_GATE_1X:
@@ -4568,6 +4607,8 @@ int DigField(struct PlayerInfo *player,
       player->programmed_action = move_direction;
       DOUBLE_PLAYER_SPEED(player);
 
+      PlaySoundLevel(x, y, SND_GATE);
+
       break;
 
     case EL_SP_PORT1_LEFT:
@@ -4609,6 +4650,8 @@ int DigField(struct PlayerInfo *player,
       player->programmed_action = move_direction;
       DOUBLE_PLAYER_SPEED(player);
 
+      PlaySoundLevel(x, y, SND_GATE);
+
       break;
 
     case EL_AUSGANG_ZU:
@@ -4780,8 +4823,7 @@ boolean PlaceBomb(struct PlayerInfo *player)
   element = Feld[jx][jy];
 
   if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
-      element == EL_DYNAMIT || element == EL_DYNABOMB ||
-      element == EL_EXPLODING)
+      IS_ACTIVE_BOMB(element) || element == EL_EXPLODING)
     return FALSE;
 
   if (element != EL_LEERRAUM)
@@ -4789,7 +4831,7 @@ boolean PlaceBomb(struct PlayerInfo *player)
 
   if (player->dynamite)
   {
-    Feld[jx][jy] = EL_DYNAMIT;
+    Feld[jx][jy] = EL_DYNAMITE_ACTIVE;
     MovDelay[jx][jy] = 96;
     player->dynamite--;
     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
@@ -4804,8 +4846,7 @@ boolean PlaceBomb(struct PlayerInfo *player)
   }
   else
   {
-    Feld[jx][jy] = EL_DYNABOMB;
-    Store2[jx][jy] = player->element_nr;       /* for DynaExplode() */
+    Feld[jx][jy] = EL_DYNABOMB_ACTIVE_1 + (player->element_nr - EL_SPIELER1);
     MovDelay[jx][jy] = 96;
     player->dynabombs_left--;
     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
@@ -4895,7 +4936,7 @@ void RaiseScoreElement(int element)
     case EL_KOKOSNUSS:
       RaiseScore(level.score[SC_KOKOSNUSS]);
       break;
-    case EL_DYNAMIT:
+    case EL_DYNAMITE_INACTIVE:
       RaiseScore(level.score[SC_DYNAMIT]);
       break;
     case EL_SCHLUESSEL: