1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
29 #include "conf_e2g.c" /* include auto-generated data structure definitions */
30 #include "conf_esg.c" /* include auto-generated data structure definitions */
31 #include "conf_e2s.c" /* include auto-generated data structure definitions */
32 #include "conf_fnt.c" /* include auto-generated data structure definitions */
33 #include "conf_g2s.c" /* include auto-generated data structure definitions */
34 #include "conf_g2m.c" /* include auto-generated data structure definitions */
35 #include "conf_act.c" /* include auto-generated data structure definitions */
38 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
39 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
41 #define DEBUG_PRINT_INIT_TIMESTAMPS TRUE
42 #define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH 1
45 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
46 static struct GraphicInfo anim_initial;
48 static int copy_properties[][5] =
52 EL_BUG_LEFT, EL_BUG_RIGHT,
53 EL_BUG_UP, EL_BUG_DOWN
57 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
58 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
62 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
63 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
67 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
68 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
72 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
73 EL_PACMAN_UP, EL_PACMAN_DOWN
77 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
78 EL_YAMYAM_UP, EL_YAMYAM_DOWN
82 EL_MOLE_LEFT, EL_MOLE_RIGHT,
83 EL_MOLE_UP, EL_MOLE_DOWN
92 static void print_timestamp_ext(char *message, char *mode)
95 #if DEBUG_PRINT_INIT_TIMESTAMPS
96 static char *debug_message = NULL;
97 static char *last_message = NULL;
98 static int counter_nr = 0;
99 int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH;
101 checked_free(debug_message);
102 debug_message = getStringCat3(mode, " ", message);
104 if (strEqual(mode, "INIT"))
106 debug_print_timestamp(counter_nr, NULL);
108 if (counter_nr + 1 < max_depth)
109 debug_print_timestamp(counter_nr, debug_message);
113 debug_print_timestamp(counter_nr, NULL);
115 else if (strEqual(mode, "DONE"))
119 if (counter_nr + 1 < max_depth ||
120 (counter_nr == 0 && max_depth == 1))
122 last_message = message;
124 if (counter_nr == 0 && max_depth == 1)
126 checked_free(debug_message);
127 debug_message = getStringCat3("TIME", " ", message);
130 debug_print_timestamp(counter_nr, debug_message);
133 else if (!strEqual(mode, "TIME") ||
134 !strEqual(message, last_message))
136 if (counter_nr < max_depth)
137 debug_print_timestamp(counter_nr, debug_message);
143 static void print_timestamp_init(char *message)
145 print_timestamp_ext(message, "INIT");
148 static void print_timestamp_time(char *message)
150 print_timestamp_ext(message, "TIME");
153 static void print_timestamp_done(char *message)
155 print_timestamp_ext(message, "DONE");
160 struct GraphicInfo *graphic_info_last = graphic_info;
162 static unsigned long action_delay = 0;
163 unsigned long action_delay_value = GameFrameDelay;
164 int sync_frame = FrameCounter;
167 if (game_status != GAME_MODE_LOADING)
170 if (anim_initial.bitmap == NULL || window == NULL)
173 if (!DelayReached(&action_delay, action_delay_value))
178 static unsigned long last_counter = -1;
179 unsigned long current_counter = Counter();
180 unsigned long delay = current_counter - last_counter;
182 if (last_counter != -1 && delay > action_delay_value + 5)
183 printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
185 last_counter = current_counter;
190 anim_initial.anim_mode = ANIM_LOOP;
191 anim_initial.anim_start_frame = 0;
192 anim_initial.offset_x = anim_initial.width;
193 anim_initial.offset_y = 0;
197 x = ALIGNED_TEXT_XPOS(&init.busy);
198 y = ALIGNED_TEXT_YPOS(&init.busy);
200 x = WIN_XSIZE / 2 - TILESIZE / 2;
201 y = WIN_YSIZE / 2 - TILESIZE / 2;
206 static boolean done = FALSE;
209 printf("::: %d, %d, %d, %d => %d, %d\n",
210 init.busy.x, init.busy.y,
211 init.busy.align, init.busy.valign,
218 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
220 if (sync_frame % anim_initial.anim_delay == 0)
221 DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
223 graphic_info = graphic_info_last;
230 FreeLevelEditorGadgets();
239 static boolean gadgets_initialized = FALSE;
241 if (gadgets_initialized)
244 CreateLevelEditorGadgets();
248 CreateScreenGadgets();
250 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
252 gadgets_initialized = TRUE;
255 inline void InitElementSmallImagesScaledUp(int graphic)
258 struct FileInfo *fi = getImageListEntryFromImageID(graphic);
260 printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
263 CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
266 void InitElementSmallImages()
268 static int special_graphics[] =
270 IMG_EDITOR_ELEMENT_BORDER,
271 IMG_EDITOR_ELEMENT_BORDER_INPUT,
272 IMG_EDITOR_CASCADE_LIST,
273 IMG_EDITOR_CASCADE_LIST_ACTIVE,
276 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
277 int num_property_mappings = getImageListPropertyMappingSize();
280 /* initialize normal images from static configuration */
281 for (i = 0; element_to_graphic[i].element > -1; i++)
282 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
284 /* initialize special images from static configuration */
285 for (i = 0; element_to_special_graphic[i].element > -1; i++)
286 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
288 /* initialize images from dynamic configuration (may be elements or other) */
289 for (i = 0; i < num_property_mappings; i++)
290 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
292 /* initialize special images from above list (non-element images) */
293 for (i = 0; special_graphics[i] > -1; i++)
294 InitElementSmallImagesScaledUp(special_graphics[i]);
297 void InitScaledImages()
301 /* scale normal images from static configuration, if not already scaled */
302 for (i = 0; i < NUM_IMAGE_FILES; i++)
303 ScaleImage(i, graphic_info[i].scale_up_factor);
307 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
308 void SetBitmaps_EM(Bitmap **em_bitmap)
310 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
311 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
315 static int getFontBitmapID(int font_nr)
319 /* (special case: do not use special font for GAME_MODE_LOADING) */
320 if (game_status >= GAME_MODE_TITLE_INITIAL &&
321 game_status <= GAME_MODE_PSEUDO_PREVIEW)
322 special = game_status;
323 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
324 special = GFX_SPECIAL_ARG_MAIN;
326 else if (game_status == GAME_MODE_PLAYING)
327 special = GFX_SPECIAL_ARG_DOOR;
331 return font_info[font_nr].special_bitmap_id[special];
336 static int getFontFromToken(char *token)
339 char *value = getHashEntry(font_token_hash, token);
346 /* !!! OPTIMIZE THIS BY USING HASH !!! */
347 for (i = 0; i < NUM_FONTS; i++)
348 if (strEqual(token, font_info[i].token_name))
352 /* if font not found, use reliable default value */
353 return FONT_INITIAL_1;
356 void InitFontGraphicInfo()
358 static struct FontBitmapInfo *font_bitmap_info = NULL;
359 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
360 int num_property_mappings = getImageListPropertyMappingSize();
361 int num_font_bitmaps = NUM_FONTS;
364 if (graphic_info == NULL) /* still at startup phase */
366 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
367 getFontBitmapID, getFontFromToken);
372 /* ---------- initialize font graphic definitions ---------- */
374 /* always start with reliable default values (normal font graphics) */
375 for (i = 0; i < NUM_FONTS; i++)
376 font_info[i].graphic = IMG_FONT_INITIAL_1;
378 /* initialize normal font/graphic mapping from static configuration */
379 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
381 int font_nr = font_to_graphic[i].font_nr;
382 int special = font_to_graphic[i].special;
383 int graphic = font_to_graphic[i].graphic;
388 font_info[font_nr].graphic = graphic;
391 /* always start with reliable default values (special font graphics) */
392 for (i = 0; i < NUM_FONTS; i++)
394 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
396 font_info[i].special_graphic[j] = font_info[i].graphic;
397 font_info[i].special_bitmap_id[j] = i;
401 /* initialize special font/graphic mapping from static configuration */
402 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
404 int font_nr = font_to_graphic[i].font_nr;
405 int special = font_to_graphic[i].special;
406 int graphic = font_to_graphic[i].graphic;
407 int base_graphic = font2baseimg(font_nr);
409 if (IS_SPECIAL_GFX_ARG(special))
411 boolean base_redefined =
412 getImageListEntryFromImageID(base_graphic)->redefined;
413 boolean special_redefined =
414 getImageListEntryFromImageID(graphic)->redefined;
415 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
417 /* if the base font ("font.title_1", for example) has been redefined,
418 but not the special font ("font.title_1.LEVELS", for example), do not
419 use an existing (in this case considered obsolete) special font
420 anymore, but use the automatically determined default font */
421 /* special case: cloned special fonts must be explicitly redefined,
422 but are not automatically redefined by redefining base font */
423 if (base_redefined && !special_redefined && !special_cloned)
426 font_info[font_nr].special_graphic[special] = graphic;
427 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
432 /* initialize special font/graphic mapping from dynamic configuration */
433 for (i = 0; i < num_property_mappings; i++)
435 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
436 int special = property_mapping[i].ext3_index;
437 int graphic = property_mapping[i].artwork_index;
442 if (IS_SPECIAL_GFX_ARG(special))
444 font_info[font_nr].special_graphic[special] = graphic;
445 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
450 /* correct special font/graphic mapping for cloned fonts for downwards
451 compatibility of PREVIEW fonts -- this is only needed for implicit
452 redefinition of special font by redefined base font, and only if other
453 fonts are cloned from this special font (like in the "Zelda" level set) */
454 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
456 int font_nr = font_to_graphic[i].font_nr;
457 int special = font_to_graphic[i].special;
458 int graphic = font_to_graphic[i].graphic;
460 if (IS_SPECIAL_GFX_ARG(special))
462 boolean special_redefined =
463 getImageListEntryFromImageID(graphic)->redefined;
464 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
466 if (special_cloned && !special_redefined)
470 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
472 int font_nr2 = font_to_graphic[j].font_nr;
473 int special2 = font_to_graphic[j].special;
474 int graphic2 = font_to_graphic[j].graphic;
476 if (IS_SPECIAL_GFX_ARG(special2) &&
477 graphic2 == graphic_info[graphic].clone_from)
479 font_info[font_nr].special_graphic[special] =
480 font_info[font_nr2].special_graphic[special2];
481 font_info[font_nr].special_bitmap_id[special] =
482 font_info[font_nr2].special_bitmap_id[special2];
489 /* reset non-redefined ".active" font graphics if normal font is redefined */
490 /* (this different treatment is needed because normal and active fonts are
491 independently defined ("active" is not a property of font definitions!) */
492 for (i = 0; i < NUM_FONTS; i++)
494 int font_nr_base = i;
495 int font_nr_active = FONT_ACTIVE(font_nr_base);
497 /* check only those fonts with exist as normal and ".active" variant */
498 if (font_nr_base != font_nr_active)
500 int base_graphic = font_info[font_nr_base].graphic;
501 int active_graphic = font_info[font_nr_active].graphic;
502 boolean base_redefined =
503 getImageListEntryFromImageID(base_graphic)->redefined;
504 boolean active_redefined =
505 getImageListEntryFromImageID(active_graphic)->redefined;
507 /* if the base font ("font.menu_1", for example) has been redefined,
508 but not the active font ("font.menu_1.active", for example), do not
509 use an existing (in this case considered obsolete) active font
510 anymore, but use the automatically determined default font */
511 if (base_redefined && !active_redefined)
512 font_info[font_nr_active].graphic = base_graphic;
514 /* now also check each "special" font (which may be the same as above) */
515 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
517 int base_graphic = font_info[font_nr_base].special_graphic[j];
518 int active_graphic = font_info[font_nr_active].special_graphic[j];
519 boolean base_redefined =
520 getImageListEntryFromImageID(base_graphic)->redefined;
521 boolean active_redefined =
522 getImageListEntryFromImageID(active_graphic)->redefined;
524 /* same as above, but check special graphic definitions, for example:
525 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
526 if (base_redefined && !active_redefined)
528 font_info[font_nr_active].special_graphic[j] =
529 font_info[font_nr_base].special_graphic[j];
530 font_info[font_nr_active].special_bitmap_id[j] =
531 font_info[font_nr_base].special_bitmap_id[j];
537 /* ---------- initialize font bitmap array ---------- */
539 if (font_bitmap_info != NULL)
540 FreeFontInfo(font_bitmap_info);
543 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
545 /* ---------- initialize font bitmap definitions ---------- */
547 for (i = 0; i < NUM_FONTS; i++)
549 if (i < NUM_INITIAL_FONTS)
551 font_bitmap_info[i] = font_initial[i];
555 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
557 int font_bitmap_id = font_info[i].special_bitmap_id[j];
558 int graphic = font_info[i].special_graphic[j];
560 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
561 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
563 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
564 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
567 /* copy font relevant information from graphics information */
568 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
569 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
570 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
571 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
572 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
574 font_bitmap_info[font_bitmap_id].draw_xoffset =
575 graphic_info[graphic].draw_xoffset;
576 font_bitmap_info[font_bitmap_id].draw_yoffset =
577 graphic_info[graphic].draw_yoffset;
579 font_bitmap_info[font_bitmap_id].num_chars =
580 graphic_info[graphic].anim_frames;
581 font_bitmap_info[font_bitmap_id].num_chars_per_line =
582 graphic_info[graphic].anim_frames_per_line;
586 InitFontInfo(font_bitmap_info, num_font_bitmaps,
587 getFontBitmapID, getFontFromToken);
590 static void CheckArtworkConfigForCustomElements(char *filename)
592 SetupFileHash *setup_file_hash;
593 boolean redefined_ce_found = FALSE;
595 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
597 BEGIN_HASH_ITERATION(setup_file_hash, itr)
599 char *token = HASH_ITERATION_TOKEN(itr);
601 if (strPrefix(token, "custom_"))
602 redefined_ce_found = TRUE;
604 END_HASH_ITERATION(setup_file_hash, itr)
606 freeSetupFileHash(setup_file_hash);
609 printf("::: redefined_ce_found == %d [%s]\n", redefined_ce_found, filename);
612 static void CheckCustomElementGraphicInfo()
614 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
615 int num_property_mappings = getImageListPropertyMappingSize();
616 boolean redefined_ce_found = FALSE;
619 /* check normal element/graphic mapping from static configuration */
620 for (i = 0; element_to_graphic[i].element > -1; i++)
622 int element = element_to_graphic[i].element;
623 int graphic = element_to_graphic[i].graphic;
625 if (IS_CUSTOM_ELEMENT(element))
626 if (getImageListEntryFromImageID(graphic)->redefined)
627 redefined_ce_found = TRUE;
630 /* check normal element/graphic mapping from dynamic configuration */
631 for (i = 0; i < num_property_mappings; i++)
633 int element = property_mapping[i].base_index;
635 if (IS_CUSTOM_ELEMENT(element))
636 redefined_ce_found = TRUE;
639 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
642 void InitElementGraphicInfo()
644 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
645 int num_property_mappings = getImageListPropertyMappingSize();
648 if (graphic_info == NULL) /* still at startup phase */
651 /* set values to -1 to identify later as "uninitialized" values */
652 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
654 for (act = 0; act < NUM_ACTIONS; act++)
656 element_info[i].graphic[act] = -1;
657 element_info[i].crumbled[act] = -1;
659 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
661 element_info[i].direction_graphic[act][dir] = -1;
662 element_info[i].direction_crumbled[act][dir] = -1;
669 /* initialize normal element/graphic mapping from static configuration */
670 for (i = 0; element_to_graphic[i].element > -1; i++)
672 int element = element_to_graphic[i].element;
673 int action = element_to_graphic[i].action;
674 int direction = element_to_graphic[i].direction;
675 boolean crumbled = element_to_graphic[i].crumbled;
676 int graphic = element_to_graphic[i].graphic;
677 int base_graphic = el2baseimg(element);
679 if (graphic_info[graphic].bitmap == NULL)
682 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
685 boolean base_redefined =
686 getImageListEntryFromImageID(base_graphic)->redefined;
687 boolean act_dir_redefined =
688 getImageListEntryFromImageID(graphic)->redefined;
690 /* if the base graphic ("emerald", for example) has been redefined,
691 but not the action graphic ("emerald.falling", for example), do not
692 use an existing (in this case considered obsolete) action graphic
693 anymore, but use the automatically determined default graphic */
694 if (base_redefined && !act_dir_redefined)
699 action = ACTION_DEFAULT;
704 element_info[element].direction_crumbled[action][direction] = graphic;
706 element_info[element].crumbled[action] = graphic;
711 element_info[element].direction_graphic[action][direction] = graphic;
713 element_info[element].graphic[action] = graphic;
717 /* initialize normal element/graphic mapping from dynamic configuration */
718 for (i = 0; i < num_property_mappings; i++)
720 int element = property_mapping[i].base_index;
721 int action = property_mapping[i].ext1_index;
722 int direction = property_mapping[i].ext2_index;
723 int special = property_mapping[i].ext3_index;
724 int graphic = property_mapping[i].artwork_index;
725 boolean crumbled = FALSE;
728 if ((element == EL_EM_DYNAMITE ||
729 element == EL_EM_DYNAMITE_ACTIVE) &&
730 action == ACTION_ACTIVE &&
731 (special == GFX_SPECIAL_ARG_EDITOR ||
732 special == GFX_SPECIAL_ARG_PANEL))
733 printf("::: DYNAMIC: %d, %d, %d -> %d\n",
734 element, action, special, graphic);
737 if (special == GFX_SPECIAL_ARG_CRUMBLED)
743 if (graphic_info[graphic].bitmap == NULL)
746 if (element >= MAX_NUM_ELEMENTS || special != -1)
750 action = ACTION_DEFAULT;
755 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
756 element_info[element].direction_crumbled[action][dir] = -1;
759 element_info[element].direction_crumbled[action][direction] = graphic;
761 element_info[element].crumbled[action] = graphic;
766 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
767 element_info[element].direction_graphic[action][dir] = -1;
770 element_info[element].direction_graphic[action][direction] = graphic;
772 element_info[element].graphic[action] = graphic;
776 /* now copy all graphics that are defined to be cloned from other graphics */
777 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
779 int graphic = element_info[i].graphic[ACTION_DEFAULT];
780 int crumbled_like, diggable_like;
785 crumbled_like = graphic_info[graphic].crumbled_like;
786 diggable_like = graphic_info[graphic].diggable_like;
788 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
790 for (act = 0; act < NUM_ACTIONS; act++)
791 element_info[i].crumbled[act] =
792 element_info[crumbled_like].crumbled[act];
793 for (act = 0; act < NUM_ACTIONS; act++)
794 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
795 element_info[i].direction_crumbled[act][dir] =
796 element_info[crumbled_like].direction_crumbled[act][dir];
799 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
801 element_info[i].graphic[ACTION_DIGGING] =
802 element_info[diggable_like].graphic[ACTION_DIGGING];
803 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
804 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
805 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
810 /* set hardcoded definitions for some runtime elements without graphic */
811 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
815 /* set hardcoded definitions for some internal elements without graphic */
816 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
818 if (IS_EDITOR_CASCADE_INACTIVE(i))
819 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
820 else if (IS_EDITOR_CASCADE_ACTIVE(i))
821 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
825 /* now set all undefined/invalid graphics to -1 to set to default after it */
826 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
828 for (act = 0; act < NUM_ACTIONS; act++)
832 graphic = element_info[i].graphic[act];
833 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
834 element_info[i].graphic[act] = -1;
836 graphic = element_info[i].crumbled[act];
837 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
838 element_info[i].crumbled[act] = -1;
840 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
842 graphic = element_info[i].direction_graphic[act][dir];
843 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
844 element_info[i].direction_graphic[act][dir] = -1;
846 graphic = element_info[i].direction_crumbled[act][dir];
847 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
848 element_info[i].direction_crumbled[act][dir] = -1;
855 /* adjust graphics with 2nd tile for movement according to direction
856 (do this before correcting '-1' values to minimize calculations) */
857 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
859 for (act = 0; act < NUM_ACTIONS; act++)
861 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
863 int graphic = element_info[i].direction_graphic[act][dir];
864 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
866 if (act == ACTION_FALLING) /* special case */
867 graphic = element_info[i].graphic[act];
870 graphic_info[graphic].double_movement &&
871 graphic_info[graphic].swap_double_tiles != 0)
873 struct GraphicInfo *g = &graphic_info[graphic];
874 int src_x_front = g->src_x;
875 int src_y_front = g->src_y;
876 int src_x_back = g->src_x + g->offset2_x;
877 int src_y_back = g->src_y + g->offset2_y;
878 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
880 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
881 src_y_front < src_y_back);
882 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
883 boolean swap_movement_tiles_autodetected =
884 (!frames_are_ordered_diagonally &&
885 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
886 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
887 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
888 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
891 /* swap frontside and backside graphic tile coordinates, if needed */
892 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
894 /* get current (wrong) backside tile coordinates */
895 getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
898 /* set frontside tile coordinates to backside tile coordinates */
899 g->src_x = src_x_back;
900 g->src_y = src_y_back;
902 /* invert tile offset to point to new backside tile coordinates */
906 /* do not swap front and backside tiles again after correction */
907 g->swap_double_tiles = 0;
916 /* now set all '-1' values to element specific default values */
917 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
919 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
920 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
921 int default_direction_graphic[NUM_DIRECTIONS_FULL];
922 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
924 if (default_graphic == -1)
925 default_graphic = IMG_UNKNOWN;
927 if (default_crumbled == -1)
928 default_crumbled = default_graphic;
930 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
931 if (default_crumbled == -1)
932 default_crumbled = IMG_EMPTY;
935 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
937 default_direction_graphic[dir] =
938 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
939 default_direction_crumbled[dir] =
940 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
942 if (default_direction_graphic[dir] == -1)
943 default_direction_graphic[dir] = default_graphic;
945 if (default_direction_crumbled[dir] == -1)
946 default_direction_crumbled[dir] = default_direction_graphic[dir];
948 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
949 if (default_direction_crumbled[dir] == -1)
950 default_direction_crumbled[dir] = default_crumbled;
954 for (act = 0; act < NUM_ACTIONS; act++)
956 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
957 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
958 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
959 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
960 act == ACTION_TURNING_FROM_RIGHT ||
961 act == ACTION_TURNING_FROM_UP ||
962 act == ACTION_TURNING_FROM_DOWN);
964 /* generic default action graphic (defined by "[default]" directive) */
965 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
966 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
967 int default_remove_graphic = IMG_EMPTY;
969 if (act_remove && default_action_graphic != -1)
970 default_remove_graphic = default_action_graphic;
972 /* look for special default action graphic (classic game specific) */
973 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
974 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
975 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
976 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
977 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
978 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
980 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
981 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
982 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
983 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
984 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
985 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
988 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
989 /* !!! make this better !!! */
990 if (i == EL_EMPTY_SPACE)
992 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
993 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
997 if (default_action_graphic == -1)
998 default_action_graphic = default_graphic;
1000 if (default_action_crumbled == -1)
1001 default_action_crumbled = default_action_graphic;
1003 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
1004 if (default_action_crumbled == -1)
1005 default_action_crumbled = default_crumbled;
1008 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1010 /* use action graphic as the default direction graphic, if undefined */
1011 int default_action_direction_graphic = element_info[i].graphic[act];
1012 int default_action_direction_crumbled = element_info[i].crumbled[act];
1014 /* no graphic for current action -- use default direction graphic */
1015 if (default_action_direction_graphic == -1)
1016 default_action_direction_graphic =
1017 (act_remove ? default_remove_graphic :
1019 element_info[i].direction_graphic[ACTION_TURNING][dir] :
1020 default_action_graphic != default_graphic ?
1021 default_action_graphic :
1022 default_direction_graphic[dir]);
1024 if (element_info[i].direction_graphic[act][dir] == -1)
1025 element_info[i].direction_graphic[act][dir] =
1026 default_action_direction_graphic;
1029 if (default_action_direction_crumbled == -1)
1030 default_action_direction_crumbled =
1031 element_info[i].direction_graphic[act][dir];
1033 if (default_action_direction_crumbled == -1)
1034 default_action_direction_crumbled =
1035 (act_remove ? default_remove_graphic :
1037 element_info[i].direction_crumbled[ACTION_TURNING][dir] :
1038 default_action_crumbled != default_crumbled ?
1039 default_action_crumbled :
1040 default_direction_crumbled[dir]);
1043 if (element_info[i].direction_crumbled[act][dir] == -1)
1044 element_info[i].direction_crumbled[act][dir] =
1045 default_action_direction_crumbled;
1048 /* no graphic for this specific action -- use default action graphic */
1049 if (element_info[i].graphic[act] == -1)
1050 element_info[i].graphic[act] =
1051 (act_remove ? default_remove_graphic :
1052 act_turning ? element_info[i].graphic[ACTION_TURNING] :
1053 default_action_graphic);
1055 if (element_info[i].crumbled[act] == -1)
1056 element_info[i].crumbled[act] = element_info[i].graphic[act];
1058 if (element_info[i].crumbled[act] == -1)
1059 element_info[i].crumbled[act] =
1060 (act_remove ? default_remove_graphic :
1061 act_turning ? element_info[i].crumbled[ACTION_TURNING] :
1062 default_action_crumbled);
1067 UPDATE_BUSY_STATE();
1070 /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
1071 /* set animation mode to "none" for each graphic with only 1 frame */
1072 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1074 for (act = 0; act < NUM_ACTIONS; act++)
1076 int graphic = element_info[i].graphic[act];
1077 int crumbled = element_info[i].crumbled[act];
1079 if (graphic_info[graphic].anim_frames == 1)
1080 graphic_info[graphic].anim_mode = ANIM_NONE;
1081 if (graphic_info[crumbled].anim_frames == 1)
1082 graphic_info[crumbled].anim_mode = ANIM_NONE;
1084 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1086 graphic = element_info[i].direction_graphic[act][dir];
1087 crumbled = element_info[i].direction_crumbled[act][dir];
1089 if (graphic_info[graphic].anim_frames == 1)
1090 graphic_info[graphic].anim_mode = ANIM_NONE;
1091 if (graphic_info[crumbled].anim_frames == 1)
1092 graphic_info[crumbled].anim_mode = ANIM_NONE;
1100 if (options.verbose)
1102 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1103 if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1105 Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1106 element_info[i].token_name, i);
1112 void InitElementSpecialGraphicInfo()
1114 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1115 int num_property_mappings = getImageListPropertyMappingSize();
1118 /* always start with reliable default values */
1119 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1120 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1121 element_info[i].special_graphic[j] =
1122 element_info[i].graphic[ACTION_DEFAULT];
1124 /* initialize special element/graphic mapping from static configuration */
1125 for (i = 0; element_to_special_graphic[i].element > -1; i++)
1127 int element = element_to_special_graphic[i].element;
1128 int special = element_to_special_graphic[i].special;
1129 int graphic = element_to_special_graphic[i].graphic;
1130 int base_graphic = el2baseimg(element);
1131 boolean base_redefined =
1132 getImageListEntryFromImageID(base_graphic)->redefined;
1133 boolean special_redefined =
1134 getImageListEntryFromImageID(graphic)->redefined;
1137 if ((element == EL_EM_DYNAMITE ||
1138 element == EL_EM_DYNAMITE_ACTIVE) &&
1139 (special == GFX_SPECIAL_ARG_EDITOR ||
1140 special == GFX_SPECIAL_ARG_PANEL))
1141 printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1142 element, special, graphic);
1145 /* if the base graphic ("emerald", for example) has been redefined,
1146 but not the special graphic ("emerald.EDITOR", for example), do not
1147 use an existing (in this case considered obsolete) special graphic
1148 anymore, but use the automatically created (down-scaled) graphic */
1149 if (base_redefined && !special_redefined)
1152 element_info[element].special_graphic[special] = graphic;
1155 /* initialize special element/graphic mapping from dynamic configuration */
1156 for (i = 0; i < num_property_mappings; i++)
1158 int element = property_mapping[i].base_index;
1159 int action = property_mapping[i].ext1_index;
1160 int direction = property_mapping[i].ext2_index;
1161 int special = property_mapping[i].ext3_index;
1162 int graphic = property_mapping[i].artwork_index;
1165 if ((element == EL_EM_DYNAMITE ||
1166 element == EL_EM_DYNAMITE_ACTIVE ||
1167 element == EL_CONVEYOR_BELT_1_MIDDLE ||
1168 element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1169 (special == GFX_SPECIAL_ARG_EDITOR ||
1170 special == GFX_SPECIAL_ARG_PANEL))
1171 printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1172 element, special, graphic, property_mapping[i].ext1_index);
1176 if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1177 action == ACTION_ACTIVE)
1179 element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1185 if (element == EL_MAGIC_WALL &&
1186 action == ACTION_ACTIVE)
1188 element = EL_MAGIC_WALL_ACTIVE;
1194 /* for action ".active", replace element with active element, if exists */
1195 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1197 element = ELEMENT_ACTIVE(element);
1202 if (element >= MAX_NUM_ELEMENTS)
1205 /* do not change special graphic if action or direction was specified */
1206 if (action != -1 || direction != -1)
1209 if (IS_SPECIAL_GFX_ARG(special))
1210 element_info[element].special_graphic[special] = graphic;
1213 /* now set all undefined/invalid graphics to default */
1214 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1215 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1216 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1217 element_info[i].special_graphic[j] =
1218 element_info[i].graphic[ACTION_DEFAULT];
1221 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1223 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1224 return get_parameter_value(value_raw, suffix, type);
1226 if (strEqual(value_raw, ARG_UNDEFINED))
1227 return ARG_UNDEFINED_VALUE;
1230 if (type == TYPE_ELEMENT)
1232 char *value = getHashEntry(element_token_hash, value_raw);
1234 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1236 else if (type == TYPE_GRAPHIC)
1238 char *value = getHashEntry(graphic_token_hash, value_raw);
1240 return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1248 /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1249 /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1251 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1252 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1253 if (strEqual(element_info[i].token_name, value_raw))
1256 /* !!! OPTIMIZE THIS BY USING HASH !!! */
1257 for (i = 0; image_config[i].token != NULL; i++)
1259 int len_config_value = strlen(image_config[i].value);
1261 if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1262 !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1263 !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1266 if (strEqual(image_config[i].token, value_raw))
1276 static int get_scaled_graphic_width(int graphic)
1278 int original_width = getOriginalImageWidthFromImageID(graphic);
1279 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1281 return original_width * scale_up_factor;
1284 static int get_scaled_graphic_height(int graphic)
1286 int original_height = getOriginalImageHeightFromImageID(graphic);
1287 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1289 return original_height * scale_up_factor;
1292 static void set_graphic_parameters_ext(int graphic, struct GraphicInfo *g,
1293 int *parameter, Bitmap *src_bitmap)
1295 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1296 int anim_frames_per_line = 1;
1298 /* always start with reliable default values */
1299 g->src_image_width = 0;
1300 g->src_image_height = 0;
1303 g->width = TILEX; /* default for element graphics */
1304 g->height = TILEY; /* default for element graphics */
1305 g->offset_x = 0; /* one or both of these values ... */
1306 g->offset_y = 0; /* ... will be corrected later */
1307 g->offset2_x = 0; /* one or both of these values ... */
1308 g->offset2_y = 0; /* ... will be corrected later */
1309 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1310 g->crumbled_like = -1; /* do not use clone element */
1311 g->diggable_like = -1; /* do not use clone element */
1312 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1313 g->scale_up_factor = 1; /* default: no scaling up */
1314 g->clone_from = -1; /* do not use clone graphic */
1315 g->anim_delay_fixed = 0;
1316 g->anim_delay_random = 0;
1317 g->post_delay_fixed = 0;
1318 g->post_delay_random = 0;
1319 g->fade_mode = FADE_MODE_DEFAULT;
1323 g->align = ALIGN_CENTER; /* default for title screens */
1324 g->valign = VALIGN_MIDDLE; /* default for title screens */
1325 g->sort_priority = 0; /* default for title screens */
1327 g->bitmap = src_bitmap;
1330 /* optional zoom factor for scaling up the image to a larger size */
1331 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1332 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1333 if (g->scale_up_factor < 1)
1334 g->scale_up_factor = 1; /* no scaling */
1338 if (g->use_image_size)
1340 /* set new default bitmap size (with scaling, but without small images) */
1341 g->width = get_scaled_graphic_width(graphic);
1342 g->height = get_scaled_graphic_height(graphic);
1346 /* optional x and y tile position of animation frame sequence */
1347 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1348 g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1349 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1350 g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1352 /* optional x and y pixel position of animation frame sequence */
1353 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1354 g->src_x = parameter[GFX_ARG_X];
1355 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1356 g->src_y = parameter[GFX_ARG_Y];
1358 /* optional width and height of each animation frame */
1359 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1360 g->width = parameter[GFX_ARG_WIDTH];
1361 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1362 g->height = parameter[GFX_ARG_HEIGHT];
1365 /* optional zoom factor for scaling up the image to a larger size */
1366 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1367 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1368 if (g->scale_up_factor < 1)
1369 g->scale_up_factor = 1; /* no scaling */
1374 /* get final bitmap size (with scaling, but without small images) */
1375 int src_image_width = get_scaled_graphic_width(graphic);
1376 int src_image_height = get_scaled_graphic_height(graphic);
1378 anim_frames_per_row = src_image_width / g->width;
1379 anim_frames_per_col = src_image_height / g->height;
1381 g->src_image_width = src_image_width;
1382 g->src_image_height = src_image_height;
1385 /* correct x or y offset dependent of vertical or horizontal frame order */
1386 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1388 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1389 parameter[GFX_ARG_OFFSET] : g->height);
1390 anim_frames_per_line = anim_frames_per_col;
1392 else /* frames are ordered horizontally */
1394 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1395 parameter[GFX_ARG_OFFSET] : g->width);
1396 anim_frames_per_line = anim_frames_per_row;
1399 /* optionally, the x and y offset of frames can be specified directly */
1400 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1401 g->offset_x = parameter[GFX_ARG_XOFFSET];
1402 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1403 g->offset_y = parameter[GFX_ARG_YOFFSET];
1405 /* optionally, moving animations may have separate start and end graphics */
1406 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1408 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1409 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1411 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1412 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1413 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1414 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1415 else /* frames are ordered horizontally */
1416 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1417 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1419 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1420 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1421 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1422 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1423 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1425 /* optionally, the second movement tile can be specified as start tile */
1426 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1427 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1429 /* automatically determine correct number of frames, if not defined */
1430 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1431 g->anim_frames = parameter[GFX_ARG_FRAMES];
1432 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1433 g->anim_frames = anim_frames_per_row;
1434 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1435 g->anim_frames = anim_frames_per_col;
1439 if (g->anim_frames == 0) /* frames must be at least 1 */
1442 g->anim_frames_per_line =
1443 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1444 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1446 g->anim_delay = parameter[GFX_ARG_DELAY];
1447 if (g->anim_delay == 0) /* delay must be at least 1 */
1450 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1452 if (g->anim_frames == 1)
1453 g->anim_mode = ANIM_NONE;
1456 /* automatically determine correct start frame, if not defined */
1457 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1458 g->anim_start_frame = 0;
1459 else if (g->anim_mode & ANIM_REVERSE)
1460 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1462 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1464 /* animation synchronized with global frame counter, not move position */
1465 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1467 /* optional element for cloning crumble graphics */
1468 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1469 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1471 /* optional element for cloning digging graphics */
1472 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1473 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1475 /* optional border size for "crumbling" diggable graphics */
1476 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1477 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1479 /* this is only used for player "boring" and "sleeping" actions */
1480 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1481 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1482 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1483 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1484 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1485 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1486 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1487 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1489 /* this is only used for toon animations */
1490 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1491 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1493 /* this is only used for drawing font characters */
1494 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1495 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1497 /* this is only used for drawing envelope graphics */
1498 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1500 /* optional graphic for cloning all graphics settings */
1501 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1502 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1504 /* optional settings for drawing title screens and title messages */
1505 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1506 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1507 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1508 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1509 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1510 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1511 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1512 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1513 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1514 g->align = parameter[GFX_ARG_ALIGN];
1515 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1516 g->valign = parameter[GFX_ARG_VALIGN];
1517 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1518 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1521 static void set_graphic_parameters(int graphic)
1524 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1525 char **parameter_raw = image->parameter;
1526 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1527 int parameter[NUM_GFX_ARGS];
1530 /* if fallback to default artwork is done, also use the default parameters */
1531 if (image->fallback_to_default)
1532 parameter_raw = image->default_parameter;
1534 /* get integer values from string parameters */
1535 for (i = 0; i < NUM_GFX_ARGS; i++)
1536 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1537 image_config_suffix[i].token,
1538 image_config_suffix[i].type);
1540 set_graphic_parameters_ext(graphic, &graphic_info[graphic],
1541 parameter, src_bitmap);
1545 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1546 char **parameter_raw = image->parameter;
1547 Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1548 int parameter[NUM_GFX_ARGS];
1549 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1550 int anim_frames_per_line = 1;
1553 /* if fallback to default artwork is done, also use the default parameters */
1554 if (image->fallback_to_default)
1555 parameter_raw = image->default_parameter;
1557 /* get integer values from string parameters */
1558 for (i = 0; i < NUM_GFX_ARGS; i++)
1559 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1560 image_config_suffix[i].token,
1561 image_config_suffix[i].type);
1563 graphic_info[graphic].bitmap = src_bitmap;
1565 /* always start with reliable default values */
1566 graphic_info[graphic].src_image_width = 0;
1567 graphic_info[graphic].src_image_height = 0;
1568 graphic_info[graphic].src_x = 0;
1569 graphic_info[graphic].src_y = 0;
1570 graphic_info[graphic].width = TILEX; /* default for element graphics */
1571 graphic_info[graphic].height = TILEY; /* default for element graphics */
1572 graphic_info[graphic].offset_x = 0; /* one or both of these values ... */
1573 graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
1574 graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
1575 graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
1576 graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1577 graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
1578 graphic_info[graphic].diggable_like = -1; /* do not use clone element */
1579 graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
1580 graphic_info[graphic].scale_up_factor = 1; /* default: no scaling up */
1581 graphic_info[graphic].clone_from = -1; /* do not use clone graphic */
1582 graphic_info[graphic].anim_delay_fixed = 0;
1583 graphic_info[graphic].anim_delay_random = 0;
1584 graphic_info[graphic].post_delay_fixed = 0;
1585 graphic_info[graphic].post_delay_random = 0;
1586 graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1587 graphic_info[graphic].fade_delay = -1;
1588 graphic_info[graphic].post_delay = -1;
1589 graphic_info[graphic].auto_delay = -1;
1590 graphic_info[graphic].align = ALIGN_CENTER; /* default for title screens */
1591 graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1592 graphic_info[graphic].sort_priority = 0; /* default for title screens */
1595 /* optional zoom factor for scaling up the image to a larger size */
1596 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1597 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1598 if (graphic_info[graphic].scale_up_factor < 1)
1599 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1603 if (graphic_info[graphic].use_image_size)
1605 /* set new default bitmap size (with scaling, but without small images) */
1606 graphic_info[graphic].width = get_scaled_graphic_width(graphic);
1607 graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1611 /* optional x and y tile position of animation frame sequence */
1612 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1613 graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1614 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1615 graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1617 /* optional x and y pixel position of animation frame sequence */
1618 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1619 graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1620 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1621 graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1623 /* optional width and height of each animation frame */
1624 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1625 graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1626 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1627 graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1630 /* optional zoom factor for scaling up the image to a larger size */
1631 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1632 graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1633 if (graphic_info[graphic].scale_up_factor < 1)
1634 graphic_info[graphic].scale_up_factor = 1; /* no scaling */
1639 /* get final bitmap size (with scaling, but without small images) */
1640 int src_image_width = get_scaled_graphic_width(graphic);
1641 int src_image_height = get_scaled_graphic_height(graphic);
1643 anim_frames_per_row = src_image_width / graphic_info[graphic].width;
1644 anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1646 graphic_info[graphic].src_image_width = src_image_width;
1647 graphic_info[graphic].src_image_height = src_image_height;
1650 /* correct x or y offset dependent of vertical or horizontal frame order */
1651 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1653 graphic_info[graphic].offset_y =
1654 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1655 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1656 anim_frames_per_line = anim_frames_per_col;
1658 else /* frames are ordered horizontally */
1660 graphic_info[graphic].offset_x =
1661 (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1662 parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1663 anim_frames_per_line = anim_frames_per_row;
1666 /* optionally, the x and y offset of frames can be specified directly */
1667 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1668 graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1669 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1670 graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1672 /* optionally, moving animations may have separate start and end graphics */
1673 graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1675 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1676 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1678 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1679 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1680 graphic_info[graphic].offset2_y =
1681 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1682 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1683 else /* frames are ordered horizontally */
1684 graphic_info[graphic].offset2_x =
1685 (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1686 parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1688 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1689 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1690 graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1691 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1692 graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1694 /* optionally, the second movement tile can be specified as start tile */
1695 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1696 graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1698 /* automatically determine correct number of frames, if not defined */
1699 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1700 graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1701 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1702 graphic_info[graphic].anim_frames = anim_frames_per_row;
1703 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1704 graphic_info[graphic].anim_frames = anim_frames_per_col;
1706 graphic_info[graphic].anim_frames = 1;
1708 if (graphic_info[graphic].anim_frames == 0) /* frames must be at least 1 */
1709 graphic_info[graphic].anim_frames = 1;
1711 graphic_info[graphic].anim_frames_per_line =
1712 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1713 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1715 graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1716 if (graphic_info[graphic].anim_delay == 0) /* delay must be at least 1 */
1717 graphic_info[graphic].anim_delay = 1;
1719 graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1721 if (graphic_info[graphic].anim_frames == 1)
1722 graphic_info[graphic].anim_mode = ANIM_NONE;
1725 /* automatically determine correct start frame, if not defined */
1726 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1727 graphic_info[graphic].anim_start_frame = 0;
1728 else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1729 graphic_info[graphic].anim_start_frame =
1730 graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1732 graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1734 /* animation synchronized with global frame counter, not move position */
1735 graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1737 /* optional element for cloning crumble graphics */
1738 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1739 graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1741 /* optional element for cloning digging graphics */
1742 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1743 graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1745 /* optional border size for "crumbling" diggable graphics */
1746 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1747 graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1749 /* this is only used for player "boring" and "sleeping" actions */
1750 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1751 graphic_info[graphic].anim_delay_fixed =
1752 parameter[GFX_ARG_ANIM_DELAY_FIXED];
1753 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1754 graphic_info[graphic].anim_delay_random =
1755 parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1756 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1757 graphic_info[graphic].post_delay_fixed =
1758 parameter[GFX_ARG_POST_DELAY_FIXED];
1759 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1760 graphic_info[graphic].post_delay_random =
1761 parameter[GFX_ARG_POST_DELAY_RANDOM];
1763 /* this is only used for toon animations */
1764 graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1765 graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
1767 /* this is only used for drawing font characters */
1768 graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1769 graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1771 /* this is only used for drawing envelope graphics */
1772 graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1774 /* optional graphic for cloning all graphics settings */
1775 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1776 graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1778 /* optional settings for drawing title screens and title messages */
1779 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1780 graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1781 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1782 graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1783 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1784 graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1785 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1786 graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1787 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1788 graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1789 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1790 graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1791 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1792 graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1795 UPDATE_BUSY_STATE();
1798 static void set_cloned_graphic_parameters(int graphic)
1800 int fallback_graphic = IMG_CHAR_EXCLAM;
1801 int max_num_images = getImageListSize();
1802 int clone_graphic = graphic_info[graphic].clone_from;
1803 int num_references_followed = 1;
1805 while (graphic_info[clone_graphic].clone_from != -1 &&
1806 num_references_followed < max_num_images)
1808 clone_graphic = graphic_info[clone_graphic].clone_from;
1810 num_references_followed++;
1813 if (num_references_followed >= max_num_images)
1815 Error(ERR_INFO_LINE, "-");
1816 Error(ERR_INFO, "warning: error found in config file:");
1817 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1818 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1819 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1820 Error(ERR_INFO, "custom graphic rejected for this element/action");
1822 if (graphic == fallback_graphic)
1823 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1825 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1826 Error(ERR_INFO_LINE, "-");
1828 graphic_info[graphic] = graphic_info[fallback_graphic];
1832 graphic_info[graphic] = graphic_info[clone_graphic];
1833 graphic_info[graphic].clone_from = clone_graphic;
1837 static void InitGraphicInfo()
1839 int fallback_graphic = IMG_CHAR_EXCLAM;
1840 int num_images = getImageListSize();
1843 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1844 static boolean clipmasks_initialized = FALSE;
1846 XGCValues clip_gc_values;
1847 unsigned long clip_gc_valuemask;
1848 GC copy_clipmask_gc = None;
1851 /* use image size as default values for width and height for these images */
1852 static int full_size_graphics[] =
1857 IMG_BACKGROUND_ENVELOPE_1,
1858 IMG_BACKGROUND_ENVELOPE_2,
1859 IMG_BACKGROUND_ENVELOPE_3,
1860 IMG_BACKGROUND_ENVELOPE_4,
1863 IMG_BACKGROUND_TITLE_INITIAL,
1864 IMG_BACKGROUND_TITLE,
1865 IMG_BACKGROUND_MAIN,
1866 IMG_BACKGROUND_LEVELS,
1867 IMG_BACKGROUND_SCORES,
1868 IMG_BACKGROUND_EDITOR,
1869 IMG_BACKGROUND_INFO,
1870 IMG_BACKGROUND_INFO_ELEMENTS,
1871 IMG_BACKGROUND_INFO_MUSIC,
1872 IMG_BACKGROUND_INFO_CREDITS,
1873 IMG_BACKGROUND_INFO_PROGRAM,
1874 IMG_BACKGROUND_INFO_LEVELSET,
1875 IMG_BACKGROUND_SETUP,
1876 IMG_BACKGROUND_DOOR,
1878 IMG_TITLESCREEN_INITIAL_1,
1879 IMG_TITLESCREEN_INITIAL_2,
1880 IMG_TITLESCREEN_INITIAL_3,
1881 IMG_TITLESCREEN_INITIAL_4,
1882 IMG_TITLESCREEN_INITIAL_5,
1892 checked_free(graphic_info);
1894 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1897 /* initialize "use_image_size" flag with default value */
1898 for (i = 0; i < num_images; i++)
1899 graphic_info[i].use_image_size = FALSE;
1901 /* initialize "use_image_size" flag from static configuration above */
1902 for (i = 0; full_size_graphics[i] != -1; i++)
1903 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1906 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1907 if (clipmasks_initialized)
1909 for (i = 0; i < num_images; i++)
1911 if (graphic_info[i].clip_mask)
1912 XFreePixmap(display, graphic_info[i].clip_mask);
1913 if (graphic_info[i].clip_gc)
1914 XFreeGC(display, graphic_info[i].clip_gc);
1916 graphic_info[i].clip_mask = None;
1917 graphic_info[i].clip_gc = None;
1922 /* first set all graphic paramaters ... */
1923 for (i = 0; i < num_images; i++)
1924 set_graphic_parameters(i);
1926 /* ... then copy these parameters for cloned graphics */
1927 for (i = 0; i < num_images; i++)
1928 if (graphic_info[i].clone_from != -1)
1929 set_cloned_graphic_parameters(i);
1931 for (i = 0; i < num_images; i++)
1936 int first_frame, last_frame;
1937 int src_bitmap_width, src_bitmap_height;
1939 /* now check if no animation frames are outside of the loaded image */
1941 if (graphic_info[i].bitmap == NULL)
1942 continue; /* skip check for optional images that are undefined */
1944 /* get image size (this can differ from the standard element tile size!) */
1945 width = graphic_info[i].width;
1946 height = graphic_info[i].height;
1948 /* get final bitmap size (with scaling, but without small images) */
1949 src_bitmap_width = graphic_info[i].src_image_width;
1950 src_bitmap_height = graphic_info[i].src_image_height;
1952 /* check if first animation frame is inside specified bitmap */
1955 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1958 /* this avoids calculating wrong start position for out-of-bounds frame */
1959 src_x = graphic_info[i].src_x;
1960 src_y = graphic_info[i].src_y;
1963 if (src_x < 0 || src_y < 0 ||
1964 src_x + width > src_bitmap_width ||
1965 src_y + height > src_bitmap_height)
1967 Error(ERR_INFO_LINE, "-");
1968 Error(ERR_INFO, "warning: error found in config file:");
1969 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1970 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1971 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1973 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1974 src_x, src_y, src_bitmap_width, src_bitmap_height);
1975 Error(ERR_INFO, "custom graphic rejected for this element/action");
1977 if (i == fallback_graphic)
1978 Error(ERR_EXIT, "fatal error: no fallback graphic available");
1980 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1981 Error(ERR_INFO_LINE, "-");
1983 graphic_info[i] = graphic_info[fallback_graphic];
1986 /* check if last animation frame is inside specified bitmap */
1988 last_frame = graphic_info[i].anim_frames - 1;
1989 getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1991 if (src_x < 0 || src_y < 0 ||
1992 src_x + width > src_bitmap_width ||
1993 src_y + height > src_bitmap_height)
1995 Error(ERR_INFO_LINE, "-");
1996 Error(ERR_INFO, "warning: error found in config file:");
1997 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1998 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1999 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
2001 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
2002 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
2003 Error(ERR_INFO, "custom graphic rejected for this element/action");
2005 if (i == fallback_graphic)
2006 Error(ERR_EXIT, "fatal error: no fallback graphic available");
2008 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
2009 Error(ERR_INFO_LINE, "-");
2011 graphic_info[i] = graphic_info[fallback_graphic];
2014 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2015 /* currently we only need a tile clip mask from the first frame */
2016 getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
2018 if (copy_clipmask_gc == None)
2020 clip_gc_values.graphics_exposures = False;
2021 clip_gc_valuemask = GCGraphicsExposures;
2022 copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
2023 clip_gc_valuemask, &clip_gc_values);
2026 graphic_info[i].clip_mask =
2027 XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
2029 src_pixmap = src_bitmap->clip_mask;
2030 XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
2031 copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
2033 clip_gc_values.graphics_exposures = False;
2034 clip_gc_values.clip_mask = graphic_info[i].clip_mask;
2035 clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
2037 graphic_info[i].clip_gc =
2038 XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
2042 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
2043 if (copy_clipmask_gc)
2044 XFreeGC(display, copy_clipmask_gc);
2046 clipmasks_initialized = TRUE;
2050 static void InitElementSoundInfo()
2052 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2053 int num_property_mappings = getSoundListPropertyMappingSize();
2056 /* set values to -1 to identify later as "uninitialized" values */
2057 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2058 for (act = 0; act < NUM_ACTIONS; act++)
2059 element_info[i].sound[act] = -1;
2061 /* initialize element/sound mapping from static configuration */
2062 for (i = 0; element_to_sound[i].element > -1; i++)
2064 int element = element_to_sound[i].element;
2065 int action = element_to_sound[i].action;
2066 int sound = element_to_sound[i].sound;
2067 boolean is_class = element_to_sound[i].is_class;
2070 action = ACTION_DEFAULT;
2073 element_info[element].sound[action] = sound;
2075 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2076 if (strEqual(element_info[j].class_name,
2077 element_info[element].class_name))
2078 element_info[j].sound[action] = sound;
2081 /* initialize element class/sound mapping from dynamic configuration */
2082 for (i = 0; i < num_property_mappings; i++)
2084 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2085 int action = property_mapping[i].ext1_index;
2086 int sound = property_mapping[i].artwork_index;
2088 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2092 action = ACTION_DEFAULT;
2094 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2095 if (strEqual(element_info[j].class_name,
2096 element_info[element_class].class_name))
2097 element_info[j].sound[action] = sound;
2100 /* initialize element/sound mapping from dynamic configuration */
2101 for (i = 0; i < num_property_mappings; i++)
2103 int element = property_mapping[i].base_index;
2104 int action = property_mapping[i].ext1_index;
2105 int sound = property_mapping[i].artwork_index;
2107 if (element >= MAX_NUM_ELEMENTS)
2111 action = ACTION_DEFAULT;
2113 element_info[element].sound[action] = sound;
2116 /* now set all '-1' values to element specific default values */
2117 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2119 for (act = 0; act < NUM_ACTIONS; act++)
2121 /* generic default action sound (defined by "[default]" directive) */
2122 int default_action_sound = element_info[EL_DEFAULT].sound[act];
2124 /* look for special default action sound (classic game specific) */
2125 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2126 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2127 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2128 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2129 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2130 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2132 /* !!! there's no such thing as a "default action sound" !!! */
2134 /* look for element specific default sound (independent from action) */
2135 if (element_info[i].sound[ACTION_DEFAULT] != -1)
2136 default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2140 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2141 /* !!! make this better !!! */
2142 if (i == EL_EMPTY_SPACE)
2143 default_action_sound = element_info[EL_DEFAULT].sound[act];
2146 /* no sound for this specific action -- use default action sound */
2147 if (element_info[i].sound[act] == -1)
2148 element_info[i].sound[act] = default_action_sound;
2152 /* copy sound settings to some elements that are only stored in level file
2153 in native R'n'D levels, but are used by game engine in native EM levels */
2154 for (i = 0; copy_properties[i][0] != -1; i++)
2155 for (j = 1; j <= 4; j++)
2156 for (act = 0; act < NUM_ACTIONS; act++)
2157 element_info[copy_properties[i][j]].sound[act] =
2158 element_info[copy_properties[i][0]].sound[act];
2161 static void InitGameModeSoundInfo()
2165 /* set values to -1 to identify later as "uninitialized" values */
2166 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2169 /* initialize gamemode/sound mapping from static configuration */
2170 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2172 int gamemode = gamemode_to_sound[i].gamemode;
2173 int sound = gamemode_to_sound[i].sound;
2176 gamemode = GAME_MODE_DEFAULT;
2178 menu.sound[gamemode] = sound;
2181 /* now set all '-1' values to levelset specific default values */
2182 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2183 if (menu.sound[i] == -1)
2184 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2187 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2188 if (menu.sound[i] != -1)
2189 printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2193 static void set_sound_parameters(int sound, char **parameter_raw)
2195 int parameter[NUM_SND_ARGS];
2198 /* get integer values from string parameters */
2199 for (i = 0; i < NUM_SND_ARGS; i++)
2201 get_parameter_value(parameter_raw[i],
2202 sound_config_suffix[i].token,
2203 sound_config_suffix[i].type);
2205 /* explicit loop mode setting in configuration overrides default value */
2206 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2207 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2209 /* sound volume to change the original volume when loading the sound file */
2210 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2212 /* sound priority to give certain sounds a higher or lower priority */
2213 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2216 static void InitSoundInfo()
2218 int *sound_effect_properties;
2219 int num_sounds = getSoundListSize();
2222 checked_free(sound_info);
2224 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2225 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2227 /* initialize sound effect for all elements to "no sound" */
2228 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2229 for (j = 0; j < NUM_ACTIONS; j++)
2230 element_info[i].sound[j] = SND_UNDEFINED;
2232 for (i = 0; i < num_sounds; i++)
2234 struct FileInfo *sound = getSoundListEntry(i);
2235 int len_effect_text = strlen(sound->token);
2237 sound_effect_properties[i] = ACTION_OTHER;
2238 sound_info[i].loop = FALSE; /* default: play sound only once */
2241 printf("::: sound %d: '%s'\n", i, sound->token);
2244 /* determine all loop sounds and identify certain sound classes */
2246 for (j = 0; element_action_info[j].suffix; j++)
2248 int len_action_text = strlen(element_action_info[j].suffix);
2250 if (len_action_text < len_effect_text &&
2251 strEqual(&sound->token[len_effect_text - len_action_text],
2252 element_action_info[j].suffix))
2254 sound_effect_properties[i] = element_action_info[j].value;
2255 sound_info[i].loop = element_action_info[j].is_loop_sound;
2261 /* associate elements and some selected sound actions */
2263 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2265 if (element_info[j].class_name)
2267 int len_class_text = strlen(element_info[j].class_name);
2269 if (len_class_text + 1 < len_effect_text &&
2270 strncmp(sound->token,
2271 element_info[j].class_name, len_class_text) == 0 &&
2272 sound->token[len_class_text] == '.')
2274 int sound_action_value = sound_effect_properties[i];
2276 element_info[j].sound[sound_action_value] = i;
2281 set_sound_parameters(i, sound->parameter);
2284 free(sound_effect_properties);
2287 static void InitGameModeMusicInfo()
2289 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2290 int num_property_mappings = getMusicListPropertyMappingSize();
2291 int default_levelset_music = -1;
2294 /* set values to -1 to identify later as "uninitialized" values */
2295 for (i = 0; i < MAX_LEVELS; i++)
2296 levelset.music[i] = -1;
2297 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2300 /* initialize gamemode/music mapping from static configuration */
2301 for (i = 0; gamemode_to_music[i].music > -1; i++)
2303 int gamemode = gamemode_to_music[i].gamemode;
2304 int music = gamemode_to_music[i].music;
2307 printf("::: gamemode == %d, music == %d\n", gamemode, music);
2311 gamemode = GAME_MODE_DEFAULT;
2313 menu.music[gamemode] = music;
2316 /* initialize gamemode/music mapping from dynamic configuration */
2317 for (i = 0; i < num_property_mappings; i++)
2319 int prefix = property_mapping[i].base_index;
2320 int gamemode = property_mapping[i].ext1_index;
2321 int level = property_mapping[i].ext2_index;
2322 int music = property_mapping[i].artwork_index;
2325 printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2326 prefix, gamemode, level, music);
2329 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2333 gamemode = GAME_MODE_DEFAULT;
2335 /* level specific music only allowed for in-game music */
2336 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2337 gamemode = GAME_MODE_PLAYING;
2342 default_levelset_music = music;
2345 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2346 levelset.music[level] = music;
2347 if (gamemode != GAME_MODE_PLAYING)
2348 menu.music[gamemode] = music;
2351 /* now set all '-1' values to menu specific default values */
2352 /* (undefined values of "levelset.music[]" might stay at "-1" to
2353 allow dynamic selection of music files from music directory!) */
2354 for (i = 0; i < MAX_LEVELS; i++)
2355 if (levelset.music[i] == -1)
2356 levelset.music[i] = default_levelset_music;
2357 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2358 if (menu.music[i] == -1)
2359 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2362 for (i = 0; i < MAX_LEVELS; i++)
2363 if (levelset.music[i] != -1)
2364 printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2365 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2366 if (menu.music[i] != -1)
2367 printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2371 static void set_music_parameters(int music, char **parameter_raw)
2373 int parameter[NUM_MUS_ARGS];
2376 /* get integer values from string parameters */
2377 for (i = 0; i < NUM_MUS_ARGS; i++)
2379 get_parameter_value(parameter_raw[i],
2380 music_config_suffix[i].token,
2381 music_config_suffix[i].type);
2383 /* explicit loop mode setting in configuration overrides default value */
2384 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2385 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2388 static void InitMusicInfo()
2390 int num_music = getMusicListSize();
2393 checked_free(music_info);
2395 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2397 for (i = 0; i < num_music; i++)
2399 struct FileInfo *music = getMusicListEntry(i);
2400 int len_music_text = strlen(music->token);
2402 music_info[i].loop = TRUE; /* default: play music in loop mode */
2404 /* determine all loop music */
2406 for (j = 0; music_prefix_info[j].prefix; j++)
2408 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2410 if (len_prefix_text < len_music_text &&
2411 strncmp(music->token,
2412 music_prefix_info[j].prefix, len_prefix_text) == 0)
2414 music_info[i].loop = music_prefix_info[j].is_loop_music;
2420 set_music_parameters(i, music->parameter);
2424 static void ReinitializeGraphics()
2426 print_timestamp_init("ReinitializeGraphics");
2428 InitGraphicInfo(); /* graphic properties mapping */
2429 print_timestamp_time("InitGraphicInfo");
2430 InitElementGraphicInfo(); /* element game graphic mapping */
2431 print_timestamp_time("InitElementGraphicInfo");
2432 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2433 print_timestamp_time("InitElementSpecialGraphicInfo");
2435 InitElementSmallImages(); /* scale elements to all needed sizes */
2436 print_timestamp_time("InitElementSmallImages");
2437 InitScaledImages(); /* scale all other images, if needed */
2438 print_timestamp_time("InitScaledImages");
2439 InitFontGraphicInfo(); /* initialize text drawing functions */
2440 print_timestamp_time("InitFontGraphicInfo");
2442 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2443 print_timestamp_time("InitGraphicInfo_EM");
2445 SetMainBackgroundImage(IMG_BACKGROUND);
2446 print_timestamp_time("SetMainBackgroundImage");
2447 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2448 print_timestamp_time("SetDoorBackgroundImage");
2451 print_timestamp_time("InitGadgets");
2453 print_timestamp_time("InitToons");
2455 print_timestamp_done("ReinitializeGraphics");
2458 static void ReinitializeSounds()
2460 InitSoundInfo(); /* sound properties mapping */
2461 InitElementSoundInfo(); /* element game sound mapping */
2462 InitGameModeSoundInfo(); /* game mode sound mapping */
2464 InitPlayLevelSound(); /* internal game sound settings */
2467 static void ReinitializeMusic()
2469 InitMusicInfo(); /* music properties mapping */
2470 InitGameModeMusicInfo(); /* game mode music mapping */
2473 static int get_special_property_bit(int element, int property_bit_nr)
2475 struct PropertyBitInfo
2481 static struct PropertyBitInfo pb_can_move_into_acid[] =
2483 /* the player may be able fall into acid when gravity is activated */
2488 { EL_SP_MURPHY, 0 },
2489 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2491 /* all elements that can move may be able to also move into acid */
2494 { EL_BUG_RIGHT, 1 },
2497 { EL_SPACESHIP, 2 },
2498 { EL_SPACESHIP_LEFT, 2 },
2499 { EL_SPACESHIP_RIGHT, 2 },
2500 { EL_SPACESHIP_UP, 2 },
2501 { EL_SPACESHIP_DOWN, 2 },
2502 { EL_BD_BUTTERFLY, 3 },
2503 { EL_BD_BUTTERFLY_LEFT, 3 },
2504 { EL_BD_BUTTERFLY_RIGHT, 3 },
2505 { EL_BD_BUTTERFLY_UP, 3 },
2506 { EL_BD_BUTTERFLY_DOWN, 3 },
2507 { EL_BD_FIREFLY, 4 },
2508 { EL_BD_FIREFLY_LEFT, 4 },
2509 { EL_BD_FIREFLY_RIGHT, 4 },
2510 { EL_BD_FIREFLY_UP, 4 },
2511 { EL_BD_FIREFLY_DOWN, 4 },
2513 { EL_YAMYAM_LEFT, 5 },
2514 { EL_YAMYAM_RIGHT, 5 },
2515 { EL_YAMYAM_UP, 5 },
2516 { EL_YAMYAM_DOWN, 5 },
2517 { EL_DARK_YAMYAM, 6 },
2520 { EL_PACMAN_LEFT, 8 },
2521 { EL_PACMAN_RIGHT, 8 },
2522 { EL_PACMAN_UP, 8 },
2523 { EL_PACMAN_DOWN, 8 },
2525 { EL_MOLE_LEFT, 9 },
2526 { EL_MOLE_RIGHT, 9 },
2528 { EL_MOLE_DOWN, 9 },
2532 { EL_SATELLITE, 13 },
2533 { EL_SP_SNIKSNAK, 14 },
2534 { EL_SP_ELECTRON, 15 },
2537 { EL_EMC_ANDROID, 18 },
2542 static struct PropertyBitInfo pb_dont_collide_with[] =
2544 { EL_SP_SNIKSNAK, 0 },
2545 { EL_SP_ELECTRON, 1 },
2553 struct PropertyBitInfo *pb_info;
2556 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2557 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2562 struct PropertyBitInfo *pb_info = NULL;
2565 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2566 if (pb_definition[i].bit_nr == property_bit_nr)
2567 pb_info = pb_definition[i].pb_info;
2569 if (pb_info == NULL)
2572 for (i = 0; pb_info[i].element != -1; i++)
2573 if (pb_info[i].element == element)
2574 return pb_info[i].bit_nr;
2579 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2580 boolean property_value)
2582 int bit_nr = get_special_property_bit(element, property_bit_nr);
2587 *bitfield |= (1 << bit_nr);
2589 *bitfield &= ~(1 << bit_nr);
2593 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2595 int bit_nr = get_special_property_bit(element, property_bit_nr);
2598 return ((*bitfield & (1 << bit_nr)) != 0);
2603 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2605 static int group_nr;
2606 static struct ElementGroupInfo *group;
2607 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2610 if (actual_group == NULL) /* not yet initialized */
2613 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2615 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2616 group_element - EL_GROUP_START + 1);
2618 /* replace element which caused too deep recursion by question mark */
2619 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2624 if (recursion_depth == 0) /* initialization */
2626 group = actual_group;
2627 group_nr = GROUP_NR(group_element);
2629 group->num_elements_resolved = 0;
2630 group->choice_pos = 0;
2632 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2633 element_info[i].in_group[group_nr] = FALSE;
2636 for (i = 0; i < actual_group->num_elements; i++)
2638 int element = actual_group->element[i];
2640 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2643 if (IS_GROUP_ELEMENT(element))
2644 ResolveGroupElementExt(element, recursion_depth + 1);
2647 group->element_resolved[group->num_elements_resolved++] = element;
2648 element_info[element].in_group[group_nr] = TRUE;
2653 void ResolveGroupElement(int group_element)
2655 ResolveGroupElementExt(group_element, 0);
2658 void InitElementPropertiesStatic()
2660 static boolean clipboard_elements_initialized = FALSE;
2662 static int ep_diggable[] =
2667 EL_SP_BUGGY_BASE_ACTIVATING,
2670 EL_INVISIBLE_SAND_ACTIVE,
2673 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2674 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2679 EL_SP_BUGGY_BASE_ACTIVE,
2686 static int ep_collectible_only[] =
2708 EL_DYNABOMB_INCREASE_NUMBER,
2709 EL_DYNABOMB_INCREASE_SIZE,
2710 EL_DYNABOMB_INCREASE_POWER,
2728 /* !!! handle separately !!! */
2729 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2735 static int ep_dont_run_into[] =
2737 /* same elements as in 'ep_dont_touch' */
2743 /* same elements as in 'ep_dont_collide_with' */
2755 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2760 EL_SP_BUGGY_BASE_ACTIVE,
2767 static int ep_dont_collide_with[] =
2769 /* same elements as in 'ep_dont_touch' */
2786 static int ep_dont_touch[] =
2796 static int ep_indestructible[] =
2800 EL_ACID_POOL_TOPLEFT,
2801 EL_ACID_POOL_TOPRIGHT,
2802 EL_ACID_POOL_BOTTOMLEFT,
2803 EL_ACID_POOL_BOTTOM,
2804 EL_ACID_POOL_BOTTOMRIGHT,
2805 EL_SP_HARDWARE_GRAY,
2806 EL_SP_HARDWARE_GREEN,
2807 EL_SP_HARDWARE_BLUE,
2809 EL_SP_HARDWARE_YELLOW,
2810 EL_SP_HARDWARE_BASE_1,
2811 EL_SP_HARDWARE_BASE_2,
2812 EL_SP_HARDWARE_BASE_3,
2813 EL_SP_HARDWARE_BASE_4,
2814 EL_SP_HARDWARE_BASE_5,
2815 EL_SP_HARDWARE_BASE_6,
2816 EL_INVISIBLE_STEELWALL,
2817 EL_INVISIBLE_STEELWALL_ACTIVE,
2818 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2819 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2820 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2821 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2822 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2823 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2824 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2825 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2826 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2827 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2828 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2829 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2831 EL_LIGHT_SWITCH_ACTIVE,
2832 EL_SIGN_EXCLAMATION,
2833 EL_SIGN_RADIOACTIVITY,
2840 EL_SIGN_ENTRY_FORBIDDEN,
2841 EL_SIGN_EMERGENCY_EXIT,
2849 EL_STEEL_EXIT_CLOSED,
2851 EL_EM_STEEL_EXIT_CLOSED,
2852 EL_EM_STEEL_EXIT_OPEN,
2853 EL_DC_STEELWALL_1_LEFT,
2854 EL_DC_STEELWALL_1_RIGHT,
2855 EL_DC_STEELWALL_1_TOP,
2856 EL_DC_STEELWALL_1_BOTTOM,
2857 EL_DC_STEELWALL_1_HORIZONTAL,
2858 EL_DC_STEELWALL_1_VERTICAL,
2859 EL_DC_STEELWALL_1_TOPLEFT,
2860 EL_DC_STEELWALL_1_TOPRIGHT,
2861 EL_DC_STEELWALL_1_BOTTOMLEFT,
2862 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2863 EL_DC_STEELWALL_1_TOPLEFT_2,
2864 EL_DC_STEELWALL_1_TOPRIGHT_2,
2865 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2866 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2867 EL_DC_STEELWALL_2_LEFT,
2868 EL_DC_STEELWALL_2_RIGHT,
2869 EL_DC_STEELWALL_2_TOP,
2870 EL_DC_STEELWALL_2_BOTTOM,
2871 EL_DC_STEELWALL_2_HORIZONTAL,
2872 EL_DC_STEELWALL_2_VERTICAL,
2873 EL_DC_STEELWALL_2_MIDDLE,
2874 EL_DC_STEELWALL_2_SINGLE,
2875 EL_STEELWALL_SLIPPERY,
2889 EL_GATE_1_GRAY_ACTIVE,
2890 EL_GATE_2_GRAY_ACTIVE,
2891 EL_GATE_3_GRAY_ACTIVE,
2892 EL_GATE_4_GRAY_ACTIVE,
2901 EL_EM_GATE_1_GRAY_ACTIVE,
2902 EL_EM_GATE_2_GRAY_ACTIVE,
2903 EL_EM_GATE_3_GRAY_ACTIVE,
2904 EL_EM_GATE_4_GRAY_ACTIVE,
2913 EL_EMC_GATE_5_GRAY_ACTIVE,
2914 EL_EMC_GATE_6_GRAY_ACTIVE,
2915 EL_EMC_GATE_7_GRAY_ACTIVE,
2916 EL_EMC_GATE_8_GRAY_ACTIVE,
2918 EL_DC_GATE_WHITE_GRAY,
2919 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2920 EL_DC_GATE_FAKE_GRAY,
2922 EL_SWITCHGATE_OPENING,
2923 EL_SWITCHGATE_CLOSED,
2924 EL_SWITCHGATE_CLOSING,
2926 EL_DC_SWITCHGATE_SWITCH_UP,
2927 EL_DC_SWITCHGATE_SWITCH_DOWN,
2930 EL_TIMEGATE_OPENING,
2932 EL_TIMEGATE_CLOSING,
2934 EL_DC_TIMEGATE_SWITCH,
2935 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2940 EL_TUBE_VERTICAL_LEFT,
2941 EL_TUBE_VERTICAL_RIGHT,
2942 EL_TUBE_HORIZONTAL_UP,
2943 EL_TUBE_HORIZONTAL_DOWN,
2948 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2949 EL_EXPANDABLE_STEELWALL_VERTICAL,
2950 EL_EXPANDABLE_STEELWALL_ANY,
2955 static int ep_slippery[] =
2969 EL_ROBOT_WHEEL_ACTIVE,
2975 EL_ACID_POOL_TOPLEFT,
2976 EL_ACID_POOL_TOPRIGHT,
2986 EL_STEELWALL_SLIPPERY,
2989 EL_EMC_WALL_SLIPPERY_1,
2990 EL_EMC_WALL_SLIPPERY_2,
2991 EL_EMC_WALL_SLIPPERY_3,
2992 EL_EMC_WALL_SLIPPERY_4,
2994 EL_EMC_MAGIC_BALL_ACTIVE,
2999 static int ep_can_change[] =
3004 static int ep_can_move[] =
3006 /* same elements as in 'pb_can_move_into_acid' */
3029 static int ep_can_fall[] =
3043 EL_QUICKSAND_FAST_FULL,
3045 EL_BD_MAGIC_WALL_FULL,
3046 EL_DC_MAGIC_WALL_FULL,
3060 static int ep_can_smash_player[] =
3086 static int ep_can_smash_enemies[] =
3095 static int ep_can_smash_everything[] =
3104 static int ep_explodes_by_fire[] =
3106 /* same elements as in 'ep_explodes_impact' */
3111 /* same elements as in 'ep_explodes_smashed' */
3121 EL_EM_DYNAMITE_ACTIVE,
3122 EL_DYNABOMB_PLAYER_1_ACTIVE,
3123 EL_DYNABOMB_PLAYER_2_ACTIVE,
3124 EL_DYNABOMB_PLAYER_3_ACTIVE,
3125 EL_DYNABOMB_PLAYER_4_ACTIVE,
3126 EL_DYNABOMB_INCREASE_NUMBER,
3127 EL_DYNABOMB_INCREASE_SIZE,
3128 EL_DYNABOMB_INCREASE_POWER,
3129 EL_SP_DISK_RED_ACTIVE,
3143 static int ep_explodes_smashed[] =
3145 /* same elements as in 'ep_explodes_impact' */
3159 static int ep_explodes_impact[] =
3168 static int ep_walkable_over[] =
3172 EL_SOKOBAN_FIELD_EMPTY,
3178 EL_EM_STEEL_EXIT_OPEN,
3187 EL_GATE_1_GRAY_ACTIVE,
3188 EL_GATE_2_GRAY_ACTIVE,
3189 EL_GATE_3_GRAY_ACTIVE,
3190 EL_GATE_4_GRAY_ACTIVE,
3198 static int ep_walkable_inside[] =
3203 EL_TUBE_VERTICAL_LEFT,
3204 EL_TUBE_VERTICAL_RIGHT,
3205 EL_TUBE_HORIZONTAL_UP,
3206 EL_TUBE_HORIZONTAL_DOWN,
3215 static int ep_walkable_under[] =
3220 static int ep_passable_over[] =
3230 EL_EM_GATE_1_GRAY_ACTIVE,
3231 EL_EM_GATE_2_GRAY_ACTIVE,
3232 EL_EM_GATE_3_GRAY_ACTIVE,
3233 EL_EM_GATE_4_GRAY_ACTIVE,
3242 EL_EMC_GATE_5_GRAY_ACTIVE,
3243 EL_EMC_GATE_6_GRAY_ACTIVE,
3244 EL_EMC_GATE_7_GRAY_ACTIVE,
3245 EL_EMC_GATE_8_GRAY_ACTIVE,
3247 EL_DC_GATE_WHITE_GRAY,
3248 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3255 static int ep_passable_inside[] =
3261 EL_SP_PORT_HORIZONTAL,
3262 EL_SP_PORT_VERTICAL,
3264 EL_SP_GRAVITY_PORT_LEFT,
3265 EL_SP_GRAVITY_PORT_RIGHT,
3266 EL_SP_GRAVITY_PORT_UP,
3267 EL_SP_GRAVITY_PORT_DOWN,
3268 EL_SP_GRAVITY_ON_PORT_LEFT,
3269 EL_SP_GRAVITY_ON_PORT_RIGHT,
3270 EL_SP_GRAVITY_ON_PORT_UP,
3271 EL_SP_GRAVITY_ON_PORT_DOWN,
3272 EL_SP_GRAVITY_OFF_PORT_LEFT,
3273 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3274 EL_SP_GRAVITY_OFF_PORT_UP,
3275 EL_SP_GRAVITY_OFF_PORT_DOWN,
3280 static int ep_passable_under[] =
3285 static int ep_droppable[] =
3290 static int ep_explodes_1x1_old[] =
3295 static int ep_pushable[] =
3307 EL_SOKOBAN_FIELD_FULL,
3316 static int ep_explodes_cross_old[] =
3321 static int ep_protected[] =
3323 /* same elements as in 'ep_walkable_inside' */
3327 EL_TUBE_VERTICAL_LEFT,
3328 EL_TUBE_VERTICAL_RIGHT,
3329 EL_TUBE_HORIZONTAL_UP,
3330 EL_TUBE_HORIZONTAL_DOWN,
3336 /* same elements as in 'ep_passable_over' */
3345 EL_EM_GATE_1_GRAY_ACTIVE,
3346 EL_EM_GATE_2_GRAY_ACTIVE,
3347 EL_EM_GATE_3_GRAY_ACTIVE,
3348 EL_EM_GATE_4_GRAY_ACTIVE,
3357 EL_EMC_GATE_5_GRAY_ACTIVE,
3358 EL_EMC_GATE_6_GRAY_ACTIVE,
3359 EL_EMC_GATE_7_GRAY_ACTIVE,
3360 EL_EMC_GATE_8_GRAY_ACTIVE,
3362 EL_DC_GATE_WHITE_GRAY,
3363 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3367 /* same elements as in 'ep_passable_inside' */
3372 EL_SP_PORT_HORIZONTAL,
3373 EL_SP_PORT_VERTICAL,
3375 EL_SP_GRAVITY_PORT_LEFT,
3376 EL_SP_GRAVITY_PORT_RIGHT,
3377 EL_SP_GRAVITY_PORT_UP,
3378 EL_SP_GRAVITY_PORT_DOWN,
3379 EL_SP_GRAVITY_ON_PORT_LEFT,
3380 EL_SP_GRAVITY_ON_PORT_RIGHT,
3381 EL_SP_GRAVITY_ON_PORT_UP,
3382 EL_SP_GRAVITY_ON_PORT_DOWN,
3383 EL_SP_GRAVITY_OFF_PORT_LEFT,
3384 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3385 EL_SP_GRAVITY_OFF_PORT_UP,
3386 EL_SP_GRAVITY_OFF_PORT_DOWN,
3391 static int ep_throwable[] =
3396 static int ep_can_explode[] =
3398 /* same elements as in 'ep_explodes_impact' */
3403 /* same elements as in 'ep_explodes_smashed' */
3409 /* elements that can explode by explosion or by dragonfire */
3413 EL_EM_DYNAMITE_ACTIVE,
3414 EL_DYNABOMB_PLAYER_1_ACTIVE,
3415 EL_DYNABOMB_PLAYER_2_ACTIVE,
3416 EL_DYNABOMB_PLAYER_3_ACTIVE,
3417 EL_DYNABOMB_PLAYER_4_ACTIVE,
3418 EL_DYNABOMB_INCREASE_NUMBER,
3419 EL_DYNABOMB_INCREASE_SIZE,
3420 EL_DYNABOMB_INCREASE_POWER,
3421 EL_SP_DISK_RED_ACTIVE,
3429 /* elements that can explode only by explosion */
3435 static int ep_gravity_reachable[] =
3441 EL_INVISIBLE_SAND_ACTIVE,
3446 EL_SP_PORT_HORIZONTAL,
3447 EL_SP_PORT_VERTICAL,
3449 EL_SP_GRAVITY_PORT_LEFT,
3450 EL_SP_GRAVITY_PORT_RIGHT,
3451 EL_SP_GRAVITY_PORT_UP,
3452 EL_SP_GRAVITY_PORT_DOWN,
3453 EL_SP_GRAVITY_ON_PORT_LEFT,
3454 EL_SP_GRAVITY_ON_PORT_RIGHT,
3455 EL_SP_GRAVITY_ON_PORT_UP,
3456 EL_SP_GRAVITY_ON_PORT_DOWN,
3457 EL_SP_GRAVITY_OFF_PORT_LEFT,
3458 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3459 EL_SP_GRAVITY_OFF_PORT_UP,
3460 EL_SP_GRAVITY_OFF_PORT_DOWN,
3466 static int ep_player[] =
3473 EL_SOKOBAN_FIELD_PLAYER,
3479 static int ep_can_pass_magic_wall[] =
3493 static int ep_can_pass_dc_magic_wall[] =
3509 static int ep_switchable[] =
3513 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3514 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3515 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3516 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3517 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3518 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3519 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3520 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3521 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3522 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3523 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3524 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3525 EL_SWITCHGATE_SWITCH_UP,
3526 EL_SWITCHGATE_SWITCH_DOWN,
3527 EL_DC_SWITCHGATE_SWITCH_UP,
3528 EL_DC_SWITCHGATE_SWITCH_DOWN,
3530 EL_LIGHT_SWITCH_ACTIVE,
3532 EL_DC_TIMEGATE_SWITCH,
3533 EL_BALLOON_SWITCH_LEFT,
3534 EL_BALLOON_SWITCH_RIGHT,
3535 EL_BALLOON_SWITCH_UP,
3536 EL_BALLOON_SWITCH_DOWN,
3537 EL_BALLOON_SWITCH_ANY,
3538 EL_BALLOON_SWITCH_NONE,
3541 EL_EMC_MAGIC_BALL_SWITCH,
3542 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3547 static int ep_bd_element[] =
3581 static int ep_sp_element[] =
3583 /* should always be valid */
3586 /* standard classic Supaplex elements */
3593 EL_SP_HARDWARE_GRAY,
3601 EL_SP_GRAVITY_PORT_RIGHT,
3602 EL_SP_GRAVITY_PORT_DOWN,
3603 EL_SP_GRAVITY_PORT_LEFT,
3604 EL_SP_GRAVITY_PORT_UP,
3609 EL_SP_PORT_VERTICAL,
3610 EL_SP_PORT_HORIZONTAL,
3616 EL_SP_HARDWARE_BASE_1,
3617 EL_SP_HARDWARE_GREEN,
3618 EL_SP_HARDWARE_BLUE,
3620 EL_SP_HARDWARE_YELLOW,
3621 EL_SP_HARDWARE_BASE_2,
3622 EL_SP_HARDWARE_BASE_3,
3623 EL_SP_HARDWARE_BASE_4,
3624 EL_SP_HARDWARE_BASE_5,
3625 EL_SP_HARDWARE_BASE_6,
3629 /* additional elements that appeared in newer Supaplex levels */
3632 /* additional gravity port elements (not switching, but setting gravity) */
3633 EL_SP_GRAVITY_ON_PORT_LEFT,
3634 EL_SP_GRAVITY_ON_PORT_RIGHT,
3635 EL_SP_GRAVITY_ON_PORT_UP,
3636 EL_SP_GRAVITY_ON_PORT_DOWN,
3637 EL_SP_GRAVITY_OFF_PORT_LEFT,
3638 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3639 EL_SP_GRAVITY_OFF_PORT_UP,
3640 EL_SP_GRAVITY_OFF_PORT_DOWN,
3642 /* more than one Murphy in a level results in an inactive clone */
3645 /* runtime Supaplex elements */
3646 EL_SP_DISK_RED_ACTIVE,
3647 EL_SP_TERMINAL_ACTIVE,
3648 EL_SP_BUGGY_BASE_ACTIVATING,
3649 EL_SP_BUGGY_BASE_ACTIVE,
3656 static int ep_sb_element[] =
3661 EL_SOKOBAN_FIELD_EMPTY,
3662 EL_SOKOBAN_FIELD_FULL,
3663 EL_SOKOBAN_FIELD_PLAYER,
3668 EL_INVISIBLE_STEELWALL,
3673 static int ep_gem[] =
3685 static int ep_food_dark_yamyam[] =
3713 static int ep_food_penguin[] =
3727 static int ep_food_pig[] =
3739 static int ep_historic_wall[] =
3750 EL_GATE_1_GRAY_ACTIVE,
3751 EL_GATE_2_GRAY_ACTIVE,
3752 EL_GATE_3_GRAY_ACTIVE,
3753 EL_GATE_4_GRAY_ACTIVE,
3762 EL_EM_GATE_1_GRAY_ACTIVE,
3763 EL_EM_GATE_2_GRAY_ACTIVE,
3764 EL_EM_GATE_3_GRAY_ACTIVE,
3765 EL_EM_GATE_4_GRAY_ACTIVE,
3772 EL_EXPANDABLE_WALL_HORIZONTAL,
3773 EL_EXPANDABLE_WALL_VERTICAL,
3774 EL_EXPANDABLE_WALL_ANY,
3775 EL_EXPANDABLE_WALL_GROWING,
3776 EL_BD_EXPANDABLE_WALL,
3783 EL_SP_HARDWARE_GRAY,
3784 EL_SP_HARDWARE_GREEN,
3785 EL_SP_HARDWARE_BLUE,
3787 EL_SP_HARDWARE_YELLOW,
3788 EL_SP_HARDWARE_BASE_1,
3789 EL_SP_HARDWARE_BASE_2,
3790 EL_SP_HARDWARE_BASE_3,
3791 EL_SP_HARDWARE_BASE_4,
3792 EL_SP_HARDWARE_BASE_5,
3793 EL_SP_HARDWARE_BASE_6,
3795 EL_SP_TERMINAL_ACTIVE,
3798 EL_INVISIBLE_STEELWALL,
3799 EL_INVISIBLE_STEELWALL_ACTIVE,
3801 EL_INVISIBLE_WALL_ACTIVE,
3802 EL_STEELWALL_SLIPPERY,
3819 static int ep_historic_solid[] =
3823 EL_EXPANDABLE_WALL_HORIZONTAL,
3824 EL_EXPANDABLE_WALL_VERTICAL,
3825 EL_EXPANDABLE_WALL_ANY,
3826 EL_BD_EXPANDABLE_WALL,
3839 EL_QUICKSAND_FILLING,
3840 EL_QUICKSAND_EMPTYING,
3842 EL_MAGIC_WALL_ACTIVE,
3843 EL_MAGIC_WALL_EMPTYING,
3844 EL_MAGIC_WALL_FILLING,
3848 EL_BD_MAGIC_WALL_ACTIVE,
3849 EL_BD_MAGIC_WALL_EMPTYING,
3850 EL_BD_MAGIC_WALL_FULL,
3851 EL_BD_MAGIC_WALL_FILLING,
3852 EL_BD_MAGIC_WALL_DEAD,
3861 EL_SP_TERMINAL_ACTIVE,
3865 EL_INVISIBLE_WALL_ACTIVE,
3866 EL_SWITCHGATE_SWITCH_UP,
3867 EL_SWITCHGATE_SWITCH_DOWN,
3868 EL_DC_SWITCHGATE_SWITCH_UP,
3869 EL_DC_SWITCHGATE_SWITCH_DOWN,
3871 EL_TIMEGATE_SWITCH_ACTIVE,
3872 EL_DC_TIMEGATE_SWITCH,
3873 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3885 /* the following elements are a direct copy of "indestructible" elements,
3886 except "EL_ACID", which is "indestructible", but not "solid"! */
3891 EL_ACID_POOL_TOPLEFT,
3892 EL_ACID_POOL_TOPRIGHT,
3893 EL_ACID_POOL_BOTTOMLEFT,
3894 EL_ACID_POOL_BOTTOM,
3895 EL_ACID_POOL_BOTTOMRIGHT,
3896 EL_SP_HARDWARE_GRAY,
3897 EL_SP_HARDWARE_GREEN,
3898 EL_SP_HARDWARE_BLUE,
3900 EL_SP_HARDWARE_YELLOW,
3901 EL_SP_HARDWARE_BASE_1,
3902 EL_SP_HARDWARE_BASE_2,
3903 EL_SP_HARDWARE_BASE_3,
3904 EL_SP_HARDWARE_BASE_4,
3905 EL_SP_HARDWARE_BASE_5,
3906 EL_SP_HARDWARE_BASE_6,
3907 EL_INVISIBLE_STEELWALL,
3908 EL_INVISIBLE_STEELWALL_ACTIVE,
3909 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3910 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3911 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3912 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3913 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3914 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3915 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3916 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3917 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3918 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3919 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3920 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3922 EL_LIGHT_SWITCH_ACTIVE,
3923 EL_SIGN_EXCLAMATION,
3924 EL_SIGN_RADIOACTIVITY,
3931 EL_SIGN_ENTRY_FORBIDDEN,
3932 EL_SIGN_EMERGENCY_EXIT,
3940 EL_STEEL_EXIT_CLOSED,
3942 EL_DC_STEELWALL_1_LEFT,
3943 EL_DC_STEELWALL_1_RIGHT,
3944 EL_DC_STEELWALL_1_TOP,
3945 EL_DC_STEELWALL_1_BOTTOM,
3946 EL_DC_STEELWALL_1_HORIZONTAL,
3947 EL_DC_STEELWALL_1_VERTICAL,
3948 EL_DC_STEELWALL_1_TOPLEFT,
3949 EL_DC_STEELWALL_1_TOPRIGHT,
3950 EL_DC_STEELWALL_1_BOTTOMLEFT,
3951 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3952 EL_DC_STEELWALL_1_TOPLEFT_2,
3953 EL_DC_STEELWALL_1_TOPRIGHT_2,
3954 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3955 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3956 EL_DC_STEELWALL_2_LEFT,
3957 EL_DC_STEELWALL_2_RIGHT,
3958 EL_DC_STEELWALL_2_TOP,
3959 EL_DC_STEELWALL_2_BOTTOM,
3960 EL_DC_STEELWALL_2_HORIZONTAL,
3961 EL_DC_STEELWALL_2_VERTICAL,
3962 EL_DC_STEELWALL_2_MIDDLE,
3963 EL_DC_STEELWALL_2_SINGLE,
3964 EL_STEELWALL_SLIPPERY,
3978 EL_GATE_1_GRAY_ACTIVE,
3979 EL_GATE_2_GRAY_ACTIVE,
3980 EL_GATE_3_GRAY_ACTIVE,
3981 EL_GATE_4_GRAY_ACTIVE,
3990 EL_EM_GATE_1_GRAY_ACTIVE,
3991 EL_EM_GATE_2_GRAY_ACTIVE,
3992 EL_EM_GATE_3_GRAY_ACTIVE,
3993 EL_EM_GATE_4_GRAY_ACTIVE,
3995 EL_SWITCHGATE_OPENING,
3996 EL_SWITCHGATE_CLOSED,
3997 EL_SWITCHGATE_CLOSING,
3999 EL_TIMEGATE_OPENING,
4001 EL_TIMEGATE_CLOSING,
4005 EL_TUBE_VERTICAL_LEFT,
4006 EL_TUBE_VERTICAL_RIGHT,
4007 EL_TUBE_HORIZONTAL_UP,
4008 EL_TUBE_HORIZONTAL_DOWN,
4017 static int ep_classic_enemy[] =
4034 static int ep_belt[] =
4036 EL_CONVEYOR_BELT_1_LEFT,
4037 EL_CONVEYOR_BELT_1_MIDDLE,
4038 EL_CONVEYOR_BELT_1_RIGHT,
4039 EL_CONVEYOR_BELT_2_LEFT,
4040 EL_CONVEYOR_BELT_2_MIDDLE,
4041 EL_CONVEYOR_BELT_2_RIGHT,
4042 EL_CONVEYOR_BELT_3_LEFT,
4043 EL_CONVEYOR_BELT_3_MIDDLE,
4044 EL_CONVEYOR_BELT_3_RIGHT,
4045 EL_CONVEYOR_BELT_4_LEFT,
4046 EL_CONVEYOR_BELT_4_MIDDLE,
4047 EL_CONVEYOR_BELT_4_RIGHT,
4052 static int ep_belt_active[] =
4054 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4055 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4056 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4057 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4058 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4059 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4060 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4061 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4062 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4063 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4064 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4065 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4070 static int ep_belt_switch[] =
4072 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4073 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4074 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4075 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4076 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4077 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4078 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4079 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4080 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4081 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4082 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4083 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4088 static int ep_tube[] =
4095 EL_TUBE_HORIZONTAL_UP,
4096 EL_TUBE_HORIZONTAL_DOWN,
4098 EL_TUBE_VERTICAL_LEFT,
4099 EL_TUBE_VERTICAL_RIGHT,
4105 static int ep_acid_pool[] =
4107 EL_ACID_POOL_TOPLEFT,
4108 EL_ACID_POOL_TOPRIGHT,
4109 EL_ACID_POOL_BOTTOMLEFT,
4110 EL_ACID_POOL_BOTTOM,
4111 EL_ACID_POOL_BOTTOMRIGHT,
4116 static int ep_keygate[] =
4126 EL_GATE_1_GRAY_ACTIVE,
4127 EL_GATE_2_GRAY_ACTIVE,
4128 EL_GATE_3_GRAY_ACTIVE,
4129 EL_GATE_4_GRAY_ACTIVE,
4138 EL_EM_GATE_1_GRAY_ACTIVE,
4139 EL_EM_GATE_2_GRAY_ACTIVE,
4140 EL_EM_GATE_3_GRAY_ACTIVE,
4141 EL_EM_GATE_4_GRAY_ACTIVE,
4150 EL_EMC_GATE_5_GRAY_ACTIVE,
4151 EL_EMC_GATE_6_GRAY_ACTIVE,
4152 EL_EMC_GATE_7_GRAY_ACTIVE,
4153 EL_EMC_GATE_8_GRAY_ACTIVE,
4155 EL_DC_GATE_WHITE_GRAY,
4156 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4161 static int ep_amoeboid[] =
4173 static int ep_amoebalive[] =
4184 static int ep_has_editor_content[] =
4206 static int ep_can_turn_each_move[] =
4208 /* !!! do something with this one !!! */
4212 static int ep_can_grow[] =
4226 static int ep_active_bomb[] =
4229 EL_EM_DYNAMITE_ACTIVE,
4230 EL_DYNABOMB_PLAYER_1_ACTIVE,
4231 EL_DYNABOMB_PLAYER_2_ACTIVE,
4232 EL_DYNABOMB_PLAYER_3_ACTIVE,
4233 EL_DYNABOMB_PLAYER_4_ACTIVE,
4234 EL_SP_DISK_RED_ACTIVE,
4239 static int ep_inactive[] =
4249 EL_QUICKSAND_FAST_EMPTY,
4272 EL_GATE_1_GRAY_ACTIVE,
4273 EL_GATE_2_GRAY_ACTIVE,
4274 EL_GATE_3_GRAY_ACTIVE,
4275 EL_GATE_4_GRAY_ACTIVE,
4284 EL_EM_GATE_1_GRAY_ACTIVE,
4285 EL_EM_GATE_2_GRAY_ACTIVE,
4286 EL_EM_GATE_3_GRAY_ACTIVE,
4287 EL_EM_GATE_4_GRAY_ACTIVE,
4296 EL_EMC_GATE_5_GRAY_ACTIVE,
4297 EL_EMC_GATE_6_GRAY_ACTIVE,
4298 EL_EMC_GATE_7_GRAY_ACTIVE,
4299 EL_EMC_GATE_8_GRAY_ACTIVE,
4301 EL_DC_GATE_WHITE_GRAY,
4302 EL_DC_GATE_WHITE_GRAY_ACTIVE,
4303 EL_DC_GATE_FAKE_GRAY,
4306 EL_INVISIBLE_STEELWALL,
4314 EL_WALL_EMERALD_YELLOW,
4315 EL_DYNABOMB_INCREASE_NUMBER,
4316 EL_DYNABOMB_INCREASE_SIZE,
4317 EL_DYNABOMB_INCREASE_POWER,
4321 EL_SOKOBAN_FIELD_EMPTY,
4322 EL_SOKOBAN_FIELD_FULL,
4323 EL_WALL_EMERALD_RED,
4324 EL_WALL_EMERALD_PURPLE,
4325 EL_ACID_POOL_TOPLEFT,
4326 EL_ACID_POOL_TOPRIGHT,
4327 EL_ACID_POOL_BOTTOMLEFT,
4328 EL_ACID_POOL_BOTTOM,
4329 EL_ACID_POOL_BOTTOMRIGHT,
4333 EL_BD_MAGIC_WALL_DEAD,
4335 EL_DC_MAGIC_WALL_DEAD,
4336 EL_AMOEBA_TO_DIAMOND,
4344 EL_SP_GRAVITY_PORT_RIGHT,
4345 EL_SP_GRAVITY_PORT_DOWN,
4346 EL_SP_GRAVITY_PORT_LEFT,
4347 EL_SP_GRAVITY_PORT_UP,
4348 EL_SP_PORT_HORIZONTAL,
4349 EL_SP_PORT_VERTICAL,
4360 EL_SP_HARDWARE_GRAY,
4361 EL_SP_HARDWARE_GREEN,
4362 EL_SP_HARDWARE_BLUE,
4364 EL_SP_HARDWARE_YELLOW,
4365 EL_SP_HARDWARE_BASE_1,
4366 EL_SP_HARDWARE_BASE_2,
4367 EL_SP_HARDWARE_BASE_3,
4368 EL_SP_HARDWARE_BASE_4,
4369 EL_SP_HARDWARE_BASE_5,
4370 EL_SP_HARDWARE_BASE_6,
4371 EL_SP_GRAVITY_ON_PORT_LEFT,
4372 EL_SP_GRAVITY_ON_PORT_RIGHT,
4373 EL_SP_GRAVITY_ON_PORT_UP,
4374 EL_SP_GRAVITY_ON_PORT_DOWN,
4375 EL_SP_GRAVITY_OFF_PORT_LEFT,
4376 EL_SP_GRAVITY_OFF_PORT_RIGHT,
4377 EL_SP_GRAVITY_OFF_PORT_UP,
4378 EL_SP_GRAVITY_OFF_PORT_DOWN,
4379 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4380 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4381 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4382 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4383 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4384 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4385 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4386 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4387 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4388 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4389 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4390 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4391 EL_SIGN_EXCLAMATION,
4392 EL_SIGN_RADIOACTIVITY,
4399 EL_SIGN_ENTRY_FORBIDDEN,
4400 EL_SIGN_EMERGENCY_EXIT,
4408 EL_DC_STEELWALL_1_LEFT,
4409 EL_DC_STEELWALL_1_RIGHT,
4410 EL_DC_STEELWALL_1_TOP,
4411 EL_DC_STEELWALL_1_BOTTOM,
4412 EL_DC_STEELWALL_1_HORIZONTAL,
4413 EL_DC_STEELWALL_1_VERTICAL,
4414 EL_DC_STEELWALL_1_TOPLEFT,
4415 EL_DC_STEELWALL_1_TOPRIGHT,
4416 EL_DC_STEELWALL_1_BOTTOMLEFT,
4417 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4418 EL_DC_STEELWALL_1_TOPLEFT_2,
4419 EL_DC_STEELWALL_1_TOPRIGHT_2,
4420 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4421 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4422 EL_DC_STEELWALL_2_LEFT,
4423 EL_DC_STEELWALL_2_RIGHT,
4424 EL_DC_STEELWALL_2_TOP,
4425 EL_DC_STEELWALL_2_BOTTOM,
4426 EL_DC_STEELWALL_2_HORIZONTAL,
4427 EL_DC_STEELWALL_2_VERTICAL,
4428 EL_DC_STEELWALL_2_MIDDLE,
4429 EL_DC_STEELWALL_2_SINGLE,
4430 EL_STEELWALL_SLIPPERY,
4435 EL_EMC_WALL_SLIPPERY_1,
4436 EL_EMC_WALL_SLIPPERY_2,
4437 EL_EMC_WALL_SLIPPERY_3,
4438 EL_EMC_WALL_SLIPPERY_4,
4459 static int ep_em_slippery_wall[] =
4464 static int ep_gfx_crumbled[] =
4475 static int ep_editor_cascade_active[] =
4477 EL_INTERNAL_CASCADE_BD_ACTIVE,
4478 EL_INTERNAL_CASCADE_EM_ACTIVE,
4479 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4480 EL_INTERNAL_CASCADE_RND_ACTIVE,
4481 EL_INTERNAL_CASCADE_SB_ACTIVE,
4482 EL_INTERNAL_CASCADE_SP_ACTIVE,
4483 EL_INTERNAL_CASCADE_DC_ACTIVE,
4484 EL_INTERNAL_CASCADE_DX_ACTIVE,
4485 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4486 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4487 EL_INTERNAL_CASCADE_CE_ACTIVE,
4488 EL_INTERNAL_CASCADE_GE_ACTIVE,
4489 EL_INTERNAL_CASCADE_REF_ACTIVE,
4490 EL_INTERNAL_CASCADE_USER_ACTIVE,
4491 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4496 static int ep_editor_cascade_inactive[] =
4498 EL_INTERNAL_CASCADE_BD,
4499 EL_INTERNAL_CASCADE_EM,
4500 EL_INTERNAL_CASCADE_EMC,
4501 EL_INTERNAL_CASCADE_RND,
4502 EL_INTERNAL_CASCADE_SB,
4503 EL_INTERNAL_CASCADE_SP,
4504 EL_INTERNAL_CASCADE_DC,
4505 EL_INTERNAL_CASCADE_DX,
4506 EL_INTERNAL_CASCADE_CHARS,
4507 EL_INTERNAL_CASCADE_STEEL_CHARS,
4508 EL_INTERNAL_CASCADE_CE,
4509 EL_INTERNAL_CASCADE_GE,
4510 EL_INTERNAL_CASCADE_REF,
4511 EL_INTERNAL_CASCADE_USER,
4512 EL_INTERNAL_CASCADE_DYNAMIC,
4517 static int ep_obsolete[] =
4521 EL_EM_KEY_1_FILE_OBSOLETE,
4522 EL_EM_KEY_2_FILE_OBSOLETE,
4523 EL_EM_KEY_3_FILE_OBSOLETE,
4524 EL_EM_KEY_4_FILE_OBSOLETE,
4525 EL_ENVELOPE_OBSOLETE,
4534 } element_properties[] =
4536 { ep_diggable, EP_DIGGABLE },
4537 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4538 { ep_dont_run_into, EP_DONT_RUN_INTO },
4539 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4540 { ep_dont_touch, EP_DONT_TOUCH },
4541 { ep_indestructible, EP_INDESTRUCTIBLE },
4542 { ep_slippery, EP_SLIPPERY },
4543 { ep_can_change, EP_CAN_CHANGE },
4544 { ep_can_move, EP_CAN_MOVE },
4545 { ep_can_fall, EP_CAN_FALL },
4546 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4547 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4548 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4549 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4550 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4551 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4552 { ep_walkable_over, EP_WALKABLE_OVER },
4553 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4554 { ep_walkable_under, EP_WALKABLE_UNDER },
4555 { ep_passable_over, EP_PASSABLE_OVER },
4556 { ep_passable_inside, EP_PASSABLE_INSIDE },
4557 { ep_passable_under, EP_PASSABLE_UNDER },
4558 { ep_droppable, EP_DROPPABLE },
4559 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4560 { ep_pushable, EP_PUSHABLE },
4561 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4562 { ep_protected, EP_PROTECTED },
4563 { ep_throwable, EP_THROWABLE },
4564 { ep_can_explode, EP_CAN_EXPLODE },
4565 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4567 { ep_player, EP_PLAYER },
4568 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4569 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4570 { ep_switchable, EP_SWITCHABLE },
4571 { ep_bd_element, EP_BD_ELEMENT },
4572 { ep_sp_element, EP_SP_ELEMENT },
4573 { ep_sb_element, EP_SB_ELEMENT },
4575 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4576 { ep_food_penguin, EP_FOOD_PENGUIN },
4577 { ep_food_pig, EP_FOOD_PIG },
4578 { ep_historic_wall, EP_HISTORIC_WALL },
4579 { ep_historic_solid, EP_HISTORIC_SOLID },
4580 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4581 { ep_belt, EP_BELT },
4582 { ep_belt_active, EP_BELT_ACTIVE },
4583 { ep_belt_switch, EP_BELT_SWITCH },
4584 { ep_tube, EP_TUBE },
4585 { ep_acid_pool, EP_ACID_POOL },
4586 { ep_keygate, EP_KEYGATE },
4587 { ep_amoeboid, EP_AMOEBOID },
4588 { ep_amoebalive, EP_AMOEBALIVE },
4589 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4590 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4591 { ep_can_grow, EP_CAN_GROW },
4592 { ep_active_bomb, EP_ACTIVE_BOMB },
4593 { ep_inactive, EP_INACTIVE },
4595 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4597 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4599 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4600 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4602 { ep_obsolete, EP_OBSOLETE },
4609 /* always start with reliable default values (element has no properties) */
4610 /* (but never initialize clipboard elements after the very first time) */
4611 /* (to be able to use clipboard elements between several levels) */
4612 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4613 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4614 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4615 SET_PROPERTY(i, j, FALSE);
4617 /* set all base element properties from above array definitions */
4618 for (i = 0; element_properties[i].elements != NULL; i++)
4619 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4620 SET_PROPERTY((element_properties[i].elements)[j],
4621 element_properties[i].property, TRUE);
4623 /* copy properties to some elements that are only stored in level file */
4624 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4625 for (j = 0; copy_properties[j][0] != -1; j++)
4626 if (HAS_PROPERTY(copy_properties[j][0], i))
4627 for (k = 1; k <= 4; k++)
4628 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4630 /* set static element properties that are not listed in array definitions */
4631 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4632 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4634 clipboard_elements_initialized = TRUE;
4637 void InitElementPropertiesEngine(int engine_version)
4639 static int no_wall_properties[] =
4642 EP_COLLECTIBLE_ONLY,
4644 EP_DONT_COLLIDE_WITH,
4647 EP_CAN_SMASH_PLAYER,
4648 EP_CAN_SMASH_ENEMIES,
4649 EP_CAN_SMASH_EVERYTHING,
4654 EP_FOOD_DARK_YAMYAM,
4670 /* important: after initialization in InitElementPropertiesStatic(), the
4671 elements are not again initialized to a default value; therefore all
4672 changes have to make sure that they leave the element with a defined
4673 property (which means that conditional property changes must be set to
4674 a reliable default value before) */
4676 /* resolve group elements */
4677 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4678 ResolveGroupElement(EL_GROUP_START + i);
4680 /* set all special, combined or engine dependent element properties */
4681 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4683 /* do not change (already initialized) clipboard elements here */
4684 if (IS_CLIPBOARD_ELEMENT(i))
4687 /* ---------- INACTIVE ------------------------------------------------- */
4688 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4689 i <= EL_CHAR_END) ||
4690 (i >= EL_STEEL_CHAR_START &&
4691 i <= EL_STEEL_CHAR_END)));
4693 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4694 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4695 IS_WALKABLE_INSIDE(i) ||
4696 IS_WALKABLE_UNDER(i)));
4698 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4699 IS_PASSABLE_INSIDE(i) ||
4700 IS_PASSABLE_UNDER(i)));
4702 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4703 IS_PASSABLE_OVER(i)));
4705 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4706 IS_PASSABLE_INSIDE(i)));
4708 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4709 IS_PASSABLE_UNDER(i)));
4711 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4714 /* ---------- COLLECTIBLE ---------------------------------------------- */
4715 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4719 /* ---------- SNAPPABLE ------------------------------------------------ */
4720 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4721 IS_COLLECTIBLE(i) ||
4725 /* ---------- WALL ----------------------------------------------------- */
4726 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4728 for (j = 0; no_wall_properties[j] != -1; j++)
4729 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4730 i >= EL_FIRST_RUNTIME_UNREAL)
4731 SET_PROPERTY(i, EP_WALL, FALSE);
4733 if (IS_HISTORIC_WALL(i))
4734 SET_PROPERTY(i, EP_WALL, TRUE);
4736 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4737 if (engine_version < VERSION_IDENT(2,2,0,0))
4738 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4740 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4742 !IS_COLLECTIBLE(i)));
4744 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4745 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4746 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4748 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4749 IS_INDESTRUCTIBLE(i)));
4751 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4753 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4754 else if (engine_version < VERSION_IDENT(2,2,0,0))
4755 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4757 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4761 if (IS_CUSTOM_ELEMENT(i))
4763 /* these are additional properties which are initially false when set */
4765 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4767 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4768 if (DONT_COLLIDE_WITH(i))
4769 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4771 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4772 if (CAN_SMASH_EVERYTHING(i))
4773 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4774 if (CAN_SMASH_ENEMIES(i))
4775 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4778 /* ---------- CAN_SMASH ------------------------------------------------ */
4779 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4780 CAN_SMASH_ENEMIES(i) ||
4781 CAN_SMASH_EVERYTHING(i)));
4783 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4784 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4785 EXPLODES_BY_FIRE(i)));
4787 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4788 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4789 EXPLODES_SMASHED(i)));
4791 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4792 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4793 EXPLODES_IMPACT(i)));
4795 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4796 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4798 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4799 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4800 i == EL_BLACK_ORB));
4802 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4803 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4805 IS_CUSTOM_ELEMENT(i)));
4807 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4808 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4809 i == EL_SP_ELECTRON));
4811 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4812 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4813 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4814 getMoveIntoAcidProperty(&level, i));
4816 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4817 if (MAYBE_DONT_COLLIDE_WITH(i))
4818 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4819 getDontCollideWithProperty(&level, i));
4821 /* ---------- SP_PORT -------------------------------------------------- */
4822 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4823 IS_PASSABLE_INSIDE(i)));
4825 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4826 for (j = 0; j < level.num_android_clone_elements; j++)
4827 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4829 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4831 /* ---------- CAN_CHANGE ----------------------------------------------- */
4832 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4833 for (j = 0; j < element_info[i].num_change_pages; j++)
4834 if (element_info[i].change_page[j].can_change)
4835 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4837 /* ---------- HAS_ACTION ----------------------------------------------- */
4838 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4839 for (j = 0; j < element_info[i].num_change_pages; j++)
4840 if (element_info[i].change_page[j].has_action)
4841 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4843 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4844 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4847 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4849 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4850 element_info[i].crumbled[ACTION_DEFAULT] !=
4851 element_info[i].graphic[ACTION_DEFAULT]);
4853 /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4854 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4855 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4858 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4859 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4860 IS_EDITOR_CASCADE_INACTIVE(i)));
4863 /* dynamically adjust element properties according to game engine version */
4865 static int ep_em_slippery_wall[] =
4870 EL_EXPANDABLE_WALL_HORIZONTAL,
4871 EL_EXPANDABLE_WALL_VERTICAL,
4872 EL_EXPANDABLE_WALL_ANY,
4873 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4874 EL_EXPANDABLE_STEELWALL_VERTICAL,
4875 EL_EXPANDABLE_STEELWALL_ANY,
4876 EL_EXPANDABLE_STEELWALL_GROWING,
4880 /* special EM style gems behaviour */
4881 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4882 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4883 level.em_slippery_gems);
4885 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4886 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4887 (level.em_slippery_gems &&
4888 engine_version > VERSION_IDENT(2,0,1,0)));
4891 /* this is needed because some graphics depend on element properties */
4892 if (game_status == GAME_MODE_PLAYING)
4893 InitElementGraphicInfo();
4896 void InitElementPropertiesAfterLoading(int engine_version)
4900 /* set some other uninitialized values of custom elements in older levels */
4901 if (engine_version < VERSION_IDENT(3,1,0,0))
4903 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4905 int element = EL_CUSTOM_START + i;
4907 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4909 element_info[element].explosion_delay = 17;
4910 element_info[element].ignition_delay = 8;
4915 static void InitGlobal()
4920 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4922 /* check if element_name_info entry defined for each element in "main.h" */
4923 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4924 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4926 element_info[i].token_name = element_name_info[i].token_name;
4927 element_info[i].class_name = element_name_info[i].class_name;
4928 element_info[i].editor_description= element_name_info[i].editor_description;
4931 printf("%04d: %s\n", i, element_name_info[i].token_name);
4935 /* create hash from image config list */
4936 image_config_hash = newSetupFileHash();
4937 for (i = 0; image_config[i].token != NULL; i++)
4938 setHashEntry(image_config_hash,
4939 image_config[i].token,
4940 image_config[i].value);
4942 /* create hash from element token list */
4943 element_token_hash = newSetupFileHash();
4944 for (i = 0; element_name_info[i].token_name != NULL; i++)
4945 setHashEntry(element_token_hash,
4946 element_name_info[i].token_name,
4949 /* create hash from graphic token list */
4950 graphic_token_hash = newSetupFileHash();
4951 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4952 if (strSuffix(image_config[i].value, ".pcx") ||
4953 strSuffix(image_config[i].value, ".wav") ||
4954 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4955 setHashEntry(graphic_token_hash,
4956 image_config[i].token,
4957 int2str(graphic++, 0));
4959 /* create hash from font token list */
4960 font_token_hash = newSetupFileHash();
4961 for (i = 0; font_info[i].token_name != NULL; i++)
4962 setHashEntry(font_token_hash,
4963 font_info[i].token_name,
4966 /* always start with reliable default values (all elements) */
4967 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4968 ActiveElement[i] = i;
4970 /* now add all entries that have an active state (active elements) */
4971 for (i = 0; element_with_active_state[i].element != -1; i++)
4973 int element = element_with_active_state[i].element;
4974 int element_active = element_with_active_state[i].element_active;
4976 ActiveElement[element] = element_active;
4979 /* always start with reliable default values (all buttons) */
4980 for (i = 0; i < NUM_IMAGE_FILES; i++)
4981 ActiveButton[i] = i;
4983 /* now add all entries that have an active state (active buttons) */
4984 for (i = 0; button_with_active_state[i].button != -1; i++)
4986 int button = button_with_active_state[i].button;
4987 int button_active = button_with_active_state[i].button_active;
4989 ActiveButton[button] = button_active;
4992 /* always start with reliable default values (all fonts) */
4993 for (i = 0; i < NUM_FONTS; i++)
4996 /* now add all entries that have an active state (active fonts) */
4997 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4999 int font = font_with_active_state[i].font_nr;
5000 int font_active = font_with_active_state[i].font_nr_active;
5002 ActiveFont[font] = font_active;
5005 global.autoplay_leveldir = NULL;
5006 global.convert_leveldir = NULL;
5008 global.frames_per_second = 0;
5009 global.fps_slowdown = FALSE;
5010 global.fps_slowdown_factor = 1;
5012 global.border_status = GAME_MODE_MAIN;
5014 global.fading_status = GAME_MODE_MAIN;
5015 global.fading_type = TYPE_ENTER_MENU;
5019 void Execute_Command(char *command)
5023 if (strEqual(command, "print graphicsinfo.conf"))
5025 printf("# You can configure additional/alternative image files here.\n");
5026 printf("# (The entries below are default and therefore commented out.)\n");
5028 printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5030 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5033 for (i = 0; image_config[i].token != NULL; i++)
5034 printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5035 image_config[i].value));
5039 else if (strEqual(command, "print soundsinfo.conf"))
5041 printf("# You can configure additional/alternative sound files here.\n");
5042 printf("# (The entries below are default and therefore commented out.)\n");
5044 printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5046 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5049 for (i = 0; sound_config[i].token != NULL; i++)
5050 printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5051 sound_config[i].value));
5055 else if (strEqual(command, "print musicinfo.conf"))
5057 printf("# You can configure additional/alternative music files here.\n");
5058 printf("# (The entries below are default and therefore commented out.)\n");
5060 printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5062 printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5065 for (i = 0; music_config[i].token != NULL; i++)
5066 printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5067 music_config[i].value));
5071 else if (strEqual(command, "print editorsetup.conf"))
5073 printf("# You can configure your personal editor element list here.\n");
5074 printf("# (The entries below are default and therefore commented out.)\n");
5077 /* this is needed to be able to check element list for cascade elements */
5078 InitElementPropertiesStatic();
5079 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5081 PrintEditorElementList();
5085 else if (strEqual(command, "print helpanim.conf"))
5087 printf("# You can configure different element help animations here.\n");
5088 printf("# (The entries below are default and therefore commented out.)\n");
5091 for (i = 0; helpanim_config[i].token != NULL; i++)
5093 printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5094 helpanim_config[i].value));
5096 if (strEqual(helpanim_config[i].token, "end"))
5102 else if (strEqual(command, "print helptext.conf"))
5104 printf("# You can configure different element help text here.\n");
5105 printf("# (The entries below are default and therefore commented out.)\n");
5108 for (i = 0; helptext_config[i].token != NULL; i++)
5109 printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5110 helptext_config[i].value));
5114 else if (strncmp(command, "dump level ", 11) == 0)
5116 char *filename = &command[11];
5118 if (!fileExists(filename))
5119 Error(ERR_EXIT, "cannot open file '%s'", filename);
5121 LoadLevelFromFilename(&level, filename);
5126 else if (strncmp(command, "dump tape ", 10) == 0)
5128 char *filename = &command[10];
5130 if (!fileExists(filename))
5131 Error(ERR_EXIT, "cannot open file '%s'", filename);
5133 LoadTapeFromFilename(filename);
5138 else if (strncmp(command, "autoplay ", 9) == 0)
5140 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5142 while (*str_ptr != '\0') /* continue parsing string */
5144 /* cut leading whitespace from string, replace it by string terminator */
5145 while (*str_ptr == ' ' || *str_ptr == '\t')
5148 if (*str_ptr == '\0') /* end of string reached */
5151 if (global.autoplay_leveldir == NULL) /* read level set string */
5153 global.autoplay_leveldir = str_ptr;
5154 global.autoplay_all = TRUE; /* default: play all tapes */
5156 for (i = 0; i < MAX_TAPES_PER_SET; i++)
5157 global.autoplay_level[i] = FALSE;
5159 else /* read level number string */
5161 int level_nr = atoi(str_ptr); /* get level_nr value */
5163 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5164 global.autoplay_level[level_nr] = TRUE;
5166 global.autoplay_all = FALSE;
5169 /* advance string pointer to the next whitespace (or end of string) */
5170 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5174 else if (strncmp(command, "convert ", 8) == 0)
5176 char *str_copy = getStringCopy(&command[8]);
5177 char *str_ptr = strchr(str_copy, ' ');
5179 global.convert_leveldir = str_copy;
5180 global.convert_level_nr = -1;
5182 if (str_ptr != NULL) /* level number follows */
5184 *str_ptr++ = '\0'; /* terminate leveldir string */
5185 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
5190 #if defined(TARGET_SDL)
5191 else if (strEqual(command, "SDL_ListModes"))
5196 SDL_Init(SDL_INIT_VIDEO);
5198 /* get available fullscreen/hardware modes */
5199 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5201 /* check if there are any modes available */
5204 printf("No modes available!\n");
5209 /* check if our resolution is restricted */
5210 if (modes == (SDL_Rect **)-1)
5212 printf("All resolutions available.\n");
5216 printf("Available Modes:\n");
5218 for(i = 0; modes[i]; i++)
5219 printf(" %d x %d\n", modes[i]->w, modes[i]->h);
5229 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5233 static void InitSetup()
5235 LoadSetup(); /* global setup info */
5237 /* set some options from setup file */
5239 if (setup.options.verbose)
5240 options.verbose = TRUE;
5243 static void InitGameInfo()
5245 game.restart_level = FALSE;
5248 static void InitPlayerInfo()
5252 /* choose default local player */
5253 local_player = &stored_player[0];
5255 for (i = 0; i < MAX_PLAYERS; i++)
5256 stored_player[i].connected = FALSE;
5258 local_player->connected = TRUE;
5261 static void InitArtworkInfo()
5266 static char *get_string_in_brackets(char *string)
5268 char *string_in_brackets = checked_malloc(strlen(string) + 3);
5270 sprintf(string_in_brackets, "[%s]", string);
5272 return string_in_brackets;
5275 static char *get_level_id_suffix(int id_nr)
5277 char *id_suffix = checked_malloc(1 + 3 + 1);
5279 if (id_nr < 0 || id_nr > 999)
5282 sprintf(id_suffix, ".%03d", id_nr);
5288 static char *get_element_class_token(int element)
5290 char *element_class_name = element_info[element].class_name;
5291 char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5293 sprintf(element_class_token, "[%s]", element_class_name);
5295 return element_class_token;
5298 static char *get_action_class_token(int action)
5300 char *action_class_name = &element_action_info[action].suffix[1];
5301 char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5303 sprintf(action_class_token, "[%s]", action_class_name);
5305 return action_class_token;
5309 static void InitArtworkConfig()
5311 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5312 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5313 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5314 static char *action_id_suffix[NUM_ACTIONS + 1];
5315 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5316 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5317 static char *level_id_suffix[MAX_LEVELS + 1];
5318 static char *dummy[1] = { NULL };
5319 static char *ignore_generic_tokens[] =
5325 static char **ignore_image_tokens;
5326 static char **ignore_sound_tokens;
5327 static char **ignore_music_tokens;
5328 int num_ignore_generic_tokens;
5329 int num_ignore_image_tokens;
5330 int num_ignore_sound_tokens;
5331 int num_ignore_music_tokens;
5334 /* dynamically determine list of generic tokens to be ignored */
5335 num_ignore_generic_tokens = 0;
5336 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5337 num_ignore_generic_tokens++;
5339 /* dynamically determine list of image tokens to be ignored */
5340 num_ignore_image_tokens = num_ignore_generic_tokens;
5341 for (i = 0; image_config_vars[i].token != NULL; i++)
5342 num_ignore_image_tokens++;
5343 ignore_image_tokens =
5344 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5345 for (i = 0; i < num_ignore_generic_tokens; i++)
5346 ignore_image_tokens[i] = ignore_generic_tokens[i];
5347 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5348 ignore_image_tokens[num_ignore_generic_tokens + i] =
5349 image_config_vars[i].token;
5350 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5352 /* dynamically determine list of sound tokens to be ignored */
5353 num_ignore_sound_tokens = num_ignore_generic_tokens;
5354 ignore_sound_tokens =
5355 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5356 for (i = 0; i < num_ignore_generic_tokens; i++)
5357 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5358 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5360 /* dynamically determine list of music tokens to be ignored */
5361 num_ignore_music_tokens = num_ignore_generic_tokens;
5362 ignore_music_tokens =
5363 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5364 for (i = 0; i < num_ignore_generic_tokens; i++)
5365 ignore_music_tokens[i] = ignore_generic_tokens[i];
5366 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5368 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5369 image_id_prefix[i] = element_info[i].token_name;
5370 for (i = 0; i < NUM_FONTS; i++)
5371 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5372 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5374 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5375 sound_id_prefix[i] = element_info[i].token_name;
5376 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5377 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5378 get_string_in_brackets(element_info[i].class_name);
5379 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5381 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5382 music_id_prefix[i] = music_prefix_info[i].prefix;
5383 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5385 for (i = 0; i < NUM_ACTIONS; i++)
5386 action_id_suffix[i] = element_action_info[i].suffix;
5387 action_id_suffix[NUM_ACTIONS] = NULL;
5389 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5390 direction_id_suffix[i] = element_direction_info[i].suffix;
5391 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5393 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5394 special_id_suffix[i] = special_suffix_info[i].suffix;
5395 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5397 for (i = 0; i < MAX_LEVELS; i++)
5398 level_id_suffix[i] = get_level_id_suffix(i);
5399 level_id_suffix[MAX_LEVELS] = NULL;
5401 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5402 image_id_prefix, action_id_suffix, direction_id_suffix,
5403 special_id_suffix, ignore_image_tokens);
5404 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5405 sound_id_prefix, action_id_suffix, dummy,
5406 special_id_suffix, ignore_sound_tokens);
5407 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5408 music_id_prefix, special_id_suffix, level_id_suffix,
5409 dummy, ignore_music_tokens);
5412 static void InitMixer()
5420 char *filename_font_initial = NULL;
5421 char *filename_anim_initial = NULL;
5422 Bitmap *bitmap_font_initial = NULL;
5426 /* determine settings for initial font (for displaying startup messages) */
5427 for (i = 0; image_config[i].token != NULL; i++)
5429 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5431 char font_token[128];
5434 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5435 len_font_token = strlen(font_token);
5437 if (strEqual(image_config[i].token, font_token))
5438 filename_font_initial = image_config[i].value;
5439 else if (strlen(image_config[i].token) > len_font_token &&
5440 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5442 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5443 font_initial[j].src_x = atoi(image_config[i].value);
5444 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5445 font_initial[j].src_y = atoi(image_config[i].value);
5446 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5447 font_initial[j].width = atoi(image_config[i].value);
5448 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5449 font_initial[j].height = atoi(image_config[i].value);
5454 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5456 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5457 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5460 if (filename_font_initial == NULL) /* should not happen */
5461 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5463 /* create additional image buffers for double-buffering and cross-fading */
5464 bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5465 bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5466 bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5467 bitmap_db_door = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5468 bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5470 /* initialize screen properties */
5471 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5472 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5474 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5475 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5476 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5477 InitGfxCustomArtworkInfo();
5479 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5481 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5482 font_initial[j].bitmap = bitmap_font_initial;
5484 InitFontGraphicInfo();
5486 font_height = getFontHeight(FC_RED);
5489 DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5491 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5493 DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5494 DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5496 DrawInitText("Loading graphics", 120, FC_GREEN);
5500 /* initialize busy animation with default values */
5501 int parameter[NUM_GFX_ARGS];
5502 for (i = 0; i < NUM_GFX_ARGS; i++)
5503 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5504 image_config_suffix[i].token,
5505 image_config_suffix[i].type);
5507 for (i = 0; i < NUM_GFX_ARGS; i++)
5508 printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5512 /* determine settings for busy animation (when displaying startup messages) */
5513 for (i = 0; image_config[i].token != NULL; i++)
5515 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5516 int len_anim_token = strlen(anim_token);
5518 if (strEqual(image_config[i].token, anim_token))
5519 filename_anim_initial = image_config[i].value;
5520 else if (strlen(image_config[i].token) > len_anim_token &&
5521 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5524 for (j = 0; image_config_suffix[j].token != NULL; j++)
5526 if (strEqual(&image_config[i].token[len_anim_token],
5527 image_config_suffix[j].token))
5529 get_graphic_parameter_value(image_config[i].value,
5530 image_config_suffix[j].token,
5531 image_config_suffix[j].type);
5534 if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5535 anim_initial.src_x = atoi(image_config[i].value);
5536 else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5537 anim_initial.src_y = atoi(image_config[i].value);
5538 else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5539 anim_initial.width = atoi(image_config[i].value);
5540 else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5541 anim_initial.height = atoi(image_config[i].value);
5542 else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5543 anim_initial.anim_frames = atoi(image_config[i].value);
5544 else if (strEqual(&image_config[i].token[len_anim_token],
5545 ".frames_per_line"))
5546 anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5547 else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5548 anim_initial.anim_delay = atoi(image_config[i].value);
5553 set_graphic_parameters_ext(0, &anim_initial, parameter, NULL);
5555 if (filename_anim_initial == NULL) /* should not happen */
5556 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5558 anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5560 init.busy.width = anim_initial.width;
5561 init.busy.height = anim_initial.height;
5563 InitMenuDesignSettings_Static();
5564 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5568 void RedrawBackground()
5570 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5571 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5573 redraw_mask = REDRAW_ALL;
5576 void InitGfxBackground()
5580 fieldbuffer = bitmap_db_field;
5581 SetDrawtoField(DRAW_BACKBUFFER);
5584 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5588 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5589 ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5592 for (x = 0; x < MAX_BUF_XSIZE; x++)
5593 for (y = 0; y < MAX_BUF_YSIZE; y++)
5596 redraw_mask = REDRAW_ALL;
5599 static void InitLevelInfo()
5601 LoadLevelInfo(); /* global level info */
5602 LoadLevelSetup_LastSeries(); /* last played series info */
5603 LoadLevelSetup_SeriesInfo(); /* last played level info */
5606 void InitLevelArtworkInfo()
5608 LoadLevelArtworkInfo();
5611 static void InitImages()
5613 print_timestamp_init("InitImages");
5615 setLevelArtworkDir(artwork.gfx_first);
5618 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5619 leveldir_current->identifier,
5620 artwork.gfx_current_identifier,
5621 artwork.gfx_current->identifier,
5622 leveldir_current->graphics_set,
5623 leveldir_current->graphics_path);
5626 UPDATE_BUSY_STATE();
5628 ReloadCustomImages();
5629 print_timestamp_time("ReloadCustomImages");
5631 UPDATE_BUSY_STATE();
5633 LoadCustomElementDescriptions();
5634 print_timestamp_time("LoadCustomElementDescriptions");
5636 UPDATE_BUSY_STATE();
5638 LoadMenuDesignSettings();
5639 print_timestamp_time("LoadMenuDesignSettings");
5641 UPDATE_BUSY_STATE();
5643 ReinitializeGraphics();
5644 print_timestamp_time("ReinitializeGraphics");
5646 UPDATE_BUSY_STATE();
5648 print_timestamp_done("InitImages");
5651 static void InitSound(char *identifier)
5653 print_timestamp_init("InitSound");
5655 if (identifier == NULL)
5656 identifier = artwork.snd_current->identifier;
5658 /* set artwork path to send it to the sound server process */
5659 setLevelArtworkDir(artwork.snd_first);
5661 InitReloadCustomSounds(identifier);
5662 print_timestamp_time("InitReloadCustomSounds");
5664 ReinitializeSounds();
5665 print_timestamp_time("ReinitializeSounds");
5667 print_timestamp_done("InitSound");
5670 static void InitMusic(char *identifier)
5672 print_timestamp_init("InitMusic");
5674 if (identifier == NULL)
5675 identifier = artwork.mus_current->identifier;
5677 /* set artwork path to send it to the sound server process */
5678 setLevelArtworkDir(artwork.mus_first);
5680 InitReloadCustomMusic(identifier);
5681 print_timestamp_time("InitReloadCustomMusic");
5683 ReinitializeMusic();
5684 print_timestamp_time("ReinitializeMusic");
5686 print_timestamp_done("InitMusic");
5689 void InitNetworkServer()
5691 #if defined(NETWORK_AVALIABLE)
5695 if (!options.network)
5698 #if defined(NETWORK_AVALIABLE)
5699 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5701 if (!ConnectToServer(options.server_host, options.server_port))
5702 Error(ERR_EXIT, "cannot connect to network game server");
5704 SendToServer_PlayerName(setup.player_name);
5705 SendToServer_ProtocolVersion();
5708 SendToServer_NrWanted(nr_wanted);
5712 static char *getNewArtworkIdentifier(int type)
5714 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5715 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5716 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5717 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5718 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5720 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5722 boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5724 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5725 char *leveldir_identifier = leveldir_current->identifier;
5727 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5728 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5730 char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5732 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5733 char *artwork_current_identifier;
5734 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5736 /* leveldir_current may be invalid (level group, parent link) */
5737 if (!validLevelSeries(leveldir_current))
5740 /* 1st step: determine artwork set to be activated in descending order:
5741 --------------------------------------------------------------------
5742 1. setup artwork (when configured to override everything else)
5743 2. artwork set configured in "levelinfo.conf" of current level set
5744 (artwork in level directory will have priority when loading later)
5745 3. artwork in level directory (stored in artwork sub-directory)
5746 4. setup artwork (currently configured in setup menu) */
5748 if (setup_override_artwork)
5749 artwork_current_identifier = setup_artwork_set;
5750 else if (leveldir_artwork_set != NULL)
5751 artwork_current_identifier = leveldir_artwork_set;
5752 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5753 artwork_current_identifier = leveldir_identifier;
5755 artwork_current_identifier = setup_artwork_set;
5758 /* 2nd step: check if it is really needed to reload artwork set
5759 ------------------------------------------------------------ */
5762 if (type == ARTWORK_TYPE_GRAPHICS)
5763 printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5764 artwork_new_identifier,
5765 ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5766 artwork_current_identifier,
5767 leveldir_current->graphics_set,
5768 leveldir_current->identifier);
5771 /* ---------- reload if level set and also artwork set has changed ------- */
5772 if (leveldir_current_identifier[type] != leveldir_identifier &&
5773 (last_has_level_artwork_set[type] || has_level_artwork_set))
5774 artwork_new_identifier = artwork_current_identifier;
5776 leveldir_current_identifier[type] = leveldir_identifier;
5777 last_has_level_artwork_set[type] = has_level_artwork_set;
5780 if (type == ARTWORK_TYPE_GRAPHICS)
5781 printf("::: 1: '%s'\n", artwork_new_identifier);
5784 /* ---------- reload if "override artwork" setting has changed ----------- */
5785 if (last_override_level_artwork[type] != setup_override_artwork)
5786 artwork_new_identifier = artwork_current_identifier;
5788 last_override_level_artwork[type] = setup_override_artwork;
5791 if (type == ARTWORK_TYPE_GRAPHICS)
5792 printf("::: 2: '%s'\n", artwork_new_identifier);
5795 /* ---------- reload if current artwork identifier has changed ----------- */
5796 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5797 artwork_current_identifier))
5798 artwork_new_identifier = artwork_current_identifier;
5800 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5803 if (type == ARTWORK_TYPE_GRAPHICS)
5804 printf("::: 3: '%s'\n", artwork_new_identifier);
5807 /* ---------- do not reload directly after starting ---------------------- */
5808 if (!initialized[type])
5809 artwork_new_identifier = NULL;
5811 initialized[type] = TRUE;
5814 if (type == ARTWORK_TYPE_GRAPHICS)
5815 printf("::: 4: '%s'\n", artwork_new_identifier);
5819 if (type == ARTWORK_TYPE_GRAPHICS)
5820 printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5821 artwork.gfx_current_identifier, artwork_current_identifier,
5822 artwork.gfx_current->identifier, leveldir_current->graphics_set,
5823 artwork_new_identifier);
5826 return artwork_new_identifier;
5829 void ReloadCustomArtwork(int force_reload)
5831 int last_game_status = game_status; /* save current game status */
5832 char *gfx_new_identifier;
5833 char *snd_new_identifier;
5834 char *mus_new_identifier;
5835 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5836 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5837 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5838 boolean reload_needed;
5841 gfx.draw_init_text = FALSE;
5843 gfx.override_level_graphics = FALSE;
5844 gfx.override_level_sounds = FALSE;
5845 gfx.override_level_music = FALSE;
5851 CheckCustomElementGraphicInfo();
5856 char *filename_base, *filename_local;
5858 /* first look for special artwork configured in level series config */
5859 filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
5861 if (fileExists(filename_base))
5862 CheckArtworkConfigForCustomElements(filename_base);
5864 filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
5866 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5867 CheckArtworkConfigForCustomElements(filename_local);
5871 gfx.override_level_graphics = setup.override_level_graphics;
5872 gfx.override_level_sounds = setup.override_level_sounds;
5873 gfx.override_level_music = setup.override_level_music;
5875 gfx.draw_init_text = TRUE;
5878 force_reload_gfx |= AdjustGraphicsForEMC();
5880 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5881 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5882 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5884 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5885 snd_new_identifier != NULL || force_reload_snd ||
5886 mus_new_identifier != NULL || force_reload_mus);
5891 print_timestamp_init("ReloadCustomArtwork");
5893 game_status = GAME_MODE_LOADING;
5895 FadeOut(REDRAW_ALL);
5898 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5900 ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5902 print_timestamp_time("ClearRectangle");
5905 printf("::: fading in ... %d\n", fading.fade_mode);
5909 printf("::: done\n");
5912 if (gfx_new_identifier != NULL || force_reload_gfx)
5915 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5916 artwork.gfx_current_identifier,
5918 artwork.gfx_current->identifier,
5919 leveldir_current->graphics_set);
5923 print_timestamp_time("InitImages");
5926 if (snd_new_identifier != NULL || force_reload_snd)
5928 InitSound(snd_new_identifier);
5929 print_timestamp_time("InitSound");
5932 if (mus_new_identifier != NULL || force_reload_mus)
5934 InitMusic(mus_new_identifier);
5935 print_timestamp_time("InitMusic");
5938 game_status = last_game_status; /* restore current game status */
5941 printf("::: ----------------DELAY 1 ...\n");
5946 printf("::: FadeOut @ ReloadCustomArtwork ...\n");
5948 FadeOut(REDRAW_ALL);
5950 printf("::: FadeOut @ ReloadCustomArtwork done\n");
5955 /* force redraw of (open or closed) door graphics */
5956 SetDoorState(DOOR_OPEN_ALL);
5957 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5962 FadeSetEnterScreen();
5963 FadeSkipNextFadeOut();
5964 // FadeSetDisabled();
5969 fading = fading_none;
5974 redraw_mask = REDRAW_ALL;
5977 print_timestamp_done("ReloadCustomArtwork");
5980 void KeyboardAutoRepeatOffUnlessAutoplay()
5982 if (global.autoplay_leveldir == NULL)
5983 KeyboardAutoRepeatOff();
5987 /* ========================================================================= */
5989 /* ========================================================================= */
5993 print_timestamp_init("OpenAll");
5995 game_status = GAME_MODE_LOADING;
5997 InitGlobal(); /* initialize some global variables */
5999 if (options.execute_command)
6000 Execute_Command(options.execute_command);
6002 if (options.serveronly)
6004 #if defined(PLATFORM_UNIX)
6005 NetworkServer(options.server_port, options.serveronly);
6007 Error(ERR_WARN, "networking only supported in Unix version");
6010 exit(0); /* never reached, server loops forever */
6017 InitArtworkInfo(); /* needed before loading gfx, sound & music */
6018 InitArtworkConfig(); /* needed before forking sound child process */
6023 InitRND(NEW_RANDOMIZE);
6024 InitSimpleRandom(NEW_RANDOMIZE);
6028 print_timestamp_time("[pre-video]");
6031 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6033 InitEventFilter(FilterMouseMotionEvents);
6035 InitElementPropertiesStatic();
6036 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6038 print_timestamp_time("[post-video]");
6042 print_timestamp_time("InitGfx");
6045 print_timestamp_time("InitLevelInfo");
6047 InitLevelArtworkInfo();
6048 print_timestamp_time("InitLevelArtworkInfo");
6050 InitImages(); /* needs to know current level directory */
6051 print_timestamp_time("InitImages");
6053 InitSound(NULL); /* needs to know current level directory */
6054 print_timestamp_time("InitSound");
6056 InitMusic(NULL); /* needs to know current level directory */
6057 print_timestamp_time("InitMusic");
6059 InitGfxBackground();
6065 if (global.autoplay_leveldir)
6070 else if (global.convert_leveldir)
6076 game_status = GAME_MODE_MAIN;
6079 FadeSetEnterScreen();
6080 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6081 FadeSkipNextFadeOut();
6082 // FadeSetDisabled();
6084 fading = fading_none;
6087 print_timestamp_time("[post-artwork]");
6089 print_timestamp_done("OpenAll");
6093 InitNetworkServer();
6096 void CloseAllAndExit(int exit_value)
6101 CloseAudio(); /* called after freeing sounds (needed for SDL) */
6109 #if defined(TARGET_SDL)
6110 if (network_server) /* terminate network server */
6111 SDL_KillThread(server_thread);
6114 CloseVideoDisplay();
6115 ClosePlatformDependentStuff();
6117 if (exit_value != 0)
6118 NotifyUserAboutErrorFile();