1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" /* include auto-generated data structure definitions */
28 #include "conf_esg.c" /* include auto-generated data structure definitions */
29 #include "conf_e2s.c" /* include auto-generated data structure definitions */
30 #include "conf_fnt.c" /* include auto-generated data structure definitions */
31 #include "conf_g2s.c" /* include auto-generated data structure definitions */
32 #include "conf_g2m.c" /* include auto-generated data structure definitions */
33 #include "conf_act.c" /* include auto-generated data structure definitions */
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
89 struct GraphicInfo *graphic_info_last = graphic_info;
91 static unsigned int action_delay = 0;
92 unsigned int action_delay_value = GameFrameDelay;
93 int sync_frame = FrameCounter;
96 if (game_status != GAME_MODE_LOADING)
99 if (anim_initial.bitmap == NULL || window == NULL)
102 if (!DelayReached(&action_delay, action_delay_value))
105 if (init_last.busy.x == -1)
106 init_last.busy.x = WIN_XSIZE / 2;
107 if (init_last.busy.y == -1)
108 init_last.busy.y = WIN_YSIZE / 2;
110 x = ALIGNED_TEXT_XPOS(&init_last.busy);
111 y = ALIGNED_TEXT_YPOS(&init_last.busy);
113 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
115 if (sync_frame % anim_initial.anim_delay == 0)
119 int width = graphic_info[graphic].width;
120 int height = graphic_info[graphic].height;
121 int frame = getGraphicAnimationFrame(graphic, sync_frame);
123 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
124 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
127 graphic_info = graphic_info_last;
134 FreeLevelEditorGadgets();
143 static boolean gadgets_initialized = FALSE;
145 if (gadgets_initialized)
148 CreateLevelEditorGadgets();
152 CreateScreenGadgets();
154 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
156 gadgets_initialized = TRUE;
159 inline static void InitElementSmallImagesScaledUp(int graphic)
161 struct GraphicInfo *g = &graphic_info[graphic];
163 // create small and game tile sized bitmaps (and scale up, if needed)
164 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
167 void InitElementSmallImages()
169 print_timestamp_init("InitElementSmallImages");
171 static int special_graphics[] =
173 IMG_EDITOR_ELEMENT_BORDER,
174 IMG_EDITOR_ELEMENT_BORDER_INPUT,
175 IMG_EDITOR_CASCADE_LIST,
176 IMG_EDITOR_CASCADE_LIST_ACTIVE,
179 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
180 int num_property_mappings = getImageListPropertyMappingSize();
183 print_timestamp_time("getImageListPropertyMapping/Size");
185 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
186 /* initialize normal images from static configuration */
187 for (i = 0; element_to_graphic[i].element > -1; i++)
188 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
189 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
191 /* initialize special images from static configuration */
192 for (i = 0; element_to_special_graphic[i].element > -1; i++)
193 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
194 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
196 /* initialize images from dynamic configuration (may be elements or other) */
197 for (i = 0; i < num_property_mappings; i++)
198 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
199 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
201 /* initialize special images from above list (non-element images) */
202 for (i = 0; special_graphics[i] > -1; i++)
203 InitElementSmallImagesScaledUp(special_graphics[i]);
204 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
206 print_timestamp_done("InitElementSmallImages");
209 void InitScaledImages()
213 /* scale normal images from static configuration, if not already scaled */
214 for (i = 0; i < NUM_IMAGE_FILES; i++)
215 ScaleImage(i, graphic_info[i].scale_up_factor);
218 void InitBitmapPointers()
220 int num_images = getImageListSize();
223 // standard size bitmap may have changed -- update default bitmap pointer
224 for (i = 0; i < num_images; i++)
225 if (graphic_info[i].bitmaps)
226 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
230 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
231 void SetBitmaps_EM(Bitmap **em_bitmap)
233 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
234 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
239 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
240 void SetBitmaps_SP(Bitmap **sp_bitmap)
242 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
246 static int getFontBitmapID(int font_nr)
250 /* (special case: do not use special font for GAME_MODE_LOADING) */
251 if (game_status >= GAME_MODE_TITLE_INITIAL &&
252 game_status <= GAME_MODE_PSEUDO_PREVIEW)
253 special = game_status;
254 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
255 special = GFX_SPECIAL_ARG_MAIN;
258 return font_info[font_nr].special_bitmap_id[special];
263 static int getFontFromToken(char *token)
265 char *value = getHashEntry(font_token_hash, token);
270 /* if font not found, use reliable default value */
271 return FONT_INITIAL_1;
274 void InitFontGraphicInfo()
276 static struct FontBitmapInfo *font_bitmap_info = NULL;
277 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
278 int num_property_mappings = getImageListPropertyMappingSize();
279 int num_font_bitmaps = NUM_FONTS;
282 if (graphic_info == NULL) /* still at startup phase */
284 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
285 getFontBitmapID, getFontFromToken);
290 /* ---------- initialize font graphic definitions ---------- */
292 /* always start with reliable default values (normal font graphics) */
293 for (i = 0; i < NUM_FONTS; i++)
294 font_info[i].graphic = IMG_FONT_INITIAL_1;
296 /* initialize normal font/graphic mapping from static configuration */
297 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
299 int font_nr = font_to_graphic[i].font_nr;
300 int special = font_to_graphic[i].special;
301 int graphic = font_to_graphic[i].graphic;
306 font_info[font_nr].graphic = graphic;
309 /* always start with reliable default values (special font graphics) */
310 for (i = 0; i < NUM_FONTS; i++)
312 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
314 font_info[i].special_graphic[j] = font_info[i].graphic;
315 font_info[i].special_bitmap_id[j] = i;
319 /* initialize special font/graphic mapping from static configuration */
320 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
322 int font_nr = font_to_graphic[i].font_nr;
323 int special = font_to_graphic[i].special;
324 int graphic = font_to_graphic[i].graphic;
325 int base_graphic = font2baseimg(font_nr);
327 if (IS_SPECIAL_GFX_ARG(special))
329 boolean base_redefined =
330 getImageListEntryFromImageID(base_graphic)->redefined;
331 boolean special_redefined =
332 getImageListEntryFromImageID(graphic)->redefined;
333 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
335 /* if the base font ("font.title_1", for example) has been redefined,
336 but not the special font ("font.title_1.LEVELS", for example), do not
337 use an existing (in this case considered obsolete) special font
338 anymore, but use the automatically determined default font */
339 /* special case: cloned special fonts must be explicitly redefined,
340 but are not automatically redefined by redefining base font */
341 if (base_redefined && !special_redefined && !special_cloned)
344 font_info[font_nr].special_graphic[special] = graphic;
345 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
350 /* initialize special font/graphic mapping from dynamic configuration */
351 for (i = 0; i < num_property_mappings; i++)
353 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
354 int special = property_mapping[i].ext3_index;
355 int graphic = property_mapping[i].artwork_index;
360 if (IS_SPECIAL_GFX_ARG(special))
362 font_info[font_nr].special_graphic[special] = graphic;
363 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
368 /* correct special font/graphic mapping for cloned fonts for downwards
369 compatibility of PREVIEW fonts -- this is only needed for implicit
370 redefinition of special font by redefined base font, and only if other
371 fonts are cloned from this special font (like in the "Zelda" level set) */
372 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
374 int font_nr = font_to_graphic[i].font_nr;
375 int special = font_to_graphic[i].special;
376 int graphic = font_to_graphic[i].graphic;
378 if (IS_SPECIAL_GFX_ARG(special))
380 boolean special_redefined =
381 getImageListEntryFromImageID(graphic)->redefined;
382 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
384 if (special_cloned && !special_redefined)
388 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
390 int font_nr2 = font_to_graphic[j].font_nr;
391 int special2 = font_to_graphic[j].special;
392 int graphic2 = font_to_graphic[j].graphic;
394 if (IS_SPECIAL_GFX_ARG(special2) &&
395 graphic2 == graphic_info[graphic].clone_from)
397 font_info[font_nr].special_graphic[special] =
398 font_info[font_nr2].special_graphic[special2];
399 font_info[font_nr].special_bitmap_id[special] =
400 font_info[font_nr2].special_bitmap_id[special2];
407 /* reset non-redefined ".active" font graphics if normal font is redefined */
408 /* (this different treatment is needed because normal and active fonts are
409 independently defined ("active" is not a property of font definitions!) */
410 for (i = 0; i < NUM_FONTS; i++)
412 int font_nr_base = i;
413 int font_nr_active = FONT_ACTIVE(font_nr_base);
415 /* check only those fonts with exist as normal and ".active" variant */
416 if (font_nr_base != font_nr_active)
418 int base_graphic = font_info[font_nr_base].graphic;
419 int active_graphic = font_info[font_nr_active].graphic;
420 boolean base_redefined =
421 getImageListEntryFromImageID(base_graphic)->redefined;
422 boolean active_redefined =
423 getImageListEntryFromImageID(active_graphic)->redefined;
425 /* if the base font ("font.menu_1", for example) has been redefined,
426 but not the active font ("font.menu_1.active", for example), do not
427 use an existing (in this case considered obsolete) active font
428 anymore, but use the automatically determined default font */
429 if (base_redefined && !active_redefined)
430 font_info[font_nr_active].graphic = base_graphic;
432 /* now also check each "special" font (which may be the same as above) */
433 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
435 int base_graphic = font_info[font_nr_base].special_graphic[j];
436 int active_graphic = font_info[font_nr_active].special_graphic[j];
437 boolean base_redefined =
438 getImageListEntryFromImageID(base_graphic)->redefined;
439 boolean active_redefined =
440 getImageListEntryFromImageID(active_graphic)->redefined;
442 /* same as above, but check special graphic definitions, for example:
443 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
444 if (base_redefined && !active_redefined)
446 font_info[font_nr_active].special_graphic[j] =
447 font_info[font_nr_base].special_graphic[j];
448 font_info[font_nr_active].special_bitmap_id[j] =
449 font_info[font_nr_base].special_bitmap_id[j];
455 /* ---------- initialize font bitmap array ---------- */
457 if (font_bitmap_info != NULL)
458 FreeFontInfo(font_bitmap_info);
461 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
463 /* ---------- initialize font bitmap definitions ---------- */
465 for (i = 0; i < NUM_FONTS; i++)
467 if (i < NUM_INITIAL_FONTS)
469 font_bitmap_info[i] = font_initial[i];
473 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
475 int font_bitmap_id = font_info[i].special_bitmap_id[j];
476 int graphic = font_info[i].special_graphic[j];
478 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
479 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
481 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
482 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
485 /* copy font relevant information from graphics information */
486 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
487 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
488 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
489 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
490 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
492 font_bitmap_info[font_bitmap_id].draw_xoffset =
493 graphic_info[graphic].draw_xoffset;
494 font_bitmap_info[font_bitmap_id].draw_yoffset =
495 graphic_info[graphic].draw_yoffset;
497 font_bitmap_info[font_bitmap_id].num_chars =
498 graphic_info[graphic].anim_frames;
499 font_bitmap_info[font_bitmap_id].num_chars_per_line =
500 graphic_info[graphic].anim_frames_per_line;
504 InitFontInfo(font_bitmap_info, num_font_bitmaps,
505 getFontBitmapID, getFontFromToken);
508 void InitElementGraphicInfo()
510 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
511 int num_property_mappings = getImageListPropertyMappingSize();
514 if (graphic_info == NULL) /* still at startup phase */
517 /* set values to -1 to identify later as "uninitialized" values */
518 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
520 for (act = 0; act < NUM_ACTIONS; act++)
522 element_info[i].graphic[act] = -1;
523 element_info[i].crumbled[act] = -1;
525 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
527 element_info[i].direction_graphic[act][dir] = -1;
528 element_info[i].direction_crumbled[act][dir] = -1;
535 /* initialize normal element/graphic mapping from static configuration */
536 for (i = 0; element_to_graphic[i].element > -1; i++)
538 int element = element_to_graphic[i].element;
539 int action = element_to_graphic[i].action;
540 int direction = element_to_graphic[i].direction;
541 boolean crumbled = element_to_graphic[i].crumbled;
542 int graphic = element_to_graphic[i].graphic;
543 int base_graphic = el2baseimg(element);
545 if (graphic_info[graphic].bitmap == NULL)
548 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
551 boolean base_redefined =
552 getImageListEntryFromImageID(base_graphic)->redefined;
553 boolean act_dir_redefined =
554 getImageListEntryFromImageID(graphic)->redefined;
556 /* if the base graphic ("emerald", for example) has been redefined,
557 but not the action graphic ("emerald.falling", for example), do not
558 use an existing (in this case considered obsolete) action graphic
559 anymore, but use the automatically determined default graphic */
560 if (base_redefined && !act_dir_redefined)
565 action = ACTION_DEFAULT;
570 element_info[element].direction_crumbled[action][direction] = graphic;
572 element_info[element].crumbled[action] = graphic;
577 element_info[element].direction_graphic[action][direction] = graphic;
579 element_info[element].graphic[action] = graphic;
583 /* initialize normal element/graphic mapping from dynamic configuration */
584 for (i = 0; i < num_property_mappings; i++)
586 int element = property_mapping[i].base_index;
587 int action = property_mapping[i].ext1_index;
588 int direction = property_mapping[i].ext2_index;
589 int special = property_mapping[i].ext3_index;
590 int graphic = property_mapping[i].artwork_index;
591 boolean crumbled = FALSE;
593 if (special == GFX_SPECIAL_ARG_CRUMBLED)
599 if (graphic_info[graphic].bitmap == NULL)
602 if (element >= MAX_NUM_ELEMENTS || special != -1)
606 action = ACTION_DEFAULT;
611 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
612 element_info[element].direction_crumbled[action][dir] = -1;
615 element_info[element].direction_crumbled[action][direction] = graphic;
617 element_info[element].crumbled[action] = graphic;
622 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
623 element_info[element].direction_graphic[action][dir] = -1;
626 element_info[element].direction_graphic[action][direction] = graphic;
628 element_info[element].graphic[action] = graphic;
632 /* now copy all graphics that are defined to be cloned from other graphics */
633 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
635 int graphic = element_info[i].graphic[ACTION_DEFAULT];
636 int crumbled_like, diggable_like;
641 crumbled_like = graphic_info[graphic].crumbled_like;
642 diggable_like = graphic_info[graphic].diggable_like;
644 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
646 for (act = 0; act < NUM_ACTIONS; act++)
647 element_info[i].crumbled[act] =
648 element_info[crumbled_like].crumbled[act];
649 for (act = 0; act < NUM_ACTIONS; act++)
650 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
651 element_info[i].direction_crumbled[act][dir] =
652 element_info[crumbled_like].direction_crumbled[act][dir];
655 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
657 element_info[i].graphic[ACTION_DIGGING] =
658 element_info[diggable_like].graphic[ACTION_DIGGING];
659 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
660 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
661 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
665 /* set hardcoded definitions for some runtime elements without graphic */
666 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
668 /* set hardcoded definitions for some internal elements without graphic */
669 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
671 if (IS_EDITOR_CASCADE_INACTIVE(i))
672 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
673 else if (IS_EDITOR_CASCADE_ACTIVE(i))
674 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
677 /* now set all undefined/invalid graphics to -1 to set to default after it */
678 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
680 for (act = 0; act < NUM_ACTIONS; act++)
684 graphic = element_info[i].graphic[act];
685 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
686 element_info[i].graphic[act] = -1;
688 graphic = element_info[i].crumbled[act];
689 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
690 element_info[i].crumbled[act] = -1;
692 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
694 graphic = element_info[i].direction_graphic[act][dir];
695 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
696 element_info[i].direction_graphic[act][dir] = -1;
698 graphic = element_info[i].direction_crumbled[act][dir];
699 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
700 element_info[i].direction_crumbled[act][dir] = -1;
707 /* adjust graphics with 2nd tile for movement according to direction
708 (do this before correcting '-1' values to minimize calculations) */
709 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
711 for (act = 0; act < NUM_ACTIONS; act++)
713 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
715 int graphic = element_info[i].direction_graphic[act][dir];
716 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
718 if (act == ACTION_FALLING) /* special case */
719 graphic = element_info[i].graphic[act];
722 graphic_info[graphic].double_movement &&
723 graphic_info[graphic].swap_double_tiles != 0)
725 struct GraphicInfo *g = &graphic_info[graphic];
726 int src_x_front = g->src_x;
727 int src_y_front = g->src_y;
728 int src_x_back = g->src_x + g->offset2_x;
729 int src_y_back = g->src_y + g->offset2_y;
730 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
732 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
733 src_y_front < src_y_back);
734 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
735 boolean swap_movement_tiles_autodetected =
736 (!frames_are_ordered_diagonally &&
737 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
738 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
739 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
740 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
743 /* swap frontside and backside graphic tile coordinates, if needed */
744 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
746 /* get current (wrong) backside tile coordinates */
747 getFixedGraphicSourceExt(graphic, 0, &dummy,
748 &src_x_back, &src_y_back, TRUE);
750 /* set frontside tile coordinates to backside tile coordinates */
751 g->src_x = src_x_back;
752 g->src_y = src_y_back;
754 /* invert tile offset to point to new backside tile coordinates */
758 /* do not swap front and backside tiles again after correction */
759 g->swap_double_tiles = 0;
768 /* now set all '-1' values to element specific default values */
769 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
771 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
772 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
773 int default_direction_graphic[NUM_DIRECTIONS_FULL];
774 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
776 if (default_graphic == -1)
777 default_graphic = IMG_UNKNOWN;
779 if (default_crumbled == -1)
780 default_crumbled = default_graphic;
782 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
784 default_direction_graphic[dir] =
785 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
786 default_direction_crumbled[dir] =
787 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
789 if (default_direction_graphic[dir] == -1)
790 default_direction_graphic[dir] = default_graphic;
792 if (default_direction_crumbled[dir] == -1)
793 default_direction_crumbled[dir] = default_direction_graphic[dir];
796 for (act = 0; act < NUM_ACTIONS; act++)
798 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
799 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
800 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
801 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
802 act == ACTION_TURNING_FROM_RIGHT ||
803 act == ACTION_TURNING_FROM_UP ||
804 act == ACTION_TURNING_FROM_DOWN);
806 /* generic default action graphic (defined by "[default]" directive) */
807 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
808 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
809 int default_remove_graphic = IMG_EMPTY;
811 if (act_remove && default_action_graphic != -1)
812 default_remove_graphic = default_action_graphic;
814 /* look for special default action graphic (classic game specific) */
815 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
816 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
817 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
818 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
819 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
820 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
822 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
823 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
824 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
825 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
826 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
827 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
829 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
830 /* !!! make this better !!! */
831 if (i == EL_EMPTY_SPACE)
833 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
834 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
837 if (default_action_graphic == -1)
838 default_action_graphic = default_graphic;
840 if (default_action_crumbled == -1)
841 default_action_crumbled = default_action_graphic;
843 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
845 /* use action graphic as the default direction graphic, if undefined */
846 int default_action_direction_graphic = element_info[i].graphic[act];
847 int default_action_direction_crumbled = element_info[i].crumbled[act];
849 /* no graphic for current action -- use default direction graphic */
850 if (default_action_direction_graphic == -1)
851 default_action_direction_graphic =
852 (act_remove ? default_remove_graphic :
854 element_info[i].direction_graphic[ACTION_TURNING][dir] :
855 default_action_graphic != default_graphic ?
856 default_action_graphic :
857 default_direction_graphic[dir]);
859 if (element_info[i].direction_graphic[act][dir] == -1)
860 element_info[i].direction_graphic[act][dir] =
861 default_action_direction_graphic;
863 if (default_action_direction_crumbled == -1)
864 default_action_direction_crumbled =
865 element_info[i].direction_graphic[act][dir];
867 if (element_info[i].direction_crumbled[act][dir] == -1)
868 element_info[i].direction_crumbled[act][dir] =
869 default_action_direction_crumbled;
872 /* no graphic for this specific action -- use default action graphic */
873 if (element_info[i].graphic[act] == -1)
874 element_info[i].graphic[act] =
875 (act_remove ? default_remove_graphic :
876 act_turning ? element_info[i].graphic[ACTION_TURNING] :
877 default_action_graphic);
879 if (element_info[i].crumbled[act] == -1)
880 element_info[i].crumbled[act] = element_info[i].graphic[act];
887 void InitElementSpecialGraphicInfo()
889 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
890 int num_property_mappings = getImageListPropertyMappingSize();
893 /* always start with reliable default values */
894 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
895 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
896 element_info[i].special_graphic[j] =
897 element_info[i].graphic[ACTION_DEFAULT];
899 /* initialize special element/graphic mapping from static configuration */
900 for (i = 0; element_to_special_graphic[i].element > -1; i++)
902 int element = element_to_special_graphic[i].element;
903 int special = element_to_special_graphic[i].special;
904 int graphic = element_to_special_graphic[i].graphic;
905 int base_graphic = el2baseimg(element);
906 boolean base_redefined =
907 getImageListEntryFromImageID(base_graphic)->redefined;
908 boolean special_redefined =
909 getImageListEntryFromImageID(graphic)->redefined;
911 /* if the base graphic ("emerald", for example) has been redefined,
912 but not the special graphic ("emerald.EDITOR", for example), do not
913 use an existing (in this case considered obsolete) special graphic
914 anymore, but use the automatically created (down-scaled) graphic */
915 if (base_redefined && !special_redefined)
918 element_info[element].special_graphic[special] = graphic;
921 /* initialize special element/graphic mapping from dynamic configuration */
922 for (i = 0; i < num_property_mappings; i++)
924 int element = property_mapping[i].base_index;
925 int action = property_mapping[i].ext1_index;
926 int direction = property_mapping[i].ext2_index;
927 int special = property_mapping[i].ext3_index;
928 int graphic = property_mapping[i].artwork_index;
930 /* for action ".active", replace element with active element, if exists */
931 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
933 element = ELEMENT_ACTIVE(element);
937 if (element >= MAX_NUM_ELEMENTS)
940 /* do not change special graphic if action or direction was specified */
941 if (action != -1 || direction != -1)
944 if (IS_SPECIAL_GFX_ARG(special))
945 element_info[element].special_graphic[special] = graphic;
948 /* now set all undefined/invalid graphics to default */
949 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
950 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
951 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
952 element_info[i].special_graphic[j] =
953 element_info[i].graphic[ACTION_DEFAULT];
956 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
958 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
959 return get_parameter_value(value_raw, suffix, type);
961 if (strEqual(value_raw, ARG_UNDEFINED))
962 return ARG_UNDEFINED_VALUE;
964 if (type == TYPE_ELEMENT)
966 char *value = getHashEntry(element_token_hash, value_raw);
970 Error(ERR_INFO_LINE, "-");
971 Error(ERR_INFO, "warning: error found in config file:");
972 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
973 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
974 Error(ERR_INFO, "custom graphic rejected for this element/action");
975 Error(ERR_INFO, "fallback done to undefined element for this graphic");
976 Error(ERR_INFO_LINE, "-");
979 return (value != NULL ? atoi(value) : EL_UNDEFINED);
981 else if (type == TYPE_GRAPHIC)
983 char *value = getHashEntry(graphic_token_hash, value_raw);
984 int fallback_graphic = IMG_CHAR_EXCLAM;
988 Error(ERR_INFO_LINE, "-");
989 Error(ERR_INFO, "warning: error found in config file:");
990 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
991 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
992 Error(ERR_INFO, "custom graphic rejected for this element/action");
993 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
994 Error(ERR_INFO_LINE, "-");
997 return (value != NULL ? atoi(value) : fallback_graphic);
1003 static int get_scaled_graphic_width(int graphic)
1005 int original_width = getOriginalImageWidthFromImageID(graphic);
1006 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1008 return original_width * scale_up_factor;
1011 static int get_scaled_graphic_height(int graphic)
1013 int original_height = getOriginalImageHeightFromImageID(graphic);
1014 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1016 return original_height * scale_up_factor;
1019 static void set_graphic_parameters_ext(int graphic, int *parameter,
1020 Bitmap **src_bitmaps)
1022 struct GraphicInfo *g = &graphic_info[graphic];
1023 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1024 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1025 int anim_frames_per_line = 1;
1027 /* always start with reliable default values */
1028 g->src_image_width = 0;
1029 g->src_image_height = 0;
1032 g->width = TILEX; /* default for element graphics */
1033 g->height = TILEY; /* default for element graphics */
1034 g->offset_x = 0; /* one or both of these values ... */
1035 g->offset_y = 0; /* ... will be corrected later */
1036 g->offset2_x = 0; /* one or both of these values ... */
1037 g->offset2_y = 0; /* ... will be corrected later */
1038 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1039 g->crumbled_like = -1; /* do not use clone element */
1040 g->diggable_like = -1; /* do not use clone element */
1041 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1042 g->scale_up_factor = 1; /* default: no scaling up */
1043 g->tile_size = TILESIZE; /* default: standard tile size */
1044 g->clone_from = -1; /* do not use clone graphic */
1045 g->anim_delay_fixed = 0;
1046 g->anim_delay_random = 0;
1047 g->post_delay_fixed = 0;
1048 g->post_delay_random = 0;
1049 g->fade_mode = FADE_MODE_DEFAULT;
1053 g->align = ALIGN_CENTER; /* default for title screens */
1054 g->valign = VALIGN_MIDDLE; /* default for title screens */
1055 g->sort_priority = 0; /* default for title screens */
1057 g->style = STYLE_DEFAULT;
1059 g->bitmaps = src_bitmaps;
1060 g->bitmap = src_bitmap;
1062 /* optional zoom factor for scaling up the image to a larger size */
1063 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1064 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1065 if (g->scale_up_factor < 1)
1066 g->scale_up_factor = 1; /* no scaling */
1068 /* optional tile size for using non-standard image size */
1069 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1071 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1074 // CHECK: should tile sizes less than standard tile size be allowed?
1075 if (g->tile_size < TILESIZE)
1076 g->tile_size = TILESIZE; /* standard tile size */
1079 // when setting tile size, also set width and height accordingly
1080 g->width = g->tile_size;
1081 g->height = g->tile_size;
1084 if (g->use_image_size)
1086 /* set new default bitmap size (with scaling, but without small images) */
1087 g->width = get_scaled_graphic_width(graphic);
1088 g->height = get_scaled_graphic_height(graphic);
1091 /* optional width and height of each animation frame */
1092 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1093 g->width = parameter[GFX_ARG_WIDTH];
1094 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1095 g->height = parameter[GFX_ARG_HEIGHT];
1097 /* optional x and y tile position of animation frame sequence */
1098 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1099 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1100 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1101 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1103 /* optional x and y pixel position of animation frame sequence */
1104 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1105 g->src_x = parameter[GFX_ARG_X];
1106 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1107 g->src_y = parameter[GFX_ARG_Y];
1113 Error(ERR_INFO_LINE, "-");
1114 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1115 g->width, getTokenFromImageID(graphic), TILEX);
1116 Error(ERR_INFO_LINE, "-");
1118 g->width = TILEX; /* will be checked to be inside bitmap later */
1123 Error(ERR_INFO_LINE, "-");
1124 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1125 g->height, getTokenFromImageID(graphic), TILEY);
1126 Error(ERR_INFO_LINE, "-");
1128 g->height = TILEY; /* will be checked to be inside bitmap later */
1134 /* get final bitmap size (with scaling, but without small images) */
1135 int src_image_width = get_scaled_graphic_width(graphic);
1136 int src_image_height = get_scaled_graphic_height(graphic);
1138 if (src_image_width == 0 || src_image_height == 0)
1140 /* only happens when loaded outside artwork system (like "global.busy") */
1141 src_image_width = src_bitmap->width;
1142 src_image_height = src_bitmap->height;
1145 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1147 anim_frames_per_row = src_image_width / g->tile_size;
1148 anim_frames_per_col = src_image_height / g->tile_size;
1152 anim_frames_per_row = src_image_width / g->width;
1153 anim_frames_per_col = src_image_height / g->height;
1156 g->src_image_width = src_image_width;
1157 g->src_image_height = src_image_height;
1160 /* correct x or y offset dependent of vertical or horizontal frame order */
1161 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1163 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1164 parameter[GFX_ARG_OFFSET] : g->height);
1165 anim_frames_per_line = anim_frames_per_col;
1167 else /* frames are ordered horizontally */
1169 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1170 parameter[GFX_ARG_OFFSET] : g->width);
1171 anim_frames_per_line = anim_frames_per_row;
1174 /* optionally, the x and y offset of frames can be specified directly */
1175 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1176 g->offset_x = parameter[GFX_ARG_XOFFSET];
1177 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1178 g->offset_y = parameter[GFX_ARG_YOFFSET];
1180 /* optionally, moving animations may have separate start and end graphics */
1181 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1183 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1184 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1186 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1187 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1188 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1189 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1190 else /* frames are ordered horizontally */
1191 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1192 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1194 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1195 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1196 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1197 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1198 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1200 /* optionally, the second movement tile can be specified as start tile */
1201 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1202 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1204 /* automatically determine correct number of frames, if not defined */
1205 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1206 g->anim_frames = parameter[GFX_ARG_FRAMES];
1207 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1208 g->anim_frames = anim_frames_per_row;
1209 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1210 g->anim_frames = anim_frames_per_col;
1214 if (g->anim_frames == 0) /* frames must be at least 1 */
1217 g->anim_frames_per_line =
1218 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1219 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1221 g->anim_delay = parameter[GFX_ARG_DELAY];
1222 if (g->anim_delay == 0) /* delay must be at least 1 */
1225 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1227 /* automatically determine correct start frame, if not defined */
1228 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1229 g->anim_start_frame = 0;
1230 else if (g->anim_mode & ANIM_REVERSE)
1231 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1233 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1235 /* animation synchronized with global frame counter, not move position */
1236 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1238 /* optional element for cloning crumble graphics */
1239 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1240 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1242 /* optional element for cloning digging graphics */
1243 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1244 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1246 /* optional border size for "crumbling" diggable graphics */
1247 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1248 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1250 /* this is only used for player "boring" and "sleeping" actions */
1251 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1252 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1253 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1254 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1255 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1256 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1257 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1258 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1260 /* this is only used for toon animations */
1261 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1262 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1264 /* this is only used for drawing font characters */
1265 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1266 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1268 /* this is only used for drawing envelope graphics */
1269 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1271 /* optional graphic for cloning all graphics settings */
1272 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1273 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1275 /* optional settings for drawing title screens and title messages */
1276 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1277 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1278 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1279 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1280 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1281 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1282 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1283 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1284 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1285 g->align = parameter[GFX_ARG_ALIGN];
1286 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1287 g->valign = parameter[GFX_ARG_VALIGN];
1288 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1289 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1291 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1292 g->class = parameter[GFX_ARG_CLASS];
1293 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1294 g->style = parameter[GFX_ARG_STYLE];
1296 /* this is only used for drawing menu buttons and text */
1297 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1298 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1299 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1300 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1303 static void set_graphic_parameters(int graphic)
1305 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1306 char **parameter_raw = image->parameter;
1307 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1308 int parameter[NUM_GFX_ARGS];
1311 /* if fallback to default artwork is done, also use the default parameters */
1312 if (image->fallback_to_default)
1313 parameter_raw = image->default_parameter;
1315 /* get integer values from string parameters */
1316 for (i = 0; i < NUM_GFX_ARGS; i++)
1317 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1318 image_config_suffix[i].token,
1319 image_config_suffix[i].type);
1321 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1323 UPDATE_BUSY_STATE();
1326 static void set_cloned_graphic_parameters(int graphic)
1328 int fallback_graphic = IMG_CHAR_EXCLAM;
1329 int max_num_images = getImageListSize();
1330 int clone_graphic = graphic_info[graphic].clone_from;
1331 int num_references_followed = 1;
1333 while (graphic_info[clone_graphic].clone_from != -1 &&
1334 num_references_followed < max_num_images)
1336 clone_graphic = graphic_info[clone_graphic].clone_from;
1338 num_references_followed++;
1341 if (num_references_followed >= max_num_images)
1343 Error(ERR_INFO_LINE, "-");
1344 Error(ERR_INFO, "warning: error found in config file:");
1345 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1346 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1347 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1348 Error(ERR_INFO, "custom graphic rejected for this element/action");
1350 if (graphic == fallback_graphic)
1351 Error(ERR_EXIT, "no fallback graphic available");
1353 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1354 Error(ERR_INFO_LINE, "-");
1356 graphic_info[graphic] = graphic_info[fallback_graphic];
1360 graphic_info[graphic] = graphic_info[clone_graphic];
1361 graphic_info[graphic].clone_from = clone_graphic;
1365 static void InitGraphicInfo()
1367 int fallback_graphic = IMG_CHAR_EXCLAM;
1368 int num_images = getImageListSize();
1371 /* use image size as default values for width and height for these images */
1372 static int full_size_graphics[] =
1375 IMG_GLOBAL_BORDER_MAIN,
1376 IMG_GLOBAL_BORDER_SCORES,
1377 IMG_GLOBAL_BORDER_EDITOR,
1378 IMG_GLOBAL_BORDER_PLAYING,
1381 IMG_BACKGROUND_ENVELOPE_1,
1382 IMG_BACKGROUND_ENVELOPE_2,
1383 IMG_BACKGROUND_ENVELOPE_3,
1384 IMG_BACKGROUND_ENVELOPE_4,
1385 IMG_BACKGROUND_REQUEST,
1388 IMG_BACKGROUND_TITLE_INITIAL,
1389 IMG_BACKGROUND_TITLE,
1390 IMG_BACKGROUND_MAIN,
1391 IMG_BACKGROUND_LEVELS,
1392 IMG_BACKGROUND_LEVELNR,
1393 IMG_BACKGROUND_SCORES,
1394 IMG_BACKGROUND_EDITOR,
1395 IMG_BACKGROUND_INFO,
1396 IMG_BACKGROUND_INFO_ELEMENTS,
1397 IMG_BACKGROUND_INFO_MUSIC,
1398 IMG_BACKGROUND_INFO_CREDITS,
1399 IMG_BACKGROUND_INFO_PROGRAM,
1400 IMG_BACKGROUND_INFO_VERSION,
1401 IMG_BACKGROUND_INFO_LEVELSET,
1402 IMG_BACKGROUND_SETUP,
1403 IMG_BACKGROUND_PLAYING,
1404 IMG_BACKGROUND_DOOR,
1405 IMG_BACKGROUND_TAPE,
1406 IMG_BACKGROUND_PANEL,
1407 IMG_BACKGROUND_PALETTE,
1408 IMG_BACKGROUND_TOOLBOX,
1410 IMG_TITLESCREEN_INITIAL_1,
1411 IMG_TITLESCREEN_INITIAL_2,
1412 IMG_TITLESCREEN_INITIAL_3,
1413 IMG_TITLESCREEN_INITIAL_4,
1414 IMG_TITLESCREEN_INITIAL_5,
1421 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1422 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1423 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1424 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1425 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1426 IMG_BACKGROUND_TITLEMESSAGE_1,
1427 IMG_BACKGROUND_TITLEMESSAGE_2,
1428 IMG_BACKGROUND_TITLEMESSAGE_3,
1429 IMG_BACKGROUND_TITLEMESSAGE_4,
1430 IMG_BACKGROUND_TITLEMESSAGE_5,
1435 checked_free(graphic_info);
1437 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1439 /* initialize "use_image_size" flag with default value */
1440 for (i = 0; i < num_images; i++)
1441 graphic_info[i].use_image_size = FALSE;
1443 /* initialize "use_image_size" flag from static configuration above */
1444 for (i = 0; full_size_graphics[i] != -1; i++)
1445 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1447 /* first set all graphic paramaters ... */
1448 for (i = 0; i < num_images; i++)
1449 set_graphic_parameters(i);
1451 /* ... then copy these parameters for cloned graphics */
1452 for (i = 0; i < num_images; i++)
1453 if (graphic_info[i].clone_from != -1)
1454 set_cloned_graphic_parameters(i);
1456 for (i = 0; i < num_images; i++)
1461 int first_frame, last_frame;
1462 int src_bitmap_width, src_bitmap_height;
1464 /* now check if no animation frames are outside of the loaded image */
1466 if (graphic_info[i].bitmap == NULL)
1467 continue; /* skip check for optional images that are undefined */
1469 /* get image size (this can differ from the standard element tile size!) */
1470 width = graphic_info[i].width;
1471 height = graphic_info[i].height;
1473 /* get final bitmap size (with scaling, but without small images) */
1474 src_bitmap_width = graphic_info[i].src_image_width;
1475 src_bitmap_height = graphic_info[i].src_image_height;
1477 /* check if first animation frame is inside specified bitmap */
1480 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1482 /* this avoids calculating wrong start position for out-of-bounds frame */
1483 src_x = graphic_info[i].src_x;
1484 src_y = graphic_info[i].src_y;
1486 if (src_x < 0 || src_y < 0 ||
1487 src_x + width > src_bitmap_width ||
1488 src_y + height > src_bitmap_height)
1490 Error(ERR_INFO_LINE, "-");
1491 Error(ERR_INFO, "warning: error found in config file:");
1492 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1493 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1494 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1496 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1497 src_x, src_y, src_bitmap_width, src_bitmap_height);
1498 Error(ERR_INFO, "custom graphic rejected for this element/action");
1500 if (i == fallback_graphic)
1501 Error(ERR_EXIT, "no fallback graphic available");
1503 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1504 Error(ERR_INFO_LINE, "-");
1506 graphic_info[i] = graphic_info[fallback_graphic];
1509 /* check if last animation frame is inside specified bitmap */
1511 last_frame = graphic_info[i].anim_frames - 1;
1512 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1514 if (src_x < 0 || src_y < 0 ||
1515 src_x + width > src_bitmap_width ||
1516 src_y + height > src_bitmap_height)
1518 Error(ERR_INFO_LINE, "-");
1519 Error(ERR_INFO, "warning: error found in config file:");
1520 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1521 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1522 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1524 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1525 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1526 Error(ERR_INFO, "::: %d, %d", width, height);
1527 Error(ERR_INFO, "custom graphic rejected for this element/action");
1529 if (i == fallback_graphic)
1530 Error(ERR_EXIT, "no fallback graphic available");
1532 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1533 Error(ERR_INFO_LINE, "-");
1535 graphic_info[i] = graphic_info[fallback_graphic];
1540 static void InitGraphicCompatibilityInfo()
1542 struct FileInfo *fi_global_door =
1543 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1544 int num_images = getImageListSize();
1547 /* the following compatibility handling is needed for the following case:
1548 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1549 graphics mainly used for door and panel graphics, like editor, tape and
1550 in-game buttons with hard-coded bitmap positions and button sizes; as
1551 these graphics now have individual definitions, redefining "global.door"
1552 to change all these graphics at once like before does not work anymore
1553 (because all those individual definitions still have their default values);
1554 to solve this, remap all those individual definitions that are not
1555 redefined to the new bitmap of "global.door" if it was redefined */
1557 /* special compatibility handling if image "global.door" was redefined */
1558 if (fi_global_door->redefined)
1560 for (i = 0; i < num_images; i++)
1562 struct FileInfo *fi = getImageListEntryFromImageID(i);
1564 /* process only those images that still use the default settings */
1567 /* process all images which default to same image as "global.door" */
1568 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1570 // printf("::: special treatment needed for token '%s'\n", fi->token);
1572 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1578 InitGraphicCompatibilityInfo_Doors();
1581 static void InitElementSoundInfo()
1583 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1584 int num_property_mappings = getSoundListPropertyMappingSize();
1587 /* set values to -1 to identify later as "uninitialized" values */
1588 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1589 for (act = 0; act < NUM_ACTIONS; act++)
1590 element_info[i].sound[act] = -1;
1592 /* initialize element/sound mapping from static configuration */
1593 for (i = 0; element_to_sound[i].element > -1; i++)
1595 int element = element_to_sound[i].element;
1596 int action = element_to_sound[i].action;
1597 int sound = element_to_sound[i].sound;
1598 boolean is_class = element_to_sound[i].is_class;
1601 action = ACTION_DEFAULT;
1604 element_info[element].sound[action] = sound;
1606 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1607 if (strEqual(element_info[j].class_name,
1608 element_info[element].class_name))
1609 element_info[j].sound[action] = sound;
1612 /* initialize element class/sound mapping from dynamic configuration */
1613 for (i = 0; i < num_property_mappings; i++)
1615 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1616 int action = property_mapping[i].ext1_index;
1617 int sound = property_mapping[i].artwork_index;
1619 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1623 action = ACTION_DEFAULT;
1625 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1626 if (strEqual(element_info[j].class_name,
1627 element_info[element_class].class_name))
1628 element_info[j].sound[action] = sound;
1631 /* initialize element/sound mapping from dynamic configuration */
1632 for (i = 0; i < num_property_mappings; i++)
1634 int element = property_mapping[i].base_index;
1635 int action = property_mapping[i].ext1_index;
1636 int sound = property_mapping[i].artwork_index;
1638 if (element >= MAX_NUM_ELEMENTS)
1642 action = ACTION_DEFAULT;
1644 element_info[element].sound[action] = sound;
1647 /* now set all '-1' values to element specific default values */
1648 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1650 for (act = 0; act < NUM_ACTIONS; act++)
1652 /* generic default action sound (defined by "[default]" directive) */
1653 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1655 /* look for special default action sound (classic game specific) */
1656 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1657 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1658 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1659 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1660 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1661 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1663 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1664 /* !!! make this better !!! */
1665 if (i == EL_EMPTY_SPACE)
1666 default_action_sound = element_info[EL_DEFAULT].sound[act];
1668 /* no sound for this specific action -- use default action sound */
1669 if (element_info[i].sound[act] == -1)
1670 element_info[i].sound[act] = default_action_sound;
1674 /* copy sound settings to some elements that are only stored in level file
1675 in native R'n'D levels, but are used by game engine in native EM levels */
1676 for (i = 0; copy_properties[i][0] != -1; i++)
1677 for (j = 1; j <= 4; j++)
1678 for (act = 0; act < NUM_ACTIONS; act++)
1679 element_info[copy_properties[i][j]].sound[act] =
1680 element_info[copy_properties[i][0]].sound[act];
1683 static void InitGameModeSoundInfo()
1687 /* set values to -1 to identify later as "uninitialized" values */
1688 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1691 /* initialize gamemode/sound mapping from static configuration */
1692 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1694 int gamemode = gamemode_to_sound[i].gamemode;
1695 int sound = gamemode_to_sound[i].sound;
1698 gamemode = GAME_MODE_DEFAULT;
1700 menu.sound[gamemode] = sound;
1703 /* now set all '-1' values to levelset specific default values */
1704 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1705 if (menu.sound[i] == -1)
1706 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1709 static void set_sound_parameters(int sound, char **parameter_raw)
1711 int parameter[NUM_SND_ARGS];
1714 /* get integer values from string parameters */
1715 for (i = 0; i < NUM_SND_ARGS; i++)
1717 get_parameter_value(parameter_raw[i],
1718 sound_config_suffix[i].token,
1719 sound_config_suffix[i].type);
1721 /* explicit loop mode setting in configuration overrides default value */
1722 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1723 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1725 /* sound volume to change the original volume when loading the sound file */
1726 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1728 /* sound priority to give certain sounds a higher or lower priority */
1729 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1732 static void InitSoundInfo()
1734 int *sound_effect_properties;
1735 int num_sounds = getSoundListSize();
1738 checked_free(sound_info);
1740 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1741 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1743 /* initialize sound effect for all elements to "no sound" */
1744 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1745 for (j = 0; j < NUM_ACTIONS; j++)
1746 element_info[i].sound[j] = SND_UNDEFINED;
1748 for (i = 0; i < num_sounds; i++)
1750 struct FileInfo *sound = getSoundListEntry(i);
1751 int len_effect_text = strlen(sound->token);
1753 sound_effect_properties[i] = ACTION_OTHER;
1754 sound_info[i].loop = FALSE; /* default: play sound only once */
1756 /* determine all loop sounds and identify certain sound classes */
1758 for (j = 0; element_action_info[j].suffix; j++)
1760 int len_action_text = strlen(element_action_info[j].suffix);
1762 if (len_action_text < len_effect_text &&
1763 strEqual(&sound->token[len_effect_text - len_action_text],
1764 element_action_info[j].suffix))
1766 sound_effect_properties[i] = element_action_info[j].value;
1767 sound_info[i].loop = element_action_info[j].is_loop_sound;
1773 /* associate elements and some selected sound actions */
1775 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1777 if (element_info[j].class_name)
1779 int len_class_text = strlen(element_info[j].class_name);
1781 if (len_class_text + 1 < len_effect_text &&
1782 strncmp(sound->token,
1783 element_info[j].class_name, len_class_text) == 0 &&
1784 sound->token[len_class_text] == '.')
1786 int sound_action_value = sound_effect_properties[i];
1788 element_info[j].sound[sound_action_value] = i;
1793 set_sound_parameters(i, sound->parameter);
1796 free(sound_effect_properties);
1799 static void InitGameModeMusicInfo()
1801 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1802 int num_property_mappings = getMusicListPropertyMappingSize();
1803 int default_levelset_music = -1;
1806 /* set values to -1 to identify later as "uninitialized" values */
1807 for (i = 0; i < MAX_LEVELS; i++)
1808 levelset.music[i] = -1;
1809 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1812 /* initialize gamemode/music mapping from static configuration */
1813 for (i = 0; gamemode_to_music[i].music > -1; i++)
1815 int gamemode = gamemode_to_music[i].gamemode;
1816 int music = gamemode_to_music[i].music;
1819 gamemode = GAME_MODE_DEFAULT;
1821 menu.music[gamemode] = music;
1824 /* initialize gamemode/music mapping from dynamic configuration */
1825 for (i = 0; i < num_property_mappings; i++)
1827 int prefix = property_mapping[i].base_index;
1828 int gamemode = property_mapping[i].ext1_index;
1829 int level = property_mapping[i].ext2_index;
1830 int music = property_mapping[i].artwork_index;
1832 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1836 gamemode = GAME_MODE_DEFAULT;
1838 /* level specific music only allowed for in-game music */
1839 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1840 gamemode = GAME_MODE_PLAYING;
1845 default_levelset_music = music;
1848 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1849 levelset.music[level] = music;
1850 if (gamemode != GAME_MODE_PLAYING)
1851 menu.music[gamemode] = music;
1854 /* now set all '-1' values to menu specific default values */
1855 /* (undefined values of "levelset.music[]" might stay at "-1" to
1856 allow dynamic selection of music files from music directory!) */
1857 for (i = 0; i < MAX_LEVELS; i++)
1858 if (levelset.music[i] == -1)
1859 levelset.music[i] = default_levelset_music;
1860 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1861 if (menu.music[i] == -1)
1862 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1865 static void set_music_parameters(int music, char **parameter_raw)
1867 int parameter[NUM_MUS_ARGS];
1870 /* get integer values from string parameters */
1871 for (i = 0; i < NUM_MUS_ARGS; i++)
1873 get_parameter_value(parameter_raw[i],
1874 music_config_suffix[i].token,
1875 music_config_suffix[i].type);
1877 /* explicit loop mode setting in configuration overrides default value */
1878 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1879 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1882 static void InitMusicInfo()
1884 int num_music = getMusicListSize();
1887 checked_free(music_info);
1889 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1891 for (i = 0; i < num_music; i++)
1893 struct FileInfo *music = getMusicListEntry(i);
1894 int len_music_text = strlen(music->token);
1896 music_info[i].loop = TRUE; /* default: play music in loop mode */
1898 /* determine all loop music */
1900 for (j = 0; music_prefix_info[j].prefix; j++)
1902 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1904 if (len_prefix_text < len_music_text &&
1905 strncmp(music->token,
1906 music_prefix_info[j].prefix, len_prefix_text) == 0)
1908 music_info[i].loop = music_prefix_info[j].is_loop_music;
1914 set_music_parameters(i, music->parameter);
1918 static void ReinitializeGraphics()
1920 print_timestamp_init("ReinitializeGraphics");
1922 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
1924 InitGraphicInfo(); /* graphic properties mapping */
1925 print_timestamp_time("InitGraphicInfo");
1926 InitElementGraphicInfo(); /* element game graphic mapping */
1927 print_timestamp_time("InitElementGraphicInfo");
1928 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
1929 print_timestamp_time("InitElementSpecialGraphicInfo");
1931 InitElementSmallImages(); /* scale elements to all needed sizes */
1932 print_timestamp_time("InitElementSmallImages");
1933 InitScaledImages(); /* scale all other images, if needed */
1934 print_timestamp_time("InitScaledImages");
1935 InitBitmapPointers(); /* set standard size bitmap pointers */
1936 print_timestamp_time("InitBitmapPointers");
1937 InitFontGraphicInfo(); /* initialize text drawing functions */
1938 print_timestamp_time("InitFontGraphicInfo");
1940 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
1941 print_timestamp_time("InitGraphicInfo_EM");
1943 InitGraphicCompatibilityInfo();
1944 print_timestamp_time("InitGraphicCompatibilityInfo");
1946 SetMainBackgroundImage(IMG_BACKGROUND);
1947 print_timestamp_time("SetMainBackgroundImage");
1948 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1949 print_timestamp_time("SetDoorBackgroundImage");
1952 print_timestamp_time("InitGadgets");
1954 print_timestamp_time("InitToons");
1956 print_timestamp_time("InitDoors");
1958 print_timestamp_done("ReinitializeGraphics");
1961 static void ReinitializeSounds()
1963 InitSoundInfo(); /* sound properties mapping */
1964 InitElementSoundInfo(); /* element game sound mapping */
1965 InitGameModeSoundInfo(); /* game mode sound mapping */
1967 InitPlayLevelSound(); /* internal game sound settings */
1970 static void ReinitializeMusic()
1972 InitMusicInfo(); /* music properties mapping */
1973 InitGameModeMusicInfo(); /* game mode music mapping */
1976 static int get_special_property_bit(int element, int property_bit_nr)
1978 struct PropertyBitInfo
1984 static struct PropertyBitInfo pb_can_move_into_acid[] =
1986 /* the player may be able fall into acid when gravity is activated */
1991 { EL_SP_MURPHY, 0 },
1992 { EL_SOKOBAN_FIELD_PLAYER, 0 },
1994 /* all elements that can move may be able to also move into acid */
1997 { EL_BUG_RIGHT, 1 },
2000 { EL_SPACESHIP, 2 },
2001 { EL_SPACESHIP_LEFT, 2 },
2002 { EL_SPACESHIP_RIGHT, 2 },
2003 { EL_SPACESHIP_UP, 2 },
2004 { EL_SPACESHIP_DOWN, 2 },
2005 { EL_BD_BUTTERFLY, 3 },
2006 { EL_BD_BUTTERFLY_LEFT, 3 },
2007 { EL_BD_BUTTERFLY_RIGHT, 3 },
2008 { EL_BD_BUTTERFLY_UP, 3 },
2009 { EL_BD_BUTTERFLY_DOWN, 3 },
2010 { EL_BD_FIREFLY, 4 },
2011 { EL_BD_FIREFLY_LEFT, 4 },
2012 { EL_BD_FIREFLY_RIGHT, 4 },
2013 { EL_BD_FIREFLY_UP, 4 },
2014 { EL_BD_FIREFLY_DOWN, 4 },
2016 { EL_YAMYAM_LEFT, 5 },
2017 { EL_YAMYAM_RIGHT, 5 },
2018 { EL_YAMYAM_UP, 5 },
2019 { EL_YAMYAM_DOWN, 5 },
2020 { EL_DARK_YAMYAM, 6 },
2023 { EL_PACMAN_LEFT, 8 },
2024 { EL_PACMAN_RIGHT, 8 },
2025 { EL_PACMAN_UP, 8 },
2026 { EL_PACMAN_DOWN, 8 },
2028 { EL_MOLE_LEFT, 9 },
2029 { EL_MOLE_RIGHT, 9 },
2031 { EL_MOLE_DOWN, 9 },
2035 { EL_SATELLITE, 13 },
2036 { EL_SP_SNIKSNAK, 14 },
2037 { EL_SP_ELECTRON, 15 },
2040 { EL_EMC_ANDROID, 18 },
2045 static struct PropertyBitInfo pb_dont_collide_with[] =
2047 { EL_SP_SNIKSNAK, 0 },
2048 { EL_SP_ELECTRON, 1 },
2056 struct PropertyBitInfo *pb_info;
2059 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2060 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2065 struct PropertyBitInfo *pb_info = NULL;
2068 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2069 if (pb_definition[i].bit_nr == property_bit_nr)
2070 pb_info = pb_definition[i].pb_info;
2072 if (pb_info == NULL)
2075 for (i = 0; pb_info[i].element != -1; i++)
2076 if (pb_info[i].element == element)
2077 return pb_info[i].bit_nr;
2082 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2083 boolean property_value)
2085 int bit_nr = get_special_property_bit(element, property_bit_nr);
2090 *bitfield |= (1 << bit_nr);
2092 *bitfield &= ~(1 << bit_nr);
2096 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2098 int bit_nr = get_special_property_bit(element, property_bit_nr);
2101 return ((*bitfield & (1 << bit_nr)) != 0);
2106 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2108 static int group_nr;
2109 static struct ElementGroupInfo *group;
2110 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2113 if (actual_group == NULL) /* not yet initialized */
2116 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2118 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2119 group_element - EL_GROUP_START + 1);
2121 /* replace element which caused too deep recursion by question mark */
2122 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2127 if (recursion_depth == 0) /* initialization */
2129 group = actual_group;
2130 group_nr = GROUP_NR(group_element);
2132 group->num_elements_resolved = 0;
2133 group->choice_pos = 0;
2135 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2136 element_info[i].in_group[group_nr] = FALSE;
2139 for (i = 0; i < actual_group->num_elements; i++)
2141 int element = actual_group->element[i];
2143 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2146 if (IS_GROUP_ELEMENT(element))
2147 ResolveGroupElementExt(element, recursion_depth + 1);
2150 group->element_resolved[group->num_elements_resolved++] = element;
2151 element_info[element].in_group[group_nr] = TRUE;
2156 void ResolveGroupElement(int group_element)
2158 ResolveGroupElementExt(group_element, 0);
2161 void InitElementPropertiesStatic()
2163 static boolean clipboard_elements_initialized = FALSE;
2165 static int ep_diggable[] =
2170 EL_SP_BUGGY_BASE_ACTIVATING,
2173 EL_INVISIBLE_SAND_ACTIVE,
2176 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2177 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2182 EL_SP_BUGGY_BASE_ACTIVE,
2189 static int ep_collectible_only[] =
2211 EL_DYNABOMB_INCREASE_NUMBER,
2212 EL_DYNABOMB_INCREASE_SIZE,
2213 EL_DYNABOMB_INCREASE_POWER,
2231 /* !!! handle separately !!! */
2232 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2238 static int ep_dont_run_into[] =
2240 /* same elements as in 'ep_dont_touch' */
2246 /* same elements as in 'ep_dont_collide_with' */
2258 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2263 EL_SP_BUGGY_BASE_ACTIVE,
2270 static int ep_dont_collide_with[] =
2272 /* same elements as in 'ep_dont_touch' */
2289 static int ep_dont_touch[] =
2299 static int ep_indestructible[] =
2303 EL_ACID_POOL_TOPLEFT,
2304 EL_ACID_POOL_TOPRIGHT,
2305 EL_ACID_POOL_BOTTOMLEFT,
2306 EL_ACID_POOL_BOTTOM,
2307 EL_ACID_POOL_BOTTOMRIGHT,
2308 EL_SP_HARDWARE_GRAY,
2309 EL_SP_HARDWARE_GREEN,
2310 EL_SP_HARDWARE_BLUE,
2312 EL_SP_HARDWARE_YELLOW,
2313 EL_SP_HARDWARE_BASE_1,
2314 EL_SP_HARDWARE_BASE_2,
2315 EL_SP_HARDWARE_BASE_3,
2316 EL_SP_HARDWARE_BASE_4,
2317 EL_SP_HARDWARE_BASE_5,
2318 EL_SP_HARDWARE_BASE_6,
2319 EL_INVISIBLE_STEELWALL,
2320 EL_INVISIBLE_STEELWALL_ACTIVE,
2321 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2322 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2323 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2324 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2325 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2326 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2327 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2328 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2329 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2330 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2331 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2332 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2334 EL_LIGHT_SWITCH_ACTIVE,
2335 EL_SIGN_EXCLAMATION,
2336 EL_SIGN_RADIOACTIVITY,
2343 EL_SIGN_ENTRY_FORBIDDEN,
2344 EL_SIGN_EMERGENCY_EXIT,
2352 EL_STEEL_EXIT_CLOSED,
2354 EL_STEEL_EXIT_OPENING,
2355 EL_STEEL_EXIT_CLOSING,
2356 EL_EM_STEEL_EXIT_CLOSED,
2357 EL_EM_STEEL_EXIT_OPEN,
2358 EL_EM_STEEL_EXIT_OPENING,
2359 EL_EM_STEEL_EXIT_CLOSING,
2360 EL_DC_STEELWALL_1_LEFT,
2361 EL_DC_STEELWALL_1_RIGHT,
2362 EL_DC_STEELWALL_1_TOP,
2363 EL_DC_STEELWALL_1_BOTTOM,
2364 EL_DC_STEELWALL_1_HORIZONTAL,
2365 EL_DC_STEELWALL_1_VERTICAL,
2366 EL_DC_STEELWALL_1_TOPLEFT,
2367 EL_DC_STEELWALL_1_TOPRIGHT,
2368 EL_DC_STEELWALL_1_BOTTOMLEFT,
2369 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2370 EL_DC_STEELWALL_1_TOPLEFT_2,
2371 EL_DC_STEELWALL_1_TOPRIGHT_2,
2372 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2373 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2374 EL_DC_STEELWALL_2_LEFT,
2375 EL_DC_STEELWALL_2_RIGHT,
2376 EL_DC_STEELWALL_2_TOP,
2377 EL_DC_STEELWALL_2_BOTTOM,
2378 EL_DC_STEELWALL_2_HORIZONTAL,
2379 EL_DC_STEELWALL_2_VERTICAL,
2380 EL_DC_STEELWALL_2_MIDDLE,
2381 EL_DC_STEELWALL_2_SINGLE,
2382 EL_STEELWALL_SLIPPERY,
2396 EL_GATE_1_GRAY_ACTIVE,
2397 EL_GATE_2_GRAY_ACTIVE,
2398 EL_GATE_3_GRAY_ACTIVE,
2399 EL_GATE_4_GRAY_ACTIVE,
2408 EL_EM_GATE_1_GRAY_ACTIVE,
2409 EL_EM_GATE_2_GRAY_ACTIVE,
2410 EL_EM_GATE_3_GRAY_ACTIVE,
2411 EL_EM_GATE_4_GRAY_ACTIVE,
2420 EL_EMC_GATE_5_GRAY_ACTIVE,
2421 EL_EMC_GATE_6_GRAY_ACTIVE,
2422 EL_EMC_GATE_7_GRAY_ACTIVE,
2423 EL_EMC_GATE_8_GRAY_ACTIVE,
2425 EL_DC_GATE_WHITE_GRAY,
2426 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2427 EL_DC_GATE_FAKE_GRAY,
2429 EL_SWITCHGATE_OPENING,
2430 EL_SWITCHGATE_CLOSED,
2431 EL_SWITCHGATE_CLOSING,
2432 EL_DC_SWITCHGATE_SWITCH_UP,
2433 EL_DC_SWITCHGATE_SWITCH_DOWN,
2435 EL_TIMEGATE_OPENING,
2437 EL_TIMEGATE_CLOSING,
2438 EL_DC_TIMEGATE_SWITCH,
2439 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2443 EL_TUBE_VERTICAL_LEFT,
2444 EL_TUBE_VERTICAL_RIGHT,
2445 EL_TUBE_HORIZONTAL_UP,
2446 EL_TUBE_HORIZONTAL_DOWN,
2451 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2452 EL_EXPANDABLE_STEELWALL_VERTICAL,
2453 EL_EXPANDABLE_STEELWALL_ANY,
2458 static int ep_slippery[] =
2472 EL_ROBOT_WHEEL_ACTIVE,
2478 EL_ACID_POOL_TOPLEFT,
2479 EL_ACID_POOL_TOPRIGHT,
2489 EL_STEELWALL_SLIPPERY,
2492 EL_EMC_WALL_SLIPPERY_1,
2493 EL_EMC_WALL_SLIPPERY_2,
2494 EL_EMC_WALL_SLIPPERY_3,
2495 EL_EMC_WALL_SLIPPERY_4,
2497 EL_EMC_MAGIC_BALL_ACTIVE,
2502 static int ep_can_change[] =
2507 static int ep_can_move[] =
2509 /* same elements as in 'pb_can_move_into_acid' */
2532 static int ep_can_fall[] =
2546 EL_QUICKSAND_FAST_FULL,
2548 EL_BD_MAGIC_WALL_FULL,
2549 EL_DC_MAGIC_WALL_FULL,
2563 static int ep_can_smash_player[] =
2589 static int ep_can_smash_enemies[] =
2598 static int ep_can_smash_everything[] =
2607 static int ep_explodes_by_fire[] =
2609 /* same elements as in 'ep_explodes_impact' */
2614 /* same elements as in 'ep_explodes_smashed' */
2624 EL_EM_DYNAMITE_ACTIVE,
2625 EL_DYNABOMB_PLAYER_1_ACTIVE,
2626 EL_DYNABOMB_PLAYER_2_ACTIVE,
2627 EL_DYNABOMB_PLAYER_3_ACTIVE,
2628 EL_DYNABOMB_PLAYER_4_ACTIVE,
2629 EL_DYNABOMB_INCREASE_NUMBER,
2630 EL_DYNABOMB_INCREASE_SIZE,
2631 EL_DYNABOMB_INCREASE_POWER,
2632 EL_SP_DISK_RED_ACTIVE,
2646 static int ep_explodes_smashed[] =
2648 /* same elements as in 'ep_explodes_impact' */
2662 static int ep_explodes_impact[] =
2671 static int ep_walkable_over[] =
2675 EL_SOKOBAN_FIELD_EMPTY,
2682 EL_EM_STEEL_EXIT_OPEN,
2683 EL_EM_STEEL_EXIT_OPENING,
2692 EL_GATE_1_GRAY_ACTIVE,
2693 EL_GATE_2_GRAY_ACTIVE,
2694 EL_GATE_3_GRAY_ACTIVE,
2695 EL_GATE_4_GRAY_ACTIVE,
2703 static int ep_walkable_inside[] =
2708 EL_TUBE_VERTICAL_LEFT,
2709 EL_TUBE_VERTICAL_RIGHT,
2710 EL_TUBE_HORIZONTAL_UP,
2711 EL_TUBE_HORIZONTAL_DOWN,
2720 static int ep_walkable_under[] =
2725 static int ep_passable_over[] =
2735 EL_EM_GATE_1_GRAY_ACTIVE,
2736 EL_EM_GATE_2_GRAY_ACTIVE,
2737 EL_EM_GATE_3_GRAY_ACTIVE,
2738 EL_EM_GATE_4_GRAY_ACTIVE,
2747 EL_EMC_GATE_5_GRAY_ACTIVE,
2748 EL_EMC_GATE_6_GRAY_ACTIVE,
2749 EL_EMC_GATE_7_GRAY_ACTIVE,
2750 EL_EMC_GATE_8_GRAY_ACTIVE,
2752 EL_DC_GATE_WHITE_GRAY,
2753 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2760 static int ep_passable_inside[] =
2766 EL_SP_PORT_HORIZONTAL,
2767 EL_SP_PORT_VERTICAL,
2769 EL_SP_GRAVITY_PORT_LEFT,
2770 EL_SP_GRAVITY_PORT_RIGHT,
2771 EL_SP_GRAVITY_PORT_UP,
2772 EL_SP_GRAVITY_PORT_DOWN,
2773 EL_SP_GRAVITY_ON_PORT_LEFT,
2774 EL_SP_GRAVITY_ON_PORT_RIGHT,
2775 EL_SP_GRAVITY_ON_PORT_UP,
2776 EL_SP_GRAVITY_ON_PORT_DOWN,
2777 EL_SP_GRAVITY_OFF_PORT_LEFT,
2778 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2779 EL_SP_GRAVITY_OFF_PORT_UP,
2780 EL_SP_GRAVITY_OFF_PORT_DOWN,
2785 static int ep_passable_under[] =
2790 static int ep_droppable[] =
2795 static int ep_explodes_1x1_old[] =
2800 static int ep_pushable[] =
2812 EL_SOKOBAN_FIELD_FULL,
2821 static int ep_explodes_cross_old[] =
2826 static int ep_protected[] =
2828 /* same elements as in 'ep_walkable_inside' */
2832 EL_TUBE_VERTICAL_LEFT,
2833 EL_TUBE_VERTICAL_RIGHT,
2834 EL_TUBE_HORIZONTAL_UP,
2835 EL_TUBE_HORIZONTAL_DOWN,
2841 /* same elements as in 'ep_passable_over' */
2850 EL_EM_GATE_1_GRAY_ACTIVE,
2851 EL_EM_GATE_2_GRAY_ACTIVE,
2852 EL_EM_GATE_3_GRAY_ACTIVE,
2853 EL_EM_GATE_4_GRAY_ACTIVE,
2862 EL_EMC_GATE_5_GRAY_ACTIVE,
2863 EL_EMC_GATE_6_GRAY_ACTIVE,
2864 EL_EMC_GATE_7_GRAY_ACTIVE,
2865 EL_EMC_GATE_8_GRAY_ACTIVE,
2867 EL_DC_GATE_WHITE_GRAY,
2868 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2872 /* same elements as in 'ep_passable_inside' */
2877 EL_SP_PORT_HORIZONTAL,
2878 EL_SP_PORT_VERTICAL,
2880 EL_SP_GRAVITY_PORT_LEFT,
2881 EL_SP_GRAVITY_PORT_RIGHT,
2882 EL_SP_GRAVITY_PORT_UP,
2883 EL_SP_GRAVITY_PORT_DOWN,
2884 EL_SP_GRAVITY_ON_PORT_LEFT,
2885 EL_SP_GRAVITY_ON_PORT_RIGHT,
2886 EL_SP_GRAVITY_ON_PORT_UP,
2887 EL_SP_GRAVITY_ON_PORT_DOWN,
2888 EL_SP_GRAVITY_OFF_PORT_LEFT,
2889 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2890 EL_SP_GRAVITY_OFF_PORT_UP,
2891 EL_SP_GRAVITY_OFF_PORT_DOWN,
2896 static int ep_throwable[] =
2901 static int ep_can_explode[] =
2903 /* same elements as in 'ep_explodes_impact' */
2908 /* same elements as in 'ep_explodes_smashed' */
2914 /* elements that can explode by explosion or by dragonfire */
2918 EL_EM_DYNAMITE_ACTIVE,
2919 EL_DYNABOMB_PLAYER_1_ACTIVE,
2920 EL_DYNABOMB_PLAYER_2_ACTIVE,
2921 EL_DYNABOMB_PLAYER_3_ACTIVE,
2922 EL_DYNABOMB_PLAYER_4_ACTIVE,
2923 EL_DYNABOMB_INCREASE_NUMBER,
2924 EL_DYNABOMB_INCREASE_SIZE,
2925 EL_DYNABOMB_INCREASE_POWER,
2926 EL_SP_DISK_RED_ACTIVE,
2934 /* elements that can explode only by explosion */
2940 static int ep_gravity_reachable[] =
2946 EL_INVISIBLE_SAND_ACTIVE,
2951 EL_SP_PORT_HORIZONTAL,
2952 EL_SP_PORT_VERTICAL,
2954 EL_SP_GRAVITY_PORT_LEFT,
2955 EL_SP_GRAVITY_PORT_RIGHT,
2956 EL_SP_GRAVITY_PORT_UP,
2957 EL_SP_GRAVITY_PORT_DOWN,
2958 EL_SP_GRAVITY_ON_PORT_LEFT,
2959 EL_SP_GRAVITY_ON_PORT_RIGHT,
2960 EL_SP_GRAVITY_ON_PORT_UP,
2961 EL_SP_GRAVITY_ON_PORT_DOWN,
2962 EL_SP_GRAVITY_OFF_PORT_LEFT,
2963 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2964 EL_SP_GRAVITY_OFF_PORT_UP,
2965 EL_SP_GRAVITY_OFF_PORT_DOWN,
2971 static int ep_player[] =
2978 EL_SOKOBAN_FIELD_PLAYER,
2984 static int ep_can_pass_magic_wall[] =
2998 static int ep_can_pass_dc_magic_wall[] =
3014 static int ep_switchable[] =
3018 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3019 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3020 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3021 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3022 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3023 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3024 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3025 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3026 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3027 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3028 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3029 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3030 EL_SWITCHGATE_SWITCH_UP,
3031 EL_SWITCHGATE_SWITCH_DOWN,
3032 EL_DC_SWITCHGATE_SWITCH_UP,
3033 EL_DC_SWITCHGATE_SWITCH_DOWN,
3035 EL_LIGHT_SWITCH_ACTIVE,
3037 EL_DC_TIMEGATE_SWITCH,
3038 EL_BALLOON_SWITCH_LEFT,
3039 EL_BALLOON_SWITCH_RIGHT,
3040 EL_BALLOON_SWITCH_UP,
3041 EL_BALLOON_SWITCH_DOWN,
3042 EL_BALLOON_SWITCH_ANY,
3043 EL_BALLOON_SWITCH_NONE,
3046 EL_EMC_MAGIC_BALL_SWITCH,
3047 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3052 static int ep_bd_element[] =
3086 static int ep_sp_element[] =
3088 /* should always be valid */
3091 /* standard classic Supaplex elements */
3098 EL_SP_HARDWARE_GRAY,
3106 EL_SP_GRAVITY_PORT_RIGHT,
3107 EL_SP_GRAVITY_PORT_DOWN,
3108 EL_SP_GRAVITY_PORT_LEFT,
3109 EL_SP_GRAVITY_PORT_UP,
3114 EL_SP_PORT_VERTICAL,
3115 EL_SP_PORT_HORIZONTAL,
3121 EL_SP_HARDWARE_BASE_1,
3122 EL_SP_HARDWARE_GREEN,
3123 EL_SP_HARDWARE_BLUE,
3125 EL_SP_HARDWARE_YELLOW,
3126 EL_SP_HARDWARE_BASE_2,
3127 EL_SP_HARDWARE_BASE_3,
3128 EL_SP_HARDWARE_BASE_4,
3129 EL_SP_HARDWARE_BASE_5,
3130 EL_SP_HARDWARE_BASE_6,
3134 /* additional elements that appeared in newer Supaplex levels */
3137 /* additional gravity port elements (not switching, but setting gravity) */
3138 EL_SP_GRAVITY_ON_PORT_LEFT,
3139 EL_SP_GRAVITY_ON_PORT_RIGHT,
3140 EL_SP_GRAVITY_ON_PORT_UP,
3141 EL_SP_GRAVITY_ON_PORT_DOWN,
3142 EL_SP_GRAVITY_OFF_PORT_LEFT,
3143 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3144 EL_SP_GRAVITY_OFF_PORT_UP,
3145 EL_SP_GRAVITY_OFF_PORT_DOWN,
3147 /* more than one Murphy in a level results in an inactive clone */
3150 /* runtime Supaplex elements */
3151 EL_SP_DISK_RED_ACTIVE,
3152 EL_SP_TERMINAL_ACTIVE,
3153 EL_SP_BUGGY_BASE_ACTIVATING,
3154 EL_SP_BUGGY_BASE_ACTIVE,
3161 static int ep_sb_element[] =
3166 EL_SOKOBAN_FIELD_EMPTY,
3167 EL_SOKOBAN_FIELD_FULL,
3168 EL_SOKOBAN_FIELD_PLAYER,
3173 EL_INVISIBLE_STEELWALL,
3178 static int ep_gem[] =
3190 static int ep_food_dark_yamyam[] =
3218 static int ep_food_penguin[] =
3232 static int ep_food_pig[] =
3244 static int ep_historic_wall[] =
3255 EL_GATE_1_GRAY_ACTIVE,
3256 EL_GATE_2_GRAY_ACTIVE,
3257 EL_GATE_3_GRAY_ACTIVE,
3258 EL_GATE_4_GRAY_ACTIVE,
3267 EL_EM_GATE_1_GRAY_ACTIVE,
3268 EL_EM_GATE_2_GRAY_ACTIVE,
3269 EL_EM_GATE_3_GRAY_ACTIVE,
3270 EL_EM_GATE_4_GRAY_ACTIVE,
3277 EL_EXPANDABLE_WALL_HORIZONTAL,
3278 EL_EXPANDABLE_WALL_VERTICAL,
3279 EL_EXPANDABLE_WALL_ANY,
3280 EL_EXPANDABLE_WALL_GROWING,
3281 EL_BD_EXPANDABLE_WALL,
3288 EL_SP_HARDWARE_GRAY,
3289 EL_SP_HARDWARE_GREEN,
3290 EL_SP_HARDWARE_BLUE,
3292 EL_SP_HARDWARE_YELLOW,
3293 EL_SP_HARDWARE_BASE_1,
3294 EL_SP_HARDWARE_BASE_2,
3295 EL_SP_HARDWARE_BASE_3,
3296 EL_SP_HARDWARE_BASE_4,
3297 EL_SP_HARDWARE_BASE_5,
3298 EL_SP_HARDWARE_BASE_6,
3300 EL_SP_TERMINAL_ACTIVE,
3303 EL_INVISIBLE_STEELWALL,
3304 EL_INVISIBLE_STEELWALL_ACTIVE,
3306 EL_INVISIBLE_WALL_ACTIVE,
3307 EL_STEELWALL_SLIPPERY,
3324 static int ep_historic_solid[] =
3328 EL_EXPANDABLE_WALL_HORIZONTAL,
3329 EL_EXPANDABLE_WALL_VERTICAL,
3330 EL_EXPANDABLE_WALL_ANY,
3331 EL_BD_EXPANDABLE_WALL,
3344 EL_QUICKSAND_FILLING,
3345 EL_QUICKSAND_EMPTYING,
3347 EL_MAGIC_WALL_ACTIVE,
3348 EL_MAGIC_WALL_EMPTYING,
3349 EL_MAGIC_WALL_FILLING,
3353 EL_BD_MAGIC_WALL_ACTIVE,
3354 EL_BD_MAGIC_WALL_EMPTYING,
3355 EL_BD_MAGIC_WALL_FULL,
3356 EL_BD_MAGIC_WALL_FILLING,
3357 EL_BD_MAGIC_WALL_DEAD,
3366 EL_SP_TERMINAL_ACTIVE,
3370 EL_INVISIBLE_WALL_ACTIVE,
3371 EL_SWITCHGATE_SWITCH_UP,
3372 EL_SWITCHGATE_SWITCH_DOWN,
3373 EL_DC_SWITCHGATE_SWITCH_UP,
3374 EL_DC_SWITCHGATE_SWITCH_DOWN,
3376 EL_TIMEGATE_SWITCH_ACTIVE,
3377 EL_DC_TIMEGATE_SWITCH,
3378 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3390 /* the following elements are a direct copy of "indestructible" elements,
3391 except "EL_ACID", which is "indestructible", but not "solid"! */
3396 EL_ACID_POOL_TOPLEFT,
3397 EL_ACID_POOL_TOPRIGHT,
3398 EL_ACID_POOL_BOTTOMLEFT,
3399 EL_ACID_POOL_BOTTOM,
3400 EL_ACID_POOL_BOTTOMRIGHT,
3401 EL_SP_HARDWARE_GRAY,
3402 EL_SP_HARDWARE_GREEN,
3403 EL_SP_HARDWARE_BLUE,
3405 EL_SP_HARDWARE_YELLOW,
3406 EL_SP_HARDWARE_BASE_1,
3407 EL_SP_HARDWARE_BASE_2,
3408 EL_SP_HARDWARE_BASE_3,
3409 EL_SP_HARDWARE_BASE_4,
3410 EL_SP_HARDWARE_BASE_5,
3411 EL_SP_HARDWARE_BASE_6,
3412 EL_INVISIBLE_STEELWALL,
3413 EL_INVISIBLE_STEELWALL_ACTIVE,
3414 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3415 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3416 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3417 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3418 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3419 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3420 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3421 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3422 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3423 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3424 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3425 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3427 EL_LIGHT_SWITCH_ACTIVE,
3428 EL_SIGN_EXCLAMATION,
3429 EL_SIGN_RADIOACTIVITY,
3436 EL_SIGN_ENTRY_FORBIDDEN,
3437 EL_SIGN_EMERGENCY_EXIT,
3445 EL_STEEL_EXIT_CLOSED,
3447 EL_DC_STEELWALL_1_LEFT,
3448 EL_DC_STEELWALL_1_RIGHT,
3449 EL_DC_STEELWALL_1_TOP,
3450 EL_DC_STEELWALL_1_BOTTOM,
3451 EL_DC_STEELWALL_1_HORIZONTAL,
3452 EL_DC_STEELWALL_1_VERTICAL,
3453 EL_DC_STEELWALL_1_TOPLEFT,
3454 EL_DC_STEELWALL_1_TOPRIGHT,
3455 EL_DC_STEELWALL_1_BOTTOMLEFT,
3456 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3457 EL_DC_STEELWALL_1_TOPLEFT_2,
3458 EL_DC_STEELWALL_1_TOPRIGHT_2,
3459 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3460 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3461 EL_DC_STEELWALL_2_LEFT,
3462 EL_DC_STEELWALL_2_RIGHT,
3463 EL_DC_STEELWALL_2_TOP,
3464 EL_DC_STEELWALL_2_BOTTOM,
3465 EL_DC_STEELWALL_2_HORIZONTAL,
3466 EL_DC_STEELWALL_2_VERTICAL,
3467 EL_DC_STEELWALL_2_MIDDLE,
3468 EL_DC_STEELWALL_2_SINGLE,
3469 EL_STEELWALL_SLIPPERY,
3483 EL_GATE_1_GRAY_ACTIVE,
3484 EL_GATE_2_GRAY_ACTIVE,
3485 EL_GATE_3_GRAY_ACTIVE,
3486 EL_GATE_4_GRAY_ACTIVE,
3495 EL_EM_GATE_1_GRAY_ACTIVE,
3496 EL_EM_GATE_2_GRAY_ACTIVE,
3497 EL_EM_GATE_3_GRAY_ACTIVE,
3498 EL_EM_GATE_4_GRAY_ACTIVE,
3500 EL_SWITCHGATE_OPENING,
3501 EL_SWITCHGATE_CLOSED,
3502 EL_SWITCHGATE_CLOSING,
3504 EL_TIMEGATE_OPENING,
3506 EL_TIMEGATE_CLOSING,
3510 EL_TUBE_VERTICAL_LEFT,
3511 EL_TUBE_VERTICAL_RIGHT,
3512 EL_TUBE_HORIZONTAL_UP,
3513 EL_TUBE_HORIZONTAL_DOWN,
3522 static int ep_classic_enemy[] =
3539 static int ep_belt[] =
3541 EL_CONVEYOR_BELT_1_LEFT,
3542 EL_CONVEYOR_BELT_1_MIDDLE,
3543 EL_CONVEYOR_BELT_1_RIGHT,
3544 EL_CONVEYOR_BELT_2_LEFT,
3545 EL_CONVEYOR_BELT_2_MIDDLE,
3546 EL_CONVEYOR_BELT_2_RIGHT,
3547 EL_CONVEYOR_BELT_3_LEFT,
3548 EL_CONVEYOR_BELT_3_MIDDLE,
3549 EL_CONVEYOR_BELT_3_RIGHT,
3550 EL_CONVEYOR_BELT_4_LEFT,
3551 EL_CONVEYOR_BELT_4_MIDDLE,
3552 EL_CONVEYOR_BELT_4_RIGHT,
3557 static int ep_belt_active[] =
3559 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3560 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3561 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3562 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3563 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3564 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3565 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3566 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3567 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3568 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3569 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3570 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3575 static int ep_belt_switch[] =
3577 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3578 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3579 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3580 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3581 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3582 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3583 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3584 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3585 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3586 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3587 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3588 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3593 static int ep_tube[] =
3600 EL_TUBE_HORIZONTAL_UP,
3601 EL_TUBE_HORIZONTAL_DOWN,
3603 EL_TUBE_VERTICAL_LEFT,
3604 EL_TUBE_VERTICAL_RIGHT,
3610 static int ep_acid_pool[] =
3612 EL_ACID_POOL_TOPLEFT,
3613 EL_ACID_POOL_TOPRIGHT,
3614 EL_ACID_POOL_BOTTOMLEFT,
3615 EL_ACID_POOL_BOTTOM,
3616 EL_ACID_POOL_BOTTOMRIGHT,
3621 static int ep_keygate[] =
3631 EL_GATE_1_GRAY_ACTIVE,
3632 EL_GATE_2_GRAY_ACTIVE,
3633 EL_GATE_3_GRAY_ACTIVE,
3634 EL_GATE_4_GRAY_ACTIVE,
3643 EL_EM_GATE_1_GRAY_ACTIVE,
3644 EL_EM_GATE_2_GRAY_ACTIVE,
3645 EL_EM_GATE_3_GRAY_ACTIVE,
3646 EL_EM_GATE_4_GRAY_ACTIVE,
3655 EL_EMC_GATE_5_GRAY_ACTIVE,
3656 EL_EMC_GATE_6_GRAY_ACTIVE,
3657 EL_EMC_GATE_7_GRAY_ACTIVE,
3658 EL_EMC_GATE_8_GRAY_ACTIVE,
3660 EL_DC_GATE_WHITE_GRAY,
3661 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3666 static int ep_amoeboid[] =
3678 static int ep_amoebalive[] =
3689 static int ep_has_editor_content[] =
3695 EL_SOKOBAN_FIELD_PLAYER,
3712 static int ep_can_turn_each_move[] =
3714 /* !!! do something with this one !!! */
3718 static int ep_can_grow[] =
3732 static int ep_active_bomb[] =
3735 EL_EM_DYNAMITE_ACTIVE,
3736 EL_DYNABOMB_PLAYER_1_ACTIVE,
3737 EL_DYNABOMB_PLAYER_2_ACTIVE,
3738 EL_DYNABOMB_PLAYER_3_ACTIVE,
3739 EL_DYNABOMB_PLAYER_4_ACTIVE,
3740 EL_SP_DISK_RED_ACTIVE,
3745 static int ep_inactive[] =
3755 EL_QUICKSAND_FAST_EMPTY,
3778 EL_GATE_1_GRAY_ACTIVE,
3779 EL_GATE_2_GRAY_ACTIVE,
3780 EL_GATE_3_GRAY_ACTIVE,
3781 EL_GATE_4_GRAY_ACTIVE,
3790 EL_EM_GATE_1_GRAY_ACTIVE,
3791 EL_EM_GATE_2_GRAY_ACTIVE,
3792 EL_EM_GATE_3_GRAY_ACTIVE,
3793 EL_EM_GATE_4_GRAY_ACTIVE,
3802 EL_EMC_GATE_5_GRAY_ACTIVE,
3803 EL_EMC_GATE_6_GRAY_ACTIVE,
3804 EL_EMC_GATE_7_GRAY_ACTIVE,
3805 EL_EMC_GATE_8_GRAY_ACTIVE,
3807 EL_DC_GATE_WHITE_GRAY,
3808 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3809 EL_DC_GATE_FAKE_GRAY,
3812 EL_INVISIBLE_STEELWALL,
3820 EL_WALL_EMERALD_YELLOW,
3821 EL_DYNABOMB_INCREASE_NUMBER,
3822 EL_DYNABOMB_INCREASE_SIZE,
3823 EL_DYNABOMB_INCREASE_POWER,
3827 EL_SOKOBAN_FIELD_EMPTY,
3828 EL_SOKOBAN_FIELD_FULL,
3829 EL_WALL_EMERALD_RED,
3830 EL_WALL_EMERALD_PURPLE,
3831 EL_ACID_POOL_TOPLEFT,
3832 EL_ACID_POOL_TOPRIGHT,
3833 EL_ACID_POOL_BOTTOMLEFT,
3834 EL_ACID_POOL_BOTTOM,
3835 EL_ACID_POOL_BOTTOMRIGHT,
3839 EL_BD_MAGIC_WALL_DEAD,
3841 EL_DC_MAGIC_WALL_DEAD,
3842 EL_AMOEBA_TO_DIAMOND,
3850 EL_SP_GRAVITY_PORT_RIGHT,
3851 EL_SP_GRAVITY_PORT_DOWN,
3852 EL_SP_GRAVITY_PORT_LEFT,
3853 EL_SP_GRAVITY_PORT_UP,
3854 EL_SP_PORT_HORIZONTAL,
3855 EL_SP_PORT_VERTICAL,
3866 EL_SP_HARDWARE_GRAY,
3867 EL_SP_HARDWARE_GREEN,
3868 EL_SP_HARDWARE_BLUE,
3870 EL_SP_HARDWARE_YELLOW,
3871 EL_SP_HARDWARE_BASE_1,
3872 EL_SP_HARDWARE_BASE_2,
3873 EL_SP_HARDWARE_BASE_3,
3874 EL_SP_HARDWARE_BASE_4,
3875 EL_SP_HARDWARE_BASE_5,
3876 EL_SP_HARDWARE_BASE_6,
3877 EL_SP_GRAVITY_ON_PORT_LEFT,
3878 EL_SP_GRAVITY_ON_PORT_RIGHT,
3879 EL_SP_GRAVITY_ON_PORT_UP,
3880 EL_SP_GRAVITY_ON_PORT_DOWN,
3881 EL_SP_GRAVITY_OFF_PORT_LEFT,
3882 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3883 EL_SP_GRAVITY_OFF_PORT_UP,
3884 EL_SP_GRAVITY_OFF_PORT_DOWN,
3885 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3886 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3887 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3888 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3889 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3890 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3891 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3892 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3893 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3894 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3895 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3896 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3897 EL_SIGN_EXCLAMATION,
3898 EL_SIGN_RADIOACTIVITY,
3905 EL_SIGN_ENTRY_FORBIDDEN,
3906 EL_SIGN_EMERGENCY_EXIT,
3914 EL_DC_STEELWALL_1_LEFT,
3915 EL_DC_STEELWALL_1_RIGHT,
3916 EL_DC_STEELWALL_1_TOP,
3917 EL_DC_STEELWALL_1_BOTTOM,
3918 EL_DC_STEELWALL_1_HORIZONTAL,
3919 EL_DC_STEELWALL_1_VERTICAL,
3920 EL_DC_STEELWALL_1_TOPLEFT,
3921 EL_DC_STEELWALL_1_TOPRIGHT,
3922 EL_DC_STEELWALL_1_BOTTOMLEFT,
3923 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3924 EL_DC_STEELWALL_1_TOPLEFT_2,
3925 EL_DC_STEELWALL_1_TOPRIGHT_2,
3926 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3927 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3928 EL_DC_STEELWALL_2_LEFT,
3929 EL_DC_STEELWALL_2_RIGHT,
3930 EL_DC_STEELWALL_2_TOP,
3931 EL_DC_STEELWALL_2_BOTTOM,
3932 EL_DC_STEELWALL_2_HORIZONTAL,
3933 EL_DC_STEELWALL_2_VERTICAL,
3934 EL_DC_STEELWALL_2_MIDDLE,
3935 EL_DC_STEELWALL_2_SINGLE,
3936 EL_STEELWALL_SLIPPERY,
3941 EL_EMC_WALL_SLIPPERY_1,
3942 EL_EMC_WALL_SLIPPERY_2,
3943 EL_EMC_WALL_SLIPPERY_3,
3944 EL_EMC_WALL_SLIPPERY_4,
3965 static int ep_em_slippery_wall[] =
3970 static int ep_gfx_crumbled[] =
3981 static int ep_editor_cascade_active[] =
3983 EL_INTERNAL_CASCADE_BD_ACTIVE,
3984 EL_INTERNAL_CASCADE_EM_ACTIVE,
3985 EL_INTERNAL_CASCADE_EMC_ACTIVE,
3986 EL_INTERNAL_CASCADE_RND_ACTIVE,
3987 EL_INTERNAL_CASCADE_SB_ACTIVE,
3988 EL_INTERNAL_CASCADE_SP_ACTIVE,
3989 EL_INTERNAL_CASCADE_DC_ACTIVE,
3990 EL_INTERNAL_CASCADE_DX_ACTIVE,
3991 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3992 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
3993 EL_INTERNAL_CASCADE_CE_ACTIVE,
3994 EL_INTERNAL_CASCADE_GE_ACTIVE,
3995 EL_INTERNAL_CASCADE_REF_ACTIVE,
3996 EL_INTERNAL_CASCADE_USER_ACTIVE,
3997 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4002 static int ep_editor_cascade_inactive[] =
4004 EL_INTERNAL_CASCADE_BD,
4005 EL_INTERNAL_CASCADE_EM,
4006 EL_INTERNAL_CASCADE_EMC,
4007 EL_INTERNAL_CASCADE_RND,
4008 EL_INTERNAL_CASCADE_SB,
4009 EL_INTERNAL_CASCADE_SP,
4010 EL_INTERNAL_CASCADE_DC,
4011 EL_INTERNAL_CASCADE_DX,
4012 EL_INTERNAL_CASCADE_CHARS,
4013 EL_INTERNAL_CASCADE_STEEL_CHARS,
4014 EL_INTERNAL_CASCADE_CE,
4015 EL_INTERNAL_CASCADE_GE,
4016 EL_INTERNAL_CASCADE_REF,
4017 EL_INTERNAL_CASCADE_USER,
4018 EL_INTERNAL_CASCADE_DYNAMIC,
4023 static int ep_obsolete[] =
4027 EL_EM_KEY_1_FILE_OBSOLETE,
4028 EL_EM_KEY_2_FILE_OBSOLETE,
4029 EL_EM_KEY_3_FILE_OBSOLETE,
4030 EL_EM_KEY_4_FILE_OBSOLETE,
4031 EL_ENVELOPE_OBSOLETE,
4040 } element_properties[] =
4042 { ep_diggable, EP_DIGGABLE },
4043 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4044 { ep_dont_run_into, EP_DONT_RUN_INTO },
4045 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4046 { ep_dont_touch, EP_DONT_TOUCH },
4047 { ep_indestructible, EP_INDESTRUCTIBLE },
4048 { ep_slippery, EP_SLIPPERY },
4049 { ep_can_change, EP_CAN_CHANGE },
4050 { ep_can_move, EP_CAN_MOVE },
4051 { ep_can_fall, EP_CAN_FALL },
4052 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4053 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4054 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4055 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4056 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4057 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4058 { ep_walkable_over, EP_WALKABLE_OVER },
4059 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4060 { ep_walkable_under, EP_WALKABLE_UNDER },
4061 { ep_passable_over, EP_PASSABLE_OVER },
4062 { ep_passable_inside, EP_PASSABLE_INSIDE },
4063 { ep_passable_under, EP_PASSABLE_UNDER },
4064 { ep_droppable, EP_DROPPABLE },
4065 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4066 { ep_pushable, EP_PUSHABLE },
4067 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4068 { ep_protected, EP_PROTECTED },
4069 { ep_throwable, EP_THROWABLE },
4070 { ep_can_explode, EP_CAN_EXPLODE },
4071 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4073 { ep_player, EP_PLAYER },
4074 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4075 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4076 { ep_switchable, EP_SWITCHABLE },
4077 { ep_bd_element, EP_BD_ELEMENT },
4078 { ep_sp_element, EP_SP_ELEMENT },
4079 { ep_sb_element, EP_SB_ELEMENT },
4081 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4082 { ep_food_penguin, EP_FOOD_PENGUIN },
4083 { ep_food_pig, EP_FOOD_PIG },
4084 { ep_historic_wall, EP_HISTORIC_WALL },
4085 { ep_historic_solid, EP_HISTORIC_SOLID },
4086 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4087 { ep_belt, EP_BELT },
4088 { ep_belt_active, EP_BELT_ACTIVE },
4089 { ep_belt_switch, EP_BELT_SWITCH },
4090 { ep_tube, EP_TUBE },
4091 { ep_acid_pool, EP_ACID_POOL },
4092 { ep_keygate, EP_KEYGATE },
4093 { ep_amoeboid, EP_AMOEBOID },
4094 { ep_amoebalive, EP_AMOEBALIVE },
4095 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4096 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4097 { ep_can_grow, EP_CAN_GROW },
4098 { ep_active_bomb, EP_ACTIVE_BOMB },
4099 { ep_inactive, EP_INACTIVE },
4101 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4103 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4105 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4106 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4108 { ep_obsolete, EP_OBSOLETE },
4115 /* always start with reliable default values (element has no properties) */
4116 /* (but never initialize clipboard elements after the very first time) */
4117 /* (to be able to use clipboard elements between several levels) */
4118 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4119 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4120 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4121 SET_PROPERTY(i, j, FALSE);
4123 /* set all base element properties from above array definitions */
4124 for (i = 0; element_properties[i].elements != NULL; i++)
4125 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4126 SET_PROPERTY((element_properties[i].elements)[j],
4127 element_properties[i].property, TRUE);
4129 /* copy properties to some elements that are only stored in level file */
4130 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4131 for (j = 0; copy_properties[j][0] != -1; j++)
4132 if (HAS_PROPERTY(copy_properties[j][0], i))
4133 for (k = 1; k <= 4; k++)
4134 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4136 /* set static element properties that are not listed in array definitions */
4137 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4138 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4140 clipboard_elements_initialized = TRUE;
4143 void InitElementPropertiesEngine(int engine_version)
4145 static int no_wall_properties[] =
4148 EP_COLLECTIBLE_ONLY,
4150 EP_DONT_COLLIDE_WITH,
4153 EP_CAN_SMASH_PLAYER,
4154 EP_CAN_SMASH_ENEMIES,
4155 EP_CAN_SMASH_EVERYTHING,
4160 EP_FOOD_DARK_YAMYAM,
4176 /* important: after initialization in InitElementPropertiesStatic(), the
4177 elements are not again initialized to a default value; therefore all
4178 changes have to make sure that they leave the element with a defined
4179 property (which means that conditional property changes must be set to
4180 a reliable default value before) */
4182 /* resolve group elements */
4183 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4184 ResolveGroupElement(EL_GROUP_START + i);
4186 /* set all special, combined or engine dependent element properties */
4187 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4189 /* do not change (already initialized) clipboard elements here */
4190 if (IS_CLIPBOARD_ELEMENT(i))
4193 /* ---------- INACTIVE ------------------------------------------------- */
4194 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4195 i <= EL_CHAR_END) ||
4196 (i >= EL_STEEL_CHAR_START &&
4197 i <= EL_STEEL_CHAR_END)));
4199 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4200 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4201 IS_WALKABLE_INSIDE(i) ||
4202 IS_WALKABLE_UNDER(i)));
4204 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4205 IS_PASSABLE_INSIDE(i) ||
4206 IS_PASSABLE_UNDER(i)));
4208 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4209 IS_PASSABLE_OVER(i)));
4211 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4212 IS_PASSABLE_INSIDE(i)));
4214 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4215 IS_PASSABLE_UNDER(i)));
4217 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4220 /* ---------- COLLECTIBLE ---------------------------------------------- */
4221 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4225 /* ---------- SNAPPABLE ------------------------------------------------ */
4226 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4227 IS_COLLECTIBLE(i) ||
4231 /* ---------- WALL ----------------------------------------------------- */
4232 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4234 for (j = 0; no_wall_properties[j] != -1; j++)
4235 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4236 i >= EL_FIRST_RUNTIME_UNREAL)
4237 SET_PROPERTY(i, EP_WALL, FALSE);
4239 if (IS_HISTORIC_WALL(i))
4240 SET_PROPERTY(i, EP_WALL, TRUE);
4242 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4243 if (engine_version < VERSION_IDENT(2,2,0,0))
4244 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4246 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4248 !IS_COLLECTIBLE(i)));
4250 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4251 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4252 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4254 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4255 IS_INDESTRUCTIBLE(i)));
4257 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4259 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4260 else if (engine_version < VERSION_IDENT(2,2,0,0))
4261 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4263 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4267 if (IS_CUSTOM_ELEMENT(i))
4269 /* these are additional properties which are initially false when set */
4271 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4273 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4274 if (DONT_COLLIDE_WITH(i))
4275 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4277 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4278 if (CAN_SMASH_EVERYTHING(i))
4279 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4280 if (CAN_SMASH_ENEMIES(i))
4281 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4284 /* ---------- CAN_SMASH ------------------------------------------------ */
4285 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4286 CAN_SMASH_ENEMIES(i) ||
4287 CAN_SMASH_EVERYTHING(i)));
4289 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4290 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4291 EXPLODES_BY_FIRE(i)));
4293 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4294 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4295 EXPLODES_SMASHED(i)));
4297 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4298 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4299 EXPLODES_IMPACT(i)));
4301 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4302 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4304 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4305 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4306 i == EL_BLACK_ORB));
4308 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4309 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4311 IS_CUSTOM_ELEMENT(i)));
4313 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4314 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4315 i == EL_SP_ELECTRON));
4317 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4318 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4319 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4320 getMoveIntoAcidProperty(&level, i));
4322 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4323 if (MAYBE_DONT_COLLIDE_WITH(i))
4324 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4325 getDontCollideWithProperty(&level, i));
4327 /* ---------- SP_PORT -------------------------------------------------- */
4328 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4329 IS_PASSABLE_INSIDE(i)));
4331 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4332 for (j = 0; j < level.num_android_clone_elements; j++)
4333 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4335 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4337 /* ---------- CAN_CHANGE ----------------------------------------------- */
4338 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4339 for (j = 0; j < element_info[i].num_change_pages; j++)
4340 if (element_info[i].change_page[j].can_change)
4341 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4343 /* ---------- HAS_ACTION ----------------------------------------------- */
4344 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4345 for (j = 0; j < element_info[i].num_change_pages; j++)
4346 if (element_info[i].change_page[j].has_action)
4347 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4349 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4350 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4353 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4354 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4355 element_info[i].crumbled[ACTION_DEFAULT] !=
4356 element_info[i].graphic[ACTION_DEFAULT]);
4358 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4359 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4360 IS_EDITOR_CASCADE_INACTIVE(i)));
4363 /* dynamically adjust element properties according to game engine version */
4365 static int ep_em_slippery_wall[] =
4370 EL_EXPANDABLE_WALL_HORIZONTAL,
4371 EL_EXPANDABLE_WALL_VERTICAL,
4372 EL_EXPANDABLE_WALL_ANY,
4373 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4374 EL_EXPANDABLE_STEELWALL_VERTICAL,
4375 EL_EXPANDABLE_STEELWALL_ANY,
4376 EL_EXPANDABLE_STEELWALL_GROWING,
4380 static int ep_em_explodes_by_fire[] =
4383 EL_EM_DYNAMITE_ACTIVE,
4388 /* special EM style gems behaviour */
4389 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4390 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4391 level.em_slippery_gems);
4393 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4394 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4395 (level.em_slippery_gems &&
4396 engine_version > VERSION_IDENT(2,0,1,0)));
4398 /* special EM style explosion behaviour regarding chain reactions */
4399 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4400 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4401 level.em_explodes_by_fire);
4404 /* this is needed because some graphics depend on element properties */
4405 if (game_status == GAME_MODE_PLAYING)
4406 InitElementGraphicInfo();
4409 void InitElementPropertiesAfterLoading(int engine_version)
4413 /* set some other uninitialized values of custom elements in older levels */
4414 if (engine_version < VERSION_IDENT(3,1,0,0))
4416 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4418 int element = EL_CUSTOM_START + i;
4420 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4422 element_info[element].explosion_delay = 17;
4423 element_info[element].ignition_delay = 8;
4428 void InitElementPropertiesGfxElement()
4432 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4434 struct ElementInfo *ei = &element_info[i];
4436 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4440 static void InitGlobal()
4445 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4447 /* check if element_name_info entry defined for each element in "main.h" */
4448 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4449 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4451 element_info[i].token_name = element_name_info[i].token_name;
4452 element_info[i].class_name = element_name_info[i].class_name;
4453 element_info[i].editor_description= element_name_info[i].editor_description;
4456 /* create hash from image config list */
4457 image_config_hash = newSetupFileHash();
4458 for (i = 0; image_config[i].token != NULL; i++)
4459 setHashEntry(image_config_hash,
4460 image_config[i].token,
4461 image_config[i].value);
4463 /* create hash from element token list */
4464 element_token_hash = newSetupFileHash();
4465 for (i = 0; element_name_info[i].token_name != NULL; i++)
4466 setHashEntry(element_token_hash,
4467 element_name_info[i].token_name,
4470 /* create hash from graphic token list */
4471 graphic_token_hash = newSetupFileHash();
4472 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4473 if (strSuffix(image_config[i].value, ".png") ||
4474 strSuffix(image_config[i].value, ".pcx") ||
4475 strSuffix(image_config[i].value, ".wav") ||
4476 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4477 setHashEntry(graphic_token_hash,
4478 image_config[i].token,
4479 int2str(graphic++, 0));
4481 /* create hash from font token list */
4482 font_token_hash = newSetupFileHash();
4483 for (i = 0; font_info[i].token_name != NULL; i++)
4484 setHashEntry(font_token_hash,
4485 font_info[i].token_name,
4488 /* set default filenames for all cloned graphics in static configuration */
4489 for (i = 0; image_config[i].token != NULL; i++)
4491 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4493 char *token = image_config[i].token;
4494 char *token_clone_from = getStringCat2(token, ".clone_from");
4495 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4497 if (token_cloned != NULL)
4499 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4501 if (value_cloned != NULL)
4503 /* set default filename in static configuration */
4504 image_config[i].value = value_cloned;
4506 /* set default filename in image config hash */
4507 setHashEntry(image_config_hash, token, value_cloned);
4511 free(token_clone_from);
4515 /* always start with reliable default values (all elements) */
4516 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4517 ActiveElement[i] = i;
4519 /* now add all entries that have an active state (active elements) */
4520 for (i = 0; element_with_active_state[i].element != -1; i++)
4522 int element = element_with_active_state[i].element;
4523 int element_active = element_with_active_state[i].element_active;
4525 ActiveElement[element] = element_active;
4528 /* always start with reliable default values (all buttons) */
4529 for (i = 0; i < NUM_IMAGE_FILES; i++)
4530 ActiveButton[i] = i;
4532 /* now add all entries that have an active state (active buttons) */
4533 for (i = 0; button_with_active_state[i].button != -1; i++)
4535 int button = button_with_active_state[i].button;
4536 int button_active = button_with_active_state[i].button_active;
4538 ActiveButton[button] = button_active;
4541 /* always start with reliable default values (all fonts) */
4542 for (i = 0; i < NUM_FONTS; i++)
4545 /* now add all entries that have an active state (active fonts) */
4546 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4548 int font = font_with_active_state[i].font_nr;
4549 int font_active = font_with_active_state[i].font_nr_active;
4551 ActiveFont[font] = font_active;
4554 global.autoplay_leveldir = NULL;
4555 global.convert_leveldir = NULL;
4556 global.create_images_dir = NULL;
4558 global.frames_per_second = 0;
4560 global.border_status = GAME_MODE_MAIN;
4562 global.use_envelope_request = FALSE;
4565 void Execute_Command(char *command)
4569 if (strEqual(command, "print graphicsinfo.conf"))
4571 Print("# You can configure additional/alternative image files here.\n");
4572 Print("# (The entries below are default and therefore commented out.)\n");
4574 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4576 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4579 for (i = 0; image_config[i].token != NULL; i++)
4580 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4581 image_config[i].value));
4585 else if (strEqual(command, "print soundsinfo.conf"))
4587 Print("# You can configure additional/alternative sound files here.\n");
4588 Print("# (The entries below are default and therefore commented out.)\n");
4590 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4592 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4595 for (i = 0; sound_config[i].token != NULL; i++)
4596 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4597 sound_config[i].value));
4601 else if (strEqual(command, "print musicinfo.conf"))
4603 Print("# You can configure additional/alternative music files here.\n");
4604 Print("# (The entries below are default and therefore commented out.)\n");
4606 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4608 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4611 for (i = 0; music_config[i].token != NULL; i++)
4612 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4613 music_config[i].value));
4617 else if (strEqual(command, "print editorsetup.conf"))
4619 Print("# You can configure your personal editor element list here.\n");
4620 Print("# (The entries below are default and therefore commented out.)\n");
4623 /* this is needed to be able to check element list for cascade elements */
4624 InitElementPropertiesStatic();
4625 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4627 PrintEditorElementList();
4631 else if (strEqual(command, "print helpanim.conf"))
4633 Print("# You can configure different element help animations here.\n");
4634 Print("# (The entries below are default and therefore commented out.)\n");
4637 for (i = 0; helpanim_config[i].token != NULL; i++)
4639 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4640 helpanim_config[i].value));
4642 if (strEqual(helpanim_config[i].token, "end"))
4648 else if (strEqual(command, "print helptext.conf"))
4650 Print("# You can configure different element help text here.\n");
4651 Print("# (The entries below are default and therefore commented out.)\n");
4654 for (i = 0; helptext_config[i].token != NULL; i++)
4655 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4656 helptext_config[i].value));
4660 else if (strPrefix(command, "dump level "))
4662 char *filename = &command[11];
4664 if (!fileExists(filename))
4665 Error(ERR_EXIT, "cannot open file '%s'", filename);
4667 LoadLevelFromFilename(&level, filename);
4672 else if (strPrefix(command, "dump tape "))
4674 char *filename = &command[10];
4676 if (!fileExists(filename))
4677 Error(ERR_EXIT, "cannot open file '%s'", filename);
4679 LoadTapeFromFilename(filename);
4684 else if (strPrefix(command, "autotest ") ||
4685 strPrefix(command, "autoplay ") ||
4686 strPrefix(command, "autoffwd "))
4688 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4690 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4691 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4692 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4694 while (*str_ptr != '\0') /* continue parsing string */
4696 /* cut leading whitespace from string, replace it by string terminator */
4697 while (*str_ptr == ' ' || *str_ptr == '\t')
4700 if (*str_ptr == '\0') /* end of string reached */
4703 if (global.autoplay_leveldir == NULL) /* read level set string */
4705 global.autoplay_leveldir = str_ptr;
4706 global.autoplay_all = TRUE; /* default: play all tapes */
4708 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4709 global.autoplay_level[i] = FALSE;
4711 else /* read level number string */
4713 int level_nr = atoi(str_ptr); /* get level_nr value */
4715 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4716 global.autoplay_level[level_nr] = TRUE;
4718 global.autoplay_all = FALSE;
4721 /* advance string pointer to the next whitespace (or end of string) */
4722 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4726 else if (strPrefix(command, "convert "))
4728 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4729 char *str_ptr = strchr(str_copy, ' ');
4731 global.convert_leveldir = str_copy;
4732 global.convert_level_nr = -1;
4734 if (str_ptr != NULL) /* level number follows */
4736 *str_ptr++ = '\0'; /* terminate leveldir string */
4737 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4740 else if (strPrefix(command, "create images "))
4742 global.create_images_dir = getStringCopy(&command[14]);
4744 if (access(global.create_images_dir, W_OK) != 0)
4745 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4746 global.create_images_dir);
4748 else if (strPrefix(command, "create CE image "))
4750 CreateCustomElementImages(&command[16]);
4756 #if defined(TARGET_SDL2)
4757 else if (strEqual(command, "SDL_ListModes"))
4759 SDL_Init(SDL_INIT_VIDEO);
4761 int num_displays = SDL_GetNumVideoDisplays();
4763 // check if there are any displays available
4764 if (num_displays < 0)
4766 Print("No displays available: %s\n", SDL_GetError());
4771 for (i = 0; i < num_displays; i++)
4773 int num_modes = SDL_GetNumDisplayModes(i);
4776 Print("Available display modes for display %d:\n", i);
4778 // check if there are any display modes available for this display
4781 Print("No display modes available for display %d: %s\n",
4787 for (j = 0; j < num_modes; j++)
4789 SDL_DisplayMode mode;
4791 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4793 Print("Cannot get display mode %d for display %d: %s\n",
4794 j, i, SDL_GetError());
4799 Print("- %d x %d\n", mode.w, mode.h);
4805 #elif defined(TARGET_SDL)
4806 else if (strEqual(command, "SDL_ListModes"))
4811 SDL_Init(SDL_INIT_VIDEO);
4813 /* get available fullscreen/hardware modes */
4814 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4816 /* check if there are any modes available */
4819 Print("No modes available!\n");
4824 /* check if our resolution is restricted */
4825 if (modes == (SDL_Rect **)-1)
4827 Print("All resolutions available.\n");
4831 Print("Available display modes:\n");
4833 for (i = 0; modes[i]; i++)
4834 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4844 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4848 static void InitSetup()
4850 LoadSetup(); /* global setup info */
4852 /* set some options from setup file */
4854 if (setup.options.verbose)
4855 options.verbose = TRUE;
4858 static void InitGameInfo()
4860 game.restart_level = FALSE;
4863 static void InitPlayerInfo()
4867 /* choose default local player */
4868 local_player = &stored_player[0];
4870 for (i = 0; i < MAX_PLAYERS; i++)
4871 stored_player[i].connected = FALSE;
4873 local_player->connected = TRUE;
4876 static void InitArtworkInfo()
4881 static char *get_string_in_brackets(char *string)
4883 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4885 sprintf(string_in_brackets, "[%s]", string);
4887 return string_in_brackets;
4890 static char *get_level_id_suffix(int id_nr)
4892 char *id_suffix = checked_malloc(1 + 3 + 1);
4894 if (id_nr < 0 || id_nr > 999)
4897 sprintf(id_suffix, ".%03d", id_nr);
4902 static void InitArtworkConfig()
4904 static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4905 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4906 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4907 static char *action_id_suffix[NUM_ACTIONS + 1];
4908 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4909 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4910 static char *level_id_suffix[MAX_LEVELS + 1];
4911 static char *dummy[1] = { NULL };
4912 static char *ignore_generic_tokens[] =
4918 static char **ignore_image_tokens;
4919 static char **ignore_sound_tokens;
4920 static char **ignore_music_tokens;
4921 int num_ignore_generic_tokens;
4922 int num_ignore_image_tokens;
4923 int num_ignore_sound_tokens;
4924 int num_ignore_music_tokens;
4927 /* dynamically determine list of generic tokens to be ignored */
4928 num_ignore_generic_tokens = 0;
4929 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4930 num_ignore_generic_tokens++;
4932 /* dynamically determine list of image tokens to be ignored */
4933 num_ignore_image_tokens = num_ignore_generic_tokens;
4934 for (i = 0; image_config_vars[i].token != NULL; i++)
4935 num_ignore_image_tokens++;
4936 ignore_image_tokens =
4937 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4938 for (i = 0; i < num_ignore_generic_tokens; i++)
4939 ignore_image_tokens[i] = ignore_generic_tokens[i];
4940 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4941 ignore_image_tokens[num_ignore_generic_tokens + i] =
4942 image_config_vars[i].token;
4943 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4945 /* dynamically determine list of sound tokens to be ignored */
4946 num_ignore_sound_tokens = num_ignore_generic_tokens;
4947 ignore_sound_tokens =
4948 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4949 for (i = 0; i < num_ignore_generic_tokens; i++)
4950 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4951 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4953 /* dynamically determine list of music tokens to be ignored */
4954 num_ignore_music_tokens = num_ignore_generic_tokens;
4955 ignore_music_tokens =
4956 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4957 for (i = 0; i < num_ignore_generic_tokens; i++)
4958 ignore_music_tokens[i] = ignore_generic_tokens[i];
4959 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4961 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4962 image_id_prefix[i] = element_info[i].token_name;
4963 for (i = 0; i < NUM_FONTS; i++)
4964 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4965 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4967 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4968 sound_id_prefix[i] = element_info[i].token_name;
4969 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4970 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4971 get_string_in_brackets(element_info[i].class_name);
4972 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4974 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4975 music_id_prefix[i] = music_prefix_info[i].prefix;
4976 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4978 for (i = 0; i < NUM_ACTIONS; i++)
4979 action_id_suffix[i] = element_action_info[i].suffix;
4980 action_id_suffix[NUM_ACTIONS] = NULL;
4982 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4983 direction_id_suffix[i] = element_direction_info[i].suffix;
4984 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4986 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4987 special_id_suffix[i] = special_suffix_info[i].suffix;
4988 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4990 for (i = 0; i < MAX_LEVELS; i++)
4991 level_id_suffix[i] = get_level_id_suffix(i);
4992 level_id_suffix[MAX_LEVELS] = NULL;
4994 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4995 image_id_prefix, action_id_suffix, direction_id_suffix,
4996 special_id_suffix, ignore_image_tokens);
4997 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4998 sound_id_prefix, action_id_suffix, dummy,
4999 special_id_suffix, ignore_sound_tokens);
5000 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5001 music_id_prefix, special_id_suffix, level_id_suffix,
5002 dummy, ignore_music_tokens);
5005 static void InitMixer()
5012 void InitGfxBuffers()
5014 static int win_xsize_last = -1;
5015 static int win_ysize_last = -1;
5017 /* create additional image buffers for double-buffering and cross-fading */
5019 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5021 /* may contain content for cross-fading -- only re-create if changed */
5022 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5023 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5025 win_xsize_last = WIN_XSIZE;
5026 win_ysize_last = WIN_YSIZE;
5029 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5030 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5031 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5032 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5033 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5035 /* initialize screen properties */
5036 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5037 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5039 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5040 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5041 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5042 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5043 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5044 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5046 /* required if door size definitions have changed */
5047 InitGraphicCompatibilityInfo_Doors();
5049 InitGfxBuffers_EM();
5050 InitGfxBuffers_SP();
5055 struct GraphicInfo *graphic_info_last = graphic_info;
5056 char *filename_font_initial = NULL;
5057 char *filename_anim_initial = NULL;
5058 Bitmap *bitmap_font_initial = NULL;
5062 /* determine settings for initial font (for displaying startup messages) */
5063 for (i = 0; image_config[i].token != NULL; i++)
5065 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5067 char font_token[128];
5070 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5071 len_font_token = strlen(font_token);
5073 if (strEqual(image_config[i].token, font_token))
5074 filename_font_initial = image_config[i].value;
5075 else if (strlen(image_config[i].token) > len_font_token &&
5076 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5078 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5079 font_initial[j].src_x = atoi(image_config[i].value);
5080 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5081 font_initial[j].src_y = atoi(image_config[i].value);
5082 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5083 font_initial[j].width = atoi(image_config[i].value);
5084 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5085 font_initial[j].height = atoi(image_config[i].value);
5090 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5092 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5093 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5096 if (filename_font_initial == NULL) /* should not happen */
5097 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5100 InitGfxCustomArtworkInfo();
5101 InitGfxOtherSettings();
5103 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5105 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5106 font_initial[j].bitmap = bitmap_font_initial;
5108 InitFontGraphicInfo();
5110 font_height = getFontHeight(FC_RED);
5112 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5113 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5114 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5117 DrawInitText("Loading graphics", 120, FC_GREEN);
5119 /* initialize settings for busy animation with default values */
5120 int parameter[NUM_GFX_ARGS];
5121 for (i = 0; i < NUM_GFX_ARGS; i++)
5122 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5123 image_config_suffix[i].token,
5124 image_config_suffix[i].type);
5126 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5127 int len_anim_token = strlen(anim_token);
5129 /* read settings for busy animation from default custom artwork config */
5130 char *gfx_config_filename = getPath3(options.graphics_directory,
5132 GRAPHICSINFO_FILENAME);
5134 if (fileExists(gfx_config_filename))
5136 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5138 if (setup_file_hash)
5140 char *filename = getHashEntry(setup_file_hash, anim_token);
5144 filename_anim_initial = getStringCopy(filename);
5146 for (j = 0; image_config_suffix[j].token != NULL; j++)
5148 int type = image_config_suffix[j].type;
5149 char *suffix = image_config_suffix[j].token;
5150 char *token = getStringCat2(anim_token, suffix);
5151 char *value = getHashEntry(setup_file_hash, token);
5153 checked_free(token);
5156 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5160 freeSetupFileHash(setup_file_hash);
5164 if (filename_anim_initial == NULL)
5166 /* read settings for busy animation from static default artwork config */
5167 for (i = 0; image_config[i].token != NULL; i++)
5169 if (strEqual(image_config[i].token, anim_token))
5170 filename_anim_initial = getStringCopy(image_config[i].value);
5171 else if (strlen(image_config[i].token) > len_anim_token &&
5172 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5174 for (j = 0; image_config_suffix[j].token != NULL; j++)
5176 if (strEqual(&image_config[i].token[len_anim_token],
5177 image_config_suffix[j].token))
5179 get_graphic_parameter_value(image_config[i].value,
5180 image_config_suffix[j].token,
5181 image_config_suffix[j].type);
5187 if (filename_anim_initial == NULL) /* should not happen */
5188 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5190 anim_initial.bitmaps =
5191 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5193 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5194 LoadCustomImage(filename_anim_initial);
5196 checked_free(filename_anim_initial);
5198 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5200 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5202 graphic_info = graphic_info_last;
5204 init.busy.width = anim_initial.width;
5205 init.busy.height = anim_initial.height;
5207 InitMenuDesignSettings_Static();
5208 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5210 /* use copy of busy animation to prevent change while reloading artwork */
5214 void InitGfxBackground()
5216 fieldbuffer = bitmap_db_field;
5217 SetDrawtoField(DRAW_BACKBUFFER);
5219 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5221 redraw_mask = REDRAW_ALL;
5224 static void InitLevelInfo()
5226 LoadLevelInfo(); /* global level info */
5227 LoadLevelSetup_LastSeries(); /* last played series info */
5228 LoadLevelSetup_SeriesInfo(); /* last played level info */
5230 if (global.autoplay_leveldir &&
5231 global.autoplay_mode != AUTOPLAY_TEST)
5233 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5234 global.autoplay_leveldir);
5235 if (leveldir_current == NULL)
5236 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5240 static void InitLevelArtworkInfo()
5242 LoadLevelArtworkInfo();
5245 static void InitImages()
5247 print_timestamp_init("InitImages");
5250 printf("::: leveldir_current->identifier == '%s'\n",
5251 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5252 printf("::: leveldir_current->graphics_path == '%s'\n",
5253 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5254 printf("::: leveldir_current->graphics_set == '%s'\n",
5255 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5256 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5257 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5260 setLevelArtworkDir(artwork.gfx_first);
5263 printf("::: leveldir_current->identifier == '%s'\n",
5264 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5265 printf("::: leveldir_current->graphics_path == '%s'\n",
5266 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5267 printf("::: leveldir_current->graphics_set == '%s'\n",
5268 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5269 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5270 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5274 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5275 leveldir_current->identifier,
5276 artwork.gfx_current_identifier,
5277 artwork.gfx_current->identifier,
5278 leveldir_current->graphics_set,
5279 leveldir_current->graphics_path);
5282 UPDATE_BUSY_STATE();
5284 ReloadCustomImages();
5285 print_timestamp_time("ReloadCustomImages");
5287 UPDATE_BUSY_STATE();
5289 LoadCustomElementDescriptions();
5290 print_timestamp_time("LoadCustomElementDescriptions");
5292 UPDATE_BUSY_STATE();
5294 LoadMenuDesignSettings();
5295 print_timestamp_time("LoadMenuDesignSettings");
5297 UPDATE_BUSY_STATE();
5299 ReinitializeGraphics();
5300 print_timestamp_time("ReinitializeGraphics");
5302 UPDATE_BUSY_STATE();
5304 print_timestamp_done("InitImages");
5307 static void InitSound(char *identifier)
5309 print_timestamp_init("InitSound");
5311 if (identifier == NULL)
5312 identifier = artwork.snd_current->identifier;
5314 /* set artwork path to send it to the sound server process */
5315 setLevelArtworkDir(artwork.snd_first);
5317 InitReloadCustomSounds(identifier);
5318 print_timestamp_time("InitReloadCustomSounds");
5320 ReinitializeSounds();
5321 print_timestamp_time("ReinitializeSounds");
5323 print_timestamp_done("InitSound");
5326 static void InitMusic(char *identifier)
5328 print_timestamp_init("InitMusic");
5330 if (identifier == NULL)
5331 identifier = artwork.mus_current->identifier;
5333 /* set artwork path to send it to the sound server process */
5334 setLevelArtworkDir(artwork.mus_first);
5336 InitReloadCustomMusic(identifier);
5337 print_timestamp_time("InitReloadCustomMusic");
5339 ReinitializeMusic();
5340 print_timestamp_time("ReinitializeMusic");
5342 print_timestamp_done("InitMusic");
5345 void InitNetworkServer()
5347 #if defined(NETWORK_AVALIABLE)
5351 if (!options.network)
5354 #if defined(NETWORK_AVALIABLE)
5355 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5357 if (!ConnectToServer(options.server_host, options.server_port))
5358 Error(ERR_EXIT, "cannot connect to network game server");
5360 SendToServer_PlayerName(setup.player_name);
5361 SendToServer_ProtocolVersion();
5364 SendToServer_NrWanted(nr_wanted);
5368 static boolean CheckArtworkConfigForCustomElements(char *filename)
5370 SetupFileHash *setup_file_hash;
5371 boolean redefined_ce_found = FALSE;
5373 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5375 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5377 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5379 char *token = HASH_ITERATION_TOKEN(itr);
5381 if (strPrefix(token, "custom_"))
5383 redefined_ce_found = TRUE;
5388 END_HASH_ITERATION(setup_file_hash, itr)
5390 freeSetupFileHash(setup_file_hash);
5393 return redefined_ce_found;
5396 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5398 char *filename_base, *filename_local;
5399 boolean redefined_ce_found = FALSE;
5401 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5404 printf("::: leveldir_current->identifier == '%s'\n",
5405 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5406 printf("::: leveldir_current->graphics_path == '%s'\n",
5407 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5408 printf("::: leveldir_current->graphics_set == '%s'\n",
5409 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5410 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5411 leveldir_current == NULL ? "[NULL]" :
5412 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5415 /* first look for special artwork configured in level series config */
5416 filename_base = getCustomArtworkLevelConfigFilename(type);
5419 printf("::: filename_base == '%s'\n", filename_base);
5422 if (fileExists(filename_base))
5423 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5425 filename_local = getCustomArtworkConfigFilename(type);
5428 printf("::: filename_local == '%s'\n", filename_local);
5431 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5432 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5435 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5438 return redefined_ce_found;
5441 static void InitOverrideArtwork()
5443 boolean redefined_ce_found = FALSE;
5445 /* to check if this level set redefines any CEs, do not use overriding */
5446 gfx.override_level_graphics = FALSE;
5447 gfx.override_level_sounds = FALSE;
5448 gfx.override_level_music = FALSE;
5450 /* now check if this level set has definitions for custom elements */
5451 if (setup.override_level_graphics == AUTO ||
5452 setup.override_level_sounds == AUTO ||
5453 setup.override_level_music == AUTO)
5454 redefined_ce_found =
5455 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5456 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5457 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5460 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5463 if (redefined_ce_found)
5465 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5466 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5467 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5468 gfx.override_level_music = (setup.override_level_music == TRUE);
5472 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5473 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5474 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5475 gfx.override_level_music = (setup.override_level_music != FALSE);
5479 printf("::: => %d, %d, %d\n",
5480 gfx.override_level_graphics,
5481 gfx.override_level_sounds,
5482 gfx.override_level_music);
5486 static char *getNewArtworkIdentifier(int type)
5488 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5489 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5490 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5491 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5492 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5493 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5494 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5495 char *leveldir_identifier = leveldir_current->identifier;
5496 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5497 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5498 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5499 char *artwork_current_identifier;
5500 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5502 /* leveldir_current may be invalid (level group, parent link) */
5503 if (!validLevelSeries(leveldir_current))
5506 /* 1st step: determine artwork set to be activated in descending order:
5507 --------------------------------------------------------------------
5508 1. setup artwork (when configured to override everything else)
5509 2. artwork set configured in "levelinfo.conf" of current level set
5510 (artwork in level directory will have priority when loading later)
5511 3. artwork in level directory (stored in artwork sub-directory)
5512 4. setup artwork (currently configured in setup menu) */
5514 if (setup_override_artwork)
5515 artwork_current_identifier = setup_artwork_set;
5516 else if (leveldir_artwork_set != NULL)
5517 artwork_current_identifier = leveldir_artwork_set;
5518 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5519 artwork_current_identifier = leveldir_identifier;
5521 artwork_current_identifier = setup_artwork_set;
5524 /* 2nd step: check if it is really needed to reload artwork set
5525 ------------------------------------------------------------ */
5527 /* ---------- reload if level set and also artwork set has changed ------- */
5528 if (leveldir_current_identifier[type] != leveldir_identifier &&
5529 (last_has_level_artwork_set[type] || has_level_artwork_set))
5530 artwork_new_identifier = artwork_current_identifier;
5532 leveldir_current_identifier[type] = leveldir_identifier;
5533 last_has_level_artwork_set[type] = has_level_artwork_set;
5535 /* ---------- reload if "override artwork" setting has changed ----------- */
5536 if (last_override_level_artwork[type] != setup_override_artwork)
5537 artwork_new_identifier = artwork_current_identifier;
5539 last_override_level_artwork[type] = setup_override_artwork;
5541 /* ---------- reload if current artwork identifier has changed ----------- */
5542 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5543 artwork_current_identifier))
5544 artwork_new_identifier = artwork_current_identifier;
5546 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5548 /* ---------- do not reload directly after starting ---------------------- */
5549 if (!initialized[type])
5550 artwork_new_identifier = NULL;
5552 initialized[type] = TRUE;
5554 return artwork_new_identifier;
5557 void ReloadCustomArtwork(int force_reload)
5559 int last_game_status = game_status; /* save current game status */
5560 char *gfx_new_identifier;
5561 char *snd_new_identifier;
5562 char *mus_new_identifier;
5563 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5564 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5565 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5566 boolean reload_needed;
5568 InitOverrideArtwork();
5570 force_reload_gfx |= AdjustGraphicsForEMC();
5572 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5573 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5574 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5576 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5577 snd_new_identifier != NULL || force_reload_snd ||
5578 mus_new_identifier != NULL || force_reload_mus);
5583 print_timestamp_init("ReloadCustomArtwork");
5585 game_status = GAME_MODE_LOADING;
5587 FadeOut(REDRAW_ALL);
5589 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5590 print_timestamp_time("ClearRectangle");
5594 if (gfx_new_identifier != NULL || force_reload_gfx)
5597 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5598 artwork.gfx_current_identifier,
5600 artwork.gfx_current->identifier,
5601 leveldir_current->graphics_set);
5605 print_timestamp_time("InitImages");
5608 if (snd_new_identifier != NULL || force_reload_snd)
5610 InitSound(snd_new_identifier);
5611 print_timestamp_time("InitSound");
5614 if (mus_new_identifier != NULL || force_reload_mus)
5616 InitMusic(mus_new_identifier);
5617 print_timestamp_time("InitMusic");
5620 game_status = last_game_status; /* restore current game status */
5622 init_last = init; /* switch to new busy animation */
5624 FadeOut(REDRAW_ALL);
5626 RedrawGlobalBorder();
5628 /* force redraw of (open or closed) door graphics */
5629 SetDoorState(DOOR_OPEN_ALL);
5630 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5632 FadeSetEnterScreen();
5633 FadeSkipNextFadeOut();
5635 print_timestamp_done("ReloadCustomArtwork");
5637 LimitScreenUpdates(FALSE);
5640 void KeyboardAutoRepeatOffUnlessAutoplay()
5642 if (global.autoplay_leveldir == NULL)
5643 KeyboardAutoRepeatOff();
5646 void DisplayExitMessage(char *format, va_list ap)
5648 // check if draw buffer and fonts for exit message are already available
5649 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5652 int font_1 = FC_RED;
5653 int font_2 = FC_YELLOW;
5654 int font_3 = FC_BLUE;
5655 int font_width = getFontWidth(font_2);
5656 int font_height = getFontHeight(font_2);
5659 int sxsize = WIN_XSIZE - 2 * sx;
5660 int sysize = WIN_YSIZE - 2 * sy;
5661 int line_length = sxsize / font_width;
5662 int max_lines = sysize / font_height;
5663 int num_lines_printed;
5667 gfx.sxsize = sxsize;
5668 gfx.sysize = sysize;
5672 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5674 DrawTextSCentered(sy, font_1, "Fatal error:");
5675 sy += 3 * font_height;;
5678 DrawTextBufferVA(sx, sy, format, ap, font_2,
5679 line_length, line_length, max_lines,
5680 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5681 sy += (num_lines_printed + 3) * font_height;
5683 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5684 sy += 3 * font_height;
5687 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5688 line_length, line_length, max_lines,
5689 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5691 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5693 redraw_mask = REDRAW_ALL;
5695 /* force drawing exit message even if screen updates are currently limited */
5696 LimitScreenUpdates(FALSE);
5700 /* deactivate toons on error message screen */
5701 setup.toons = FALSE;
5703 WaitForEventToContinue();
5707 /* ========================================================================= */
5709 /* ========================================================================= */
5713 print_timestamp_init("OpenAll");
5715 game_status = GAME_MODE_LOADING;
5719 InitGlobal(); /* initialize some global variables */
5721 print_timestamp_time("[init global stuff]");
5725 print_timestamp_time("[init setup/config stuff (1)]");
5727 if (options.execute_command)
5728 Execute_Command(options.execute_command);
5730 if (options.serveronly)
5732 #if defined(PLATFORM_UNIX)
5733 NetworkServer(options.server_port, options.serveronly);
5735 Error(ERR_WARN, "networking only supported in Unix version");
5738 exit(0); /* never reached, server loops forever */
5742 print_timestamp_time("[init setup/config stuff (2)]");
5744 print_timestamp_time("[init setup/config stuff (3)]");
5745 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5746 print_timestamp_time("[init setup/config stuff (4)]");
5747 InitArtworkConfig(); /* needed before forking sound child process */
5748 print_timestamp_time("[init setup/config stuff (5)]");
5750 print_timestamp_time("[init setup/config stuff (6)]");
5752 InitRND(NEW_RANDOMIZE);
5753 InitSimpleRandom(NEW_RANDOMIZE);
5757 print_timestamp_time("[init setup/config stuff]");
5760 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5762 InitEventFilter(FilterEvents);
5764 print_timestamp_time("[init video stuff]");
5766 InitElementPropertiesStatic();
5767 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5768 InitElementPropertiesGfxElement();
5770 print_timestamp_time("[init element properties stuff]");
5774 print_timestamp_time("InitGfx");
5777 print_timestamp_time("InitLevelInfo");
5779 InitLevelArtworkInfo();
5780 print_timestamp_time("InitLevelArtworkInfo");
5782 InitOverrideArtwork(); /* needs to know current level directory */
5783 print_timestamp_time("InitOverrideArtwork");
5785 InitImages(); /* needs to know current level directory */
5786 print_timestamp_time("InitImages");
5788 InitSound(NULL); /* needs to know current level directory */
5789 print_timestamp_time("InitSound");
5791 InitMusic(NULL); /* needs to know current level directory */
5792 print_timestamp_time("InitMusic");
5794 InitGfxBackground();
5799 if (global.autoplay_leveldir)
5804 else if (global.convert_leveldir)
5809 else if (global.create_images_dir)
5811 CreateLevelSketchImages();
5815 game_status = GAME_MODE_MAIN;
5817 FadeSetEnterScreen();
5818 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5819 FadeSkipNextFadeOut();
5821 print_timestamp_time("[post-artwork]");
5823 print_timestamp_done("OpenAll");
5827 InitNetworkServer();
5830 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5832 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5833 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5834 #if defined(PLATFORM_ANDROID)
5835 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5836 SDL_AndroidGetInternalStoragePath());
5837 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5838 SDL_AndroidGetExternalStoragePath());
5839 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5840 (SDL_AndroidGetExternalStorageState() ==
5841 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5842 SDL_AndroidGetExternalStorageState() ==
5843 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5848 void CloseAllAndExit(int exit_value)
5853 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5860 #if defined(TARGET_SDL)
5861 #if defined(TARGET_SDL2)
5863 // set a flag to tell the network server thread to quit and wait for it
5864 // using SDL_WaitThread()
5866 if (network_server) /* terminate network server */
5867 SDL_KillThread(server_thread);
5871 CloseVideoDisplay();
5872 ClosePlatformDependentStuff();
5874 if (exit_value != 0)
5876 /* fall back to default level set (current set may have caused an error) */
5877 SaveLevelSetup_LastSeries_Deactivate();
5879 /* tell user where to find error log file which may contain more details */
5880 // (error notification now directly displayed on screen inside R'n'D
5881 // NotifyUserAboutErrorFile(); /* currently only works for Windows */