rnd-20070220-1-src
[rocksndiamonds.git] / src / tools.c
index ddc8353b5c9da4a33b9d0caa3d3911f3690ac87d..62965af09d2df0e90ce0f15107f6e4c2d9453fe6 100644 (file)
@@ -19,6 +19,7 @@
 #include "cartoons.h"
 #include "network.h"
 #include "tape.h"
+#include "screens.h"
 
 
 /* select level set with EMC X11 graphics before activating EM GFX debugging */
@@ -240,6 +241,11 @@ void DrawMaskedBorder_ALL()
 
 void DrawMaskedBorder(int redraw_mask)
 {
+  /* do not draw masked screen borders when displaying title screens */
+  if (effectiveGameStatus() == GAME_MODE_TITLE ||
+      effectiveGameStatus() == GAME_MODE_MESSAGE)
+    return;
+
   if (redraw_mask & REDRAW_ALL)
     DrawMaskedBorder_ALL();
   else
@@ -274,7 +280,7 @@ void BackToFront()
 
   if (redraw_mask & REDRAW_TILES &&
       game_status == GAME_MODE_PLAYING &&
-      border.draw_masked[game_status])
+      border.draw_masked[GAME_MODE_PLAYING])
     redraw_mask |= REDRAW_FIELD;
 
   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
@@ -314,15 +320,16 @@ void BackToFront()
 
   SyncDisplay();
 
-#if 1
-  DrawMaskedBorder(redraw_mask);
-#endif
+  /* prevent drawing masked border to backbuffer when using playfield buffer */
+  if (game_status != GAME_MODE_PLAYING ||
+      redraw_mask & REDRAW_FROM_BACKBUFFER ||
+      buffer == backbuffer)
+    DrawMaskedBorder(redraw_mask);
+  else
+    DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
 
   if (redraw_mask & REDRAW_ALL)
   {
-#if 0
-    DrawMaskedBorder(REDRAW_ALL);
-#endif
     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 
     redraw_mask = REDRAW_NONE;
@@ -333,9 +340,6 @@ void BackToFront()
     if (game_status != GAME_MODE_PLAYING ||
        redraw_mask & REDRAW_FROM_BACKBUFFER)
     {
-#if 0
-      DrawMaskedBorder(REDRAW_FIELD);
-#endif
       BlitBitmap(backbuffer, window,
                 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
     }
@@ -354,21 +358,23 @@ void BackToFront()
          ABS(ScreenMovPos) == ScrollStepSize ||
          redraw_tiles > REDRAWTILES_THRESHOLD)
       {
-#if 1
-       if (border.draw_masked[GFX_SPECIAL_ARG_MAIN])
+       if (border.draw_masked[GAME_MODE_PLAYING])
        {
-         BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
+         if (buffer != backbuffer)
+         {
+           /* copy playfield buffer to backbuffer to add masked border */
+           BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
+           DrawMaskedBorder(REDRAW_FIELD);
+         }
 
-         DrawMaskedBorder(REDRAW_FIELD);
          BlitBitmap(backbuffer, window,
                     REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
                     REAL_SX, REAL_SY);
        }
        else
+       {
          BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
-#else
-       BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
-#endif
+       }
 
 #if 0
 #ifdef DEBUG
@@ -392,28 +398,13 @@ void BackToFront()
   if (redraw_mask & REDRAW_DOORS)
   {
     if (redraw_mask & REDRAW_DOOR_1)
-    {
-#if 0
-      DrawMaskedBorder(REDRAW_DOOR_1);
-#endif
       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
-    }
 
     if (redraw_mask & REDRAW_DOOR_2)
-    {
-#if 0
-      DrawMaskedBorder(REDRAW_DOOR_2);
-#endif
       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
-    }
 
     if (redraw_mask & REDRAW_DOOR_3)
-    {
-#if 0
-      DrawMaskedBorder(REDRAW_DOOR_3);
-#endif
       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
-    }
 
     redraw_mask &= ~REDRAW_DOORS;
   }
@@ -597,10 +588,30 @@ void FadeCrossSaveBackbuffer()
   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 }
 
+void SetWindowBackgroundImageIfDefined(int graphic)
+{
+  if (graphic_info[graphic].bitmap)
+    SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
+}
+
 void SetMainBackgroundImageIfDefined(int graphic)
 {
   if (graphic_info[graphic].bitmap)
-    SetMainBackgroundImage(graphic);
+    SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
+}
+
+void SetDoorBackgroundImageIfDefined(int graphic)
+{
+  if (graphic_info[graphic].bitmap)
+    SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
+}
+
+void SetWindowBackgroundImage(int graphic)
+{
+  SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
+                           graphic_info[graphic].bitmap ?
+                           graphic_info[graphic].bitmap :
+                           graphic_info[IMG_BACKGROUND].bitmap);
 }
 
 void SetMainBackgroundImage(int graphic)
