rnd-20050103-1-src
[rocksndiamonds.git] / src / init.c
index 881a5c333b9812809a010a6c700db35e97b47b5f..e07ea102e26ee56ab13af0f8f23aa7edd36a7c28 100644 (file)
@@ -258,12 +258,19 @@ void InitElementSmallImages()
   for (i = 0; element_to_special_graphic[i].element > -1; i++)
     InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
 
-  /* initialize images from dynamic configuration */
+  /* initialize images from dynamic configuration (may be elements or other) */
+#if 1
+  for (i = 0; i < num_property_mappings; i++)
+    InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
+#else
+  /* !!! THIS DOES NOT WORK -- "artwork_index" is graphic, not element !!! */
+  /* !!! ALSO, non-element graphics might need scaling-up !!! */
   for (i = 0; i < num_property_mappings; i++)
     if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
       InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
+#endif
 
-#if 1
+#if 0
   /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
   for (i = IMG_EMC_OBJECT; i <= IMG_EMC_SPRITE; i++)
     InitElementSmallImagesScaledUp(i);
@@ -468,8 +475,10 @@ void InitElementGraphicInfo()
     if ((action > -1 || direction > -1 || crumbled == TRUE) &&
        base_graphic != -1)
     {
-      boolean base_redefined = getImageListEntry(base_graphic)->redefined;
-      boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
+      boolean base_redefined =
+       getImageListEntryFromImageID(base_graphic)->redefined;
+      boolean act_dir_redefined =
+       getImageListEntryFromImageID(graphic)->redefined;
 
       /* if the base graphic ("emerald", for example) has been redefined,
         but not the action graphic ("emerald.falling", for example), do not
@@ -615,6 +624,94 @@ void InitElementGraphicInfo()
   }
 #endif
 
+#if 1
+  /* adjust graphics with 2nd tile for movement according to direction
+     (do this before correcting '-1' values to minimize calculations) */
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    for (act = 0; act < NUM_ACTIONS; act++)
+    {
+      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
+      {
+       int graphic = element_info[i].direction_graphic[act][dir];
+       int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
+
+       if (act == ACTION_FALLING)      /* special case */
+         graphic = element_info[i].graphic[act];
+
+       if (graphic != -1 &&
+           graphic_info[graphic].double_movement &&
+           graphic_info[graphic].swap_double_tiles != 0)
+       {
+         struct GraphicInfo *g = &graphic_info[graphic];
+         int src_x_front = g->src_x;
+         int src_y_front = g->src_y;
+         int src_x_back = g->src_x + g->offset2_x;
+         int src_y_back = g->src_y + g->offset2_y;
+         boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
+                                                  g->offset_y != 0);
+         boolean front_is_left_or_upper = (src_x_front < src_x_back ||
+                                           src_y_front < src_y_back);
+#if 0
+         boolean second_tile_is_back =
+           ((move_dir == MV_BIT_LEFT  && front_is_left_or_upper) ||
+            (move_dir == MV_BIT_UP    && front_is_left_or_upper));
+         boolean second_tile_is_front =
+           ((move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
+            (move_dir == MV_BIT_DOWN  && front_is_left_or_upper));
+         boolean second_tile_should_be_front =
+           (g->second_tile_is_start == 0);
+         boolean second_tile_should_be_back =
+           (g->second_tile_is_start == 1);
+#endif
+         boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
+         boolean swap_movement_tiles_autodetected =
+           (!frames_are_ordered_diagonally &&
+            ((move_dir == MV_BIT_LEFT  && !front_is_left_or_upper) ||
+             (move_dir == MV_BIT_UP    && !front_is_left_or_upper) ||
+             (move_dir == MV_BIT_RIGHT &&  front_is_left_or_upper) ||
+             (move_dir == MV_BIT_DOWN  &&  front_is_left_or_upper)));
+         Bitmap *dummy;
+
+#if 0
+         printf("::: CHECKING element %d ('%s'), '%s', dir %d [(%d -> %d, %d), %d => %d]\n",
+                i, element_info[i].token_name,
+                element_action_info[act].suffix, move_dir,
+                g->swap_double_tiles,
+                swap_movement_tiles_never,
+                swap_movement_tiles_always,
+                swap_movement_tiles_autodetected,
+                swap_movement_tiles);
+#endif
+
+         /* swap frontside and backside graphic tile coordinates, if needed */
+         if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
+         {
+           /* get current (wrong) backside tile coordinates */
+           getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
+                               TRUE);
+
+           /* set frontside tile coordinates to backside tile coordinates */
+           g->src_x = src_x_back;
+           g->src_y = src_y_back;
+
+           /* invert tile offset to point to new backside tile coordinates */
+           g->offset2_x *= -1;
+           g->offset2_y *= -1;
+
+           /* do not swap front and backside tiles again after correction */
+           g->swap_double_tiles = 0;
+
+#if 0
+           printf("    CORRECTED\n");
+#endif
+         }
+       }
+      }
+    }
+  }
+#endif
+
   /* now set all '-1' values to element specific default values */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -625,8 +722,14 @@ void InitElementGraphicInfo()
 
     if (default_graphic == -1)
       default_graphic = IMG_UNKNOWN;
