rnd-20030111-2-src
[rocksndiamonds.git] / src / tools.c
index 8ed62a521b36a2fbc2fefd7ceeadf38f710e9ae1..354f196c48797f47612d8157fa2650029fa848c5 100644 (file)
@@ -279,7 +279,7 @@ void BackToFront()
       info1[0] = '\0';
 
     sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
-    DrawTextExt(window, SX, SY, text, FS_SMALL, FC_YELLOW);
+    DrawTextExt(window, SX, SY, text, FS_SMALL, FC_YELLOW, FONT_OPAQUE);
   }
 
   FlushDisplay();
@@ -362,9 +362,32 @@ void FadeToFront()
   BackToFront();
 }
 
+void SetMainBackgroundImage(int graphic)
+{
+  SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
+                         new_graphic_info[graphic].bitmap ?
+                         new_graphic_info[graphic].bitmap :
+                         new_graphic_info[IMG_BACKGROUND_DEFAULT].bitmap);
+}
+
+void SetDoorBackgroundImage(int graphic)
+{
+  SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
+                         new_graphic_info[graphic].bitmap ?
+                         new_graphic_info[graphic].bitmap :
+                         new_graphic_info[IMG_BACKGROUND_DEFAULT].bitmap);
+}
+
+void DrawBackground(int dest_x, int dest_y, int width, int height)
+{
+  ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
+
+  redraw_mask |= REDRAW_FIELD;
+}
+
 void ClearWindow()
 {
-  ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+  DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
 
   if (setup.soft_scrolling && game_status == PLAYING)
   {
@@ -379,8 +402,37 @@ void ClearWindow()
     ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
     SetDrawtoField(DRAW_DIRECT);
   }
+}
 
-  redraw_mask |= REDRAW_FIELD;
+void MarkTileDirty(int x, int y)
+{
+  int xx = redraw_x1 + x;
+  int yy = redraw_y1 + y;
+
+  if (!redraw[xx][yy])
+    redraw_tiles++;
+
+  redraw[xx][yy] = TRUE;
+  redraw_mask |= REDRAW_TILES;
+}
+
+void SetBorderElement()
+{
+  int x, y;
+
+  BorderElement = EL_EMPTY;
+
+  for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
+  {
+    for(x=0; x<lev_fieldx; x++)
+    {
+      if (!IS_MASSIVE(Feld[x][y]))
+       BorderElement = EL_STEELWALL;
+
+      if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
+       x = lev_fieldx - 2;
+    }
+  }
 }
 
 static int getGraphicAnimationPhase(int frames, int delay, int mode)
@@ -416,35 +468,40 @@ inline int getGraphicAnimationFrame(int graphic, int sync_frame)
                           sync_frame);
 }
 
-void MarkTileDirty(int x, int y)
+inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
+                                   int graphic, int sync_frame, int mask_mode)
 {
-  int xx = redraw_x1 + x;
-  int yy = redraw_y1 + y;
+  int frame = getGraphicAnimationFrame(graphic, sync_frame);
 
-  if (!redraw[xx][yy])
-    redraw_tiles++;
-
-  redraw[xx][yy] = TRUE;
-  redraw_mask |= REDRAW_TILES;
+  if (mask_mode == USE_MASKING)
+    DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
+  else
+    DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
 }
 
-void SetBorderElement()
+inline boolean DrawGraphicAnimation(int x, int y, int graphic)
 {
-  int x, y;
+  int lx = LEVELX(x), ly = LEVELY(y);
 
-  BorderElement = EL_EMPTY;
+  if (!IN_SCR_FIELD(x, y) ||
+      (GfxFrame[lx][ly] % new_graphic_info[graphic].anim_delay) != 0)
+    return FALSE;
 
-  for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
-  {
-    for(x=0; x<lev_fieldx; x++)
-    {
-      if (!IS_MASSIVE(Feld[x][y]))
-       BorderElement = EL_STEELWALL;
+  DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
+                         graphic, GfxFrame[lx][ly], NO_MASKING);
+  MarkTileDirty(x, y);
 
-      if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
-       x = lev_fieldx - 2;
-    }
-  }
+  return TRUE;
+}
+
+boolean DrawLevelGraphicAnimation(int x, int y, int graphic)
+{
+  return DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
+}
+
+boolean DrawLevelElementAnimation(int x, int y, int element)
+{
+  return DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
 }
 
 void DrawAllPlayers()