@@ -713,6 +724,39 @@ void SetBorderElement()
   }
 }
 
+void FloodFillLevel(int from_x, int from_y, int fill_element,
+                   short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
+                   int max_fieldx, int max_fieldy)
+{
+  int i,x,y;
+  int old_element;
+  static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
+  static int safety = 0;
+
+  /* check if starting field still has the desired content */
+  if (field[from_x][from_y] == fill_element)
+    return;
+
+  safety++;
+
+  if (safety > max_fieldx * max_fieldy)
+    Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
+
+  old_element = field[from_x][from_y];
+  field[from_x][from_y] = fill_element;
+
+  for (i = 0; i < 4; i++)
+  {
+    x = from_x + check[i][0];
+    y = from_y + check[i][1];
+
+    if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
+      FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
+  }
+
+  safety--;
+}
+
 void SetRandomAnimationValue(int x, int y)
 {
   gfx.anim_random_frame = GfxRandom[x][y];
@@ -1380,13 +1424,17 @@ void DrawScreenField(int x, int y)
     boolean cut_mode = NO_CUTTING;
 
     if (element == EL_QUICKSAND_EMPTYING ||
+       element == EL_QUICKSAND_FAST_EMPTYING ||
        element == EL_MAGIC_WALL_EMPTYING ||
        element == EL_BD_MAGIC_WALL_EMPTYING ||
+       element == EL_DC_MAGIC_WALL_EMPTYING ||
        element == EL_AMOEBA_DROPPING)
       cut_mode = CUT_ABOVE;
     else if (element == EL_QUICKSAND_FILLING ||
+            element == EL_QUICKSAND_FAST_FILLING ||
             element == EL_MAGIC_WALL_FILLING ||
-            element == EL_BD_MAGIC_WALL_FILLING)
+            element == EL_BD_MAGIC_WALL_FILLING ||
+            element == EL_DC_MAGIC_WALL_FILLING)
       cut_mode = CUT_BELOW;
 
     if (cut_mode == CUT_ABOVE)
@@ -1428,8 +1476,10 @@ void DrawScreenField(int x, int y)
     content_old = Store[oldx][oldy];
 
     if (element_old == EL_QUICKSAND_EMPTYING ||
+       element_old == EL_QUICKSAND_FAST_EMPTYING ||
        element_old == EL_MAGIC_WALL_EMPTYING ||
        element_old == EL_BD_MAGIC_WALL_EMPTYING ||
+       element_old == EL_DC_MAGIC_WALL_EMPTYING ||
        element_old == EL_AMOEBA_DROPPING)
       cut_mode = CUT_ABOVE;
 
@@ -1576,9 +1626,17 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
     for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
       DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
 
+#if 1
+    DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
+                  level.envelope[envelope_nr].text, font_nr, max_xsize,
+                  xsize - 2, ysize - 2, mask_mode,
+                  level.envelope[envelope_nr].autowrap,
+                  level.envelope[envelope_nr].centered, FALSE);
+#else
     DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
                       level.envelope[envelope_nr].text, font_nr, max_xsize,
                       xsize - 2, ysize - 2, mask_mode);
+#endif
 
     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
     BackToFront();
@@ -1742,7 +1800,7 @@ static void DrawPreviewLevelExt(int from_x, int from_y)
 #define MICROLABEL_IMPORTED_BY_HEAD    6
 #define MICROLABEL_IMPORTED_BY         7
 