+#if 1
+    if (default_crumbled == -1)
+      default_crumbled = default_graphic;
+#else
+    /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
     if (default_crumbled == -1)
       default_crumbled = IMG_EMPTY;
+#endif
 
     for (dir = 0; dir < NUM_DIRECTIONS; dir++)
     {
@@ -637,8 +740,14 @@ void InitElementGraphicInfo()
 
       if (default_direction_graphic[dir] == -1)
        default_direction_graphic[dir] = default_graphic;
+#if 1
+      if (default_direction_crumbled[dir] == -1)
+       default_direction_crumbled[dir] = default_direction_graphic[dir];
+#else
+      /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
       if (default_direction_crumbled[dir] == -1)
        default_direction_crumbled[dir] = default_crumbled;
+#endif
     }
 
     for (act = 0; act < NUM_ACTIONS; act++)
@@ -654,6 +763,10 @@ void InitElementGraphicInfo()
       /* generic default action graphic (defined by "[default]" directive) */
       int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
       int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
+      int default_remove_graphic = IMG_EMPTY;
+
+      if (act_remove && default_action_graphic != -1)
+       default_remove_graphic = default_action_graphic;
 
       /* look for special default action graphic (classic game specific) */
       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
@@ -682,47 +795,81 @@ void InitElementGraphicInfo()
 
       if (default_action_graphic == -1)
        default_action_graphic = default_graphic;
+#if 1
+      if (default_action_crumbled == -1)
+       default_action_crumbled = default_action_graphic;
+#else
+      /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
       if (default_action_crumbled == -1)
        default_action_crumbled = default_crumbled;
