+#endif
+
+#if 0
+#if DEBUG
+ if (options.verbose)
+ {
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
+ i != EL_UNKNOWN)
+ Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
+ element_info[i].token_name, i);
+ }
+#endif
+#endif
+}
+
+void InitElementSpecialGraphicInfo()
+{
+ struct PropertyMapping *property_mapping = getImageListPropertyMapping();
+ int num_property_mappings = getImageListPropertyMappingSize();
+ int i, j;
+
+ /* always start with reliable default values */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
+ element_info[i].special_graphic[j] =
+ element_info[i].graphic[ACTION_DEFAULT];
+
+ /* initialize special element/graphic mapping from static configuration */
+ for (i = 0; element_to_special_graphic[i].element > -1; i++)
+ {
+ int element = element_to_special_graphic[i].element;
+ int special = element_to_special_graphic[i].special;
+ int graphic = element_to_special_graphic[i].graphic;
+ int base_graphic = el2baseimg(element);
+ boolean base_redefined =
+ getImageListEntryFromImageID(base_graphic)->redefined;
+ boolean special_redefined =
+ getImageListEntryFromImageID(graphic)->redefined;
+
+#if 0
+ if ((element == EL_EM_DYNAMITE ||
+ element == EL_EM_DYNAMITE_ACTIVE) &&
+ (special == GFX_SPECIAL_ARG_EDITOR ||
+ special == GFX_SPECIAL_ARG_PANEL))
+ printf("::: SPECIAL STATIC: %d, %d -> %d\n",
+ element, special, graphic);
+#endif
+
+ /* if the base graphic ("emerald", for example) has been redefined,
+ but not the special graphic ("emerald.EDITOR", for example), do not
+ use an existing (in this case considered obsolete) special graphic
+ anymore, but use the automatically created (down-scaled) graphic */
+ if (base_redefined && !special_redefined)
+ continue;
+
+ element_info[element].special_graphic[special] = graphic;
+ }
+
+ /* initialize special element/graphic mapping from dynamic configuration */
+ for (i = 0; i < num_property_mappings; i++)
+ {
+ int element = property_mapping[i].base_index;
+ int action = property_mapping[i].ext1_index;
+ int direction = property_mapping[i].ext2_index;
+ int special = property_mapping[i].ext3_index;
+ int graphic = property_mapping[i].artwork_index;
+
+#if 0
+ if ((element == EL_EM_DYNAMITE ||
+ element == EL_EM_DYNAMITE_ACTIVE ||
+ element == EL_CONVEYOR_BELT_1_MIDDLE ||
+ element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
+ (special == GFX_SPECIAL_ARG_EDITOR ||
+ special == GFX_SPECIAL_ARG_PANEL))
+ printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
+ element, special, graphic, property_mapping[i].ext1_index);
+#endif
+
+#if 0
+ if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
+ action == ACTION_ACTIVE)
+ {
+ element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
+ action = -1;
+ }
+#endif
+
+#if 0
+ if (element == EL_MAGIC_WALL &&
+ action == ACTION_ACTIVE)
+ {
+ element = EL_MAGIC_WALL_ACTIVE;
+ action = -1;
+ }
+#endif
+
+#if 1
+ /* for action ".active", replace element with active element, if exists */
+ if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
+ {
+ element = ELEMENT_ACTIVE(element);
+ action = -1;
+ }
+#endif
+
+ if (element >= MAX_NUM_ELEMENTS)
+ continue;
+
+ /* do not change special graphic if action or direction was specified */
+ if (action != -1 || direction != -1)
+ continue;
+
+ if (IS_SPECIAL_GFX_ARG(special))
+ element_info[element].special_graphic[special] = graphic;
+ }
+
+ /* now set all undefined/invalid graphics to default */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
+ if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
+ element_info[i].special_graphic[j] =
+ element_info[i].graphic[ACTION_DEFAULT];
+}
+
+static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
+{
+ if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
+ return get_parameter_value(value_raw, suffix, type);
+
+ if (strEqual(value_raw, ARG_UNDEFINED))
+ return ARG_UNDEFINED_VALUE;
+
+#if 1
+ if (type == TYPE_ELEMENT)
+ {
+ char *value = getHashEntry(element_token_hash, value_raw);
+
+ return (value != NULL ? atoi(value) : EL_UNDEFINED);
+ }
+ else if (type == TYPE_GRAPHIC)
+ {
+ char *value = getHashEntry(graphic_token_hash, value_raw);
+
+ return (value != NULL ? atoi(value) : IMG_UNDEFINED);
+ }
+
+#else
+
+ int i;
+ int x = 0;
+
+ /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
+ /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
+
+ /* !!! OPTIMIZE THIS BY USING HASH !!! */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ if (strEqual(element_info[i].token_name, value_raw))
+ return i;
+
+ /* !!! OPTIMIZE THIS BY USING HASH !!! */
+ for (i = 0; image_config[i].token != NULL; i++)
+ {
+ int len_config_value = strlen(image_config[i].value);
+
+ if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
+ !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
+ !strEqual(image_config[i].value, UNDEFINED_FILENAME))
+ continue;
+
+ if (strEqual(image_config[i].token, value_raw))
+ return x;
+
+ x++;
+ }
+#endif
+
+ return -1;
+}
+
+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)
+{
+ 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_ext(int graphic, int *parameter,
+ Bitmap *src_bitmap)
+{
+ struct GraphicInfo *g = &graphic_info[graphic];
+ int anim_frames_per_row = 1, anim_frames_per_col = 1;
+ int anim_frames_per_line = 1;
+
+ /* always start with reliable default values */
+ g->src_image_width = 0;
+ g->src_image_height = 0;
+ g->src_x = 0;
+ g->src_y = 0;
+ g->width = TILEX; /* default for element graphics */
+ g->height = TILEY; /* default for element graphics */
+ g->offset_x = 0; /* one or both of these values ... */
+ g->offset_y = 0; /* ... will be corrected later */
+ g->offset2_x = 0; /* one or both of these values ... */
+ g->offset2_y = 0; /* ... will be corrected later */
+ g->swap_double_tiles = -1; /* auto-detect tile swapping */
+ g->crumbled_like = -1; /* do not use clone element */
+ g->diggable_like = -1; /* do not use clone element */
+ g->border_size = TILEX / 8; /* "CRUMBLED" border size */
+ g->scale_up_factor = 1; /* default: no scaling up */
+ g->clone_from = -1; /* do not use clone graphic */
+ g->anim_delay_fixed = 0;
+ g->anim_delay_random = 0;
+ g->post_delay_fixed = 0;
+ g->post_delay_random = 0;
+ g->fade_mode = FADE_MODE_DEFAULT;
+ g->fade_delay = -1;
+ g->post_delay = -1;
+ g->auto_delay = -1;
+ g->align = ALIGN_CENTER; /* default for title screens */
+ g->valign = VALIGN_MIDDLE; /* default for title screens */
+ g->sort_priority = 0; /* default for title screens */
+
+ g->bitmap = src_bitmap;
+
+#if 1
+ /* optional zoom factor for scaling up the image to a larger size */
+ if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
+ g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
+ if (g->scale_up_factor < 1)
+ g->scale_up_factor = 1; /* no scaling */
+#endif
+
+#if 1
+ if (g->use_image_size)
+ {
+ /* set new default bitmap size (with scaling, but without small images) */
+ g->width = get_scaled_graphic_width(graphic);
+ g->height = get_scaled_graphic_height(graphic);
+ }
+#endif
+
+ /* optional x and y tile position of animation frame sequence */
+ if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
+ g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
+ if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
+ g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
+
+ /* optional x and y pixel position of animation frame sequence */
+ if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
+ g->src_x = parameter[GFX_ARG_X];
+ if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
+ g->src_y = parameter[GFX_ARG_Y];
+
+ /* optional width and height of each animation frame */
+ if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
+ g->width = parameter[GFX_ARG_WIDTH];
+ if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
+ g->height = parameter[GFX_ARG_HEIGHT];
+
+#if 0
+ /* optional zoom factor for scaling up the image to a larger size */
+ if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
+ g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
+ if (g->scale_up_factor < 1)
+ g->scale_up_factor = 1; /* no scaling */
+#endif
+
+ if (src_bitmap)
+ {
+ /* get final bitmap size (with scaling, but without small images) */
+ int src_image_width = get_scaled_graphic_width(graphic);
+ int src_image_height = get_scaled_graphic_height(graphic);
+
+ if (src_image_width == 0 || src_image_height == 0)
+ {
+ /* only happens when loaded outside artwork system (like "global.busy") */
+ src_image_width = src_bitmap->width;
+ src_image_height = src_bitmap->height;
+ }
+
+ anim_frames_per_row = src_image_width / g->width;
+ anim_frames_per_col = src_image_height / g->height;
+
+ g->src_image_width = src_image_width;
+ g->src_image_height = src_image_height;
+ }
+
+ /* correct x or y offset dependent of vertical or horizontal frame order */
+ if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
+ {
+ g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
+ parameter[GFX_ARG_OFFSET] : g->height);
+ anim_frames_per_line = anim_frames_per_col;
+ }
+ else /* frames are ordered horizontally */
+ {
+ g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
+ parameter[GFX_ARG_OFFSET] : g->width);
+ anim_frames_per_line = anim_frames_per_row;
+ }
+
+ /* optionally, the x and y offset of frames can be specified directly */
+ if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
+ g->offset_x = parameter[GFX_ARG_XOFFSET];
+ if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
+ g->offset_y = parameter[GFX_ARG_YOFFSET];
+
+ /* optionally, moving animations may have separate start and end graphics */
+ g->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 */
+ g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
+ parameter[GFX_ARG_2ND_OFFSET] : g->height);
+ else /* frames are ordered horizontally */
+ g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
+ parameter[GFX_ARG_2ND_OFFSET] : g->width);