-static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
+static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
 {
   int max_text_width = SXSIZE;
   int font_width = getFontWidth(font_nr);
@@ -1759,7 +1817,7 @@ static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
 
 static void DrawPreviewLevelLabelExt(int mode)
 {
-  struct MenuPosInfo *pos = &menu.main.text.level_info_2;
+  struct TextPosInfo *pos = &menu.main.text.level_info_2;
   char label_text[MAX_OUTPUT_LINESIZE + 1];
   int max_len_label_text;
   int font_nr = FONT_TEXT_2;
@@ -1776,6 +1834,11 @@ static void DrawPreviewLevelLabelExt(int mode)
   max_len_label_text = SXSIZE / getFontWidth(font_nr);
 #endif
 
+#if 1
+  if (pos->chars != -1)
+    max_len_label_text = pos->chars;
+#endif
+
   for (i = 0; i < max_len_label_text; i++)
     label_text[i] = ' ';
   label_text[max_len_label_text] = '\0';
@@ -1862,7 +1925,7 @@ void DrawPreviewLevel(boolean restart)
 
     if (leveldir_current->name)
     {
-      struct MenuPosInfo *pos = &menu.main.text.level_info_1;
+      struct TextPosInfo *pos = &menu.main.text.level_info_1;
       char label_text[MAX_OUTPUT_LINESIZE + 1];
       int font_nr = FONT_TEXT_1;
 #if 1
@@ -1875,6 +1938,11 @@ void DrawPreviewLevel(boolean restart)
       int lxpos, lypos;
 #endif
 
+#if 1
+      if (pos->chars != -1)
+       max_len_label_text = pos->chars;
+#endif
+
       strncpy(label_text, leveldir_current->name, max_len_label_text);
       label_text[max_len_label_text] = '\0';
 
@@ -2487,7 +2555,11 @@ boolean Request(char *text, unsigned int req_state)
     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
     {
       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
+#if 1
+      font_nr = FONT_TEXT_1;
+#else
       font_nr = FONT_LEVEL_NUMBER;
+#endif
 
       break;
     }
@@ -2733,6 +2805,23 @@ boolean Request(char *text, unsigned int req_state)
        result = 0;
     }
 
+#if 1
+
+    if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
+    {
+      HandleGameActions();
+      BackToFront();
+    }
+    else
+    {
+      DoAnimation();
+
+      if (!PendingEvent())     /* delay only if no pending events */
+       Delay(10);
+    }
+
+#else
+
     DoAnimation();
 
 #if 1
@@ -2741,6 +2830,8 @@ boolean Request(char *text, unsigned int req_state)
 #else
     /* don't eat all CPU time */
     Delay(10);
+#endif
+
 #endif
   }
 
@@ -4454,19 +4545,19 @@ em_object_mapping_list[] =
   },
   {
     Xexit,                             TRUE,   FALSE,
-    EL_EXIT_CLOSED,                    -1, -1
+    EL_EM_EXIT_CLOSED,                 -1, -1
   },
   {
     Xexit_1,                           TRUE,   FALSE,
-    EL_EXIT_OPEN,                      -1, -1
+    EL_EM_EXIT_OPEN,                   -1, -1
   },
   {
     Xexit_2,                           FALSE,  FALSE,
-    EL_EXIT_OPEN,                      -1, -1
+    EL_EM_EXIT_OPEN,                   -1, -1
   },
   {
     Xexit_3,                           FALSE,  FALSE,
-    EL_EXIT_OPEN,                      -1, -1
+    EL_EM_EXIT_OPEN,                   -1, -1
   },
   {
     Xdynamite,                         TRUE,   FALSE,
@@ -5375,10 +5466,14 @@ int get_next_element(int element)
   {
     case EL_QUICKSAND_FILLING:         return EL_QUICKSAND_FULL;
     case EL_QUICKSAND_EMPTYING:                return EL_QUICKSAND_EMPTY;
+    case EL_QUICKSAND_FAST_FILLING:    return EL_QUICKSAND_FAST_FULL;
+    case EL_QUICKSAND_FAST_EMPTYING:   return EL_QUICKSAND_FAST_EMPTY;
     case EL_MAGIC_WALL_FILLING:                return EL_MAGIC_WALL_FULL;
     case EL_MAGIC_WALL_EMPTYING:       return EL_MAGIC_WALL_ACTIVE;
     case EL_BD_MAGIC_WALL_FILLING:     return EL_BD_MAGIC_WALL_FULL;
     case EL_BD_MAGIC_WALL_EMPTYING:    return EL_BD_MAGIC_WALL_ACTIVE;
+    case EL_DC_MAGIC_WALL_FILLING:     return EL_DC_MAGIC_WALL_FULL;
+    case EL_DC_MAGIC_WALL_EMPTYING:    return EL_DC_MAGIC_WALL_ACTIVE;
     case EL_AMOEBA_DROPPING:           return EL_AMOEBA_WET;
 
     default:                           return element;
@@ -5483,6 +5578,115 @@ int font2baseimg(int font_nr)
   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
 }
 
+int getBeltNrFromBeltElement(int element)
+{
+  return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
+         element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
+         element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
+}
+
+int getBeltNrFromBeltActiveElement(int element)
+{
+  return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
+         element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
+         element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
+}
+
+int getBeltNrFromBeltSwitchElement(int element)
+{
+  return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
+         element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
+         element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
+}
+
+int getBeltDirNrFromBeltElement(int element)
+{
+  static int belt_base_element[4] =
+  {
+    EL_CONVEYOR_BELT_1_LEFT,
+    EL_CONVEYOR_BELT_2_LEFT,
+    EL_CONVEYOR_BELT_3_LEFT,
+    EL_CONVEYOR_BELT_4_LEFT
+  };
+
+  int belt_nr = getBeltNrFromBeltElement(element);
+  int belt_dir_nr = element - belt_base_element[belt_nr];
+
+  return (belt_dir_nr % 3);
+}
+
+int getBeltDirNrFromBeltSwitchElement(int element)
+{
+  static int belt_base_element[4] =
+  {
+    EL_CONVEYOR_BELT_1_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_2_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_3_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_4_SWITCH_LEFT
+  };
+
+  int belt_nr = getBeltNrFromBeltSwitchElement(element);
+  int belt_dir_nr = element - belt_base_element[belt_nr];
+
+  return (belt_dir_nr % 3);
+}
+
+int getBeltDirFromBeltElement(int element)
+{
+  static int belt_move_dir[3] =
+  {
+    MV_LEFT,
+    MV_NONE,
+    MV_RIGHT
+  };
+
+  int belt_dir_nr = getBeltDirNrFromBeltElement(element);
+
+  return belt_move_dir[belt_dir_nr];
+}
+
+int getBeltDirFromBeltSwitchElement(int element)
+{
+  static int belt_move_dir[3] =
+  {
+    MV_LEFT,
+    MV_NONE,
+    MV_RIGHT
+  };
+
+  int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
+
+  return belt_move_dir[belt_dir_nr];
+}
+
+int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
+{
+  static int belt_base_element[4] =
+  {
+    EL_CONVEYOR_BELT_1_LEFT,
+    EL_CONVEYOR_BELT_2_LEFT,
+    EL_CONVEYOR_BELT_3_LEFT,
+    EL_CONVEYOR_BELT_4_LEFT
+  };
+  int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
+
+  return belt_base_element[belt_nr] + belt_dir_nr;
+}
+
+int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
+{
+  static int belt_base_element[4] =
+  {
+    EL_CONVEYOR_BELT_1_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_2_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_3_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_4_SWITCH_LEFT
+  };
+  int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
+
+  return belt_base_element[belt_nr] + belt_dir_nr;
+}
+
 int getNumActivePlayers_EM()
 {
   int num_players = 0;
@@ -6196,9 +6400,26 @@ void PlayMenuMusic()
   if (music == MUS_UNDEFINED)
     return;
 
+  if (!setup.sound_music)
+    return;
+
   PlayMusic(music);
 }
 
+void PlaySoundActivating()
+{
+#if 0
+  PlaySound(SND_MENU_ITEM_ACTIVATING);
+#endif
+}
+
+void PlaySoundSelecting()
+{
+#if 0
+  PlaySound(SND_MENU_ITEM_SELECTING);
+#endif
+}
+
 void ToggleFullscreenIfNeeded()
 {
   boolean change_fullscreen = (setup.fullscreen !=