1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" /* include auto-generated data structure definitions */
28 #include "conf_esg.c" /* include auto-generated data structure definitions */
29 #include "conf_e2s.c" /* include auto-generated data structure definitions */
30 #include "conf_fnt.c" /* include auto-generated data structure definitions */
31 #include "conf_g2s.c" /* include auto-generated data structure definitions */
32 #include "conf_g2m.c" /* include auto-generated data structure definitions */
33 #include "conf_act.c" /* include auto-generated data structure definitions */
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
89 struct GraphicInfo *graphic_info_last = graphic_info;
91 static unsigned int action_delay = 0;
92 unsigned int action_delay_value = GameFrameDelay;
93 int sync_frame = FrameCounter;
96 if (game_status != GAME_MODE_LOADING)
99 if (anim_initial.bitmap == NULL || window == NULL)
102 if (!DelayReached(&action_delay, action_delay_value))
105 if (init_last.busy.x == -1)
106 init_last.busy.x = WIN_XSIZE / 2;
107 if (init_last.busy.y == -1)
108 init_last.busy.y = WIN_YSIZE / 2;
110 x = ALIGNED_TEXT_XPOS(&init_last.busy);
111 y = ALIGNED_TEXT_YPOS(&init_last.busy);
113 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
115 if (sync_frame % anim_initial.anim_delay == 0)
119 int width = graphic_info[graphic].width;
120 int height = graphic_info[graphic].height;
121 int frame = getGraphicAnimationFrame(graphic, sync_frame);
123 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
124 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
127 graphic_info = graphic_info_last;
134 FreeLevelEditorGadgets();
143 static boolean gadgets_initialized = FALSE;
145 if (gadgets_initialized)
148 CreateLevelEditorGadgets();
152 CreateScreenGadgets();
154 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
156 gadgets_initialized = TRUE;
159 inline static void InitElementSmallImagesScaledUp(int graphic)
161 struct GraphicInfo *g = &graphic_info[graphic];
163 // create small and game tile sized bitmaps (and scale up, if needed)
164 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
167 void InitElementSmallImages()
169 print_timestamp_init("InitElementSmallImages");
171 static int special_graphics[] =
173 IMG_EDITOR_ELEMENT_BORDER,
174 IMG_EDITOR_ELEMENT_BORDER_INPUT,
175 IMG_EDITOR_CASCADE_LIST,
176 IMG_EDITOR_CASCADE_LIST_ACTIVE,
179 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
180 int num_property_mappings = getImageListPropertyMappingSize();
183 print_timestamp_time("getImageListPropertyMapping/Size");
185 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
186 /* initialize normal images from static configuration */
187 for (i = 0; element_to_graphic[i].element > -1; i++)
188 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
189 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
191 /* initialize special images from static configuration */
192 for (i = 0; element_to_special_graphic[i].element > -1; i++)
193 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
194 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
196 /* initialize images from dynamic configuration (may be elements or other) */
197 for (i = 0; i < num_property_mappings; i++)
198 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
199 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
201 /* initialize special images from above list (non-element images) */
202 for (i = 0; special_graphics[i] > -1; i++)
203 InitElementSmallImagesScaledUp(special_graphics[i]);
204 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
206 print_timestamp_done("InitElementSmallImages");
209 void InitScaledImages()
213 /* scale normal images from static configuration, if not already scaled */
214 for (i = 0; i < NUM_IMAGE_FILES; i++)
215 ScaleImage(i, graphic_info[i].scale_up_factor);
218 void InitBitmapPointers()
220 int num_images = getImageListSize();
223 // standard size bitmap may have changed -- update default bitmap pointer
224 for (i = 0; i < num_images; i++)
225 if (graphic_info[i].bitmaps)
226 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
230 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
231 void SetBitmaps_EM(Bitmap **em_bitmap)
233 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
234 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
239 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
240 void SetBitmaps_SP(Bitmap **sp_bitmap)
242 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
246 static int getFontBitmapID(int font_nr)
250 /* (special case: do not use special font for GAME_MODE_LOADING) */
251 if (game_status >= GAME_MODE_TITLE_INITIAL &&
252 game_status <= GAME_MODE_PSEUDO_PREVIEW)
253 special = game_status;
254 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
255 special = GFX_SPECIAL_ARG_MAIN;
258 return font_info[font_nr].special_bitmap_id[special];
263 static int getFontFromToken(char *token)
265 char *value = getHashEntry(font_token_hash, token);
270 /* if font not found, use reliable default value */
271 return FONT_INITIAL_1;
274 void InitFontGraphicInfo()
276 static struct FontBitmapInfo *font_bitmap_info = NULL;
277 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
278 int num_property_mappings = getImageListPropertyMappingSize();
279 int num_font_bitmaps = NUM_FONTS;
282 if (graphic_info == NULL) /* still at startup phase */
284 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
285 getFontBitmapID, getFontFromToken);
290 /* ---------- initialize font graphic definitions ---------- */
292 /* always start with reliable default values (normal font graphics) */
293 for (i = 0; i < NUM_FONTS; i++)
294 font_info[i].graphic = IMG_FONT_INITIAL_1;
296 /* initialize normal font/graphic mapping from static configuration */
297 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
299 int font_nr = font_to_graphic[i].font_nr;
300 int special = font_to_graphic[i].special;
301 int graphic = font_to_graphic[i].graphic;
306 font_info[font_nr].graphic = graphic;
309 /* always start with reliable default values (special font graphics) */
310 for (i = 0; i < NUM_FONTS; i++)
312 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
314 font_info[i].special_graphic[j] = font_info[i].graphic;
315 font_info[i].special_bitmap_id[j] = i;
319 /* initialize special font/graphic mapping from static configuration */
320 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
322 int font_nr = font_to_graphic[i].font_nr;
323 int special = font_to_graphic[i].special;
324 int graphic = font_to_graphic[i].graphic;
325 int base_graphic = font2baseimg(font_nr);
327 if (IS_SPECIAL_GFX_ARG(special))
329 boolean base_redefined =
330 getImageListEntryFromImageID(base_graphic)->redefined;
331 boolean special_redefined =
332 getImageListEntryFromImageID(graphic)->redefined;
333 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
335 /* if the base font ("font.title_1", for example) has been redefined,
336 but not the special font ("font.title_1.LEVELS", for example), do not
337 use an existing (in this case considered obsolete) special font
338 anymore, but use the automatically determined default font */
339 /* special case: cloned special fonts must be explicitly redefined,
340 but are not automatically redefined by redefining base font */
341 if (base_redefined && !special_redefined && !special_cloned)
344 font_info[font_nr].special_graphic[special] = graphic;
345 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
350 /* initialize special font/graphic mapping from dynamic configuration */
351 for (i = 0; i < num_property_mappings; i++)
353 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
354 int special = property_mapping[i].ext3_index;
355 int graphic = property_mapping[i].artwork_index;
360 if (IS_SPECIAL_GFX_ARG(special))
362 font_info[font_nr].special_graphic[special] = graphic;
363 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
368 /* correct special font/graphic mapping for cloned fonts for downwards
369 compatibility of PREVIEW fonts -- this is only needed for implicit
370 redefinition of special font by redefined base font, and only if other
371 fonts are cloned from this special font (like in the "Zelda" level set) */
372 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
374 int font_nr = font_to_graphic[i].font_nr;
375 int special = font_to_graphic[i].special;
376 int graphic = font_to_graphic[i].graphic;
378 if (IS_SPECIAL_GFX_ARG(special))
380 boolean special_redefined =
381 getImageListEntryFromImageID(graphic)->redefined;
382 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
384 if (special_cloned && !special_redefined)
388 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
390 int font_nr2 = font_to_graphic[j].font_nr;
391 int special2 = font_to_graphic[j].special;
392 int graphic2 = font_to_graphic[j].graphic;
394 if (IS_SPECIAL_GFX_ARG(special2) &&
395 graphic2 == graphic_info[graphic].clone_from)
397 font_info[font_nr].special_graphic[special] =
398 font_info[font_nr2].special_graphic[special2];
399 font_info[font_nr].special_bitmap_id[special] =
400 font_info[font_nr2].special_bitmap_id[special2];
407 /* reset non-redefined ".active" font graphics if normal font is redefined */
408 /* (this different treatment is needed because normal and active fonts are
409 independently defined ("active" is not a property of font definitions!) */
410 for (i = 0; i < NUM_FONTS; i++)
412 int font_nr_base = i;
413 int font_nr_active = FONT_ACTIVE(font_nr_base);
415 /* check only those fonts with exist as normal and ".active" variant */
416 if (font_nr_base != font_nr_active)
418 int base_graphic = font_info[font_nr_base].graphic;
419 int active_graphic = font_info[font_nr_active].graphic;
420 boolean base_redefined =
421 getImageListEntryFromImageID(base_graphic)->redefined;
422 boolean active_redefined =
423 getImageListEntryFromImageID(active_graphic)->redefined;
425 /* if the base font ("font.menu_1", for example) has been redefined,
426 but not the active font ("font.menu_1.active", for example), do not
427 use an existing (in this case considered obsolete) active font
428 anymore, but use the automatically determined default font */
429 if (base_redefined && !active_redefined)
430 font_info[font_nr_active].graphic = base_graphic;
432 /* now also check each "special" font (which may be the same as above) */
433 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
435 int base_graphic = font_info[font_nr_base].special_graphic[j];
436 int active_graphic = font_info[font_nr_active].special_graphic[j];
437 boolean base_redefined =
438 getImageListEntryFromImageID(base_graphic)->redefined;
439 boolean active_redefined =
440 getImageListEntryFromImageID(active_graphic)->redefined;
442 /* same as above, but check special graphic definitions, for example:
443 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
444 if (base_redefined && !active_redefined)
446 font_info[font_nr_active].special_graphic[j] =
447 font_info[font_nr_base].special_graphic[j];
448 font_info[font_nr_active].special_bitmap_id[j] =
449 font_info[font_nr_base].special_bitmap_id[j];
455 /* ---------- initialize font bitmap array ---------- */
457 if (font_bitmap_info != NULL)
458 FreeFontInfo(font_bitmap_info);
461 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
463 /* ---------- initialize font bitmap definitions ---------- */
465 for (i = 0; i < NUM_FONTS; i++)
467 if (i < NUM_INITIAL_FONTS)
469 font_bitmap_info[i] = font_initial[i];
473 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
475 int font_bitmap_id = font_info[i].special_bitmap_id[j];
476 int graphic = font_info[i].special_graphic[j];
478 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
479 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
481 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
482 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
485 /* copy font relevant information from graphics information */
486 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
487 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
488 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
489 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
490 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
492 font_bitmap_info[font_bitmap_id].draw_xoffset =
493 graphic_info[graphic].draw_xoffset;
494 font_bitmap_info[font_bitmap_id].draw_yoffset =
495 graphic_info[graphic].draw_yoffset;
497 font_bitmap_info[font_bitmap_id].num_chars =
498 graphic_info[graphic].anim_frames;
499 font_bitmap_info[font_bitmap_id].num_chars_per_line =
500 graphic_info[graphic].anim_frames_per_line;
504 InitFontInfo(font_bitmap_info, num_font_bitmaps,
505 getFontBitmapID, getFontFromToken);
508 void InitGlobalAnimGraphicInfo()
510 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
511 int num_property_mappings = getImageListPropertyMappingSize();
514 if (graphic_info == NULL) /* still at startup phase */
517 /* always start with reliable default values (no global animations) */
518 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
519 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS; j++)
520 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
521 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
523 /* initialize global animation definitions from static configuration */
524 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
525 global_anim_info[i].graphic[0][GFX_SPECIAL_ARG_DEFAULT] =
526 IMG_GLOBAL_ANIM_1 + i;
528 /* initialize global animation definitions from dynamic configuration */
529 for (i = 0; i < num_property_mappings; i++)
531 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
532 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
533 int special = property_mapping[i].ext3_index;
534 int graphic = property_mapping[i].artwork_index;
536 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIMS)
539 /* map animation part to first part, if not specified */
543 /* map animation screen to default, if not specified */
544 if (!IS_SPECIAL_GFX_ARG(special))
545 special = GFX_SPECIAL_ARG_DEFAULT;
547 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
551 printf("::: InitGlobalAnimGraphicInfo\n");
553 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
554 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS; j++)
555 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
556 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
557 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
558 printf("::: %d, %d, %d => %d\n",
559 i, j, k, global_anim_info[i].graphic[j][k]);
563 void InitElementGraphicInfo()
565 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
566 int num_property_mappings = getImageListPropertyMappingSize();
569 if (graphic_info == NULL) /* still at startup phase */
572 /* set values to -1 to identify later as "uninitialized" values */
573 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
575 for (act = 0; act < NUM_ACTIONS; act++)
577 element_info[i].graphic[act] = -1;
578 element_info[i].crumbled[act] = -1;
580 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
582 element_info[i].direction_graphic[act][dir] = -1;
583 element_info[i].direction_crumbled[act][dir] = -1;
590 /* initialize normal element/graphic mapping from static configuration */
591 for (i = 0; element_to_graphic[i].element > -1; i++)
593 int element = element_to_graphic[i].element;
594 int action = element_to_graphic[i].action;
595 int direction = element_to_graphic[i].direction;
596 boolean crumbled = element_to_graphic[i].crumbled;
597 int graphic = element_to_graphic[i].graphic;
598 int base_graphic = el2baseimg(element);
600 if (graphic_info[graphic].bitmap == NULL)
603 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
606 boolean base_redefined =
607 getImageListEntryFromImageID(base_graphic)->redefined;
608 boolean act_dir_redefined =
609 getImageListEntryFromImageID(graphic)->redefined;
611 /* if the base graphic ("emerald", for example) has been redefined,
612 but not the action graphic ("emerald.falling", for example), do not
613 use an existing (in this case considered obsolete) action graphic
614 anymore, but use the automatically determined default graphic */
615 if (base_redefined && !act_dir_redefined)
620 action = ACTION_DEFAULT;
625 element_info[element].direction_crumbled[action][direction] = graphic;
627 element_info[element].crumbled[action] = graphic;
632 element_info[element].direction_graphic[action][direction] = graphic;
634 element_info[element].graphic[action] = graphic;
638 /* initialize normal element/graphic mapping from dynamic configuration */
639 for (i = 0; i < num_property_mappings; i++)
641 int element = property_mapping[i].base_index;
642 int action = property_mapping[i].ext1_index;
643 int direction = property_mapping[i].ext2_index;
644 int special = property_mapping[i].ext3_index;
645 int graphic = property_mapping[i].artwork_index;
646 boolean crumbled = FALSE;
648 if (special == GFX_SPECIAL_ARG_CRUMBLED)
654 if (graphic_info[graphic].bitmap == NULL)
657 if (element >= MAX_NUM_ELEMENTS || special != -1)
661 action = ACTION_DEFAULT;
666 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
667 element_info[element].direction_crumbled[action][dir] = -1;
670 element_info[element].direction_crumbled[action][direction] = graphic;
672 element_info[element].crumbled[action] = graphic;
677 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
678 element_info[element].direction_graphic[action][dir] = -1;
681 element_info[element].direction_graphic[action][direction] = graphic;
683 element_info[element].graphic[action] = graphic;
687 /* now copy all graphics that are defined to be cloned from other graphics */
688 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
690 int graphic = element_info[i].graphic[ACTION_DEFAULT];
691 int crumbled_like, diggable_like;
696 crumbled_like = graphic_info[graphic].crumbled_like;
697 diggable_like = graphic_info[graphic].diggable_like;
699 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
701 for (act = 0; act < NUM_ACTIONS; act++)
702 element_info[i].crumbled[act] =
703 element_info[crumbled_like].crumbled[act];
704 for (act = 0; act < NUM_ACTIONS; act++)
705 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
706 element_info[i].direction_crumbled[act][dir] =
707 element_info[crumbled_like].direction_crumbled[act][dir];
710 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
712 element_info[i].graphic[ACTION_DIGGING] =
713 element_info[diggable_like].graphic[ACTION_DIGGING];
714 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
715 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
716 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
720 /* set hardcoded definitions for some runtime elements without graphic */
721 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
723 /* set hardcoded definitions for some internal elements without graphic */
724 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
726 if (IS_EDITOR_CASCADE_INACTIVE(i))
727 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
728 else if (IS_EDITOR_CASCADE_ACTIVE(i))
729 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
732 /* now set all undefined/invalid graphics to -1 to set to default after it */
733 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
735 for (act = 0; act < NUM_ACTIONS; act++)
739 graphic = element_info[i].graphic[act];
740 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
741 element_info[i].graphic[act] = -1;
743 graphic = element_info[i].crumbled[act];
744 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
745 element_info[i].crumbled[act] = -1;
747 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
749 graphic = element_info[i].direction_graphic[act][dir];
750 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
751 element_info[i].direction_graphic[act][dir] = -1;
753 graphic = element_info[i].direction_crumbled[act][dir];
754 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
755 element_info[i].direction_crumbled[act][dir] = -1;
762 /* adjust graphics with 2nd tile for movement according to direction
763 (do this before correcting '-1' values to minimize calculations) */
764 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
766 for (act = 0; act < NUM_ACTIONS; act++)
768 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
770 int graphic = element_info[i].direction_graphic[act][dir];
771 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
773 if (act == ACTION_FALLING) /* special case */
774 graphic = element_info[i].graphic[act];
777 graphic_info[graphic].double_movement &&
778 graphic_info[graphic].swap_double_tiles != 0)
780 struct GraphicInfo *g = &graphic_info[graphic];
781 int src_x_front = g->src_x;
782 int src_y_front = g->src_y;
783 int src_x_back = g->src_x + g->offset2_x;
784 int src_y_back = g->src_y + g->offset2_y;
785 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
787 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
788 src_y_front < src_y_back);
789 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
790 boolean swap_movement_tiles_autodetected =
791 (!frames_are_ordered_diagonally &&
792 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
793 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
794 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
795 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
798 /* swap frontside and backside graphic tile coordinates, if needed */
799 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
801 /* get current (wrong) backside tile coordinates */
802 getFixedGraphicSourceExt(graphic, 0, &dummy,
803 &src_x_back, &src_y_back, TRUE);
805 /* set frontside tile coordinates to backside tile coordinates */
806 g->src_x = src_x_back;
807 g->src_y = src_y_back;
809 /* invert tile offset to point to new backside tile coordinates */
813 /* do not swap front and backside tiles again after correction */
814 g->swap_double_tiles = 0;
823 /* now set all '-1' values to element specific default values */
824 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
826 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
827 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
828 int default_direction_graphic[NUM_DIRECTIONS_FULL];
829 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
831 if (default_graphic == -1)
832 default_graphic = IMG_UNKNOWN;
834 if (default_crumbled == -1)
835 default_crumbled = default_graphic;
837 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
839 default_direction_graphic[dir] =
840 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
841 default_direction_crumbled[dir] =
842 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
844 if (default_direction_graphic[dir] == -1)
845 default_direction_graphic[dir] = default_graphic;
847 if (default_direction_crumbled[dir] == -1)
848 default_direction_crumbled[dir] = default_direction_graphic[dir];
851 for (act = 0; act < NUM_ACTIONS; act++)
853 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
854 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
855 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
856 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
857 act == ACTION_TURNING_FROM_RIGHT ||
858 act == ACTION_TURNING_FROM_UP ||
859 act == ACTION_TURNING_FROM_DOWN);
861 /* generic default action graphic (defined by "[default]" directive) */
862 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
863 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
864 int default_remove_graphic = IMG_EMPTY;
866 if (act_remove && default_action_graphic != -1)
867 default_remove_graphic = default_action_graphic;
869 /* look for special default action graphic (classic game specific) */
870 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
871 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
872 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
873 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
874 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
875 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
877 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
878 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
879 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
880 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
881 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
882 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
884 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
885 /* !!! make this better !!! */
886 if (i == EL_EMPTY_SPACE)
888 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
889 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
892 if (default_action_graphic == -1)
893 default_action_graphic = default_graphic;
895 if (default_action_crumbled == -1)
896 default_action_crumbled = default_action_graphic;
898 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
900 /* use action graphic as the default direction graphic, if undefined */
901 int default_action_direction_graphic = element_info[i].graphic[act];
902 int default_action_direction_crumbled = element_info[i].crumbled[act];
904 /* no graphic for current action -- use default direction graphic */
905 if (default_action_direction_graphic == -1)
906 default_action_direction_graphic =
907 (act_remove ? default_remove_graphic :
909 element_info[i].direction_graphic[ACTION_TURNING][dir] :
910 default_action_graphic != default_graphic ?
911 default_action_graphic :
912 default_direction_graphic[dir]);
914 if (element_info[i].direction_graphic[act][dir] == -1)
915 element_info[i].direction_graphic[act][dir] =
916 default_action_direction_graphic;
918 if (default_action_direction_crumbled == -1)
919 default_action_direction_crumbled =
920 element_info[i].direction_graphic[act][dir];
922 if (element_info[i].direction_crumbled[act][dir] == -1)
923 element_info[i].direction_crumbled[act][dir] =
924 default_action_direction_crumbled;
927 /* no graphic for this specific action -- use default action graphic */
928 if (element_info[i].graphic[act] == -1)
929 element_info[i].graphic[act] =
930 (act_remove ? default_remove_graphic :
931 act_turning ? element_info[i].graphic[ACTION_TURNING] :
932 default_action_graphic);
934 if (element_info[i].crumbled[act] == -1)
935 element_info[i].crumbled[act] = element_info[i].graphic[act];
942 void InitElementSpecialGraphicInfo()
944 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
945 int num_property_mappings = getImageListPropertyMappingSize();
948 /* always start with reliable default values */
949 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
950 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
951 element_info[i].special_graphic[j] =
952 element_info[i].graphic[ACTION_DEFAULT];
954 /* initialize special element/graphic mapping from static configuration */
955 for (i = 0; element_to_special_graphic[i].element > -1; i++)
957 int element = element_to_special_graphic[i].element;
958 int special = element_to_special_graphic[i].special;
959 int graphic = element_to_special_graphic[i].graphic;
960 int base_graphic = el2baseimg(element);
961 boolean base_redefined =
962 getImageListEntryFromImageID(base_graphic)->redefined;
963 boolean special_redefined =
964 getImageListEntryFromImageID(graphic)->redefined;
966 /* if the base graphic ("emerald", for example) has been redefined,
967 but not the special graphic ("emerald.EDITOR", for example), do not
968 use an existing (in this case considered obsolete) special graphic
969 anymore, but use the automatically created (down-scaled) graphic */
970 if (base_redefined && !special_redefined)
973 element_info[element].special_graphic[special] = graphic;
976 /* initialize special element/graphic mapping from dynamic configuration */
977 for (i = 0; i < num_property_mappings; i++)
979 int element = property_mapping[i].base_index;
980 int action = property_mapping[i].ext1_index;
981 int direction = property_mapping[i].ext2_index;
982 int special = property_mapping[i].ext3_index;
983 int graphic = property_mapping[i].artwork_index;
985 /* for action ".active", replace element with active element, if exists */
986 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
988 element = ELEMENT_ACTIVE(element);
992 if (element >= MAX_NUM_ELEMENTS)
995 /* do not change special graphic if action or direction was specified */
996 if (action != -1 || direction != -1)
999 if (IS_SPECIAL_GFX_ARG(special))
1000 element_info[element].special_graphic[special] = graphic;
1003 /* now set all undefined/invalid graphics to default */
1004 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1005 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1006 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1007 element_info[i].special_graphic[j] =
1008 element_info[i].graphic[ACTION_DEFAULT];
1011 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1013 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1014 return get_parameter_value(value_raw, suffix, type);
1016 if (strEqual(value_raw, ARG_UNDEFINED))
1017 return ARG_UNDEFINED_VALUE;
1019 if (type == TYPE_ELEMENT)
1021 char *value = getHashEntry(element_token_hash, value_raw);
1025 Error(ERR_INFO_LINE, "-");
1026 Error(ERR_INFO, "warning: error found in config file:");
1027 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1028 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1029 Error(ERR_INFO, "custom graphic rejected for this element/action");
1030 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1031 Error(ERR_INFO_LINE, "-");
1034 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1036 else if (type == TYPE_GRAPHIC)
1038 char *value = getHashEntry(graphic_token_hash, value_raw);
1039 int fallback_graphic = IMG_CHAR_EXCLAM;
1043 Error(ERR_INFO_LINE, "-");
1044 Error(ERR_INFO, "warning: error found in config file:");
1045 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1046 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1047 Error(ERR_INFO, "custom graphic rejected for this element/action");
1048 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1049 Error(ERR_INFO_LINE, "-");
1052 return (value != NULL ? atoi(value) : fallback_graphic);
1058 static int get_scaled_graphic_width(int graphic)
1060 int original_width = getOriginalImageWidthFromImageID(graphic);
1061 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1063 return original_width * scale_up_factor;
1066 static int get_scaled_graphic_height(int graphic)
1068 int original_height = getOriginalImageHeightFromImageID(graphic);
1069 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1071 return original_height * scale_up_factor;
1074 static void set_graphic_parameters_ext(int graphic, int *parameter,
1075 Bitmap **src_bitmaps)
1077 struct GraphicInfo *g = &graphic_info[graphic];
1078 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1079 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1080 int anim_frames_per_line = 1;
1082 /* always start with reliable default values */
1083 g->src_image_width = 0;
1084 g->src_image_height = 0;
1087 g->width = TILEX; /* default for element graphics */
1088 g->height = TILEY; /* default for element graphics */
1089 g->offset_x = 0; /* one or both of these values ... */
1090 g->offset_y = 0; /* ... will be corrected later */
1091 g->offset2_x = 0; /* one or both of these values ... */
1092 g->offset2_y = 0; /* ... will be corrected later */
1093 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1094 g->crumbled_like = -1; /* do not use clone element */
1095 g->diggable_like = -1; /* do not use clone element */
1096 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1097 g->scale_up_factor = 1; /* default: no scaling up */
1098 g->tile_size = TILESIZE; /* default: standard tile size */
1099 g->clone_from = -1; /* do not use clone graphic */
1100 g->anim_delay_fixed = 0;
1101 g->anim_delay_random = 0;
1102 g->post_delay_fixed = 0;
1103 g->post_delay_random = 0;
1104 g->fade_mode = FADE_MODE_DEFAULT;
1108 g->align = ALIGN_CENTER; /* default for title screens */
1109 g->valign = VALIGN_MIDDLE; /* default for title screens */
1110 g->sort_priority = 0; /* default for title screens */
1112 g->style = STYLE_DEFAULT;
1114 g->bitmaps = src_bitmaps;
1115 g->bitmap = src_bitmap;
1117 /* optional zoom factor for scaling up the image to a larger size */
1118 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1119 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1120 if (g->scale_up_factor < 1)
1121 g->scale_up_factor = 1; /* no scaling */
1123 /* optional tile size for using non-standard image size */
1124 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1126 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1129 // CHECK: should tile sizes less than standard tile size be allowed?
1130 if (g->tile_size < TILESIZE)
1131 g->tile_size = TILESIZE; /* standard tile size */
1134 // when setting tile size, also set width and height accordingly
1135 g->width = g->tile_size;
1136 g->height = g->tile_size;
1139 if (g->use_image_size)
1141 /* set new default bitmap size (with scaling, but without small images) */
1142 g->width = get_scaled_graphic_width(graphic);
1143 g->height = get_scaled_graphic_height(graphic);
1146 /* optional width and height of each animation frame */
1147 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1148 g->width = parameter[GFX_ARG_WIDTH];
1149 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1150 g->height = parameter[GFX_ARG_HEIGHT];
1152 /* optional x and y tile position of animation frame sequence */
1153 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1154 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1155 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1156 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1158 /* optional x and y pixel position of animation frame sequence */
1159 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1160 g->src_x = parameter[GFX_ARG_X];
1161 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1162 g->src_y = parameter[GFX_ARG_Y];
1168 Error(ERR_INFO_LINE, "-");
1169 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1170 g->width, getTokenFromImageID(graphic), TILEX);
1171 Error(ERR_INFO_LINE, "-");
1173 g->width = TILEX; /* will be checked to be inside bitmap later */
1178 Error(ERR_INFO_LINE, "-");
1179 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1180 g->height, getTokenFromImageID(graphic), TILEY);
1181 Error(ERR_INFO_LINE, "-");
1183 g->height = TILEY; /* will be checked to be inside bitmap later */
1189 /* get final bitmap size (with scaling, but without small images) */
1190 int src_image_width = get_scaled_graphic_width(graphic);
1191 int src_image_height = get_scaled_graphic_height(graphic);
1193 if (src_image_width == 0 || src_image_height == 0)
1195 /* only happens when loaded outside artwork system (like "global.busy") */
1196 src_image_width = src_bitmap->width;
1197 src_image_height = src_bitmap->height;
1200 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1202 anim_frames_per_row = src_image_width / g->tile_size;
1203 anim_frames_per_col = src_image_height / g->tile_size;
1207 anim_frames_per_row = src_image_width / g->width;
1208 anim_frames_per_col = src_image_height / g->height;
1211 g->src_image_width = src_image_width;
1212 g->src_image_height = src_image_height;
1215 /* correct x or y offset dependent of vertical or horizontal frame order */
1216 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1218 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1219 parameter[GFX_ARG_OFFSET] : g->height);
1220 anim_frames_per_line = anim_frames_per_col;
1222 else /* frames are ordered horizontally */
1224 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1225 parameter[GFX_ARG_OFFSET] : g->width);
1226 anim_frames_per_line = anim_frames_per_row;
1229 /* optionally, the x and y offset of frames can be specified directly */
1230 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1231 g->offset_x = parameter[GFX_ARG_XOFFSET];
1232 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1233 g->offset_y = parameter[GFX_ARG_YOFFSET];
1235 /* optionally, moving animations may have separate start and end graphics */
1236 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1238 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1239 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1241 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1242 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1243 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1244 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1245 else /* frames are ordered horizontally */
1246 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1247 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1249 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1250 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1251 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1252 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1253 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1255 /* optionally, the second movement tile can be specified as start tile */
1256 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1257 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1259 /* automatically determine correct number of frames, if not defined */
1260 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1261 g->anim_frames = parameter[GFX_ARG_FRAMES];
1262 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1263 g->anim_frames = anim_frames_per_row;
1264 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1265 g->anim_frames = anim_frames_per_col;
1269 if (g->anim_frames == 0) /* frames must be at least 1 */
1272 g->anim_frames_per_line =
1273 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1274 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1276 g->anim_delay = parameter[GFX_ARG_DELAY];
1277 if (g->anim_delay == 0) /* delay must be at least 1 */
1280 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1282 /* automatically determine correct start frame, if not defined */
1283 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1284 g->anim_start_frame = 0;
1285 else if (g->anim_mode & ANIM_REVERSE)
1286 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1288 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1290 /* animation synchronized with global frame counter, not move position */
1291 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1293 /* optional element for cloning crumble graphics */
1294 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1295 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1297 /* optional element for cloning digging graphics */
1298 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1299 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1301 /* optional border size for "crumbling" diggable graphics */
1302 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1303 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1305 /* this is only used for player "boring" and "sleeping" actions */
1306 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1307 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1308 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1309 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1310 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1311 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1312 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1313 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1315 /* this is only used for toon animations */
1316 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1317 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1319 /* this is only used for drawing font characters */
1320 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1321 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1323 /* this is only used for drawing envelope graphics */
1324 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1326 /* optional graphic for cloning all graphics settings */
1327 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1328 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1330 /* optional settings for drawing title screens and title messages */
1331 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1332 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1333 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1334 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1335 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1336 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1337 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1338 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1339 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1340 g->align = parameter[GFX_ARG_ALIGN];
1341 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1342 g->valign = parameter[GFX_ARG_VALIGN];
1343 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1344 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1346 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1347 g->class = parameter[GFX_ARG_CLASS];
1348 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1349 g->style = parameter[GFX_ARG_STYLE];
1351 /* this is only used for drawing menu buttons and text */
1352 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1353 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1354 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1355 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1358 static void set_graphic_parameters(int graphic)
1360 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1361 char **parameter_raw = image->parameter;
1362 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1363 int parameter[NUM_GFX_ARGS];
1366 /* if fallback to default artwork is done, also use the default parameters */
1367 if (image->fallback_to_default)
1368 parameter_raw = image->default_parameter;
1370 /* get integer values from string parameters */
1371 for (i = 0; i < NUM_GFX_ARGS; i++)
1372 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1373 image_config_suffix[i].token,
1374 image_config_suffix[i].type);
1376 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1378 UPDATE_BUSY_STATE();
1381 static void set_cloned_graphic_parameters(int graphic)
1383 int fallback_graphic = IMG_CHAR_EXCLAM;
1384 int max_num_images = getImageListSize();
1385 int clone_graphic = graphic_info[graphic].clone_from;
1386 int num_references_followed = 1;
1388 while (graphic_info[clone_graphic].clone_from != -1 &&
1389 num_references_followed < max_num_images)
1391 clone_graphic = graphic_info[clone_graphic].clone_from;
1393 num_references_followed++;
1396 if (num_references_followed >= max_num_images)
1398 Error(ERR_INFO_LINE, "-");
1399 Error(ERR_INFO, "warning: error found in config file:");
1400 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1401 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1402 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1403 Error(ERR_INFO, "custom graphic rejected for this element/action");
1405 if (graphic == fallback_graphic)
1406 Error(ERR_EXIT, "no fallback graphic available");
1408 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1409 Error(ERR_INFO_LINE, "-");
1411 graphic_info[graphic] = graphic_info[fallback_graphic];
1415 graphic_info[graphic] = graphic_info[clone_graphic];
1416 graphic_info[graphic].clone_from = clone_graphic;
1420 static void InitGraphicInfo()
1422 int fallback_graphic = IMG_CHAR_EXCLAM;
1423 int num_images = getImageListSize();
1426 /* use image size as default values for width and height for these images */
1427 static int full_size_graphics[] =
1430 IMG_GLOBAL_BORDER_MAIN,
1431 IMG_GLOBAL_BORDER_SCORES,
1432 IMG_GLOBAL_BORDER_EDITOR,
1433 IMG_GLOBAL_BORDER_PLAYING,
1436 IMG_BACKGROUND_ENVELOPE_1,
1437 IMG_BACKGROUND_ENVELOPE_2,
1438 IMG_BACKGROUND_ENVELOPE_3,
1439 IMG_BACKGROUND_ENVELOPE_4,
1440 IMG_BACKGROUND_REQUEST,
1443 IMG_BACKGROUND_TITLE_INITIAL,
1444 IMG_BACKGROUND_TITLE,
1445 IMG_BACKGROUND_MAIN,
1446 IMG_BACKGROUND_LEVELS,
1447 IMG_BACKGROUND_LEVELNR,
1448 IMG_BACKGROUND_SCORES,
1449 IMG_BACKGROUND_EDITOR,
1450 IMG_BACKGROUND_INFO,
1451 IMG_BACKGROUND_INFO_ELEMENTS,
1452 IMG_BACKGROUND_INFO_MUSIC,
1453 IMG_BACKGROUND_INFO_CREDITS,
1454 IMG_BACKGROUND_INFO_PROGRAM,
1455 IMG_BACKGROUND_INFO_VERSION,
1456 IMG_BACKGROUND_INFO_LEVELSET,
1457 IMG_BACKGROUND_SETUP,
1458 IMG_BACKGROUND_PLAYING,
1459 IMG_BACKGROUND_DOOR,
1460 IMG_BACKGROUND_TAPE,
1461 IMG_BACKGROUND_PANEL,
1462 IMG_BACKGROUND_PALETTE,
1463 IMG_BACKGROUND_TOOLBOX,
1465 IMG_TITLESCREEN_INITIAL_1,
1466 IMG_TITLESCREEN_INITIAL_2,
1467 IMG_TITLESCREEN_INITIAL_3,
1468 IMG_TITLESCREEN_INITIAL_4,
1469 IMG_TITLESCREEN_INITIAL_5,
1476 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1477 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1478 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1479 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1480 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1481 IMG_BACKGROUND_TITLEMESSAGE_1,
1482 IMG_BACKGROUND_TITLEMESSAGE_2,
1483 IMG_BACKGROUND_TITLEMESSAGE_3,
1484 IMG_BACKGROUND_TITLEMESSAGE_4,
1485 IMG_BACKGROUND_TITLEMESSAGE_5,
1490 checked_free(graphic_info);
1492 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1494 /* initialize "use_image_size" flag with default value */
1495 for (i = 0; i < num_images; i++)
1496 graphic_info[i].use_image_size = FALSE;
1498 /* initialize "use_image_size" flag from static configuration above */
1499 for (i = 0; full_size_graphics[i] != -1; i++)
1500 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1502 /* first set all graphic paramaters ... */
1503 for (i = 0; i < num_images; i++)
1504 set_graphic_parameters(i);
1506 /* ... then copy these parameters for cloned graphics */
1507 for (i = 0; i < num_images; i++)
1508 if (graphic_info[i].clone_from != -1)
1509 set_cloned_graphic_parameters(i);
1511 for (i = 0; i < num_images; i++)
1516 int first_frame, last_frame;
1517 int src_bitmap_width, src_bitmap_height;
1519 /* now check if no animation frames are outside of the loaded image */
1521 if (graphic_info[i].bitmap == NULL)
1522 continue; /* skip check for optional images that are undefined */
1524 /* get image size (this can differ from the standard element tile size!) */
1525 width = graphic_info[i].width;
1526 height = graphic_info[i].height;
1528 /* get final bitmap size (with scaling, but without small images) */
1529 src_bitmap_width = graphic_info[i].src_image_width;
1530 src_bitmap_height = graphic_info[i].src_image_height;
1532 /* check if first animation frame is inside specified bitmap */
1535 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1537 /* this avoids calculating wrong start position for out-of-bounds frame */
1538 src_x = graphic_info[i].src_x;
1539 src_y = graphic_info[i].src_y;
1541 if (src_x < 0 || src_y < 0 ||
1542 src_x + width > src_bitmap_width ||
1543 src_y + height > src_bitmap_height)
1545 Error(ERR_INFO_LINE, "-");
1546 Error(ERR_INFO, "warning: error found in config file:");
1547 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1548 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1549 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1551 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1552 src_x, src_y, src_bitmap_width, src_bitmap_height);
1553 Error(ERR_INFO, "custom graphic rejected for this element/action");
1555 if (i == fallback_graphic)
1556 Error(ERR_EXIT, "no fallback graphic available");
1558 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1559 Error(ERR_INFO_LINE, "-");
1561 graphic_info[i] = graphic_info[fallback_graphic];
1564 /* check if last animation frame is inside specified bitmap */
1566 last_frame = graphic_info[i].anim_frames - 1;
1567 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1569 if (src_x < 0 || src_y < 0 ||
1570 src_x + width > src_bitmap_width ||
1571 src_y + height > src_bitmap_height)
1573 Error(ERR_INFO_LINE, "-");
1574 Error(ERR_INFO, "warning: error found in config file:");
1575 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1576 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1577 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1579 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1580 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1581 Error(ERR_INFO, "::: %d, %d", width, height);
1582 Error(ERR_INFO, "custom graphic rejected for this element/action");
1584 if (i == fallback_graphic)
1585 Error(ERR_EXIT, "no fallback graphic available");
1587 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1588 Error(ERR_INFO_LINE, "-");
1590 graphic_info[i] = graphic_info[fallback_graphic];
1595 static void InitGraphicCompatibilityInfo()
1597 struct FileInfo *fi_global_door =
1598 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1599 int num_images = getImageListSize();
1602 /* the following compatibility handling is needed for the following case:
1603 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1604 graphics mainly used for door and panel graphics, like editor, tape and
1605 in-game buttons with hard-coded bitmap positions and button sizes; as
1606 these graphics now have individual definitions, redefining "global.door"
1607 to change all these graphics at once like before does not work anymore
1608 (because all those individual definitions still have their default values);
1609 to solve this, remap all those individual definitions that are not
1610 redefined to the new bitmap of "global.door" if it was redefined */
1612 /* special compatibility handling if image "global.door" was redefined */
1613 if (fi_global_door->redefined)
1615 for (i = 0; i < num_images; i++)
1617 struct FileInfo *fi = getImageListEntryFromImageID(i);
1619 /* process only those images that still use the default settings */
1622 /* process all images which default to same image as "global.door" */
1623 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1625 // printf("::: special treatment needed for token '%s'\n", fi->token);
1627 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1633 InitGraphicCompatibilityInfo_Doors();
1636 static void InitElementSoundInfo()
1638 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1639 int num_property_mappings = getSoundListPropertyMappingSize();
1642 /* set values to -1 to identify later as "uninitialized" values */
1643 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1644 for (act = 0; act < NUM_ACTIONS; act++)
1645 element_info[i].sound[act] = -1;
1647 /* initialize element/sound mapping from static configuration */
1648 for (i = 0; element_to_sound[i].element > -1; i++)
1650 int element = element_to_sound[i].element;
1651 int action = element_to_sound[i].action;
1652 int sound = element_to_sound[i].sound;
1653 boolean is_class = element_to_sound[i].is_class;
1656 action = ACTION_DEFAULT;
1659 element_info[element].sound[action] = sound;
1661 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1662 if (strEqual(element_info[j].class_name,
1663 element_info[element].class_name))
1664 element_info[j].sound[action] = sound;
1667 /* initialize element class/sound mapping from dynamic configuration */
1668 for (i = 0; i < num_property_mappings; i++)
1670 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1671 int action = property_mapping[i].ext1_index;
1672 int sound = property_mapping[i].artwork_index;
1674 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1678 action = ACTION_DEFAULT;
1680 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1681 if (strEqual(element_info[j].class_name,
1682 element_info[element_class].class_name))
1683 element_info[j].sound[action] = sound;
1686 /* initialize element/sound mapping from dynamic configuration */
1687 for (i = 0; i < num_property_mappings; i++)
1689 int element = property_mapping[i].base_index;
1690 int action = property_mapping[i].ext1_index;
1691 int sound = property_mapping[i].artwork_index;
1693 if (element >= MAX_NUM_ELEMENTS)
1697 action = ACTION_DEFAULT;
1699 element_info[element].sound[action] = sound;
1702 /* now set all '-1' values to element specific default values */
1703 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1705 for (act = 0; act < NUM_ACTIONS; act++)
1707 /* generic default action sound (defined by "[default]" directive) */
1708 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1710 /* look for special default action sound (classic game specific) */
1711 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1712 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1713 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1714 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1715 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1716 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1718 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1719 /* !!! make this better !!! */
1720 if (i == EL_EMPTY_SPACE)
1721 default_action_sound = element_info[EL_DEFAULT].sound[act];
1723 /* no sound for this specific action -- use default action sound */
1724 if (element_info[i].sound[act] == -1)
1725 element_info[i].sound[act] = default_action_sound;
1729 /* copy sound settings to some elements that are only stored in level file
1730 in native R'n'D levels, but are used by game engine in native EM levels */
1731 for (i = 0; copy_properties[i][0] != -1; i++)
1732 for (j = 1; j <= 4; j++)
1733 for (act = 0; act < NUM_ACTIONS; act++)
1734 element_info[copy_properties[i][j]].sound[act] =
1735 element_info[copy_properties[i][0]].sound[act];
1738 static void InitGameModeSoundInfo()
1742 /* set values to -1 to identify later as "uninitialized" values */
1743 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1746 /* initialize gamemode/sound mapping from static configuration */
1747 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1749 int gamemode = gamemode_to_sound[i].gamemode;
1750 int sound = gamemode_to_sound[i].sound;
1753 gamemode = GAME_MODE_DEFAULT;
1755 menu.sound[gamemode] = sound;
1758 /* now set all '-1' values to levelset specific default values */
1759 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1760 if (menu.sound[i] == -1)
1761 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1764 static void set_sound_parameters(int sound, char **parameter_raw)
1766 int parameter[NUM_SND_ARGS];
1769 /* get integer values from string parameters */
1770 for (i = 0; i < NUM_SND_ARGS; i++)
1772 get_parameter_value(parameter_raw[i],
1773 sound_config_suffix[i].token,
1774 sound_config_suffix[i].type);
1776 /* explicit loop mode setting in configuration overrides default value */
1777 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1778 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1780 /* sound volume to change the original volume when loading the sound file */
1781 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1783 /* sound priority to give certain sounds a higher or lower priority */
1784 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1787 static void InitSoundInfo()
1789 int *sound_effect_properties;
1790 int num_sounds = getSoundListSize();
1793 checked_free(sound_info);
1795 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1796 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1798 /* initialize sound effect for all elements to "no sound" */
1799 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1800 for (j = 0; j < NUM_ACTIONS; j++)
1801 element_info[i].sound[j] = SND_UNDEFINED;
1803 for (i = 0; i < num_sounds; i++)
1805 struct FileInfo *sound = getSoundListEntry(i);
1806 int len_effect_text = strlen(sound->token);
1808 sound_effect_properties[i] = ACTION_OTHER;
1809 sound_info[i].loop = FALSE; /* default: play sound only once */
1811 /* determine all loop sounds and identify certain sound classes */
1813 for (j = 0; element_action_info[j].suffix; j++)
1815 int len_action_text = strlen(element_action_info[j].suffix);
1817 if (len_action_text < len_effect_text &&
1818 strEqual(&sound->token[len_effect_text - len_action_text],
1819 element_action_info[j].suffix))
1821 sound_effect_properties[i] = element_action_info[j].value;
1822 sound_info[i].loop = element_action_info[j].is_loop_sound;
1828 /* associate elements and some selected sound actions */
1830 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1832 if (element_info[j].class_name)
1834 int len_class_text = strlen(element_info[j].class_name);
1836 if (len_class_text + 1 < len_effect_text &&
1837 strncmp(sound->token,
1838 element_info[j].class_name, len_class_text) == 0 &&
1839 sound->token[len_class_text] == '.')
1841 int sound_action_value = sound_effect_properties[i];
1843 element_info[j].sound[sound_action_value] = i;
1848 set_sound_parameters(i, sound->parameter);
1851 free(sound_effect_properties);
1854 static void InitGameModeMusicInfo()
1856 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1857 int num_property_mappings = getMusicListPropertyMappingSize();
1858 int default_levelset_music = -1;
1861 /* set values to -1 to identify later as "uninitialized" values */
1862 for (i = 0; i < MAX_LEVELS; i++)
1863 levelset.music[i] = -1;
1864 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1867 /* initialize gamemode/music mapping from static configuration */
1868 for (i = 0; gamemode_to_music[i].music > -1; i++)
1870 int gamemode = gamemode_to_music[i].gamemode;
1871 int music = gamemode_to_music[i].music;
1874 gamemode = GAME_MODE_DEFAULT;
1876 menu.music[gamemode] = music;
1879 /* initialize gamemode/music mapping from dynamic configuration */
1880 for (i = 0; i < num_property_mappings; i++)
1882 int prefix = property_mapping[i].base_index;
1883 int gamemode = property_mapping[i].ext1_index;
1884 int level = property_mapping[i].ext2_index;
1885 int music = property_mapping[i].artwork_index;
1887 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1891 gamemode = GAME_MODE_DEFAULT;
1893 /* level specific music only allowed for in-game music */
1894 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1895 gamemode = GAME_MODE_PLAYING;
1900 default_levelset_music = music;
1903 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1904 levelset.music[level] = music;
1905 if (gamemode != GAME_MODE_PLAYING)
1906 menu.music[gamemode] = music;
1909 /* now set all '-1' values to menu specific default values */
1910 /* (undefined values of "levelset.music[]" might stay at "-1" to
1911 allow dynamic selection of music files from music directory!) */
1912 for (i = 0; i < MAX_LEVELS; i++)
1913 if (levelset.music[i] == -1)
1914 levelset.music[i] = default_levelset_music;
1915 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1916 if (menu.music[i] == -1)
1917 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1920 static void set_music_parameters(int music, char **parameter_raw)
1922 int parameter[NUM_MUS_ARGS];
1925 /* get integer values from string parameters */
1926 for (i = 0; i < NUM_MUS_ARGS; i++)
1928 get_parameter_value(parameter_raw[i],
1929 music_config_suffix[i].token,
1930 music_config_suffix[i].type);
1932 /* explicit loop mode setting in configuration overrides default value */
1933 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1934 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1937 static void InitMusicInfo()
1939 int num_music = getMusicListSize();
1942 checked_free(music_info);
1944 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1946 for (i = 0; i < num_music; i++)
1948 struct FileInfo *music = getMusicListEntry(i);
1949 int len_music_text = strlen(music->token);
1951 music_info[i].loop = TRUE; /* default: play music in loop mode */
1953 /* determine all loop music */
1955 for (j = 0; music_prefix_info[j].prefix; j++)
1957 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1959 if (len_prefix_text < len_music_text &&
1960 strncmp(music->token,
1961 music_prefix_info[j].prefix, len_prefix_text) == 0)
1963 music_info[i].loop = music_prefix_info[j].is_loop_music;
1969 set_music_parameters(i, music->parameter);
1973 static void ReinitializeGraphics()
1975 print_timestamp_init("ReinitializeGraphics");
1977 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
1979 InitGraphicInfo(); /* graphic properties mapping */
1980 print_timestamp_time("InitGraphicInfo");
1981 InitElementGraphicInfo(); /* element game graphic mapping */
1982 print_timestamp_time("InitElementGraphicInfo");
1983 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1984 print_timestamp_time("InitElementSpecialGraphicInfo");
1986 InitElementSmallImages(); /* scale elements to all needed sizes */
1987 print_timestamp_time("InitElementSmallImages");
1988 InitScaledImages(); /* scale all other images, if needed */
1989 print_timestamp_time("InitScaledImages");
1990 InitBitmapPointers(); /* set standard size bitmap pointers */
1991 print_timestamp_time("InitBitmapPointers");
1992 InitFontGraphicInfo(); /* initialize text drawing functions */
1993 print_timestamp_time("InitFontGraphicInfo");
1994 InitGlobalAnimGraphicInfo(); /* initialize global animations */
1995 print_timestamp_time("InitGlobalAnimGraphicInfo");
1997 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1998 print_timestamp_time("InitGraphicInfo_EM");
2000 InitGraphicCompatibilityInfo();
2001 print_timestamp_time("InitGraphicCompatibilityInfo");
2003 SetMainBackgroundImage(IMG_BACKGROUND);
2004 print_timestamp_time("SetMainBackgroundImage");
2005 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2006 print_timestamp_time("SetDoorBackgroundImage");
2009 print_timestamp_time("InitGadgets");
2011 print_timestamp_time("InitToons");
2013 print_timestamp_time("InitDoors");
2015 print_timestamp_done("ReinitializeGraphics");
2018 static void ReinitializeSounds()
2020 InitSoundInfo(); /* sound properties mapping */
2021 InitElementSoundInfo(); /* element game sound mapping */
2022 InitGameModeSoundInfo(); /* game mode sound mapping */
2024 InitPlayLevelSound(); /* internal game sound settings */
2027 static void ReinitializeMusic()
2029 InitMusicInfo(); /* music properties mapping */
2030 InitGameModeMusicInfo(); /* game mode music mapping */
2033 static int get_special_property_bit(int element, int property_bit_nr)
2035 struct PropertyBitInfo
2041 static struct PropertyBitInfo pb_can_move_into_acid[] =
2043 /* the player may be able fall into acid when gravity is activated */
2048 { EL_SP_MURPHY, 0 },
2049 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2051 /* all elements that can move may be able to also move into acid */
2054 { EL_BUG_RIGHT, 1 },
2057 { EL_SPACESHIP, 2 },
2058 { EL_SPACESHIP_LEFT, 2 },
2059 { EL_SPACESHIP_RIGHT, 2 },
2060 { EL_SPACESHIP_UP, 2 },
2061 { EL_SPACESHIP_DOWN, 2 },
2062 { EL_BD_BUTTERFLY, 3 },
2063 { EL_BD_BUTTERFLY_LEFT, 3 },
2064 { EL_BD_BUTTERFLY_RIGHT, 3 },
2065 { EL_BD_BUTTERFLY_UP, 3 },
2066 { EL_BD_BUTTERFLY_DOWN, 3 },
2067 { EL_BD_FIREFLY, 4 },
2068 { EL_BD_FIREFLY_LEFT, 4 },
2069 { EL_BD_FIREFLY_RIGHT, 4 },
2070 { EL_BD_FIREFLY_UP, 4 },
2071 { EL_BD_FIREFLY_DOWN, 4 },
2073 { EL_YAMYAM_LEFT, 5 },
2074 { EL_YAMYAM_RIGHT, 5 },
2075 { EL_YAMYAM_UP, 5 },
2076 { EL_YAMYAM_DOWN, 5 },
2077 { EL_DARK_YAMYAM, 6 },
2080 { EL_PACMAN_LEFT, 8 },
2081 { EL_PACMAN_RIGHT, 8 },
2082 { EL_PACMAN_UP, 8 },
2083 { EL_PACMAN_DOWN, 8 },
2085 { EL_MOLE_LEFT, 9 },
2086 { EL_MOLE_RIGHT, 9 },
2088 { EL_MOLE_DOWN, 9 },
2092 { EL_SATELLITE, 13 },
2093 { EL_SP_SNIKSNAK, 14 },
2094 { EL_SP_ELECTRON, 15 },
2097 { EL_EMC_ANDROID, 18 },
2102 static struct PropertyBitInfo pb_dont_collide_with[] =
2104 { EL_SP_SNIKSNAK, 0 },
2105 { EL_SP_ELECTRON, 1 },
2113 struct PropertyBitInfo *pb_info;
2116 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2117 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2122 struct PropertyBitInfo *pb_info = NULL;
2125 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2126 if (pb_definition[i].bit_nr == property_bit_nr)
2127 pb_info = pb_definition[i].pb_info;
2129 if (pb_info == NULL)
2132 for (i = 0; pb_info[i].element != -1; i++)
2133 if (pb_info[i].element == element)
2134 return pb_info[i].bit_nr;
2139 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2140 boolean property_value)
2142 int bit_nr = get_special_property_bit(element, property_bit_nr);
2147 *bitfield |= (1 << bit_nr);
2149 *bitfield &= ~(1 << bit_nr);
2153 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2155 int bit_nr = get_special_property_bit(element, property_bit_nr);
2158 return ((*bitfield & (1 << bit_nr)) != 0);
2163 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2165 static int group_nr;
2166 static struct ElementGroupInfo *group;
2167 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2170 if (actual_group == NULL) /* not yet initialized */
2173 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2175 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2176 group_element - EL_GROUP_START + 1);
2178 /* replace element which caused too deep recursion by question mark */
2179 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2184 if (recursion_depth == 0) /* initialization */
2186 group = actual_group;
2187 group_nr = GROUP_NR(group_element);
2189 group->num_elements_resolved = 0;
2190 group->choice_pos = 0;
2192 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2193 element_info[i].in_group[group_nr] = FALSE;
2196 for (i = 0; i < actual_group->num_elements; i++)
2198 int element = actual_group->element[i];
2200 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2203 if (IS_GROUP_ELEMENT(element))
2204 ResolveGroupElementExt(element, recursion_depth + 1);
2207 group->element_resolved[group->num_elements_resolved++] = element;
2208 element_info[element].in_group[group_nr] = TRUE;
2213 void ResolveGroupElement(int group_element)
2215 ResolveGroupElementExt(group_element, 0);
2218 void InitElementPropertiesStatic()
2220 static boolean clipboard_elements_initialized = FALSE;
2222 static int ep_diggable[] =
2227 EL_SP_BUGGY_BASE_ACTIVATING,
2230 EL_INVISIBLE_SAND_ACTIVE,
2233 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2234 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2239 EL_SP_BUGGY_BASE_ACTIVE,
2246 static int ep_collectible_only[] =
2268 EL_DYNABOMB_INCREASE_NUMBER,
2269 EL_DYNABOMB_INCREASE_SIZE,
2270 EL_DYNABOMB_INCREASE_POWER,
2288 /* !!! handle separately !!! */
2289 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2295 static int ep_dont_run_into[] =
2297 /* same elements as in 'ep_dont_touch' */
2303 /* same elements as in 'ep_dont_collide_with' */
2315 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2320 EL_SP_BUGGY_BASE_ACTIVE,
2327 static int ep_dont_collide_with[] =
2329 /* same elements as in 'ep_dont_touch' */
2346 static int ep_dont_touch[] =
2356 static int ep_indestructible[] =
2360 EL_ACID_POOL_TOPLEFT,
2361 EL_ACID_POOL_TOPRIGHT,
2362 EL_ACID_POOL_BOTTOMLEFT,
2363 EL_ACID_POOL_BOTTOM,
2364 EL_ACID_POOL_BOTTOMRIGHT,
2365 EL_SP_HARDWARE_GRAY,
2366 EL_SP_HARDWARE_GREEN,
2367 EL_SP_HARDWARE_BLUE,
2369 EL_SP_HARDWARE_YELLOW,
2370 EL_SP_HARDWARE_BASE_1,
2371 EL_SP_HARDWARE_BASE_2,
2372 EL_SP_HARDWARE_BASE_3,
2373 EL_SP_HARDWARE_BASE_4,
2374 EL_SP_HARDWARE_BASE_5,
2375 EL_SP_HARDWARE_BASE_6,
2376 EL_INVISIBLE_STEELWALL,
2377 EL_INVISIBLE_STEELWALL_ACTIVE,
2378 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2379 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2380 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2381 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2382 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2383 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2384 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2385 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2386 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2387 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2388 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2389 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2391 EL_LIGHT_SWITCH_ACTIVE,
2392 EL_SIGN_EXCLAMATION,
2393 EL_SIGN_RADIOACTIVITY,
2400 EL_SIGN_ENTRY_FORBIDDEN,
2401 EL_SIGN_EMERGENCY_EXIT,
2409 EL_STEEL_EXIT_CLOSED,
2411 EL_STEEL_EXIT_OPENING,
2412 EL_STEEL_EXIT_CLOSING,
2413 EL_EM_STEEL_EXIT_CLOSED,
2414 EL_EM_STEEL_EXIT_OPEN,
2415 EL_EM_STEEL_EXIT_OPENING,
2416 EL_EM_STEEL_EXIT_CLOSING,
2417 EL_DC_STEELWALL_1_LEFT,
2418 EL_DC_STEELWALL_1_RIGHT,
2419 EL_DC_STEELWALL_1_TOP,
2420 EL_DC_STEELWALL_1_BOTTOM,
2421 EL_DC_STEELWALL_1_HORIZONTAL,
2422 EL_DC_STEELWALL_1_VERTICAL,
2423 EL_DC_STEELWALL_1_TOPLEFT,
2424 EL_DC_STEELWALL_1_TOPRIGHT,
2425 EL_DC_STEELWALL_1_BOTTOMLEFT,
2426 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2427 EL_DC_STEELWALL_1_TOPLEFT_2,
2428 EL_DC_STEELWALL_1_TOPRIGHT_2,
2429 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2430 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2431 EL_DC_STEELWALL_2_LEFT,
2432 EL_DC_STEELWALL_2_RIGHT,
2433 EL_DC_STEELWALL_2_TOP,
2434 EL_DC_STEELWALL_2_BOTTOM,
2435 EL_DC_STEELWALL_2_HORIZONTAL,
2436 EL_DC_STEELWALL_2_VERTICAL,
2437 EL_DC_STEELWALL_2_MIDDLE,
2438 EL_DC_STEELWALL_2_SINGLE,
2439 EL_STEELWALL_SLIPPERY,
2453 EL_GATE_1_GRAY_ACTIVE,
2454 EL_GATE_2_GRAY_ACTIVE,
2455 EL_GATE_3_GRAY_ACTIVE,
2456 EL_GATE_4_GRAY_ACTIVE,
2465 EL_EM_GATE_1_GRAY_ACTIVE,
2466 EL_EM_GATE_2_GRAY_ACTIVE,
2467 EL_EM_GATE_3_GRAY_ACTIVE,
2468 EL_EM_GATE_4_GRAY_ACTIVE,
2477 EL_EMC_GATE_5_GRAY_ACTIVE,
2478 EL_EMC_GATE_6_GRAY_ACTIVE,
2479 EL_EMC_GATE_7_GRAY_ACTIVE,
2480 EL_EMC_GATE_8_GRAY_ACTIVE,
2482 EL_DC_GATE_WHITE_GRAY,
2483 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2484 EL_DC_GATE_FAKE_GRAY,
2486 EL_SWITCHGATE_OPENING,
2487 EL_SWITCHGATE_CLOSED,
2488 EL_SWITCHGATE_CLOSING,
2489 EL_DC_SWITCHGATE_SWITCH_UP,
2490 EL_DC_SWITCHGATE_SWITCH_DOWN,
2492 EL_TIMEGATE_OPENING,
2494 EL_TIMEGATE_CLOSING,
2495 EL_DC_TIMEGATE_SWITCH,
2496 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2500 EL_TUBE_VERTICAL_LEFT,
2501 EL_TUBE_VERTICAL_RIGHT,
2502 EL_TUBE_HORIZONTAL_UP,
2503 EL_TUBE_HORIZONTAL_DOWN,
2508 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2509 EL_EXPANDABLE_STEELWALL_VERTICAL,
2510 EL_EXPANDABLE_STEELWALL_ANY,
2515 static int ep_slippery[] =
2529 EL_ROBOT_WHEEL_ACTIVE,
2535 EL_ACID_POOL_TOPLEFT,
2536 EL_ACID_POOL_TOPRIGHT,
2546 EL_STEELWALL_SLIPPERY,
2549 EL_EMC_WALL_SLIPPERY_1,
2550 EL_EMC_WALL_SLIPPERY_2,
2551 EL_EMC_WALL_SLIPPERY_3,
2552 EL_EMC_WALL_SLIPPERY_4,
2554 EL_EMC_MAGIC_BALL_ACTIVE,
2559 static int ep_can_change[] =
2564 static int ep_can_move[] =
2566 /* same elements as in 'pb_can_move_into_acid' */
2589 static int ep_can_fall[] =
2603 EL_QUICKSAND_FAST_FULL,
2605 EL_BD_MAGIC_WALL_FULL,
2606 EL_DC_MAGIC_WALL_FULL,
2620 static int ep_can_smash_player[] =
2646 static int ep_can_smash_enemies[] =
2655 static int ep_can_smash_everything[] =
2664 static int ep_explodes_by_fire[] =
2666 /* same elements as in 'ep_explodes_impact' */
2671 /* same elements as in 'ep_explodes_smashed' */
2681 EL_EM_DYNAMITE_ACTIVE,
2682 EL_DYNABOMB_PLAYER_1_ACTIVE,
2683 EL_DYNABOMB_PLAYER_2_ACTIVE,
2684 EL_DYNABOMB_PLAYER_3_ACTIVE,
2685 EL_DYNABOMB_PLAYER_4_ACTIVE,
2686 EL_DYNABOMB_INCREASE_NUMBER,
2687 EL_DYNABOMB_INCREASE_SIZE,
2688 EL_DYNABOMB_INCREASE_POWER,
2689 EL_SP_DISK_RED_ACTIVE,
2703 static int ep_explodes_smashed[] =
2705 /* same elements as in 'ep_explodes_impact' */
2719 static int ep_explodes_impact[] =
2728 static int ep_walkable_over[] =
2732 EL_SOKOBAN_FIELD_EMPTY,
2739 EL_EM_STEEL_EXIT_OPEN,
2740 EL_EM_STEEL_EXIT_OPENING,
2749 EL_GATE_1_GRAY_ACTIVE,
2750 EL_GATE_2_GRAY_ACTIVE,
2751 EL_GATE_3_GRAY_ACTIVE,
2752 EL_GATE_4_GRAY_ACTIVE,
2760 static int ep_walkable_inside[] =
2765 EL_TUBE_VERTICAL_LEFT,
2766 EL_TUBE_VERTICAL_RIGHT,
2767 EL_TUBE_HORIZONTAL_UP,
2768 EL_TUBE_HORIZONTAL_DOWN,
2777 static int ep_walkable_under[] =
2782 static int ep_passable_over[] =
2792 EL_EM_GATE_1_GRAY_ACTIVE,
2793 EL_EM_GATE_2_GRAY_ACTIVE,
2794 EL_EM_GATE_3_GRAY_ACTIVE,
2795 EL_EM_GATE_4_GRAY_ACTIVE,
2804 EL_EMC_GATE_5_GRAY_ACTIVE,
2805 EL_EMC_GATE_6_GRAY_ACTIVE,
2806 EL_EMC_GATE_7_GRAY_ACTIVE,
2807 EL_EMC_GATE_8_GRAY_ACTIVE,
2809 EL_DC_GATE_WHITE_GRAY,
2810 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2817 static int ep_passable_inside[] =
2823 EL_SP_PORT_HORIZONTAL,
2824 EL_SP_PORT_VERTICAL,
2826 EL_SP_GRAVITY_PORT_LEFT,
2827 EL_SP_GRAVITY_PORT_RIGHT,
2828 EL_SP_GRAVITY_PORT_UP,
2829 EL_SP_GRAVITY_PORT_DOWN,
2830 EL_SP_GRAVITY_ON_PORT_LEFT,
2831 EL_SP_GRAVITY_ON_PORT_RIGHT,
2832 EL_SP_GRAVITY_ON_PORT_UP,
2833 EL_SP_GRAVITY_ON_PORT_DOWN,
2834 EL_SP_GRAVITY_OFF_PORT_LEFT,
2835 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2836 EL_SP_GRAVITY_OFF_PORT_UP,
2837 EL_SP_GRAVITY_OFF_PORT_DOWN,
2842 static int ep_passable_under[] =
2847 static int ep_droppable[] =
2852 static int ep_explodes_1x1_old[] =
2857 static int ep_pushable[] =
2869 EL_SOKOBAN_FIELD_FULL,
2878 static int ep_explodes_cross_old[] =
2883 static int ep_protected[] =
2885 /* same elements as in 'ep_walkable_inside' */
2889 EL_TUBE_VERTICAL_LEFT,
2890 EL_TUBE_VERTICAL_RIGHT,
2891 EL_TUBE_HORIZONTAL_UP,
2892 EL_TUBE_HORIZONTAL_DOWN,
2898 /* same elements as in 'ep_passable_over' */
2907 EL_EM_GATE_1_GRAY_ACTIVE,
2908 EL_EM_GATE_2_GRAY_ACTIVE,
2909 EL_EM_GATE_3_GRAY_ACTIVE,
2910 EL_EM_GATE_4_GRAY_ACTIVE,
2919 EL_EMC_GATE_5_GRAY_ACTIVE,
2920 EL_EMC_GATE_6_GRAY_ACTIVE,
2921 EL_EMC_GATE_7_GRAY_ACTIVE,
2922 EL_EMC_GATE_8_GRAY_ACTIVE,
2924 EL_DC_GATE_WHITE_GRAY,
2925 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2929 /* same elements as in 'ep_passable_inside' */
2934 EL_SP_PORT_HORIZONTAL,
2935 EL_SP_PORT_VERTICAL,
2937 EL_SP_GRAVITY_PORT_LEFT,
2938 EL_SP_GRAVITY_PORT_RIGHT,
2939 EL_SP_GRAVITY_PORT_UP,
2940 EL_SP_GRAVITY_PORT_DOWN,
2941 EL_SP_GRAVITY_ON_PORT_LEFT,
2942 EL_SP_GRAVITY_ON_PORT_RIGHT,
2943 EL_SP_GRAVITY_ON_PORT_UP,
2944 EL_SP_GRAVITY_ON_PORT_DOWN,
2945 EL_SP_GRAVITY_OFF_PORT_LEFT,
2946 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2947 EL_SP_GRAVITY_OFF_PORT_UP,
2948 EL_SP_GRAVITY_OFF_PORT_DOWN,
2953 static int ep_throwable[] =
2958 static int ep_can_explode[] =
2960 /* same elements as in 'ep_explodes_impact' */
2965 /* same elements as in 'ep_explodes_smashed' */
2971 /* elements that can explode by explosion or by dragonfire */
2975 EL_EM_DYNAMITE_ACTIVE,
2976 EL_DYNABOMB_PLAYER_1_ACTIVE,
2977 EL_DYNABOMB_PLAYER_2_ACTIVE,
2978 EL_DYNABOMB_PLAYER_3_ACTIVE,
2979 EL_DYNABOMB_PLAYER_4_ACTIVE,
2980 EL_DYNABOMB_INCREASE_NUMBER,
2981 EL_DYNABOMB_INCREASE_SIZE,
2982 EL_DYNABOMB_INCREASE_POWER,
2983 EL_SP_DISK_RED_ACTIVE,
2991 /* elements that can explode only by explosion */
2997 static int ep_gravity_reachable[] =
3003 EL_INVISIBLE_SAND_ACTIVE,
3008 EL_SP_PORT_HORIZONTAL,
3009 EL_SP_PORT_VERTICAL,
3011 EL_SP_GRAVITY_PORT_LEFT,
3012 EL_SP_GRAVITY_PORT_RIGHT,
3013 EL_SP_GRAVITY_PORT_UP,
3014 EL_SP_GRAVITY_PORT_DOWN,
3015 EL_SP_GRAVITY_ON_PORT_LEFT,
3016 EL_SP_GRAVITY_ON_PORT_RIGHT,
3017 EL_SP_GRAVITY_ON_PORT_UP,
3018 EL_SP_GRAVITY_ON_PORT_DOWN,
3019 EL_SP_GRAVITY_OFF_PORT_LEFT,
3020 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3021 EL_SP_GRAVITY_OFF_PORT_UP,
3022 EL_SP_GRAVITY_OFF_PORT_DOWN,
3028 static int ep_player[] =
3035 EL_SOKOBAN_FIELD_PLAYER,
3041 static int ep_can_pass_magic_wall[] =
3055 static int ep_can_pass_dc_magic_wall[] =
3071 static int ep_switchable[] =
3075 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3076 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3077 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3078 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3079 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3080 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3081 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3082 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3083 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3084 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3085 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3086 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3087 EL_SWITCHGATE_SWITCH_UP,
3088 EL_SWITCHGATE_SWITCH_DOWN,
3089 EL_DC_SWITCHGATE_SWITCH_UP,
3090 EL_DC_SWITCHGATE_SWITCH_DOWN,
3092 EL_LIGHT_SWITCH_ACTIVE,
3094 EL_DC_TIMEGATE_SWITCH,
3095 EL_BALLOON_SWITCH_LEFT,
3096 EL_BALLOON_SWITCH_RIGHT,
3097 EL_BALLOON_SWITCH_UP,
3098 EL_BALLOON_SWITCH_DOWN,
3099 EL_BALLOON_SWITCH_ANY,
3100 EL_BALLOON_SWITCH_NONE,
3103 EL_EMC_MAGIC_BALL_SWITCH,
3104 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3109 static int ep_bd_element[] =
3143 static int ep_sp_element[] =
3145 /* should always be valid */
3148 /* standard classic Supaplex elements */
3155 EL_SP_HARDWARE_GRAY,
3163 EL_SP_GRAVITY_PORT_RIGHT,
3164 EL_SP_GRAVITY_PORT_DOWN,
3165 EL_SP_GRAVITY_PORT_LEFT,
3166 EL_SP_GRAVITY_PORT_UP,
3171 EL_SP_PORT_VERTICAL,
3172 EL_SP_PORT_HORIZONTAL,
3178 EL_SP_HARDWARE_BASE_1,
3179 EL_SP_HARDWARE_GREEN,
3180 EL_SP_HARDWARE_BLUE,
3182 EL_SP_HARDWARE_YELLOW,
3183 EL_SP_HARDWARE_BASE_2,
3184 EL_SP_HARDWARE_BASE_3,
3185 EL_SP_HARDWARE_BASE_4,
3186 EL_SP_HARDWARE_BASE_5,
3187 EL_SP_HARDWARE_BASE_6,
3191 /* additional elements that appeared in newer Supaplex levels */
3194 /* additional gravity port elements (not switching, but setting gravity) */
3195 EL_SP_GRAVITY_ON_PORT_LEFT,
3196 EL_SP_GRAVITY_ON_PORT_RIGHT,
3197 EL_SP_GRAVITY_ON_PORT_UP,
3198 EL_SP_GRAVITY_ON_PORT_DOWN,
3199 EL_SP_GRAVITY_OFF_PORT_LEFT,
3200 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3201 EL_SP_GRAVITY_OFF_PORT_UP,
3202 EL_SP_GRAVITY_OFF_PORT_DOWN,
3204 /* more than one Murphy in a level results in an inactive clone */
3207 /* runtime Supaplex elements */
3208 EL_SP_DISK_RED_ACTIVE,
3209 EL_SP_TERMINAL_ACTIVE,
3210 EL_SP_BUGGY_BASE_ACTIVATING,
3211 EL_SP_BUGGY_BASE_ACTIVE,
3218 static int ep_sb_element[] =
3223 EL_SOKOBAN_FIELD_EMPTY,
3224 EL_SOKOBAN_FIELD_FULL,
3225 EL_SOKOBAN_FIELD_PLAYER,
3230 EL_INVISIBLE_STEELWALL,
3235 static int ep_gem[] =
3247 static int ep_food_dark_yamyam[] =
3275 static int ep_food_penguin[] =
3289 static int ep_food_pig[] =
3301 static int ep_historic_wall[] =
3312 EL_GATE_1_GRAY_ACTIVE,
3313 EL_GATE_2_GRAY_ACTIVE,
3314 EL_GATE_3_GRAY_ACTIVE,
3315 EL_GATE_4_GRAY_ACTIVE,
3324 EL_EM_GATE_1_GRAY_ACTIVE,
3325 EL_EM_GATE_2_GRAY_ACTIVE,
3326 EL_EM_GATE_3_GRAY_ACTIVE,
3327 EL_EM_GATE_4_GRAY_ACTIVE,
3334 EL_EXPANDABLE_WALL_HORIZONTAL,
3335 EL_EXPANDABLE_WALL_VERTICAL,
3336 EL_EXPANDABLE_WALL_ANY,
3337 EL_EXPANDABLE_WALL_GROWING,
3338 EL_BD_EXPANDABLE_WALL,
3345 EL_SP_HARDWARE_GRAY,
3346 EL_SP_HARDWARE_GREEN,
3347 EL_SP_HARDWARE_BLUE,
3349 EL_SP_HARDWARE_YELLOW,
3350 EL_SP_HARDWARE_BASE_1,
3351 EL_SP_HARDWARE_BASE_2,
3352 EL_SP_HARDWARE_BASE_3,
3353 EL_SP_HARDWARE_BASE_4,
3354 EL_SP_HARDWARE_BASE_5,
3355 EL_SP_HARDWARE_BASE_6,
3357 EL_SP_TERMINAL_ACTIVE,
3360 EL_INVISIBLE_STEELWALL,
3361 EL_INVISIBLE_STEELWALL_ACTIVE,
3363 EL_INVISIBLE_WALL_ACTIVE,
3364 EL_STEELWALL_SLIPPERY,
3381 static int ep_historic_solid[] =
3385 EL_EXPANDABLE_WALL_HORIZONTAL,
3386 EL_EXPANDABLE_WALL_VERTICAL,
3387 EL_EXPANDABLE_WALL_ANY,
3388 EL_BD_EXPANDABLE_WALL,
3401 EL_QUICKSAND_FILLING,
3402 EL_QUICKSAND_EMPTYING,
3404 EL_MAGIC_WALL_ACTIVE,
3405 EL_MAGIC_WALL_EMPTYING,
3406 EL_MAGIC_WALL_FILLING,
3410 EL_BD_MAGIC_WALL_ACTIVE,
3411 EL_BD_MAGIC_WALL_EMPTYING,
3412 EL_BD_MAGIC_WALL_FULL,
3413 EL_BD_MAGIC_WALL_FILLING,
3414 EL_BD_MAGIC_WALL_DEAD,
3423 EL_SP_TERMINAL_ACTIVE,
3427 EL_INVISIBLE_WALL_ACTIVE,
3428 EL_SWITCHGATE_SWITCH_UP,
3429 EL_SWITCHGATE_SWITCH_DOWN,
3430 EL_DC_SWITCHGATE_SWITCH_UP,
3431 EL_DC_SWITCHGATE_SWITCH_DOWN,
3433 EL_TIMEGATE_SWITCH_ACTIVE,
3434 EL_DC_TIMEGATE_SWITCH,
3435 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3447 /* the following elements are a direct copy of "indestructible" elements,
3448 except "EL_ACID", which is "indestructible", but not "solid"! */
3453 EL_ACID_POOL_TOPLEFT,
3454 EL_ACID_POOL_TOPRIGHT,
3455 EL_ACID_POOL_BOTTOMLEFT,
3456 EL_ACID_POOL_BOTTOM,
3457 EL_ACID_POOL_BOTTOMRIGHT,
3458 EL_SP_HARDWARE_GRAY,
3459 EL_SP_HARDWARE_GREEN,
3460 EL_SP_HARDWARE_BLUE,
3462 EL_SP_HARDWARE_YELLOW,
3463 EL_SP_HARDWARE_BASE_1,
3464 EL_SP_HARDWARE_BASE_2,
3465 EL_SP_HARDWARE_BASE_3,
3466 EL_SP_HARDWARE_BASE_4,
3467 EL_SP_HARDWARE_BASE_5,
3468 EL_SP_HARDWARE_BASE_6,
3469 EL_INVISIBLE_STEELWALL,
3470 EL_INVISIBLE_STEELWALL_ACTIVE,
3471 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3472 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3473 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3474 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3475 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3476 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3477 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3478 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3479 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3480 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3481 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3482 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3484 EL_LIGHT_SWITCH_ACTIVE,
3485 EL_SIGN_EXCLAMATION,
3486 EL_SIGN_RADIOACTIVITY,
3493 EL_SIGN_ENTRY_FORBIDDEN,
3494 EL_SIGN_EMERGENCY_EXIT,
3502 EL_STEEL_EXIT_CLOSED,
3504 EL_DC_STEELWALL_1_LEFT,
3505 EL_DC_STEELWALL_1_RIGHT,
3506 EL_DC_STEELWALL_1_TOP,
3507 EL_DC_STEELWALL_1_BOTTOM,
3508 EL_DC_STEELWALL_1_HORIZONTAL,
3509 EL_DC_STEELWALL_1_VERTICAL,
3510 EL_DC_STEELWALL_1_TOPLEFT,
3511 EL_DC_STEELWALL_1_TOPRIGHT,
3512 EL_DC_STEELWALL_1_BOTTOMLEFT,
3513 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3514 EL_DC_STEELWALL_1_TOPLEFT_2,
3515 EL_DC_STEELWALL_1_TOPRIGHT_2,
3516 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3517 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3518 EL_DC_STEELWALL_2_LEFT,
3519 EL_DC_STEELWALL_2_RIGHT,
3520 EL_DC_STEELWALL_2_TOP,
3521 EL_DC_STEELWALL_2_BOTTOM,
3522 EL_DC_STEELWALL_2_HORIZONTAL,
3523 EL_DC_STEELWALL_2_VERTICAL,
3524 EL_DC_STEELWALL_2_MIDDLE,
3525 EL_DC_STEELWALL_2_SINGLE,
3526 EL_STEELWALL_SLIPPERY,
3540 EL_GATE_1_GRAY_ACTIVE,
3541 EL_GATE_2_GRAY_ACTIVE,
3542 EL_GATE_3_GRAY_ACTIVE,
3543 EL_GATE_4_GRAY_ACTIVE,
3552 EL_EM_GATE_1_GRAY_ACTIVE,
3553 EL_EM_GATE_2_GRAY_ACTIVE,
3554 EL_EM_GATE_3_GRAY_ACTIVE,
3555 EL_EM_GATE_4_GRAY_ACTIVE,
3557 EL_SWITCHGATE_OPENING,
3558 EL_SWITCHGATE_CLOSED,
3559 EL_SWITCHGATE_CLOSING,
3561 EL_TIMEGATE_OPENING,
3563 EL_TIMEGATE_CLOSING,
3567 EL_TUBE_VERTICAL_LEFT,
3568 EL_TUBE_VERTICAL_RIGHT,
3569 EL_TUBE_HORIZONTAL_UP,
3570 EL_TUBE_HORIZONTAL_DOWN,
3579 static int ep_classic_enemy[] =
3596 static int ep_belt[] =
3598 EL_CONVEYOR_BELT_1_LEFT,
3599 EL_CONVEYOR_BELT_1_MIDDLE,
3600 EL_CONVEYOR_BELT_1_RIGHT,
3601 EL_CONVEYOR_BELT_2_LEFT,
3602 EL_CONVEYOR_BELT_2_MIDDLE,
3603 EL_CONVEYOR_BELT_2_RIGHT,
3604 EL_CONVEYOR_BELT_3_LEFT,
3605 EL_CONVEYOR_BELT_3_MIDDLE,
3606 EL_CONVEYOR_BELT_3_RIGHT,
3607 EL_CONVEYOR_BELT_4_LEFT,
3608 EL_CONVEYOR_BELT_4_MIDDLE,
3609 EL_CONVEYOR_BELT_4_RIGHT,
3614 static int ep_belt_active[] =
3616 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3617 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3618 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3619 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3620 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3621 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3622 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3623 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3624 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3625 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3626 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3627 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3632 static int ep_belt_switch[] =
3634 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3635 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3636 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3637 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3638 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3639 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3640 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3641 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3642 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3643 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3644 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3645 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3650 static int ep_tube[] =
3657 EL_TUBE_HORIZONTAL_UP,
3658 EL_TUBE_HORIZONTAL_DOWN,
3660 EL_TUBE_VERTICAL_LEFT,
3661 EL_TUBE_VERTICAL_RIGHT,
3667 static int ep_acid_pool[] =
3669 EL_ACID_POOL_TOPLEFT,
3670 EL_ACID_POOL_TOPRIGHT,
3671 EL_ACID_POOL_BOTTOMLEFT,
3672 EL_ACID_POOL_BOTTOM,
3673 EL_ACID_POOL_BOTTOMRIGHT,
3678 static int ep_keygate[] =
3688 EL_GATE_1_GRAY_ACTIVE,
3689 EL_GATE_2_GRAY_ACTIVE,
3690 EL_GATE_3_GRAY_ACTIVE,
3691 EL_GATE_4_GRAY_ACTIVE,
3700 EL_EM_GATE_1_GRAY_ACTIVE,
3701 EL_EM_GATE_2_GRAY_ACTIVE,
3702 EL_EM_GATE_3_GRAY_ACTIVE,
3703 EL_EM_GATE_4_GRAY_ACTIVE,
3712 EL_EMC_GATE_5_GRAY_ACTIVE,
3713 EL_EMC_GATE_6_GRAY_ACTIVE,
3714 EL_EMC_GATE_7_GRAY_ACTIVE,
3715 EL_EMC_GATE_8_GRAY_ACTIVE,
3717 EL_DC_GATE_WHITE_GRAY,
3718 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3723 static int ep_amoeboid[] =
3735 static int ep_amoebalive[] =
3746 static int ep_has_editor_content[] =
3752 EL_SOKOBAN_FIELD_PLAYER,
3769 static int ep_can_turn_each_move[] =
3771 /* !!! do something with this one !!! */
3775 static int ep_can_grow[] =
3789 static int ep_active_bomb[] =
3792 EL_EM_DYNAMITE_ACTIVE,
3793 EL_DYNABOMB_PLAYER_1_ACTIVE,
3794 EL_DYNABOMB_PLAYER_2_ACTIVE,
3795 EL_DYNABOMB_PLAYER_3_ACTIVE,
3796 EL_DYNABOMB_PLAYER_4_ACTIVE,
3797 EL_SP_DISK_RED_ACTIVE,
3802 static int ep_inactive[] =
3812 EL_QUICKSAND_FAST_EMPTY,
3835 EL_GATE_1_GRAY_ACTIVE,
3836 EL_GATE_2_GRAY_ACTIVE,
3837 EL_GATE_3_GRAY_ACTIVE,
3838 EL_GATE_4_GRAY_ACTIVE,
3847 EL_EM_GATE_1_GRAY_ACTIVE,
3848 EL_EM_GATE_2_GRAY_ACTIVE,
3849 EL_EM_GATE_3_GRAY_ACTIVE,
3850 EL_EM_GATE_4_GRAY_ACTIVE,
3859 EL_EMC_GATE_5_GRAY_ACTIVE,
3860 EL_EMC_GATE_6_GRAY_ACTIVE,
3861 EL_EMC_GATE_7_GRAY_ACTIVE,
3862 EL_EMC_GATE_8_GRAY_ACTIVE,
3864 EL_DC_GATE_WHITE_GRAY,
3865 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3866 EL_DC_GATE_FAKE_GRAY,
3869 EL_INVISIBLE_STEELWALL,
3877 EL_WALL_EMERALD_YELLOW,
3878 EL_DYNABOMB_INCREASE_NUMBER,
3879 EL_DYNABOMB_INCREASE_SIZE,
3880 EL_DYNABOMB_INCREASE_POWER,
3884 EL_SOKOBAN_FIELD_EMPTY,
3885 EL_SOKOBAN_FIELD_FULL,
3886 EL_WALL_EMERALD_RED,
3887 EL_WALL_EMERALD_PURPLE,
3888 EL_ACID_POOL_TOPLEFT,
3889 EL_ACID_POOL_TOPRIGHT,
3890 EL_ACID_POOL_BOTTOMLEFT,
3891 EL_ACID_POOL_BOTTOM,
3892 EL_ACID_POOL_BOTTOMRIGHT,
3896 EL_BD_MAGIC_WALL_DEAD,
3898 EL_DC_MAGIC_WALL_DEAD,
3899 EL_AMOEBA_TO_DIAMOND,
3907 EL_SP_GRAVITY_PORT_RIGHT,
3908 EL_SP_GRAVITY_PORT_DOWN,
3909 EL_SP_GRAVITY_PORT_LEFT,
3910 EL_SP_GRAVITY_PORT_UP,
3911 EL_SP_PORT_HORIZONTAL,
3912 EL_SP_PORT_VERTICAL,
3923 EL_SP_HARDWARE_GRAY,
3924 EL_SP_HARDWARE_GREEN,
3925 EL_SP_HARDWARE_BLUE,
3927 EL_SP_HARDWARE_YELLOW,
3928 EL_SP_HARDWARE_BASE_1,
3929 EL_SP_HARDWARE_BASE_2,
3930 EL_SP_HARDWARE_BASE_3,
3931 EL_SP_HARDWARE_BASE_4,
3932 EL_SP_HARDWARE_BASE_5,
3933 EL_SP_HARDWARE_BASE_6,
3934 EL_SP_GRAVITY_ON_PORT_LEFT,
3935 EL_SP_GRAVITY_ON_PORT_RIGHT,
3936 EL_SP_GRAVITY_ON_PORT_UP,
3937 EL_SP_GRAVITY_ON_PORT_DOWN,
3938 EL_SP_GRAVITY_OFF_PORT_LEFT,
3939 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3940 EL_SP_GRAVITY_OFF_PORT_UP,
3941 EL_SP_GRAVITY_OFF_PORT_DOWN,
3942 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3943 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3944 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3945 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3946 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3947 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3948 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3949 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3950 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3951 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3952 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3953 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3954 EL_SIGN_EXCLAMATION,
3955 EL_SIGN_RADIOACTIVITY,
3962 EL_SIGN_ENTRY_FORBIDDEN,
3963 EL_SIGN_EMERGENCY_EXIT,
3971 EL_DC_STEELWALL_1_LEFT,
3972 EL_DC_STEELWALL_1_RIGHT,
3973 EL_DC_STEELWALL_1_TOP,
3974 EL_DC_STEELWALL_1_BOTTOM,
3975 EL_DC_STEELWALL_1_HORIZONTAL,
3976 EL_DC_STEELWALL_1_VERTICAL,
3977 EL_DC_STEELWALL_1_TOPLEFT,
3978 EL_DC_STEELWALL_1_TOPRIGHT,
3979 EL_DC_STEELWALL_1_BOTTOMLEFT,
3980 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3981 EL_DC_STEELWALL_1_TOPLEFT_2,
3982 EL_DC_STEELWALL_1_TOPRIGHT_2,
3983 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3984 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3985 EL_DC_STEELWALL_2_LEFT,
3986 EL_DC_STEELWALL_2_RIGHT,
3987 EL_DC_STEELWALL_2_TOP,
3988 EL_DC_STEELWALL_2_BOTTOM,
3989 EL_DC_STEELWALL_2_HORIZONTAL,
3990 EL_DC_STEELWALL_2_VERTICAL,
3991 EL_DC_STEELWALL_2_MIDDLE,
3992 EL_DC_STEELWALL_2_SINGLE,
3993 EL_STEELWALL_SLIPPERY,
3998 EL_EMC_WALL_SLIPPERY_1,
3999 EL_EMC_WALL_SLIPPERY_2,
4000 EL_EMC_WALL_SLIPPERY_3,
4001 EL_EMC_WALL_SLIPPERY_4,
4022 static int ep_em_slippery_wall[] =
4027 static int ep_gfx_crumbled[] =
4038 static int ep_editor_cascade_active[] =
4040 EL_INTERNAL_CASCADE_BD_ACTIVE,
4041 EL_INTERNAL_CASCADE_EM_ACTIVE,
4042 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4043 EL_INTERNAL_CASCADE_RND_ACTIVE,
4044 EL_INTERNAL_CASCADE_SB_ACTIVE,
4045 EL_INTERNAL_CASCADE_SP_ACTIVE,
4046 EL_INTERNAL_CASCADE_DC_ACTIVE,
4047 EL_INTERNAL_CASCADE_DX_ACTIVE,
4048 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4049 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4050 EL_INTERNAL_CASCADE_CE_ACTIVE,
4051 EL_INTERNAL_CASCADE_GE_ACTIVE,
4052 EL_INTERNAL_CASCADE_REF_ACTIVE,
4053 EL_INTERNAL_CASCADE_USER_ACTIVE,
4054 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4059 static int ep_editor_cascade_inactive[] =
4061 EL_INTERNAL_CASCADE_BD,
4062 EL_INTERNAL_CASCADE_EM,
4063 EL_INTERNAL_CASCADE_EMC,
4064 EL_INTERNAL_CASCADE_RND,
4065 EL_INTERNAL_CASCADE_SB,
4066 EL_INTERNAL_CASCADE_SP,
4067 EL_INTERNAL_CASCADE_DC,
4068 EL_INTERNAL_CASCADE_DX,
4069 EL_INTERNAL_CASCADE_CHARS,
4070 EL_INTERNAL_CASCADE_STEEL_CHARS,
4071 EL_INTERNAL_CASCADE_CE,
4072 EL_INTERNAL_CASCADE_GE,
4073 EL_INTERNAL_CASCADE_REF,
4074 EL_INTERNAL_CASCADE_USER,
4075 EL_INTERNAL_CASCADE_DYNAMIC,
4080 static int ep_obsolete[] =
4084 EL_EM_KEY_1_FILE_OBSOLETE,
4085 EL_EM_KEY_2_FILE_OBSOLETE,
4086 EL_EM_KEY_3_FILE_OBSOLETE,
4087 EL_EM_KEY_4_FILE_OBSOLETE,
4088 EL_ENVELOPE_OBSOLETE,
4097 } element_properties[] =
4099 { ep_diggable, EP_DIGGABLE },
4100 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4101 { ep_dont_run_into, EP_DONT_RUN_INTO },
4102 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4103 { ep_dont_touch, EP_DONT_TOUCH },
4104 { ep_indestructible, EP_INDESTRUCTIBLE },
4105 { ep_slippery, EP_SLIPPERY },
4106 { ep_can_change, EP_CAN_CHANGE },
4107 { ep_can_move, EP_CAN_MOVE },
4108 { ep_can_fall, EP_CAN_FALL },
4109 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4110 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4111 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4112 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4113 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4114 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4115 { ep_walkable_over, EP_WALKABLE_OVER },
4116 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4117 { ep_walkable_under, EP_WALKABLE_UNDER },
4118 { ep_passable_over, EP_PASSABLE_OVER },
4119 { ep_passable_inside, EP_PASSABLE_INSIDE },
4120 { ep_passable_under, EP_PASSABLE_UNDER },
4121 { ep_droppable, EP_DROPPABLE },
4122 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4123 { ep_pushable, EP_PUSHABLE },
4124 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4125 { ep_protected, EP_PROTECTED },
4126 { ep_throwable, EP_THROWABLE },
4127 { ep_can_explode, EP_CAN_EXPLODE },
4128 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4130 { ep_player, EP_PLAYER },
4131 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4132 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4133 { ep_switchable, EP_SWITCHABLE },
4134 { ep_bd_element, EP_BD_ELEMENT },
4135 { ep_sp_element, EP_SP_ELEMENT },
4136 { ep_sb_element, EP_SB_ELEMENT },
4138 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4139 { ep_food_penguin, EP_FOOD_PENGUIN },
4140 { ep_food_pig, EP_FOOD_PIG },
4141 { ep_historic_wall, EP_HISTORIC_WALL },
4142 { ep_historic_solid, EP_HISTORIC_SOLID },
4143 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4144 { ep_belt, EP_BELT },
4145 { ep_belt_active, EP_BELT_ACTIVE },
4146 { ep_belt_switch, EP_BELT_SWITCH },
4147 { ep_tube, EP_TUBE },
4148 { ep_acid_pool, EP_ACID_POOL },
4149 { ep_keygate, EP_KEYGATE },
4150 { ep_amoeboid, EP_AMOEBOID },
4151 { ep_amoebalive, EP_AMOEBALIVE },
4152 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4153 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4154 { ep_can_grow, EP_CAN_GROW },
4155 { ep_active_bomb, EP_ACTIVE_BOMB },
4156 { ep_inactive, EP_INACTIVE },
4158 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4160 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4162 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4163 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4165 { ep_obsolete, EP_OBSOLETE },
4172 /* always start with reliable default values (element has no properties) */
4173 /* (but never initialize clipboard elements after the very first time) */
4174 /* (to be able to use clipboard elements between several levels) */
4175 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4176 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4177 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4178 SET_PROPERTY(i, j, FALSE);
4180 /* set all base element properties from above array definitions */
4181 for (i = 0; element_properties[i].elements != NULL; i++)
4182 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4183 SET_PROPERTY((element_properties[i].elements)[j],
4184 element_properties[i].property, TRUE);
4186 /* copy properties to some elements that are only stored in level file */
4187 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4188 for (j = 0; copy_properties[j][0] != -1; j++)
4189 if (HAS_PROPERTY(copy_properties[j][0], i))
4190 for (k = 1; k <= 4; k++)
4191 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4193 /* set static element properties that are not listed in array definitions */
4194 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4195 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4197 clipboard_elements_initialized = TRUE;
4200 void InitElementPropertiesEngine(int engine_version)
4202 static int no_wall_properties[] =
4205 EP_COLLECTIBLE_ONLY,
4207 EP_DONT_COLLIDE_WITH,
4210 EP_CAN_SMASH_PLAYER,
4211 EP_CAN_SMASH_ENEMIES,
4212 EP_CAN_SMASH_EVERYTHING,
4217 EP_FOOD_DARK_YAMYAM,
4233 /* important: after initialization in InitElementPropertiesStatic(), the
4234 elements are not again initialized to a default value; therefore all
4235 changes have to make sure that they leave the element with a defined
4236 property (which means that conditional property changes must be set to
4237 a reliable default value before) */
4239 /* resolve group elements */
4240 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4241 ResolveGroupElement(EL_GROUP_START + i);
4243 /* set all special, combined or engine dependent element properties */
4244 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4246 /* do not change (already initialized) clipboard elements here */
4247 if (IS_CLIPBOARD_ELEMENT(i))
4250 /* ---------- INACTIVE ------------------------------------------------- */
4251 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4252 i <= EL_CHAR_END) ||
4253 (i >= EL_STEEL_CHAR_START &&
4254 i <= EL_STEEL_CHAR_END)));
4256 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4257 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4258 IS_WALKABLE_INSIDE(i) ||
4259 IS_WALKABLE_UNDER(i)));
4261 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4262 IS_PASSABLE_INSIDE(i) ||
4263 IS_PASSABLE_UNDER(i)));
4265 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4266 IS_PASSABLE_OVER(i)));
4268 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4269 IS_PASSABLE_INSIDE(i)));
4271 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4272 IS_PASSABLE_UNDER(i)));
4274 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4277 /* ---------- COLLECTIBLE ---------------------------------------------- */
4278 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4282 /* ---------- SNAPPABLE ------------------------------------------------ */
4283 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4284 IS_COLLECTIBLE(i) ||
4288 /* ---------- WALL ----------------------------------------------------- */
4289 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4291 for (j = 0; no_wall_properties[j] != -1; j++)
4292 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4293 i >= EL_FIRST_RUNTIME_UNREAL)
4294 SET_PROPERTY(i, EP_WALL, FALSE);
4296 if (IS_HISTORIC_WALL(i))
4297 SET_PROPERTY(i, EP_WALL, TRUE);
4299 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4300 if (engine_version < VERSION_IDENT(2,2,0,0))
4301 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4303 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4305 !IS_COLLECTIBLE(i)));
4307 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4308 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4309 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4311 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4312 IS_INDESTRUCTIBLE(i)));
4314 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4316 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4317 else if (engine_version < VERSION_IDENT(2,2,0,0))
4318 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4320 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4324 if (IS_CUSTOM_ELEMENT(i))
4326 /* these are additional properties which are initially false when set */
4328 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4330 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4331 if (DONT_COLLIDE_WITH(i))
4332 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4334 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4335 if (CAN_SMASH_EVERYTHING(i))
4336 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4337 if (CAN_SMASH_ENEMIES(i))
4338 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4341 /* ---------- CAN_SMASH ------------------------------------------------ */
4342 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4343 CAN_SMASH_ENEMIES(i) ||
4344 CAN_SMASH_EVERYTHING(i)));
4346 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4347 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4348 EXPLODES_BY_FIRE(i)));
4350 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4351 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4352 EXPLODES_SMASHED(i)));
4354 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4355 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4356 EXPLODES_IMPACT(i)));
4358 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4359 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4361 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4362 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4363 i == EL_BLACK_ORB));
4365 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4366 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4368 IS_CUSTOM_ELEMENT(i)));
4370 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4371 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4372 i == EL_SP_ELECTRON));
4374 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4375 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4376 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4377 getMoveIntoAcidProperty(&level, i));
4379 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4380 if (MAYBE_DONT_COLLIDE_WITH(i))
4381 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4382 getDontCollideWithProperty(&level, i));
4384 /* ---------- SP_PORT -------------------------------------------------- */
4385 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4386 IS_PASSABLE_INSIDE(i)));
4388 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4389 for (j = 0; j < level.num_android_clone_elements; j++)
4390 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4392 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4394 /* ---------- CAN_CHANGE ----------------------------------------------- */
4395 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4396 for (j = 0; j < element_info[i].num_change_pages; j++)
4397 if (element_info[i].change_page[j].can_change)
4398 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4400 /* ---------- HAS_ACTION ----------------------------------------------- */
4401 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4402 for (j = 0; j < element_info[i].num_change_pages; j++)
4403 if (element_info[i].change_page[j].has_action)
4404 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4406 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4407 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4410 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4411 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4412 element_info[i].crumbled[ACTION_DEFAULT] !=
4413 element_info[i].graphic[ACTION_DEFAULT]);
4415 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4416 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4417 IS_EDITOR_CASCADE_INACTIVE(i)));
4420 /* dynamically adjust element properties according to game engine version */
4422 static int ep_em_slippery_wall[] =
4427 EL_EXPANDABLE_WALL_HORIZONTAL,
4428 EL_EXPANDABLE_WALL_VERTICAL,
4429 EL_EXPANDABLE_WALL_ANY,
4430 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4431 EL_EXPANDABLE_STEELWALL_VERTICAL,
4432 EL_EXPANDABLE_STEELWALL_ANY,
4433 EL_EXPANDABLE_STEELWALL_GROWING,
4437 static int ep_em_explodes_by_fire[] =
4440 EL_EM_DYNAMITE_ACTIVE,
4445 /* special EM style gems behaviour */
4446 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4447 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4448 level.em_slippery_gems);
4450 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4451 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4452 (level.em_slippery_gems &&
4453 engine_version > VERSION_IDENT(2,0,1,0)));
4455 /* special EM style explosion behaviour regarding chain reactions */
4456 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4457 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4458 level.em_explodes_by_fire);
4461 /* this is needed because some graphics depend on element properties */
4462 if (game_status == GAME_MODE_PLAYING)
4463 InitElementGraphicInfo();
4466 void InitElementPropertiesAfterLoading(int engine_version)
4470 /* set some other uninitialized values of custom elements in older levels */
4471 if (engine_version < VERSION_IDENT(3,1,0,0))
4473 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4475 int element = EL_CUSTOM_START + i;
4477 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4479 element_info[element].explosion_delay = 17;
4480 element_info[element].ignition_delay = 8;
4485 void InitElementPropertiesGfxElement()
4489 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4491 struct ElementInfo *ei = &element_info[i];
4493 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4497 static void InitGlobal()
4502 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4504 /* check if element_name_info entry defined for each element in "main.h" */
4505 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4506 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4508 element_info[i].token_name = element_name_info[i].token_name;
4509 element_info[i].class_name = element_name_info[i].class_name;
4510 element_info[i].editor_description= element_name_info[i].editor_description;
4513 /* create hash from image config list */
4514 image_config_hash = newSetupFileHash();
4515 for (i = 0; image_config[i].token != NULL; i++)
4516 setHashEntry(image_config_hash,
4517 image_config[i].token,
4518 image_config[i].value);
4520 /* create hash from element token list */
4521 element_token_hash = newSetupFileHash();
4522 for (i = 0; element_name_info[i].token_name != NULL; i++)
4523 setHashEntry(element_token_hash,
4524 element_name_info[i].token_name,
4527 /* create hash from graphic token list */
4528 graphic_token_hash = newSetupFileHash();
4529 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4530 if (strSuffix(image_config[i].value, ".png") ||
4531 strSuffix(image_config[i].value, ".pcx") ||
4532 strSuffix(image_config[i].value, ".wav") ||
4533 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4534 setHashEntry(graphic_token_hash,
4535 image_config[i].token,
4536 int2str(graphic++, 0));
4538 /* create hash from font token list */
4539 font_token_hash = newSetupFileHash();
4540 for (i = 0; font_info[i].token_name != NULL; i++)
4541 setHashEntry(font_token_hash,
4542 font_info[i].token_name,
4545 /* set default filenames for all cloned graphics in static configuration */
4546 for (i = 0; image_config[i].token != NULL; i++)
4548 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4550 char *token = image_config[i].token;
4551 char *token_clone_from = getStringCat2(token, ".clone_from");
4552 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4554 if (token_cloned != NULL)
4556 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4558 if (value_cloned != NULL)
4560 /* set default filename in static configuration */
4561 image_config[i].value = value_cloned;
4563 /* set default filename in image config hash */
4564 setHashEntry(image_config_hash, token, value_cloned);
4568 free(token_clone_from);
4572 /* always start with reliable default values (all elements) */
4573 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4574 ActiveElement[i] = i;
4576 /* now add all entries that have an active state (active elements) */
4577 for (i = 0; element_with_active_state[i].element != -1; i++)
4579 int element = element_with_active_state[i].element;
4580 int element_active = element_with_active_state[i].element_active;
4582 ActiveElement[element] = element_active;
4585 /* always start with reliable default values (all buttons) */
4586 for (i = 0; i < NUM_IMAGE_FILES; i++)
4587 ActiveButton[i] = i;
4589 /* now add all entries that have an active state (active buttons) */
4590 for (i = 0; button_with_active_state[i].button != -1; i++)
4592 int button = button_with_active_state[i].button;
4593 int button_active = button_with_active_state[i].button_active;
4595 ActiveButton[button] = button_active;
4598 /* always start with reliable default values (all fonts) */
4599 for (i = 0; i < NUM_FONTS; i++)
4602 /* now add all entries that have an active state (active fonts) */
4603 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4605 int font = font_with_active_state[i].font_nr;
4606 int font_active = font_with_active_state[i].font_nr_active;
4608 ActiveFont[font] = font_active;
4611 global.autoplay_leveldir = NULL;
4612 global.convert_leveldir = NULL;
4613 global.create_images_dir = NULL;
4615 global.frames_per_second = 0;
4617 global.border_status = GAME_MODE_MAIN;
4619 global.use_envelope_request = FALSE;
4622 void Execute_Command(char *command)
4626 if (strEqual(command, "print graphicsinfo.conf"))
4628 Print("# You can configure additional/alternative image files here.\n");
4629 Print("# (The entries below are default and therefore commented out.)\n");
4631 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4633 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4636 for (i = 0; image_config[i].token != NULL; i++)
4637 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4638 image_config[i].value));
4642 else if (strEqual(command, "print soundsinfo.conf"))
4644 Print("# You can configure additional/alternative sound files here.\n");
4645 Print("# (The entries below are default and therefore commented out.)\n");
4647 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4649 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4652 for (i = 0; sound_config[i].token != NULL; i++)
4653 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4654 sound_config[i].value));
4658 else if (strEqual(command, "print musicinfo.conf"))
4660 Print("# You can configure additional/alternative music files here.\n");
4661 Print("# (The entries below are default and therefore commented out.)\n");
4663 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4665 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4668 for (i = 0; music_config[i].token != NULL; i++)
4669 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4670 music_config[i].value));
4674 else if (strEqual(command, "print editorsetup.conf"))
4676 Print("# You can configure your personal editor element list here.\n");
4677 Print("# (The entries below are default and therefore commented out.)\n");
4680 /* this is needed to be able to check element list for cascade elements */
4681 InitElementPropertiesStatic();
4682 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4684 PrintEditorElementList();
4688 else if (strEqual(command, "print helpanim.conf"))
4690 Print("# You can configure different element help animations here.\n");
4691 Print("# (The entries below are default and therefore commented out.)\n");
4694 for (i = 0; helpanim_config[i].token != NULL; i++)
4696 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4697 helpanim_config[i].value));
4699 if (strEqual(helpanim_config[i].token, "end"))
4705 else if (strEqual(command, "print helptext.conf"))
4707 Print("# You can configure different element help text here.\n");
4708 Print("# (The entries below are default and therefore commented out.)\n");
4711 for (i = 0; helptext_config[i].token != NULL; i++)
4712 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4713 helptext_config[i].value));
4717 else if (strPrefix(command, "dump level "))
4719 char *filename = &command[11];
4721 if (!fileExists(filename))
4722 Error(ERR_EXIT, "cannot open file '%s'", filename);
4724 LoadLevelFromFilename(&level, filename);
4729 else if (strPrefix(command, "dump tape "))
4731 char *filename = &command[10];
4733 if (!fileExists(filename))
4734 Error(ERR_EXIT, "cannot open file '%s'", filename);
4736 LoadTapeFromFilename(filename);
4741 else if (strPrefix(command, "autotest ") ||
4742 strPrefix(command, "autoplay ") ||
4743 strPrefix(command, "autoffwd "))
4745 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4747 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4748 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4749 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4751 while (*str_ptr != '\0') /* continue parsing string */
4753 /* cut leading whitespace from string, replace it by string terminator */
4754 while (*str_ptr == ' ' || *str_ptr == '\t')
4757 if (*str_ptr == '\0') /* end of string reached */
4760 if (global.autoplay_leveldir == NULL) /* read level set string */
4762 global.autoplay_leveldir = str_ptr;
4763 global.autoplay_all = TRUE; /* default: play all tapes */
4765 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4766 global.autoplay_level[i] = FALSE;
4768 else /* read level number string */
4770 int level_nr = atoi(str_ptr); /* get level_nr value */
4772 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4773 global.autoplay_level[level_nr] = TRUE;
4775 global.autoplay_all = FALSE;
4778 /* advance string pointer to the next whitespace (or end of string) */
4779 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4783 else if (strPrefix(command, "convert "))
4785 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4786 char *str_ptr = strchr(str_copy, ' ');
4788 global.convert_leveldir = str_copy;
4789 global.convert_level_nr = -1;
4791 if (str_ptr != NULL) /* level number follows */
4793 *str_ptr++ = '\0'; /* terminate leveldir string */
4794 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4797 else if (strPrefix(command, "create images "))
4799 global.create_images_dir = getStringCopy(&command[14]);
4801 if (access(global.create_images_dir, W_OK) != 0)
4802 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4803 global.create_images_dir);
4805 else if (strPrefix(command, "create CE image "))
4807 CreateCustomElementImages(&command[16]);
4813 #if defined(TARGET_SDL2)
4814 else if (strEqual(command, "SDL_ListModes"))
4816 SDL_Init(SDL_INIT_VIDEO);
4818 int num_displays = SDL_GetNumVideoDisplays();
4820 // check if there are any displays available
4821 if (num_displays < 0)
4823 Print("No displays available: %s\n", SDL_GetError());
4828 for (i = 0; i < num_displays; i++)
4830 int num_modes = SDL_GetNumDisplayModes(i);
4833 Print("Available display modes for display %d:\n", i);
4835 // check if there are any display modes available for this display
4838 Print("No display modes available for display %d: %s\n",
4844 for (j = 0; j < num_modes; j++)
4846 SDL_DisplayMode mode;
4848 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4850 Print("Cannot get display mode %d for display %d: %s\n",
4851 j, i, SDL_GetError());
4856 Print("- %d x %d\n", mode.w, mode.h);
4862 #elif defined(TARGET_SDL)
4863 else if (strEqual(command, "SDL_ListModes"))
4868 SDL_Init(SDL_INIT_VIDEO);
4870 /* get available fullscreen/hardware modes */
4871 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4873 /* check if there are any modes available */
4876 Print("No modes available!\n");
4881 /* check if our resolution is restricted */
4882 if (modes == (SDL_Rect **)-1)
4884 Print("All resolutions available.\n");
4888 Print("Available display modes:\n");
4890 for (i = 0; modes[i]; i++)
4891 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4901 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4905 static void InitSetup()
4907 LoadSetup(); /* global setup info */
4909 /* set some options from setup file */
4911 if (setup.options.verbose)
4912 options.verbose = TRUE;
4915 static void InitGameInfo()
4917 game.restart_level = FALSE;
4920 static void InitPlayerInfo()
4924 /* choose default local player */
4925 local_player = &stored_player[0];
4927 for (i = 0; i < MAX_PLAYERS; i++)
4928 stored_player[i].connected = FALSE;
4930 local_player->connected = TRUE;
4933 static void InitArtworkInfo()
4938 static char *get_string_in_brackets(char *string)
4940 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4942 sprintf(string_in_brackets, "[%s]", string);
4944 return string_in_brackets;
4947 static char *get_level_id_suffix(int id_nr)
4949 char *id_suffix = checked_malloc(1 + 3 + 1);
4951 if (id_nr < 0 || id_nr > 999)
4954 sprintf(id_suffix, ".%03d", id_nr);
4959 static void InitArtworkConfig()
4961 static char *image_id_prefix[MAX_NUM_ELEMENTS +
4963 NUM_GLOBAL_ANIMS + 1];
4964 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4965 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4966 static char *action_id_suffix[NUM_ACTIONS + 1];
4967 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4968 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4969 static char *level_id_suffix[MAX_LEVELS + 1];
4970 static char *dummy[1] = { NULL };
4971 static char *ignore_generic_tokens[] =
4977 static char **ignore_image_tokens;
4978 static char **ignore_sound_tokens;
4979 static char **ignore_music_tokens;
4980 int num_ignore_generic_tokens;
4981 int num_ignore_image_tokens;
4982 int num_ignore_sound_tokens;
4983 int num_ignore_music_tokens;
4986 /* dynamically determine list of generic tokens to be ignored */
4987 num_ignore_generic_tokens = 0;
4988 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4989 num_ignore_generic_tokens++;
4991 /* dynamically determine list of image tokens to be ignored */
4992 num_ignore_image_tokens = num_ignore_generic_tokens;
4993 for (i = 0; image_config_vars[i].token != NULL; i++)
4994 num_ignore_image_tokens++;
4995 ignore_image_tokens =
4996 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4997 for (i = 0; i < num_ignore_generic_tokens; i++)
4998 ignore_image_tokens[i] = ignore_generic_tokens[i];
4999 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5000 ignore_image_tokens[num_ignore_generic_tokens + i] =
5001 image_config_vars[i].token;
5002 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5004 /* dynamically determine list of sound tokens to be ignored */
5005 num_ignore_sound_tokens = num_ignore_generic_tokens;
5006 ignore_sound_tokens =
5007 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5008 for (i = 0; i < num_ignore_generic_tokens; i++)
5009 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5010 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5012 /* dynamically determine list of music tokens to be ignored */
5013 num_ignore_music_tokens = num_ignore_generic_tokens;
5014 ignore_music_tokens =
5015 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5016 for (i = 0; i < num_ignore_generic_tokens; i++)
5017 ignore_music_tokens[i] = ignore_generic_tokens[i];
5018 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5020 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5021 image_id_prefix[i] = element_info[i].token_name;
5022 for (i = 0; i < NUM_FONTS; i++)
5023 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5024 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
5025 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5026 global_anim_info[i].token_name;
5027 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIMS] = NULL;
5029 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5030 sound_id_prefix[i] = element_info[i].token_name;
5031 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5032 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5033 get_string_in_brackets(element_info[i].class_name);
5034 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5036 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5037 music_id_prefix[i] = music_prefix_info[i].prefix;
5038 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5040 for (i = 0; i < NUM_ACTIONS; i++)
5041 action_id_suffix[i] = element_action_info[i].suffix;
5042 action_id_suffix[NUM_ACTIONS] = NULL;
5044 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5045 direction_id_suffix[i] = element_direction_info[i].suffix;
5046 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5048 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5049 special_id_suffix[i] = special_suffix_info[i].suffix;
5050 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5052 for (i = 0; i < MAX_LEVELS; i++)
5053 level_id_suffix[i] = get_level_id_suffix(i);
5054 level_id_suffix[MAX_LEVELS] = NULL;
5056 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5057 image_id_prefix, action_id_suffix, direction_id_suffix,
5058 special_id_suffix, ignore_image_tokens);
5059 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5060 sound_id_prefix, action_id_suffix, dummy,
5061 special_id_suffix, ignore_sound_tokens);
5062 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5063 music_id_prefix, special_id_suffix, level_id_suffix,
5064 dummy, ignore_music_tokens);
5067 static void InitMixer()
5074 void InitGfxBuffers()
5076 static int win_xsize_last = -1;
5077 static int win_ysize_last = -1;
5079 /* create additional image buffers for double-buffering and cross-fading */
5081 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5083 /* may contain content for cross-fading -- only re-create if changed */
5084 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5085 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5087 win_xsize_last = WIN_XSIZE;
5088 win_ysize_last = WIN_YSIZE;
5091 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5092 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5093 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5094 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5095 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5097 /* initialize screen properties */
5098 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5099 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5101 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5102 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5103 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5104 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5105 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5106 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5108 /* required if door size definitions have changed */
5109 InitGraphicCompatibilityInfo_Doors();
5111 InitGfxBuffers_EM();
5112 InitGfxBuffers_SP();
5117 struct GraphicInfo *graphic_info_last = graphic_info;
5118 char *filename_font_initial = NULL;
5119 char *filename_anim_initial = NULL;
5120 Bitmap *bitmap_font_initial = NULL;
5124 /* determine settings for initial font (for displaying startup messages) */
5125 for (i = 0; image_config[i].token != NULL; i++)
5127 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5129 char font_token[128];
5132 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5133 len_font_token = strlen(font_token);
5135 if (strEqual(image_config[i].token, font_token))
5136 filename_font_initial = image_config[i].value;
5137 else if (strlen(image_config[i].token) > len_font_token &&
5138 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5140 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5141 font_initial[j].src_x = atoi(image_config[i].value);
5142 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5143 font_initial[j].src_y = atoi(image_config[i].value);
5144 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5145 font_initial[j].width = atoi(image_config[i].value);
5146 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5147 font_initial[j].height = atoi(image_config[i].value);
5152 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5154 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5155 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5158 if (filename_font_initial == NULL) /* should not happen */
5159 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5162 InitGfxCustomArtworkInfo();
5163 InitGfxOtherSettings();
5165 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5167 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5168 font_initial[j].bitmap = bitmap_font_initial;
5170 InitFontGraphicInfo();
5172 font_height = getFontHeight(FC_RED);
5174 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5175 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5176 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5179 DrawInitText("Loading graphics", 120, FC_GREEN);
5181 /* initialize settings for busy animation with default values */
5182 int parameter[NUM_GFX_ARGS];
5183 for (i = 0; i < NUM_GFX_ARGS; i++)
5184 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5185 image_config_suffix[i].token,
5186 image_config_suffix[i].type);
5188 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5189 int len_anim_token = strlen(anim_token);
5191 /* read settings for busy animation from default custom artwork config */
5192 char *gfx_config_filename = getPath3(options.graphics_directory,
5194 GRAPHICSINFO_FILENAME);
5196 if (fileExists(gfx_config_filename))
5198 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5200 if (setup_file_hash)
5202 char *filename = getHashEntry(setup_file_hash, anim_token);
5206 filename_anim_initial = getStringCopy(filename);
5208 for (j = 0; image_config_suffix[j].token != NULL; j++)
5210 int type = image_config_suffix[j].type;
5211 char *suffix = image_config_suffix[j].token;
5212 char *token = getStringCat2(anim_token, suffix);
5213 char *value = getHashEntry(setup_file_hash, token);
5215 checked_free(token);
5218 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5222 freeSetupFileHash(setup_file_hash);
5226 if (filename_anim_initial == NULL)
5228 /* read settings for busy animation from static default artwork config */
5229 for (i = 0; image_config[i].token != NULL; i++)
5231 if (strEqual(image_config[i].token, anim_token))
5232 filename_anim_initial = getStringCopy(image_config[i].value);
5233 else if (strlen(image_config[i].token) > len_anim_token &&
5234 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5236 for (j = 0; image_config_suffix[j].token != NULL; j++)
5238 if (strEqual(&image_config[i].token[len_anim_token],
5239 image_config_suffix[j].token))
5241 get_graphic_parameter_value(image_config[i].value,
5242 image_config_suffix[j].token,
5243 image_config_suffix[j].type);
5249 if (filename_anim_initial == NULL) /* should not happen */
5250 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5252 anim_initial.bitmaps =
5253 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5255 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5256 LoadCustomImage(filename_anim_initial);
5258 checked_free(filename_anim_initial);
5260 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5262 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5264 graphic_info = graphic_info_last;
5266 init.busy.width = anim_initial.width;
5267 init.busy.height = anim_initial.height;
5269 InitMenuDesignSettings_Static();
5270 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5272 /* use copy of busy animation to prevent change while reloading artwork */
5276 void InitGfxBackground()
5278 fieldbuffer = bitmap_db_field;
5279 SetDrawtoField(DRAW_BACKBUFFER);
5281 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5283 redraw_mask = REDRAW_ALL;
5286 static void InitLevelInfo()
5288 LoadLevelInfo(); /* global level info */
5289 LoadLevelSetup_LastSeries(); /* last played series info */
5290 LoadLevelSetup_SeriesInfo(); /* last played level info */
5292 if (global.autoplay_leveldir &&
5293 global.autoplay_mode != AUTOPLAY_TEST)
5295 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5296 global.autoplay_leveldir);
5297 if (leveldir_current == NULL)
5298 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5302 static void InitLevelArtworkInfo()
5304 LoadLevelArtworkInfo();
5307 static void InitImages()
5309 print_timestamp_init("InitImages");
5312 printf("::: leveldir_current->identifier == '%s'\n",
5313 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5314 printf("::: leveldir_current->graphics_path == '%s'\n",
5315 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5316 printf("::: leveldir_current->graphics_set == '%s'\n",
5317 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5318 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5319 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5322 setLevelArtworkDir(artwork.gfx_first);
5325 printf("::: leveldir_current->identifier == '%s'\n",
5326 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5327 printf("::: leveldir_current->graphics_path == '%s'\n",
5328 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5329 printf("::: leveldir_current->graphics_set == '%s'\n",
5330 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5331 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5332 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5336 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5337 leveldir_current->identifier,
5338 artwork.gfx_current_identifier,
5339 artwork.gfx_current->identifier,
5340 leveldir_current->graphics_set,
5341 leveldir_current->graphics_path);
5344 UPDATE_BUSY_STATE();
5346 ReloadCustomImages();
5347 print_timestamp_time("ReloadCustomImages");
5349 UPDATE_BUSY_STATE();
5351 LoadCustomElementDescriptions();
5352 print_timestamp_time("LoadCustomElementDescriptions");
5354 UPDATE_BUSY_STATE();
5356 LoadMenuDesignSettings();
5357 print_timestamp_time("LoadMenuDesignSettings");
5359 UPDATE_BUSY_STATE();
5361 ReinitializeGraphics();
5362 print_timestamp_time("ReinitializeGraphics");
5364 UPDATE_BUSY_STATE();
5366 print_timestamp_done("InitImages");
5369 static void InitSound(char *identifier)
5371 print_timestamp_init("InitSound");
5373 if (identifier == NULL)
5374 identifier = artwork.snd_current->identifier;
5376 /* set artwork path to send it to the sound server process */
5377 setLevelArtworkDir(artwork.snd_first);
5379 InitReloadCustomSounds(identifier);
5380 print_timestamp_time("InitReloadCustomSounds");
5382 ReinitializeSounds();
5383 print_timestamp_time("ReinitializeSounds");
5385 print_timestamp_done("InitSound");
5388 static void InitMusic(char *identifier)
5390 print_timestamp_init("InitMusic");
5392 if (identifier == NULL)
5393 identifier = artwork.mus_current->identifier;
5395 /* set artwork path to send it to the sound server process */
5396 setLevelArtworkDir(artwork.mus_first);
5398 InitReloadCustomMusic(identifier);
5399 print_timestamp_time("InitReloadCustomMusic");
5401 ReinitializeMusic();
5402 print_timestamp_time("ReinitializeMusic");
5404 print_timestamp_done("InitMusic");
5407 void InitNetworkServer()
5409 #if defined(NETWORK_AVALIABLE)
5413 if (!options.network)
5416 #if defined(NETWORK_AVALIABLE)
5417 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5419 if (!ConnectToServer(options.server_host, options.server_port))
5420 Error(ERR_EXIT, "cannot connect to network game server");
5422 SendToServer_PlayerName(setup.player_name);
5423 SendToServer_ProtocolVersion();
5426 SendToServer_NrWanted(nr_wanted);
5430 static boolean CheckArtworkConfigForCustomElements(char *filename)
5432 SetupFileHash *setup_file_hash;
5433 boolean redefined_ce_found = FALSE;
5435 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5437 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5439 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5441 char *token = HASH_ITERATION_TOKEN(itr);
5443 if (strPrefix(token, "custom_"))
5445 redefined_ce_found = TRUE;
5450 END_HASH_ITERATION(setup_file_hash, itr)
5452 freeSetupFileHash(setup_file_hash);
5455 return redefined_ce_found;
5458 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5460 char *filename_base, *filename_local;
5461 boolean redefined_ce_found = FALSE;
5463 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5466 printf("::: leveldir_current->identifier == '%s'\n",
5467 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5468 printf("::: leveldir_current->graphics_path == '%s'\n",
5469 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5470 printf("::: leveldir_current->graphics_set == '%s'\n",
5471 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5472 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5473 leveldir_current == NULL ? "[NULL]" :
5474 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5477 /* first look for special artwork configured in level series config */
5478 filename_base = getCustomArtworkLevelConfigFilename(type);
5481 printf("::: filename_base == '%s'\n", filename_base);
5484 if (fileExists(filename_base))
5485 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5487 filename_local = getCustomArtworkConfigFilename(type);
5490 printf("::: filename_local == '%s'\n", filename_local);
5493 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5494 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5497 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5500 return redefined_ce_found;
5503 static void InitOverrideArtwork()
5505 boolean redefined_ce_found = FALSE;
5507 /* to check if this level set redefines any CEs, do not use overriding */
5508 gfx.override_level_graphics = FALSE;
5509 gfx.override_level_sounds = FALSE;
5510 gfx.override_level_music = FALSE;
5512 /* now check if this level set has definitions for custom elements */
5513 if (setup.override_level_graphics == AUTO ||
5514 setup.override_level_sounds == AUTO ||
5515 setup.override_level_music == AUTO)
5516 redefined_ce_found =
5517 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5518 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5519 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5522 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5525 if (redefined_ce_found)
5527 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5528 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5529 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5530 gfx.override_level_music = (setup.override_level_music == TRUE);
5534 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5535 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5536 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5537 gfx.override_level_music = (setup.override_level_music != FALSE);
5541 printf("::: => %d, %d, %d\n",
5542 gfx.override_level_graphics,
5543 gfx.override_level_sounds,
5544 gfx.override_level_music);
5548 static char *getNewArtworkIdentifier(int type)
5550 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5551 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5552 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5553 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5554 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5555 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5556 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5557 char *leveldir_identifier = leveldir_current->identifier;
5558 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5559 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5560 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5561 char *artwork_current_identifier;
5562 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5564 /* leveldir_current may be invalid (level group, parent link) */
5565 if (!validLevelSeries(leveldir_current))
5568 /* 1st step: determine artwork set to be activated in descending order:
5569 --------------------------------------------------------------------
5570 1. setup artwork (when configured to override everything else)
5571 2. artwork set configured in "levelinfo.conf" of current level set
5572 (artwork in level directory will have priority when loading later)
5573 3. artwork in level directory (stored in artwork sub-directory)
5574 4. setup artwork (currently configured in setup menu) */
5576 if (setup_override_artwork)
5577 artwork_current_identifier = setup_artwork_set;
5578 else if (leveldir_artwork_set != NULL)
5579 artwork_current_identifier = leveldir_artwork_set;
5580 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5581 artwork_current_identifier = leveldir_identifier;
5583 artwork_current_identifier = setup_artwork_set;
5586 /* 2nd step: check if it is really needed to reload artwork set
5587 ------------------------------------------------------------ */
5589 /* ---------- reload if level set and also artwork set has changed ------- */
5590 if (leveldir_current_identifier[type] != leveldir_identifier &&
5591 (last_has_level_artwork_set[type] || has_level_artwork_set))
5592 artwork_new_identifier = artwork_current_identifier;
5594 leveldir_current_identifier[type] = leveldir_identifier;
5595 last_has_level_artwork_set[type] = has_level_artwork_set;
5597 /* ---------- reload if "override artwork" setting has changed ----------- */
5598 if (last_override_level_artwork[type] != setup_override_artwork)
5599 artwork_new_identifier = artwork_current_identifier;
5601 last_override_level_artwork[type] = setup_override_artwork;
5603 /* ---------- reload if current artwork identifier has changed ----------- */
5604 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5605 artwork_current_identifier))
5606 artwork_new_identifier = artwork_current_identifier;
5608 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5610 /* ---------- do not reload directly after starting ---------------------- */
5611 if (!initialized[type])
5612 artwork_new_identifier = NULL;
5614 initialized[type] = TRUE;
5616 return artwork_new_identifier;
5619 void ReloadCustomArtwork(int force_reload)
5621 int last_game_status = game_status; /* save current game status */
5622 char *gfx_new_identifier;
5623 char *snd_new_identifier;
5624 char *mus_new_identifier;
5625 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5626 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5627 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5628 boolean reload_needed;
5630 InitOverrideArtwork();
5632 force_reload_gfx |= AdjustGraphicsForEMC();
5634 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5635 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5636 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5638 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5639 snd_new_identifier != NULL || force_reload_snd ||
5640 mus_new_identifier != NULL || force_reload_mus);
5645 print_timestamp_init("ReloadCustomArtwork");
5647 game_status = GAME_MODE_LOADING;
5649 FadeOut(REDRAW_ALL);
5651 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5652 print_timestamp_time("ClearRectangle");
5656 if (gfx_new_identifier != NULL || force_reload_gfx)
5659 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5660 artwork.gfx_current_identifier,
5662 artwork.gfx_current->identifier,
5663 leveldir_current->graphics_set);
5667 print_timestamp_time("InitImages");
5670 if (snd_new_identifier != NULL || force_reload_snd)
5672 InitSound(snd_new_identifier);
5673 print_timestamp_time("InitSound");
5676 if (mus_new_identifier != NULL || force_reload_mus)
5678 InitMusic(mus_new_identifier);
5679 print_timestamp_time("InitMusic");
5682 game_status = last_game_status; /* restore current game status */
5684 init_last = init; /* switch to new busy animation */
5686 FadeOut(REDRAW_ALL);
5688 RedrawGlobalBorder();
5690 /* force redraw of (open or closed) door graphics */
5691 SetDoorState(DOOR_OPEN_ALL);
5692 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5694 FadeSetEnterScreen();
5695 FadeSkipNextFadeOut();
5697 print_timestamp_done("ReloadCustomArtwork");
5699 LimitScreenUpdates(FALSE);
5702 void KeyboardAutoRepeatOffUnlessAutoplay()
5704 if (global.autoplay_leveldir == NULL)
5705 KeyboardAutoRepeatOff();
5708 void DisplayExitMessage(char *format, va_list ap)
5710 // check if draw buffer and fonts for exit message are already available
5711 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5714 int font_1 = FC_RED;
5715 int font_2 = FC_YELLOW;
5716 int font_3 = FC_BLUE;
5717 int font_width = getFontWidth(font_2);
5718 int font_height = getFontHeight(font_2);
5721 int sxsize = WIN_XSIZE - 2 * sx;
5722 int sysize = WIN_YSIZE - 2 * sy;
5723 int line_length = sxsize / font_width;
5724 int max_lines = sysize / font_height;
5725 int num_lines_printed;
5729 gfx.sxsize = sxsize;
5730 gfx.sysize = sysize;
5734 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5736 DrawTextSCentered(sy, font_1, "Fatal error:");
5737 sy += 3 * font_height;;
5740 DrawTextBufferVA(sx, sy, format, ap, font_2,
5741 line_length, line_length, max_lines,
5742 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5743 sy += (num_lines_printed + 3) * font_height;
5745 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5746 sy += 3 * font_height;
5749 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5750 line_length, line_length, max_lines,
5751 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5753 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5755 redraw_mask = REDRAW_ALL;
5757 /* force drawing exit message even if screen updates are currently limited */
5758 LimitScreenUpdates(FALSE);
5762 /* deactivate toons on error message screen */
5763 setup.toons = FALSE;
5765 WaitForEventToContinue();
5769 /* ========================================================================= */
5771 /* ========================================================================= */
5775 print_timestamp_init("OpenAll");
5777 game_status = GAME_MODE_LOADING;
5781 InitGlobal(); /* initialize some global variables */
5783 print_timestamp_time("[init global stuff]");
5787 print_timestamp_time("[init setup/config stuff (1)]");
5789 if (options.execute_command)
5790 Execute_Command(options.execute_command);
5792 if (options.serveronly)
5794 #if defined(PLATFORM_UNIX)
5795 NetworkServer(options.server_port, options.serveronly);
5797 Error(ERR_WARN, "networking only supported in Unix version");
5800 exit(0); /* never reached, server loops forever */
5804 print_timestamp_time("[init setup/config stuff (2)]");
5806 print_timestamp_time("[init setup/config stuff (3)]");
5807 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5808 print_timestamp_time("[init setup/config stuff (4)]");
5809 InitArtworkConfig(); /* needed before forking sound child process */
5810 print_timestamp_time("[init setup/config stuff (5)]");
5812 print_timestamp_time("[init setup/config stuff (6)]");
5814 InitRND(NEW_RANDOMIZE);
5815 InitSimpleRandom(NEW_RANDOMIZE);
5819 print_timestamp_time("[init setup/config stuff]");
5822 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5824 InitEventFilter(FilterEvents);
5826 print_timestamp_time("[init video stuff]");
5828 InitElementPropertiesStatic();
5829 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5830 InitElementPropertiesGfxElement();
5832 print_timestamp_time("[init element properties stuff]");
5836 print_timestamp_time("InitGfx");
5839 print_timestamp_time("InitLevelInfo");
5841 InitLevelArtworkInfo();
5842 print_timestamp_time("InitLevelArtworkInfo");
5844 InitOverrideArtwork(); /* needs to know current level directory */
5845 print_timestamp_time("InitOverrideArtwork");
5847 InitImages(); /* needs to know current level directory */
5848 print_timestamp_time("InitImages");
5850 InitSound(NULL); /* needs to know current level directory */
5851 print_timestamp_time("InitSound");
5853 InitMusic(NULL); /* needs to know current level directory */
5854 print_timestamp_time("InitMusic");
5856 InitGfxBackground();
5861 if (global.autoplay_leveldir)
5866 else if (global.convert_leveldir)
5871 else if (global.create_images_dir)
5873 CreateLevelSketchImages();
5877 game_status = GAME_MODE_MAIN;
5879 FadeSetEnterScreen();
5880 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5881 FadeSkipNextFadeOut();
5883 print_timestamp_time("[post-artwork]");
5885 print_timestamp_done("OpenAll");
5889 InitNetworkServer();
5892 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5894 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5895 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5896 #if defined(PLATFORM_ANDROID)
5897 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5898 SDL_AndroidGetInternalStoragePath());
5899 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5900 SDL_AndroidGetExternalStoragePath());
5901 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5902 (SDL_AndroidGetExternalStorageState() ==
5903 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5904 SDL_AndroidGetExternalStorageState() ==
5905 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5910 void CloseAllAndExit(int exit_value)
5915 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5922 #if defined(TARGET_SDL)
5923 #if defined(TARGET_SDL2)
5925 // set a flag to tell the network server thread to quit and wait for it
5926 // using SDL_WaitThread()
5928 if (network_server) /* terminate network server */
5929 SDL_KillThread(server_thread);
5933 CloseVideoDisplay();
5934 ClosePlatformDependentStuff();
5936 if (exit_value != 0)
5938 /* fall back to default level set (current set may have caused an error) */
5939 SaveLevelSetup_LastSeries_Deactivate();
5941 /* tell user where to find error log file which may contain more details */
5942 // (error notification now directly displayed on screen inside R'n'D
5943 // NotifyUserAboutErrorFile(); /* currently only works for Windows */