+#endif
 
       for (dir = 0; dir < NUM_DIRECTIONS; dir++)
       {
+       /* use action graphic as the default direction graphic, if undefined */
        int default_action_direction_graphic = element_info[i].graphic[act];
        int default_action_direction_crumbled = element_info[i].crumbled[act];
 
        /* no graphic for current action -- use default direction graphic */
        if (default_action_direction_graphic == -1)
          default_action_direction_graphic =
-           (act_remove ? IMG_EMPTY :
+           (act_remove ? default_remove_graphic :
             act_turning ?
             element_info[i].direction_graphic[ACTION_TURNING][dir] :
+            default_action_graphic != default_graphic ?
+            default_action_graphic :
             default_direction_graphic[dir]);
+
+       if (element_info[i].direction_graphic[act][dir] == -1)
+         element_info[i].direction_graphic[act][dir] =
+           default_action_direction_graphic;
+
+#if 1
+       if (default_action_direction_crumbled == -1)
+         default_action_direction_crumbled =
+           element_info[i].direction_graphic[act][dir];
+#else
        if (default_action_direction_crumbled == -1)
          default_action_direction_crumbled =
-           (act_remove ? IMG_EMPTY :
+           (act_remove ? default_remove_graphic :
             act_turning ?
             element_info[i].direction_crumbled[ACTION_TURNING][dir] :
+            default_action_crumbled != default_crumbled ?
+            default_action_crumbled :
             default_direction_crumbled[dir]);
+#endif
 
-       if (element_info[i].direction_graphic[act][dir] == -1)
-         element_info[i].direction_graphic[act][dir] =
-           default_action_direction_graphic;
        if (element_info[i].direction_crumbled[act][dir] == -1)
          element_info[i].direction_crumbled[act][dir] =
            default_action_direction_crumbled;
+
+#if 0
+       if (i == EL_EMC_GRASS &&
+           act == ACTION_DIGGING &&
+           dir == MV_BIT_DOWN)
+         printf("::: direction_crumbled == %d, %d, %d\n",
+                element_info[i].direction_crumbled[act][dir],
+                default_action_direction_crumbled,
+                element_info[i].crumbled[act]);
+#endif
       }
 
       /* no graphic for this specific action -- use default action graphic */
       if (element_info[i].graphic[act] == -1)
        element_info[i].graphic[act] =
-         (act_remove ? IMG_EMPTY :
+         (act_remove ? default_remove_graphic :
           act_turning ? element_info[i].graphic[ACTION_TURNING] :
           default_action_graphic);
+#if 1
+      if (element_info[i].crumbled[act] == -1)
+       element_info[i].crumbled[act] = element_info[i].graphic[act];
+#else
       if (element_info[i].crumbled[act] == -1)
        element_info[i].crumbled[act] =
-         (act_remove ? IMG_EMPTY :
+         (act_remove ? default_remove_graphic :
           act_turning ? element_info[i].crumbled[ACTION_TURNING] :
           default_action_crumbled);
+#endif
     }
   }
 
@@ -787,8 +934,10 @@ void InitElementSpecialGraphicInfo()
     int special = element_to_special_graphic[i].special;
     int graphic = element_to_special_graphic[i].graphic;
     int base_graphic = el2baseimg(element);
-    boolean base_redefined = getImageListEntry(base_graphic)->redefined;
-    boolean special_redefined = getImageListEntry(graphic)->redefined;
+    boolean base_redefined =
+      getImageListEntryFromImageID(base_graphic)->redefined;
+    boolean special_redefined =
+      getImageListEntryFromImageID(graphic)->redefined;
 
     /* if the base graphic ("emerald", for example) has been redefined,
        but not the special graphic ("emerald.EDITOR", for example), do not
@@ -835,9 +984,27 @@ static int get_element_from_token(char *token)
   return -1;
 }
 
-static void set_graphic_parameters(int graphic, char **parameter_raw)
+static int get_scaled_graphic_width(int graphic)
+{
+  int original_width = getOriginalImageWidthFromImageID(graphic);
+  int scale_up_factor = graphic_info[graphic].scale_up_factor;
+
+  return original_width * scale_up_factor;
+}
+
+static int get_scaled_graphic_height(int graphic)
 {
-  Bitmap *src_bitmap = getBitmapFromImageID(graphic);
+  int original_height = getOriginalImageHeightFromImageID(graphic);
+  int scale_up_factor = graphic_info[graphic].scale_up_factor;
+
+  return original_height * scale_up_factor;
+}
+
+static void set_graphic_parameters(int graphic, int graphic_copy_from)
+{
+  struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
+  char **parameter_raw = image->parameter;
+  Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
   int parameter[NUM_GFX_ARGS];
   int anim_frames_per_row = 1, anim_frames_per_col = 1;
   int anim_frames_per_line = 1;
@@ -863,6 +1030,9 @@ static void set_graphic_parameters(int graphic, char **parameter_raw)
   graphic_info[graphic].height = TILEY;
   graphic_info[graphic].offset_x = 0;  /* one or both of these values ... */
   graphic_info[graphic].offset_y = 0;  /* ... will be corrected later */
+  graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
+  graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
+  graphic_info[graphic].swap_double_tiles = -1;        /* auto-detect tile swapping */
   graphic_info[graphic].crumbled_like = -1;    /* do not use clone element */
   graphic_info[graphic].diggable_like = -1;    /* do not use clone element */
   graphic_info[graphic].border_size = TILEX / 8;  /* "CRUMBLED" border size */
@@ -898,10 +1068,9 @@ static void set_graphic_parameters(int graphic, char **parameter_raw)
 
   if (src_bitmap)
   {
-    /* bitmap is not scaled at this stage, so calculate final size */
-    int scale_up_factor = graphic_info[graphic].scale_up_factor;
-    int src_bitmap_width  = src_bitmap->width  * scale_up_factor;
-    int src_bitmap_height = src_bitmap->height * scale_up_factor;
+    /* get final bitmap size (with scaling, but without small images) */
+    int src_bitmap_width  = get_scaled_graphic_width(graphic);
+    int src_bitmap_height = get_scaled_graphic_height(graphic);
 
     anim_frames_per_row = src_bitmap_width  / graphic_info[graphic].width;
     anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
@@ -929,6 +1098,32 @@ static void set_graphic_parameters(int graphic, char **parameter_raw)
   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
     graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
 
+  /* optionally, moving animations may have separate start and end graphics */
+  graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
+
+  if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
+    parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
+
+  /* correct x or y offset2 dependent of vertical or horizontal frame order */
+  if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
+    graphic_info[graphic].offset2_y =
+      (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
+       parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
+  else                                 /* frames are ordered horizontally */
+    graphic_info[graphic].offset2_x =
+      (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
+       parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
+
+  /* optionally, the x and y offset of 2nd graphic can be specified directly */
+  if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
+  if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
+
+  /* optionally, the second movement tile can be specified as start tile */
+  if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
+
   /* automatically determine correct number of frames, if not defined */
   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
     graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
@@ -1006,8 +1201,6 @@ static void set_graphic_parameters(int graphic, char **parameter_raw)
 static void InitGraphicInfo()
 {
   int fallback_graphic = IMG_CHAR_EXCLAM;
-  struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
-  Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
   int num_images = getImageListSize();
   int i;
 
@@ -1045,11 +1238,10 @@ static void InitGraphicInfo()
 
   for (i = 0; i < num_images; i++)
   {
-    struct FileInfo *image = getImageListEntry(i);
     Bitmap *src_bitmap;
     int src_x, src_y;
     int first_frame, last_frame;
-    int scale_up_factor, src_bitmap_width, src_bitmap_height;
+    int src_bitmap_width, src_bitmap_height;
 
 #if 0
     printf("::: image: '%s' [%d]\n", image->token, i);
@@ -1061,17 +1253,16 @@ static void InitGraphicInfo()
           getTokenFromImageID(i));
 #endif
 
-    set_graphic_parameters(i, image->parameter);
+    set_graphic_parameters(i, i);
 
     /* now check if no animation frames are outside of the loaded image */
 
     if (graphic_info[i].bitmap == NULL)
       continue;                /* skip check for optional images that are undefined */
 
-    /* bitmap is not scaled at this stage, so calculate final size */
-    scale_up_factor = graphic_info[i].scale_up_factor;
-    src_bitmap_width  = graphic_info[i].bitmap->width  * scale_up_factor;
-    src_bitmap_height = graphic_info[i].bitmap->height * scale_up_factor;
+    /* get final bitmap size (with scaling, but without small images) */
+    src_bitmap_width  = get_scaled_graphic_width(i);
+    src_bitmap_height = get_scaled_graphic_height(i);
 
     first_frame = 0;
     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
@@ -1092,7 +1283,7 @@ static void InitGraphicInfo()
            src_x, src_y);
       Error(ERR_RETURN, "custom graphic rejected for this element/action");
 
-#if 1
+#if 0
       Error(ERR_RETURN, "scale_up_factor == %d", scale_up_factor);
 #endif
 
@@ -1102,8 +1293,7 @@ static void InitGraphicInfo()
       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
       Error(ERR_RETURN_LINE, "-");
 
-      set_graphic_parameters(i, fallback_image->default_parameter);
-      graphic_info[i].bitmap = fallback_bitmap;
+      set_graphic_parameters(i, fallback_graphic);
     }
 
     last_frame = graphic_info[i].anim_frames - 1;
@@ -1131,12 +1321,11 @@ static void InitGraphicInfo()
       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
       Error(ERR_RETURN_LINE, "-");
 
-      set_graphic_parameters(i, fallback_image->default_parameter);
-      graphic_info[i].bitmap = fallback_bitmap;
+      set_graphic_parameters(i, fallback_graphic);
     }
 
 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
-    /* currently we need only a tile clip mask from the first frame */
+    /* currently we only need a tile clip mask from the first frame */
     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
 
     if (copy_clipmask_gc == None)
@@ -1610,6 +1799,8 @@ static void ReinitializeGraphics()
   InitElementSmallImages();            /* scale images to all needed sizes */
   InitFontGraphicInfo();               /* initialize text drawing functions */
 
+  InitGraphicInfo_EM();                        /* graphic mapping for EM engine */
+
   SetMainBackgroundImage(IMG_BACKGROUND);
   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
 
@@ -3678,8 +3869,15 @@ void InitElementPropertiesEngine(int engine_version)
        SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
 
     /* ---------- GFX_CRUMBLED --------------------------------------------- */
+#if 1
+    SET_PROPERTY(i, EP_GFX_CRUMBLED,
+                element_info[i].crumbled[ACTION_DEFAULT] !=
+                element_info[i].graphic[ACTION_DEFAULT]);
+#else
+    /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
     SET_PROPERTY(i, EP_GFX_CRUMBLED,
                 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
+#endif
   }
 
 #if 0