@@ -657,9 +714,10 @@ void DrawPlayer(struct PlayerInfo *player)
   {
     int px = SCREENX(next_jx), py = SCREENY(next_jy);
 
-    if (element == EL_SOKOBAN_FIELD_EMPTY ||
-       Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
-      DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT, 0,
+    if ((sxx || syy) &&
+       (element == EL_SOKOBAN_FIELD_EMPTY ||
+        Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
+      DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
                                 NO_CUTTING);
     else
     {
@@ -669,9 +727,7 @@ void DrawPlayer(struct PlayerInfo *player)
       int frame = 0;
 #endif
 
-      if ((element == EL_ROCK ||
-          element == EL_BD_ROCK ||
-          element == EL_SP_ZONK) && sxx)
+      if ((sxx || syy) && IS_PUSHABLE(element))
       {
        graphic = el_dir_act2img(element, player->MovDir, GFX_ACTION_MOVING);
 #if 1
@@ -725,7 +781,7 @@ void DrawPlayer(struct PlayerInfo *player)
 #endif
 
     if (game.emulation == EMU_SUPAPLEX)
-      DrawGraphic(sx, sy, GFX_SP_DISK_RED, 0);
+      DrawGraphic(sx, sy, IMG_SP_DISK_RED, 0);
     else
       DrawGraphicThruMask(sx, sy, graphic, frame);
   }
@@ -737,7 +793,7 @@ void DrawPlayer(struct PlayerInfo *player)
                   stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
                   IMG_SP_EXPLOSION);
     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
-    int phase = Frame[last_jx][last_jy] - 1;
+    int phase = ExplodePhase[last_jx][last_jy] - 1;
     int frame = getGraphicAnimationFrame(graphic, phase - delay);
 
     if (phase >= delay)
@@ -768,25 +824,7 @@ void DrawPlayer(struct PlayerInfo *player)
   MarkTileDirty(sx,sy);
 }
 
-void DrawGraphicAnimationExt(int x, int y, int graphic, int mask_mode)
-{
-  if (IN_SCR_FIELD(x, y))
-  {
-    int frame = getGraphicAnimationFrame(graphic, -1);
-
-    if (mask_mode == USE_MASKING)
-      DrawGraphicThruMask(x, y, graphic, frame);
-    else
-      DrawGraphic(x, y, graphic, frame);
-  }
-}
-
-void DrawGraphicAnimation(int x, int y, int graphic)
-{
-  DrawGraphicAnimationExt(x, y, graphic, NO_MASKING);
-}
-
-#if 1
+#if 0
 void getOldGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
 {
   if (graphic >= 0 && graphic_info[graphic].bitmap != NULL)
@@ -875,7 +913,7 @@ void DrawGraphic(int x, int y, int graphic, int frame)
   MarkTileDirty(x, y);
 }
 
-#if 1
+#if 0
 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
 {
   Bitmap *src_bitmap;
@@ -965,6 +1003,17 @@ void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
   int src_x = mini_startx + new_graphic_info[graphic].src_x / 2;
   int src_y = mini_starty + new_graphic_info[graphic].src_y / 2;
 
+  if (src_x + MINI_TILEX > src_bitmap->width ||
+      src_y + MINI_TILEY > src_bitmap->height)
+  {
+    /* graphic of desired size seems not to be contained in this image;
+       dirty workaround: get it from the middle of the normal sized image */
+
+    getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
+    src_x += (TILEX / 2 - MINI_TILEX / 2);
+    src_y += (TILEY / 2 - MINI_TILEY / 2);
+  }
+
   *bitmap = src_bitmap;
   *x = src_x;
   *y = src_y;
@@ -1272,7 +1321,11 @@ inline static int getFramePosition(int x, int y)
   else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
     frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
 #else
+
   frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
+
+  frame_pos = GfxFrame[x][y];
+
 #endif
 
   return frame_pos;
@@ -1291,6 +1344,12 @@ inline static int getGfxAction(int x, int y)
   gfx_action = GfxAction[x][y];
 #endif
 
+#if DEBUG
+  if (gfx_action < 0)
+    printf("getGfxAction: THIS SHOULD NEVER HAPPEN: GfxAction[%d][%d] == %d\n",
+          x, y, gfx_action);
+#endif
+
   return gfx_action;
 }
 
@@ -1298,11 +1357,23 @@ void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
                          int cut_mode, int mask_mode)
 {
   int ux = LEVELX(x), uy = LEVELY(y);
-  int move_dir = MovDir[ux][uy];
-  int move_pos = getFramePosition(ux, uy);
-  int gfx_action = getGfxAction(ux, uy);
-  int graphic = el_dir_act2img(element, move_dir, gfx_action);
-  int frame = getGraphicAnimationFrame(graphic, move_pos);
+  int graphic;
+  int frame;
+
+  if (IN_LEV_FIELD(ux, uy))
+  {
+    int move_dir = MovDir[ux][uy];
+    int move_pos = getFramePosition(ux, uy);
+    int gfx_action = getGfxAction(ux, uy);
+
+    graphic = el_dir_act2img(element, move_dir, gfx_action);
+    frame = getGraphicAnimationFrame(graphic, move_pos);
+  }
+  else
+  {
+    graphic = el2img(element);
+    frame = getGraphicAnimationFrame(graphic, 0);
+  }
 
   if (element == EL_WALL_GROWING)
   {
@@ -1682,6 +1753,17 @@ void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
   int src_x = mini_startx + new_graphic_info[graphic].src_x / 8;
   int src_y = mini_starty + new_graphic_info[graphic].src_y / 8;
 
+  if (src_x + MICRO_TILEX > src_bitmap->width ||
+      src_y + MICRO_TILEY > src_bitmap->height)
+  {
+    /* graphic of desired size seems not to be contained in this image;
+       dirty workaround: get it from the middle of the normal sized image */
+
+    getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
+    src_x += (TILEX / 2 - MICRO_TILEX / 2);
+    src_y += (TILEY / 2 - MICRO_TILEY / 2);
+  }
+
   *bitmap = src_bitmap;
   *x = src_x;
   *y = src_y;
@@ -1691,12 +1773,7 @@ void DrawMicroElement(int xpos, int ypos, int element)
 {
   Bitmap *src_bitmap;
   int src_x, src_y;
-  int graphic;
-
-  if (element == EL_EMPTY)
-    return;
-
-  graphic = el2img(element);
+  int graphic = el2img(element);
 
   getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
   BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
@@ -1707,6 +1784,7 @@ void DrawLevel()
 {
   int x,y;
 
+  SetDrawBackgroundMask(REDRAW_NONE);
   ClearWindow();
 
   for(x=BX1; x<=BX2; x++)
@@ -1731,7 +1809,7 @@ static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
 {
   int x, y;
 
-  ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
+  DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
 
   if (lev_fieldx < STD_LEV_FIELDX)
     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
@@ -1750,7 +1828,8 @@ static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
        DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
                         Ur[lx][ly]);
-      else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
+      else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
+              && BorderElement != EL_EMPTY)
        DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
                         BorderElement);
     }
@@ -1772,7 +1851,7 @@ static void DrawMicroLevelLabelExt(int mode)
 {
   char label_text[MAX_MICROLABEL_SIZE + 1];
 
-  ClearRectangle(drawto, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
+  DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
 
   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
                       mode == MICROLABEL_CREATED_BY ? "created by" :
@@ -1924,8 +2003,10 @@ boolean Request(char *text, unsigned int req_state)
             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
 
+  SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
+
   /* clear door drawing field */
-  ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
+  DrawBackground(DX, DY, DXSIZE, DYSIZE);
 
   /* write text for request */
   for(ty=0; ty < MAX_REQUEST_LINES; ty++)
@@ -1953,8 +2034,8 @@ boolean Request(char *text, unsigned int req_state)
     strncpy(text_line, text, tl);
     text_line[tl] = 0;
 
-    DrawTextExt(drawto, DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
-               text_line, FS_SMALL, FC_YELLOW);
+    DrawText(DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
+            text_line, FS_SMALL, FC_YELLOW);
 
     text += tl + (tc == ' ' ? 1 : 0);
   }
@@ -1988,7 +2069,11 @@ boolean Request(char *text, unsigned int req_state)
 #endif
 
   if (!(req_state & REQUEST_WAIT_FOR))
-    return(FALSE);
+  {
+    SetDrawBackgroundMask(REDRAW_FIELD);
+
+    return FALSE;
+  }
 
   if (game_status != MAINMENU)
     InitAnimation();
@@ -1997,6 +2082,8 @@ boolean Request(char *text, unsigned int req_state)
 
   request_gadget_id = -1;
 
+  SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
+
   while(result < 0)
   {
     if (PendingEvent())
@@ -2132,6 +2219,8 @@ boolean Request(char *text, unsigned int req_state)
 
   RemapAllGadgets();
 
+  SetDrawBackgroundMask(REDRAW_FIELD);
+
 #if defined(PLATFORM_UNIX)
   /* continue network game after request */
   if (options.network &&
@@ -2140,7 +2229,7 @@ boolean Request(char *text, unsigned int req_state)
     SendToServer_ContinuePlaying();
 #endif
 
-  return(result);
+  return result;
 }
 
 unsigned int OpenDoor(unsigned int door_state)
@@ -2218,10 +2307,17 @@ unsigned int MoveDoor(unsigned int door_state)
   {
     stepsize = 20;
     door_delay_value = 0;
+
     StopSound(SND_MENU_DOOR_OPENING);
     StopSound(SND_MENU_DOOR_CLOSING);
   }
 
+  if (global.autoplay_leveldir)
+  {
+    door_state |= DOOR_NO_DELAY;
+    door_state &= ~DOOR_CLOSE_ALL;
+  }
+
   if (door_state & DOOR_ACTION)
   {
     if (!(door_state & DOOR_NO_DELAY))
@@ -2237,10 +2333,11 @@ unsigned int MoveDoor(unsigned int door_state)
 
     for(x=start; x<=DXSIZE; x+=stepsize)
     {
-      Bitmap *bitmap = new_graphic_info[IMG_MENU_DOOR].bitmap;
+      Bitmap *bitmap = new_graphic_info[IMG_GLOBAL_DOOR].bitmap;
       GC gc = bitmap->stored_clip_gc;
 
-      WaitUntilDelayReached(&door_delay, door_delay_value);
+      if (!(door_state & DOOR_NO_DELAY))
+       WaitUntilDelayReached(&door_delay, door_delay_value);
 
       if (door_state & DOOR_ACTION_1)
       {
@@ -2342,8 +2439,12 @@ unsigned int MoveDoor(unsigned int door_state)
 void DrawSpecialEditorDoor()
 {
   /* draw bigger toolbox window */
-  BlitBitmap(new_graphic_info[IMG_MENU_DOOR].bitmap, drawto,
-            DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
+  BlitBitmap(new_graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
+            DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
+            EX - 4, EY - 12);
+  BlitBitmap(new_graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
+            EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
+            EX - 4, EY - 4);
 
   redraw_mask |= REDRAW_ALL;
 }
@@ -2351,8 +2452,9 @@ void DrawSpecialEditorDoor()
 void UndrawSpecialEditorDoor()
 {
   /* draw normal tape recorder window */
-  BlitBitmap(new_graphic_info[IMG_MENU_BACK].bitmap, drawto,
-            562, 344, 108, 56, EX - 4, EY - 12);
+  BlitBitmap(new_graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
+            EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
+            EX - 4, EY - 12);
 
   redraw_mask |= REDRAW_ALL;
 }
@@ -2480,7 +2582,7 @@ void CreateToolButtons()
 
   for (i=0; i<NUM_TOOL_BUTTONS; i++)
   {
-    Bitmap *gd_bitmap = new_graphic_info[IMG_MENU_DOOR].bitmap;
+    Bitmap *gd_bitmap = new_graphic_info[IMG_GLOBAL_DOOR].bitmap;
     Bitmap *deco_bitmap = None;
     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
     struct GadgetInfo *gi;
@@ -2532,6 +2634,14 @@ void CreateToolButtons()
   }
 }
 
+void FreeToolButtons()
+{
+  int i;
+
+  for (i=0; i<NUM_TOOL_BUTTONS; i++)
+    FreeGadget(tool_gadget[i]);
+}
+
 static void UnmapToolButtons()
 {
   int i;
@@ -2869,9 +2979,9 @@ int el2gfx(int element)
 #if DEBUG
   int graphic_OLD = el2gfx_OLD(element);
 
-  if (element >= MAX_ELEMENTS)
+  if (element >= MAX_NUM_ELEMENTS)
   {
-    Error(ERR_WARN, "el2gfx: element == %d >= MAX_ELEMENTS", element);
+    Error(ERR_WARN, "el2gfx: element == %d >= MAX_NUM_ELEMENTS", element);
   }
 
   if (graphic_NEW != graphic_OLD)
@@ -2905,6 +3015,24 @@ int el_dir2img(int element, int direction)
 
 int el_dir_act2img(int element, int direction, int action)
 {
+#if DEBUG
+  if (element < 0)
+  {    
+    printf("el_dir_act2img: THIS SHOULD NEVER HAPPEN: element == %d\n",
+          element);
+
+    return IMG_EMPTY;
+  }
+
+  if (action < 0)
+  {    
+    printf("el_dir_act2img: THIS SHOULD NEVER HAPPEN: action == %d\n",
+          action);
+
+    return IMG_EMPTY;
+  }
+#endif
+
   action = graphics_action_mapping[action];
   direction = MV_DIR_BIT(direction);