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];
229 void InitImageTextures()
233 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
235 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
237 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
239 int graphic = global_anim_info[i].graphic[j][k];
241 if (graphic == IMG_UNDEFINED)
244 // (re)create textures from images for fast GPU blitting, if possible
245 ReCreateImageTextures(graphic);
252 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
253 void SetBitmaps_EM(Bitmap **em_bitmap)
255 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
256 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
261 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
262 void SetBitmaps_SP(Bitmap **sp_bitmap)
264 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
268 static int getFontBitmapID(int font_nr)
272 /* (special case: do not use special font for GAME_MODE_LOADING) */
273 if (game_status >= GAME_MODE_TITLE_INITIAL &&
274 game_status <= GAME_MODE_PSEUDO_PREVIEW)
275 special = game_status;
276 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
277 special = GFX_SPECIAL_ARG_MAIN;
280 return font_info[font_nr].special_bitmap_id[special];
285 static int getFontFromToken(char *token)
287 char *value = getHashEntry(font_token_hash, token);
292 /* if font not found, use reliable default value */
293 return FONT_INITIAL_1;
296 void InitFontGraphicInfo()
298 static struct FontBitmapInfo *font_bitmap_info = NULL;
299 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
300 int num_property_mappings = getImageListPropertyMappingSize();
301 int num_font_bitmaps = NUM_FONTS;
304 if (graphic_info == NULL) /* still at startup phase */
306 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
307 getFontBitmapID, getFontFromToken);
312 /* ---------- initialize font graphic definitions ---------- */
314 /* always start with reliable default values (normal font graphics) */
315 for (i = 0; i < NUM_FONTS; i++)
316 font_info[i].graphic = IMG_FONT_INITIAL_1;
318 /* initialize normal font/graphic mapping from static configuration */
319 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
321 int font_nr = font_to_graphic[i].font_nr;
322 int special = font_to_graphic[i].special;
323 int graphic = font_to_graphic[i].graphic;
328 font_info[font_nr].graphic = graphic;
331 /* always start with reliable default values (special font graphics) */
332 for (i = 0; i < NUM_FONTS; i++)
334 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
336 font_info[i].special_graphic[j] = font_info[i].graphic;
337 font_info[i].special_bitmap_id[j] = i;
341 /* initialize special font/graphic mapping from static configuration */
342 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
344 int font_nr = font_to_graphic[i].font_nr;
345 int special = font_to_graphic[i].special;
346 int graphic = font_to_graphic[i].graphic;
347 int base_graphic = font2baseimg(font_nr);
349 if (IS_SPECIAL_GFX_ARG(special))
351 boolean base_redefined =
352 getImageListEntryFromImageID(base_graphic)->redefined;
353 boolean special_redefined =
354 getImageListEntryFromImageID(graphic)->redefined;
355 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
357 /* if the base font ("font.title_1", for example) has been redefined,
358 but not the special font ("font.title_1.LEVELS", for example), do not
359 use an existing (in this case considered obsolete) special font
360 anymore, but use the automatically determined default font */
361 /* special case: cloned special fonts must be explicitly redefined,
362 but are not automatically redefined by redefining base font */
363 if (base_redefined && !special_redefined && !special_cloned)
366 font_info[font_nr].special_graphic[special] = graphic;
367 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
372 /* initialize special font/graphic mapping from dynamic configuration */
373 for (i = 0; i < num_property_mappings; i++)
375 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
376 int special = property_mapping[i].ext3_index;
377 int graphic = property_mapping[i].artwork_index;
382 if (IS_SPECIAL_GFX_ARG(special))
384 font_info[font_nr].special_graphic[special] = graphic;
385 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
390 /* correct special font/graphic mapping for cloned fonts for downwards
391 compatibility of PREVIEW fonts -- this is only needed for implicit
392 redefinition of special font by redefined base font, and only if other
393 fonts are cloned from this special font (like in the "Zelda" level set) */
394 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
396 int font_nr = font_to_graphic[i].font_nr;
397 int special = font_to_graphic[i].special;
398 int graphic = font_to_graphic[i].graphic;
400 if (IS_SPECIAL_GFX_ARG(special))
402 boolean special_redefined =
403 getImageListEntryFromImageID(graphic)->redefined;
404 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
406 if (special_cloned && !special_redefined)
410 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
412 int font_nr2 = font_to_graphic[j].font_nr;
413 int special2 = font_to_graphic[j].special;
414 int graphic2 = font_to_graphic[j].graphic;
416 if (IS_SPECIAL_GFX_ARG(special2) &&
417 graphic2 == graphic_info[graphic].clone_from)
419 font_info[font_nr].special_graphic[special] =
420 font_info[font_nr2].special_graphic[special2];
421 font_info[font_nr].special_bitmap_id[special] =
422 font_info[font_nr2].special_bitmap_id[special2];
429 /* reset non-redefined ".active" font graphics if normal font is redefined */
430 /* (this different treatment is needed because normal and active fonts are
431 independently defined ("active" is not a property of font definitions!) */
432 for (i = 0; i < NUM_FONTS; i++)
434 int font_nr_base = i;
435 int font_nr_active = FONT_ACTIVE(font_nr_base);
437 /* check only those fonts with exist as normal and ".active" variant */
438 if (font_nr_base != font_nr_active)
440 int base_graphic = font_info[font_nr_base].graphic;
441 int active_graphic = font_info[font_nr_active].graphic;
442 boolean base_redefined =
443 getImageListEntryFromImageID(base_graphic)->redefined;
444 boolean active_redefined =
445 getImageListEntryFromImageID(active_graphic)->redefined;
447 /* if the base font ("font.menu_1", for example) has been redefined,
448 but not the active font ("font.menu_1.active", for example), do not
449 use an existing (in this case considered obsolete) active font
450 anymore, but use the automatically determined default font */
451 if (base_redefined && !active_redefined)
452 font_info[font_nr_active].graphic = base_graphic;
454 /* now also check each "special" font (which may be the same as above) */
455 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
457 int base_graphic = font_info[font_nr_base].special_graphic[j];
458 int active_graphic = font_info[font_nr_active].special_graphic[j];
459 boolean base_redefined =
460 getImageListEntryFromImageID(base_graphic)->redefined;
461 boolean active_redefined =
462 getImageListEntryFromImageID(active_graphic)->redefined;
464 /* same as above, but check special graphic definitions, for example:
465 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
466 if (base_redefined && !active_redefined)
468 font_info[font_nr_active].special_graphic[j] =
469 font_info[font_nr_base].special_graphic[j];
470 font_info[font_nr_active].special_bitmap_id[j] =
471 font_info[font_nr_base].special_bitmap_id[j];
477 /* ---------- initialize font bitmap array ---------- */
479 if (font_bitmap_info != NULL)
480 FreeFontInfo(font_bitmap_info);
483 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
485 /* ---------- initialize font bitmap definitions ---------- */
487 for (i = 0; i < NUM_FONTS; i++)
489 if (i < NUM_INITIAL_FONTS)
491 font_bitmap_info[i] = font_initial[i];
495 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
497 int font_bitmap_id = font_info[i].special_bitmap_id[j];
498 int graphic = font_info[i].special_graphic[j];
500 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
501 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
503 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
504 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
507 /* copy font relevant information from graphics information */
508 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
509 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
510 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
511 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
512 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
514 font_bitmap_info[font_bitmap_id].draw_xoffset =
515 graphic_info[graphic].draw_xoffset;
516 font_bitmap_info[font_bitmap_id].draw_yoffset =
517 graphic_info[graphic].draw_yoffset;
519 font_bitmap_info[font_bitmap_id].num_chars =
520 graphic_info[graphic].anim_frames;
521 font_bitmap_info[font_bitmap_id].num_chars_per_line =
522 graphic_info[graphic].anim_frames_per_line;
526 InitFontInfo(font_bitmap_info, num_font_bitmaps,
527 getFontBitmapID, getFontFromToken);
530 void InitGlobalAnimGraphicInfo()
532 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
533 int num_property_mappings = getImageListPropertyMappingSize();
536 if (graphic_info == NULL) /* still at startup phase */
539 /* always start with reliable default values (no global animations) */
540 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
541 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
542 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
543 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
545 /* initialize global animation definitions from static configuration */
546 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
548 int j = GLOBAL_ANIM_ID_PART_BASE;
549 int k = GFX_SPECIAL_ARG_DEFAULT;
551 global_anim_info[i].graphic[j][k] = IMG_GLOBAL_ANIM_1_GFX + i;
554 /* initialize global animation definitions from dynamic configuration */
555 for (i = 0; i < num_property_mappings; i++)
557 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
558 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
559 int special = property_mapping[i].ext3_index;
560 int graphic = property_mapping[i].artwork_index;
562 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
565 /* set animation part to base part, if not specified */
566 if (!IS_GLOBAL_ANIM_PART(part_nr))
567 part_nr = GLOBAL_ANIM_ID_PART_BASE;
569 /* set animation screen to default, if not specified */
570 if (!IS_SPECIAL_GFX_ARG(special))
571 special = GFX_SPECIAL_ARG_DEFAULT;
573 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
577 printf("::: InitGlobalAnimGraphicInfo\n");
579 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
580 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
581 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
582 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
583 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
584 printf("::: - anim %d, part %d, mode %d => %d\n",
585 i, j, k, global_anim_info[i].graphic[j][k]);
589 void InitElementGraphicInfo()
591 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
592 int num_property_mappings = getImageListPropertyMappingSize();
595 if (graphic_info == NULL) /* still at startup phase */
598 /* set values to -1 to identify later as "uninitialized" values */
599 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
601 for (act = 0; act < NUM_ACTIONS; act++)
603 element_info[i].graphic[act] = -1;
604 element_info[i].crumbled[act] = -1;
606 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
608 element_info[i].direction_graphic[act][dir] = -1;
609 element_info[i].direction_crumbled[act][dir] = -1;
616 /* initialize normal element/graphic mapping from static configuration */
617 for (i = 0; element_to_graphic[i].element > -1; i++)
619 int element = element_to_graphic[i].element;
620 int action = element_to_graphic[i].action;
621 int direction = element_to_graphic[i].direction;
622 boolean crumbled = element_to_graphic[i].crumbled;
623 int graphic = element_to_graphic[i].graphic;
624 int base_graphic = el2baseimg(element);
626 if (graphic_info[graphic].bitmap == NULL)
629 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
632 boolean base_redefined =
633 getImageListEntryFromImageID(base_graphic)->redefined;
634 boolean act_dir_redefined =
635 getImageListEntryFromImageID(graphic)->redefined;
637 /* if the base graphic ("emerald", for example) has been redefined,
638 but not the action graphic ("emerald.falling", for example), do not
639 use an existing (in this case considered obsolete) action graphic
640 anymore, but use the automatically determined default graphic */
641 if (base_redefined && !act_dir_redefined)
646 action = ACTION_DEFAULT;
651 element_info[element].direction_crumbled[action][direction] = graphic;
653 element_info[element].crumbled[action] = graphic;
658 element_info[element].direction_graphic[action][direction] = graphic;
660 element_info[element].graphic[action] = graphic;
664 /* initialize normal element/graphic mapping from dynamic configuration */
665 for (i = 0; i < num_property_mappings; i++)
667 int element = property_mapping[i].base_index;
668 int action = property_mapping[i].ext1_index;
669 int direction = property_mapping[i].ext2_index;
670 int special = property_mapping[i].ext3_index;
671 int graphic = property_mapping[i].artwork_index;
672 boolean crumbled = FALSE;
674 if (special == GFX_SPECIAL_ARG_CRUMBLED)
680 if (graphic_info[graphic].bitmap == NULL)
683 if (element >= MAX_NUM_ELEMENTS || special != -1)
687 action = ACTION_DEFAULT;
692 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
693 element_info[element].direction_crumbled[action][dir] = -1;
696 element_info[element].direction_crumbled[action][direction] = graphic;
698 element_info[element].crumbled[action] = graphic;
703 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
704 element_info[element].direction_graphic[action][dir] = -1;
707 element_info[element].direction_graphic[action][direction] = graphic;
709 element_info[element].graphic[action] = graphic;
713 /* now copy all graphics that are defined to be cloned from other graphics */
714 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
716 int graphic = element_info[i].graphic[ACTION_DEFAULT];
717 int crumbled_like, diggable_like;
722 crumbled_like = graphic_info[graphic].crumbled_like;
723 diggable_like = graphic_info[graphic].diggable_like;
725 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
727 for (act = 0; act < NUM_ACTIONS; act++)
728 element_info[i].crumbled[act] =
729 element_info[crumbled_like].crumbled[act];
730 for (act = 0; act < NUM_ACTIONS; act++)
731 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
732 element_info[i].direction_crumbled[act][dir] =
733 element_info[crumbled_like].direction_crumbled[act][dir];
736 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
738 element_info[i].graphic[ACTION_DIGGING] =
739 element_info[diggable_like].graphic[ACTION_DIGGING];
740 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
741 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
742 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
746 /* set hardcoded definitions for some runtime elements without graphic */
747 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
749 /* set hardcoded definitions for some internal elements without graphic */
750 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
752 if (IS_EDITOR_CASCADE_INACTIVE(i))
753 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
754 else if (IS_EDITOR_CASCADE_ACTIVE(i))
755 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
758 /* now set all undefined/invalid graphics to -1 to set to default after it */
759 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
761 for (act = 0; act < NUM_ACTIONS; act++)
765 graphic = element_info[i].graphic[act];
766 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
767 element_info[i].graphic[act] = -1;
769 graphic = element_info[i].crumbled[act];
770 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
771 element_info[i].crumbled[act] = -1;
773 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
775 graphic = element_info[i].direction_graphic[act][dir];
776 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
777 element_info[i].direction_graphic[act][dir] = -1;
779 graphic = element_info[i].direction_crumbled[act][dir];
780 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
781 element_info[i].direction_crumbled[act][dir] = -1;
788 /* adjust graphics with 2nd tile for movement according to direction
789 (do this before correcting '-1' values to minimize calculations) */
790 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
792 for (act = 0; act < NUM_ACTIONS; act++)
794 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
796 int graphic = element_info[i].direction_graphic[act][dir];
797 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
799 if (act == ACTION_FALLING) /* special case */
800 graphic = element_info[i].graphic[act];
803 graphic_info[graphic].double_movement &&
804 graphic_info[graphic].swap_double_tiles != 0)
806 struct GraphicInfo *g = &graphic_info[graphic];
807 int src_x_front = g->src_x;
808 int src_y_front = g->src_y;
809 int src_x_back = g->src_x + g->offset2_x;
810 int src_y_back = g->src_y + g->offset2_y;
811 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
813 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
814 src_y_front < src_y_back);
815 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
816 boolean swap_movement_tiles_autodetected =
817 (!frames_are_ordered_diagonally &&
818 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
819 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
820 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
821 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
824 /* swap frontside and backside graphic tile coordinates, if needed */
825 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
827 /* get current (wrong) backside tile coordinates */
828 getFixedGraphicSourceExt(graphic, 0, &dummy,
829 &src_x_back, &src_y_back, TRUE);
831 /* set frontside tile coordinates to backside tile coordinates */
832 g->src_x = src_x_back;
833 g->src_y = src_y_back;
835 /* invert tile offset to point to new backside tile coordinates */
839 /* do not swap front and backside tiles again after correction */
840 g->swap_double_tiles = 0;
849 /* now set all '-1' values to element specific default values */
850 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
852 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
853 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
854 int default_direction_graphic[NUM_DIRECTIONS_FULL];
855 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
857 if (default_graphic == -1)
858 default_graphic = IMG_UNKNOWN;
860 if (default_crumbled == -1)
861 default_crumbled = default_graphic;
863 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
865 default_direction_graphic[dir] =
866 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
867 default_direction_crumbled[dir] =
868 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
870 if (default_direction_graphic[dir] == -1)
871 default_direction_graphic[dir] = default_graphic;
873 if (default_direction_crumbled[dir] == -1)
874 default_direction_crumbled[dir] = default_direction_graphic[dir];
877 for (act = 0; act < NUM_ACTIONS; act++)
879 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
880 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
881 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
882 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
883 act == ACTION_TURNING_FROM_RIGHT ||
884 act == ACTION_TURNING_FROM_UP ||
885 act == ACTION_TURNING_FROM_DOWN);
887 /* generic default action graphic (defined by "[default]" directive) */
888 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
889 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
890 int default_remove_graphic = IMG_EMPTY;
892 if (act_remove && default_action_graphic != -1)
893 default_remove_graphic = default_action_graphic;
895 /* look for special default action graphic (classic game specific) */
896 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
897 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
898 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
899 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
900 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
901 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
903 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
904 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
905 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
906 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
907 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
908 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
910 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
911 /* !!! make this better !!! */
912 if (i == EL_EMPTY_SPACE)
914 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
915 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
918 if (default_action_graphic == -1)
919 default_action_graphic = default_graphic;
921 if (default_action_crumbled == -1)
922 default_action_crumbled = default_action_graphic;
924 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
926 /* use action graphic as the default direction graphic, if undefined */
927 int default_action_direction_graphic = element_info[i].graphic[act];
928 int default_action_direction_crumbled = element_info[i].crumbled[act];
930 /* no graphic for current action -- use default direction graphic */
931 if (default_action_direction_graphic == -1)
932 default_action_direction_graphic =
933 (act_remove ? default_remove_graphic :
935 element_info[i].direction_graphic[ACTION_TURNING][dir] :
936 default_action_graphic != default_graphic ?
937 default_action_graphic :
938 default_direction_graphic[dir]);
940 if (element_info[i].direction_graphic[act][dir] == -1)
941 element_info[i].direction_graphic[act][dir] =
942 default_action_direction_graphic;
944 if (default_action_direction_crumbled == -1)
945 default_action_direction_crumbled =
946 element_info[i].direction_graphic[act][dir];
948 if (element_info[i].direction_crumbled[act][dir] == -1)
949 element_info[i].direction_crumbled[act][dir] =
950 default_action_direction_crumbled;
953 /* no graphic for this specific action -- use default action graphic */
954 if (element_info[i].graphic[act] == -1)
955 element_info[i].graphic[act] =
956 (act_remove ? default_remove_graphic :
957 act_turning ? element_info[i].graphic[ACTION_TURNING] :
958 default_action_graphic);
960 if (element_info[i].crumbled[act] == -1)
961 element_info[i].crumbled[act] = element_info[i].graphic[act];
968 void InitElementSpecialGraphicInfo()
970 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
971 int num_property_mappings = getImageListPropertyMappingSize();
974 /* always start with reliable default values */
975 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
976 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
977 element_info[i].special_graphic[j] =
978 element_info[i].graphic[ACTION_DEFAULT];
980 /* initialize special element/graphic mapping from static configuration */
981 for (i = 0; element_to_special_graphic[i].element > -1; i++)
983 int element = element_to_special_graphic[i].element;
984 int special = element_to_special_graphic[i].special;
985 int graphic = element_to_special_graphic[i].graphic;
986 int base_graphic = el2baseimg(element);
987 boolean base_redefined =
988 getImageListEntryFromImageID(base_graphic)->redefined;
989 boolean special_redefined =
990 getImageListEntryFromImageID(graphic)->redefined;
992 /* if the base graphic ("emerald", for example) has been redefined,
993 but not the special graphic ("emerald.EDITOR", for example), do not
994 use an existing (in this case considered obsolete) special graphic
995 anymore, but use the automatically created (down-scaled) graphic */
996 if (base_redefined && !special_redefined)
999 element_info[element].special_graphic[special] = graphic;
1002 /* initialize special element/graphic mapping from dynamic configuration */
1003 for (i = 0; i < num_property_mappings; i++)
1005 int element = property_mapping[i].base_index;
1006 int action = property_mapping[i].ext1_index;
1007 int direction = property_mapping[i].ext2_index;
1008 int special = property_mapping[i].ext3_index;
1009 int graphic = property_mapping[i].artwork_index;
1011 /* for action ".active", replace element with active element, if exists */
1012 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1014 element = ELEMENT_ACTIVE(element);
1018 if (element >= MAX_NUM_ELEMENTS)
1021 /* do not change special graphic if action or direction was specified */
1022 if (action != -1 || direction != -1)
1025 if (IS_SPECIAL_GFX_ARG(special))
1026 element_info[element].special_graphic[special] = graphic;
1029 /* now set all undefined/invalid graphics to default */
1030 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1031 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1032 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1033 element_info[i].special_graphic[j] =
1034 element_info[i].graphic[ACTION_DEFAULT];
1037 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1039 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1040 return get_parameter_value(value_raw, suffix, type);
1042 if (strEqual(value_raw, ARG_UNDEFINED))
1043 return ARG_UNDEFINED_VALUE;
1045 if (type == TYPE_ELEMENT)
1047 char *value = getHashEntry(element_token_hash, value_raw);
1051 Error(ERR_INFO_LINE, "-");
1052 Error(ERR_INFO, "warning: error found in config file:");
1053 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1054 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1055 Error(ERR_INFO, "custom graphic rejected for this element/action");
1056 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1057 Error(ERR_INFO_LINE, "-");
1060 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1062 else if (type == TYPE_GRAPHIC)
1064 char *value = getHashEntry(graphic_token_hash, value_raw);
1065 int fallback_graphic = IMG_CHAR_EXCLAM;
1069 Error(ERR_INFO_LINE, "-");
1070 Error(ERR_INFO, "warning: error found in config file:");
1071 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1072 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1073 Error(ERR_INFO, "custom graphic rejected for this element/action");
1074 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1075 Error(ERR_INFO_LINE, "-");
1078 return (value != NULL ? atoi(value) : fallback_graphic);
1084 static int get_scaled_graphic_width(int graphic)
1086 int original_width = getOriginalImageWidthFromImageID(graphic);
1087 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1089 return original_width * scale_up_factor;
1092 static int get_scaled_graphic_height(int graphic)
1094 int original_height = getOriginalImageHeightFromImageID(graphic);
1095 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1097 return original_height * scale_up_factor;
1100 static void set_graphic_parameters_ext(int graphic, int *parameter,
1101 Bitmap **src_bitmaps)
1103 struct GraphicInfo *g = &graphic_info[graphic];
1104 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1105 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1106 int anim_frames_per_line = 1;
1108 /* always start with reliable default values */
1109 g->src_image_width = 0;
1110 g->src_image_height = 0;
1113 g->width = TILEX; /* default for element graphics */
1114 g->height = TILEY; /* default for element graphics */
1115 g->offset_x = 0; /* one or both of these values ... */
1116 g->offset_y = 0; /* ... will be corrected later */
1117 g->offset2_x = 0; /* one or both of these values ... */
1118 g->offset2_y = 0; /* ... will be corrected later */
1119 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1120 g->crumbled_like = -1; /* do not use clone element */
1121 g->diggable_like = -1; /* do not use clone element */
1122 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1123 g->scale_up_factor = 1; /* default: no scaling up */
1124 g->tile_size = TILESIZE; /* default: standard tile size */
1125 g->clone_from = -1; /* do not use clone graphic */
1126 g->anim_delay_fixed = 0;
1127 g->anim_delay_random = 0;
1128 g->post_delay_fixed = 0;
1129 g->post_delay_random = 0;
1130 g->fade_mode = FADE_MODE_DEFAULT;
1134 g->align = ALIGN_CENTER; /* default for title screens */
1135 g->valign = VALIGN_MIDDLE; /* default for title screens */
1136 g->sort_priority = 0; /* default for title screens */
1138 g->style = STYLE_DEFAULT;
1140 g->bitmaps = src_bitmaps;
1141 g->bitmap = src_bitmap;
1143 /* optional zoom factor for scaling up the image to a larger size */
1144 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1145 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1146 if (g->scale_up_factor < 1)
1147 g->scale_up_factor = 1; /* no scaling */
1149 /* optional tile size for using non-standard image size */
1150 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1152 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1155 // CHECK: should tile sizes less than standard tile size be allowed?
1156 if (g->tile_size < TILESIZE)
1157 g->tile_size = TILESIZE; /* standard tile size */
1160 // when setting tile size, also set width and height accordingly
1161 g->width = g->tile_size;
1162 g->height = g->tile_size;
1165 if (g->use_image_size)
1167 /* set new default bitmap size (with scaling, but without small images) */
1168 g->width = get_scaled_graphic_width(graphic);
1169 g->height = get_scaled_graphic_height(graphic);
1172 /* optional width and height of each animation frame */
1173 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1174 g->width = parameter[GFX_ARG_WIDTH];
1175 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1176 g->height = parameter[GFX_ARG_HEIGHT];
1178 /* optional x and y tile position of animation frame sequence */
1179 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1180 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1181 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1182 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1184 /* optional x and y pixel position of animation frame sequence */
1185 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1186 g->src_x = parameter[GFX_ARG_X];
1187 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1188 g->src_y = parameter[GFX_ARG_Y];
1194 Error(ERR_INFO_LINE, "-");
1195 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1196 g->width, getTokenFromImageID(graphic), TILEX);
1197 Error(ERR_INFO_LINE, "-");
1199 g->width = TILEX; /* will be checked to be inside bitmap later */
1204 Error(ERR_INFO_LINE, "-");
1205 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1206 g->height, getTokenFromImageID(graphic), TILEY);
1207 Error(ERR_INFO_LINE, "-");
1209 g->height = TILEY; /* will be checked to be inside bitmap later */
1215 /* get final bitmap size (with scaling, but without small images) */
1216 int src_image_width = get_scaled_graphic_width(graphic);
1217 int src_image_height = get_scaled_graphic_height(graphic);
1219 if (src_image_width == 0 || src_image_height == 0)
1221 /* only happens when loaded outside artwork system (like "global.busy") */
1222 src_image_width = src_bitmap->width;
1223 src_image_height = src_bitmap->height;
1226 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1228 anim_frames_per_row = src_image_width / g->tile_size;
1229 anim_frames_per_col = src_image_height / g->tile_size;
1233 anim_frames_per_row = src_image_width / g->width;
1234 anim_frames_per_col = src_image_height / g->height;
1237 g->src_image_width = src_image_width;
1238 g->src_image_height = src_image_height;
1241 /* correct x or y offset dependent of vertical or horizontal frame order */
1242 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1244 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1245 parameter[GFX_ARG_OFFSET] : g->height);
1246 anim_frames_per_line = anim_frames_per_col;
1248 else /* frames are ordered horizontally */
1250 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1251 parameter[GFX_ARG_OFFSET] : g->width);
1252 anim_frames_per_line = anim_frames_per_row;
1255 /* optionally, the x and y offset of frames can be specified directly */
1256 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1257 g->offset_x = parameter[GFX_ARG_XOFFSET];
1258 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1259 g->offset_y = parameter[GFX_ARG_YOFFSET];
1261 /* optionally, moving animations may have separate start and end graphics */
1262 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1264 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1265 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1267 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1268 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1269 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1270 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1271 else /* frames are ordered horizontally */
1272 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1273 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1275 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1276 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1277 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1278 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1279 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1281 /* optionally, the second movement tile can be specified as start tile */
1282 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1283 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1285 /* automatically determine correct number of frames, if not defined */
1286 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1287 g->anim_frames = parameter[GFX_ARG_FRAMES];
1288 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1289 g->anim_frames = anim_frames_per_row;
1290 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1291 g->anim_frames = anim_frames_per_col;
1295 if (g->anim_frames == 0) /* frames must be at least 1 */
1298 g->anim_frames_per_line =
1299 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1300 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1302 g->anim_delay = parameter[GFX_ARG_DELAY];
1303 if (g->anim_delay == 0) /* delay must be at least 1 */
1306 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1308 /* automatically determine correct start frame, if not defined */
1309 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1310 g->anim_start_frame = 0;
1311 else if (g->anim_mode & ANIM_REVERSE)
1312 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1314 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1316 /* animation synchronized with global frame counter, not move position */
1317 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1319 /* optional element for cloning crumble graphics */
1320 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1321 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1323 /* optional element for cloning digging graphics */
1324 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1325 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1327 /* optional border size for "crumbling" diggable graphics */
1328 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1329 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1331 /* this is only used for player "boring" and "sleeping" actions */
1332 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1333 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1334 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1335 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1336 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1337 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1338 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1339 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1341 /* this is only used for toon animations */
1342 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1343 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1344 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1345 g->step_frames = parameter[GFX_ARG_STEP_FRAMES];
1346 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1347 g->direction = parameter[GFX_ARG_DIRECTION];
1348 g->position = parameter[GFX_ARG_POSITION];
1349 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1350 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1352 /* this is only used for drawing font characters */
1353 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1354 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1356 /* this is only used for drawing envelope graphics */
1357 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1359 /* optional graphic for cloning all graphics settings */
1360 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1361 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1363 /* optional settings for drawing title screens and title messages */
1364 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1365 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1366 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1367 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1368 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1369 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1370 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1371 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1372 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1373 g->align = parameter[GFX_ARG_ALIGN];
1374 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1375 g->valign = parameter[GFX_ARG_VALIGN];
1376 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1377 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1379 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1380 g->class = parameter[GFX_ARG_CLASS];
1381 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1382 g->style = parameter[GFX_ARG_STYLE];
1384 /* this is only used for drawing menu buttons and text */
1385 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1386 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1387 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1388 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1391 static void set_graphic_parameters(int graphic)
1393 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1394 char **parameter_raw = image->parameter;
1395 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1396 int parameter[NUM_GFX_ARGS];
1399 /* if fallback to default artwork is done, also use the default parameters */
1400 if (image->fallback_to_default)
1401 parameter_raw = image->default_parameter;
1403 /* get integer values from string parameters */
1404 for (i = 0; i < NUM_GFX_ARGS; i++)
1405 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1406 image_config_suffix[i].token,
1407 image_config_suffix[i].type);
1409 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1411 UPDATE_BUSY_STATE();
1414 static void set_cloned_graphic_parameters(int graphic)
1416 int fallback_graphic = IMG_CHAR_EXCLAM;
1417 int max_num_images = getImageListSize();
1418 int clone_graphic = graphic_info[graphic].clone_from;
1419 int num_references_followed = 1;
1421 while (graphic_info[clone_graphic].clone_from != -1 &&
1422 num_references_followed < max_num_images)
1424 clone_graphic = graphic_info[clone_graphic].clone_from;
1426 num_references_followed++;
1429 if (num_references_followed >= max_num_images)
1431 Error(ERR_INFO_LINE, "-");
1432 Error(ERR_INFO, "warning: error found in config file:");
1433 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1434 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1435 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1436 Error(ERR_INFO, "custom graphic rejected for this element/action");
1438 if (graphic == fallback_graphic)
1439 Error(ERR_EXIT, "no fallback graphic available");
1441 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1442 Error(ERR_INFO_LINE, "-");
1444 graphic_info[graphic] = graphic_info[fallback_graphic];
1448 graphic_info[graphic] = graphic_info[clone_graphic];
1449 graphic_info[graphic].clone_from = clone_graphic;
1453 static void InitGraphicInfo()
1455 int fallback_graphic = IMG_CHAR_EXCLAM;
1456 int num_images = getImageListSize();
1459 /* use image size as default values for width and height for these images */
1460 static int full_size_graphics[] =
1463 IMG_GLOBAL_BORDER_MAIN,
1464 IMG_GLOBAL_BORDER_SCORES,
1465 IMG_GLOBAL_BORDER_EDITOR,
1466 IMG_GLOBAL_BORDER_PLAYING,
1469 IMG_BACKGROUND_ENVELOPE_1,
1470 IMG_BACKGROUND_ENVELOPE_2,
1471 IMG_BACKGROUND_ENVELOPE_3,
1472 IMG_BACKGROUND_ENVELOPE_4,
1473 IMG_BACKGROUND_REQUEST,
1476 IMG_BACKGROUND_TITLE_INITIAL,
1477 IMG_BACKGROUND_TITLE,
1478 IMG_BACKGROUND_MAIN,
1479 IMG_BACKGROUND_LEVELS,
1480 IMG_BACKGROUND_LEVELNR,
1481 IMG_BACKGROUND_SCORES,
1482 IMG_BACKGROUND_EDITOR,
1483 IMG_BACKGROUND_INFO,
1484 IMG_BACKGROUND_INFO_ELEMENTS,
1485 IMG_BACKGROUND_INFO_MUSIC,
1486 IMG_BACKGROUND_INFO_CREDITS,
1487 IMG_BACKGROUND_INFO_PROGRAM,
1488 IMG_BACKGROUND_INFO_VERSION,
1489 IMG_BACKGROUND_INFO_LEVELSET,
1490 IMG_BACKGROUND_SETUP,
1491 IMG_BACKGROUND_PLAYING,
1492 IMG_BACKGROUND_DOOR,
1493 IMG_BACKGROUND_TAPE,
1494 IMG_BACKGROUND_PANEL,
1495 IMG_BACKGROUND_PALETTE,
1496 IMG_BACKGROUND_TOOLBOX,
1498 IMG_TITLESCREEN_INITIAL_1,
1499 IMG_TITLESCREEN_INITIAL_2,
1500 IMG_TITLESCREEN_INITIAL_3,
1501 IMG_TITLESCREEN_INITIAL_4,
1502 IMG_TITLESCREEN_INITIAL_5,
1509 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1510 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1511 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1512 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1513 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1514 IMG_BACKGROUND_TITLEMESSAGE_1,
1515 IMG_BACKGROUND_TITLEMESSAGE_2,
1516 IMG_BACKGROUND_TITLEMESSAGE_3,
1517 IMG_BACKGROUND_TITLEMESSAGE_4,
1518 IMG_BACKGROUND_TITLEMESSAGE_5,
1523 checked_free(graphic_info);
1525 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1527 /* initialize "use_image_size" flag with default value */
1528 for (i = 0; i < num_images; i++)
1529 graphic_info[i].use_image_size = FALSE;
1531 /* initialize "use_image_size" flag from static configuration above */
1532 for (i = 0; full_size_graphics[i] != -1; i++)
1533 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1535 /* first set all graphic paramaters ... */
1536 for (i = 0; i < num_images; i++)
1537 set_graphic_parameters(i);
1539 /* ... then copy these parameters for cloned graphics */
1540 for (i = 0; i < num_images; i++)
1541 if (graphic_info[i].clone_from != -1)
1542 set_cloned_graphic_parameters(i);
1544 for (i = 0; i < num_images; i++)
1549 int first_frame, last_frame;
1550 int src_bitmap_width, src_bitmap_height;
1552 /* now check if no animation frames are outside of the loaded image */
1554 if (graphic_info[i].bitmap == NULL)
1555 continue; /* skip check for optional images that are undefined */
1557 /* get image size (this can differ from the standard element tile size!) */
1558 width = graphic_info[i].width;
1559 height = graphic_info[i].height;
1561 /* get final bitmap size (with scaling, but without small images) */
1562 src_bitmap_width = graphic_info[i].src_image_width;
1563 src_bitmap_height = graphic_info[i].src_image_height;
1565 /* check if first animation frame is inside specified bitmap */
1568 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1570 /* this avoids calculating wrong start position for out-of-bounds frame */
1571 src_x = graphic_info[i].src_x;
1572 src_y = graphic_info[i].src_y;
1574 if (src_x < 0 || src_y < 0 ||
1575 src_x + width > src_bitmap_width ||
1576 src_y + height > src_bitmap_height)
1578 Error(ERR_INFO_LINE, "-");
1579 Error(ERR_INFO, "warning: error found in config file:");
1580 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1581 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1582 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1584 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1585 src_x, src_y, src_bitmap_width, src_bitmap_height);
1586 Error(ERR_INFO, "custom graphic rejected for this element/action");
1588 if (i == fallback_graphic)
1589 Error(ERR_EXIT, "no fallback graphic available");
1591 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1592 Error(ERR_INFO_LINE, "-");
1594 graphic_info[i] = graphic_info[fallback_graphic];
1597 /* check if last animation frame is inside specified bitmap */
1599 last_frame = graphic_info[i].anim_frames - 1;
1600 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1602 if (src_x < 0 || src_y < 0 ||
1603 src_x + width > src_bitmap_width ||
1604 src_y + height > src_bitmap_height)
1606 Error(ERR_INFO_LINE, "-");
1607 Error(ERR_INFO, "warning: error found in config file:");
1608 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1609 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1610 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1612 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1613 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1614 Error(ERR_INFO, "::: %d, %d", width, height);
1615 Error(ERR_INFO, "custom graphic rejected for this element/action");
1617 if (i == fallback_graphic)
1618 Error(ERR_EXIT, "no fallback graphic available");
1620 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1621 Error(ERR_INFO_LINE, "-");
1623 graphic_info[i] = graphic_info[fallback_graphic];
1628 static void InitGraphicCompatibilityInfo()
1630 struct FileInfo *fi_global_door =
1631 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1632 int num_images = getImageListSize();
1635 /* the following compatibility handling is needed for the following case:
1636 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1637 graphics mainly used for door and panel graphics, like editor, tape and
1638 in-game buttons with hard-coded bitmap positions and button sizes; as
1639 these graphics now have individual definitions, redefining "global.door"
1640 to change all these graphics at once like before does not work anymore
1641 (because all those individual definitions still have their default values);
1642 to solve this, remap all those individual definitions that are not
1643 redefined to the new bitmap of "global.door" if it was redefined */
1645 /* special compatibility handling if image "global.door" was redefined */
1646 if (fi_global_door->redefined)
1648 for (i = 0; i < num_images; i++)
1650 struct FileInfo *fi = getImageListEntryFromImageID(i);
1652 /* process only those images that still use the default settings */
1655 /* process all images which default to same image as "global.door" */
1656 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1658 // printf("::: special treatment needed for token '%s'\n", fi->token);
1660 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1666 InitGraphicCompatibilityInfo_Doors();
1669 static void InitElementSoundInfo()
1671 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1672 int num_property_mappings = getSoundListPropertyMappingSize();
1675 /* set values to -1 to identify later as "uninitialized" values */
1676 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1677 for (act = 0; act < NUM_ACTIONS; act++)
1678 element_info[i].sound[act] = -1;
1680 /* initialize element/sound mapping from static configuration */
1681 for (i = 0; element_to_sound[i].element > -1; i++)
1683 int element = element_to_sound[i].element;
1684 int action = element_to_sound[i].action;
1685 int sound = element_to_sound[i].sound;
1686 boolean is_class = element_to_sound[i].is_class;
1689 action = ACTION_DEFAULT;
1692 element_info[element].sound[action] = sound;
1694 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1695 if (strEqual(element_info[j].class_name,
1696 element_info[element].class_name))
1697 element_info[j].sound[action] = sound;
1700 /* initialize element class/sound mapping from dynamic configuration */
1701 for (i = 0; i < num_property_mappings; i++)
1703 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1704 int action = property_mapping[i].ext1_index;
1705 int sound = property_mapping[i].artwork_index;
1707 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1711 action = ACTION_DEFAULT;
1713 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1714 if (strEqual(element_info[j].class_name,
1715 element_info[element_class].class_name))
1716 element_info[j].sound[action] = sound;
1719 /* initialize element/sound mapping from dynamic configuration */
1720 for (i = 0; i < num_property_mappings; i++)
1722 int element = property_mapping[i].base_index;
1723 int action = property_mapping[i].ext1_index;
1724 int sound = property_mapping[i].artwork_index;
1726 if (element >= MAX_NUM_ELEMENTS)
1730 action = ACTION_DEFAULT;
1732 element_info[element].sound[action] = sound;
1735 /* now set all '-1' values to element specific default values */
1736 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1738 for (act = 0; act < NUM_ACTIONS; act++)
1740 /* generic default action sound (defined by "[default]" directive) */
1741 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1743 /* look for special default action sound (classic game specific) */
1744 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1745 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1746 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1747 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1748 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1749 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1751 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1752 /* !!! make this better !!! */
1753 if (i == EL_EMPTY_SPACE)
1754 default_action_sound = element_info[EL_DEFAULT].sound[act];
1756 /* no sound for this specific action -- use default action sound */
1757 if (element_info[i].sound[act] == -1)
1758 element_info[i].sound[act] = default_action_sound;
1762 /* copy sound settings to some elements that are only stored in level file
1763 in native R'n'D levels, but are used by game engine in native EM levels */
1764 for (i = 0; copy_properties[i][0] != -1; i++)
1765 for (j = 1; j <= 4; j++)
1766 for (act = 0; act < NUM_ACTIONS; act++)
1767 element_info[copy_properties[i][j]].sound[act] =
1768 element_info[copy_properties[i][0]].sound[act];
1771 static void InitGameModeSoundInfo()
1775 /* set values to -1 to identify later as "uninitialized" values */
1776 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1779 /* initialize gamemode/sound mapping from static configuration */
1780 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1782 int gamemode = gamemode_to_sound[i].gamemode;
1783 int sound = gamemode_to_sound[i].sound;
1786 gamemode = GAME_MODE_DEFAULT;
1788 menu.sound[gamemode] = sound;
1791 /* now set all '-1' values to levelset specific default values */
1792 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1793 if (menu.sound[i] == -1)
1794 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1797 static void set_sound_parameters(int sound, char **parameter_raw)
1799 int parameter[NUM_SND_ARGS];
1802 /* get integer values from string parameters */
1803 for (i = 0; i < NUM_SND_ARGS; i++)
1805 get_parameter_value(parameter_raw[i],
1806 sound_config_suffix[i].token,
1807 sound_config_suffix[i].type);
1809 /* explicit loop mode setting in configuration overrides default value */
1810 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1811 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1813 /* sound volume to change the original volume when loading the sound file */
1814 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1816 /* sound priority to give certain sounds a higher or lower priority */
1817 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1820 static void InitSoundInfo()
1822 int *sound_effect_properties;
1823 int num_sounds = getSoundListSize();
1826 checked_free(sound_info);
1828 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1829 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1831 /* initialize sound effect for all elements to "no sound" */
1832 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1833 for (j = 0; j < NUM_ACTIONS; j++)
1834 element_info[i].sound[j] = SND_UNDEFINED;
1836 for (i = 0; i < num_sounds; i++)
1838 struct FileInfo *sound = getSoundListEntry(i);
1839 int len_effect_text = strlen(sound->token);
1841 sound_effect_properties[i] = ACTION_OTHER;
1842 sound_info[i].loop = FALSE; /* default: play sound only once */
1844 /* determine all loop sounds and identify certain sound classes */
1846 for (j = 0; element_action_info[j].suffix; j++)
1848 int len_action_text = strlen(element_action_info[j].suffix);
1850 if (len_action_text < len_effect_text &&
1851 strEqual(&sound->token[len_effect_text - len_action_text],
1852 element_action_info[j].suffix))
1854 sound_effect_properties[i] = element_action_info[j].value;
1855 sound_info[i].loop = element_action_info[j].is_loop_sound;
1861 /* associate elements and some selected sound actions */
1863 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1865 if (element_info[j].class_name)
1867 int len_class_text = strlen(element_info[j].class_name);
1869 if (len_class_text + 1 < len_effect_text &&
1870 strncmp(sound->token,
1871 element_info[j].class_name, len_class_text) == 0 &&
1872 sound->token[len_class_text] == '.')
1874 int sound_action_value = sound_effect_properties[i];
1876 element_info[j].sound[sound_action_value] = i;
1881 set_sound_parameters(i, sound->parameter);
1884 free(sound_effect_properties);
1887 static void InitGameModeMusicInfo()
1889 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1890 int num_property_mappings = getMusicListPropertyMappingSize();
1891 int default_levelset_music = -1;
1894 /* set values to -1 to identify later as "uninitialized" values */
1895 for (i = 0; i < MAX_LEVELS; i++)
1896 levelset.music[i] = -1;
1897 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1900 /* initialize gamemode/music mapping from static configuration */
1901 for (i = 0; gamemode_to_music[i].music > -1; i++)
1903 int gamemode = gamemode_to_music[i].gamemode;
1904 int music = gamemode_to_music[i].music;
1907 gamemode = GAME_MODE_DEFAULT;
1909 menu.music[gamemode] = music;
1912 /* initialize gamemode/music mapping from dynamic configuration */
1913 for (i = 0; i < num_property_mappings; i++)
1915 int prefix = property_mapping[i].base_index;
1916 int gamemode = property_mapping[i].ext1_index;
1917 int level = property_mapping[i].ext2_index;
1918 int music = property_mapping[i].artwork_index;
1920 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1924 gamemode = GAME_MODE_DEFAULT;
1926 /* level specific music only allowed for in-game music */
1927 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1928 gamemode = GAME_MODE_PLAYING;
1933 default_levelset_music = music;
1936 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1937 levelset.music[level] = music;
1938 if (gamemode != GAME_MODE_PLAYING)
1939 menu.music[gamemode] = music;
1942 /* now set all '-1' values to menu specific default values */
1943 /* (undefined values of "levelset.music[]" might stay at "-1" to
1944 allow dynamic selection of music files from music directory!) */
1945 for (i = 0; i < MAX_LEVELS; i++)
1946 if (levelset.music[i] == -1)
1947 levelset.music[i] = default_levelset_music;
1948 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1949 if (menu.music[i] == -1)
1950 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1953 static void set_music_parameters(int music, char **parameter_raw)
1955 int parameter[NUM_MUS_ARGS];
1958 /* get integer values from string parameters */
1959 for (i = 0; i < NUM_MUS_ARGS; i++)
1961 get_parameter_value(parameter_raw[i],
1962 music_config_suffix[i].token,
1963 music_config_suffix[i].type);
1965 /* explicit loop mode setting in configuration overrides default value */
1966 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1967 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1970 static void InitMusicInfo()
1972 int num_music = getMusicListSize();
1975 checked_free(music_info);
1977 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1979 for (i = 0; i < num_music; i++)
1981 struct FileInfo *music = getMusicListEntry(i);
1982 int len_music_text = strlen(music->token);
1984 music_info[i].loop = TRUE; /* default: play music in loop mode */
1986 /* determine all loop music */
1988 for (j = 0; music_prefix_info[j].prefix; j++)
1990 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1992 if (len_prefix_text < len_music_text &&
1993 strncmp(music->token,
1994 music_prefix_info[j].prefix, len_prefix_text) == 0)
1996 music_info[i].loop = music_prefix_info[j].is_loop_music;
2002 set_music_parameters(i, music->parameter);
2006 static void ReinitializeGraphics()
2008 print_timestamp_init("ReinitializeGraphics");
2010 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2012 InitGraphicInfo(); /* graphic properties mapping */
2013 print_timestamp_time("InitGraphicInfo");
2014 InitElementGraphicInfo(); /* element game graphic mapping */
2015 print_timestamp_time("InitElementGraphicInfo");
2016 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2017 print_timestamp_time("InitElementSpecialGraphicInfo");
2019 InitElementSmallImages(); /* scale elements to all needed sizes */
2020 print_timestamp_time("InitElementSmallImages");
2021 InitScaledImages(); /* scale all other images, if needed */
2022 print_timestamp_time("InitScaledImages");
2023 InitBitmapPointers(); /* set standard size bitmap pointers */
2024 print_timestamp_time("InitBitmapPointers");
2025 InitFontGraphicInfo(); /* initialize text drawing functions */
2026 print_timestamp_time("InitFontGraphicInfo");
2027 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2028 print_timestamp_time("InitGlobalAnimGraphicInfo");
2030 InitImageTextures(); /* create textures for certain images */
2031 print_timestamp_time("InitImageTextures");
2033 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2034 print_timestamp_time("InitGraphicInfo_EM");
2036 InitGraphicCompatibilityInfo();
2037 print_timestamp_time("InitGraphicCompatibilityInfo");
2039 SetMainBackgroundImage(IMG_BACKGROUND);
2040 print_timestamp_time("SetMainBackgroundImage");
2041 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2042 print_timestamp_time("SetDoorBackgroundImage");
2045 print_timestamp_time("InitGadgets");
2047 print_timestamp_time("InitToons");
2049 print_timestamp_time("InitDoors");
2051 print_timestamp_done("ReinitializeGraphics");
2054 static void ReinitializeSounds()
2056 InitSoundInfo(); /* sound properties mapping */
2057 InitElementSoundInfo(); /* element game sound mapping */
2058 InitGameModeSoundInfo(); /* game mode sound mapping */
2060 InitPlayLevelSound(); /* internal game sound settings */
2063 static void ReinitializeMusic()
2065 InitMusicInfo(); /* music properties mapping */
2066 InitGameModeMusicInfo(); /* game mode music mapping */
2069 static int get_special_property_bit(int element, int property_bit_nr)
2071 struct PropertyBitInfo
2077 static struct PropertyBitInfo pb_can_move_into_acid[] =
2079 /* the player may be able fall into acid when gravity is activated */
2084 { EL_SP_MURPHY, 0 },
2085 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2087 /* all elements that can move may be able to also move into acid */
2090 { EL_BUG_RIGHT, 1 },
2093 { EL_SPACESHIP, 2 },
2094 { EL_SPACESHIP_LEFT, 2 },
2095 { EL_SPACESHIP_RIGHT, 2 },
2096 { EL_SPACESHIP_UP, 2 },
2097 { EL_SPACESHIP_DOWN, 2 },
2098 { EL_BD_BUTTERFLY, 3 },
2099 { EL_BD_BUTTERFLY_LEFT, 3 },
2100 { EL_BD_BUTTERFLY_RIGHT, 3 },
2101 { EL_BD_BUTTERFLY_UP, 3 },
2102 { EL_BD_BUTTERFLY_DOWN, 3 },
2103 { EL_BD_FIREFLY, 4 },
2104 { EL_BD_FIREFLY_LEFT, 4 },
2105 { EL_BD_FIREFLY_RIGHT, 4 },
2106 { EL_BD_FIREFLY_UP, 4 },
2107 { EL_BD_FIREFLY_DOWN, 4 },
2109 { EL_YAMYAM_LEFT, 5 },
2110 { EL_YAMYAM_RIGHT, 5 },
2111 { EL_YAMYAM_UP, 5 },
2112 { EL_YAMYAM_DOWN, 5 },
2113 { EL_DARK_YAMYAM, 6 },
2116 { EL_PACMAN_LEFT, 8 },
2117 { EL_PACMAN_RIGHT, 8 },
2118 { EL_PACMAN_UP, 8 },
2119 { EL_PACMAN_DOWN, 8 },
2121 { EL_MOLE_LEFT, 9 },
2122 { EL_MOLE_RIGHT, 9 },
2124 { EL_MOLE_DOWN, 9 },
2128 { EL_SATELLITE, 13 },
2129 { EL_SP_SNIKSNAK, 14 },
2130 { EL_SP_ELECTRON, 15 },
2133 { EL_EMC_ANDROID, 18 },
2138 static struct PropertyBitInfo pb_dont_collide_with[] =
2140 { EL_SP_SNIKSNAK, 0 },
2141 { EL_SP_ELECTRON, 1 },
2149 struct PropertyBitInfo *pb_info;
2152 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2153 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2158 struct PropertyBitInfo *pb_info = NULL;
2161 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2162 if (pb_definition[i].bit_nr == property_bit_nr)
2163 pb_info = pb_definition[i].pb_info;
2165 if (pb_info == NULL)
2168 for (i = 0; pb_info[i].element != -1; i++)
2169 if (pb_info[i].element == element)
2170 return pb_info[i].bit_nr;
2175 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2176 boolean property_value)
2178 int bit_nr = get_special_property_bit(element, property_bit_nr);
2183 *bitfield |= (1 << bit_nr);
2185 *bitfield &= ~(1 << bit_nr);
2189 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2191 int bit_nr = get_special_property_bit(element, property_bit_nr);
2194 return ((*bitfield & (1 << bit_nr)) != 0);
2199 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2201 static int group_nr;
2202 static struct ElementGroupInfo *group;
2203 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2206 if (actual_group == NULL) /* not yet initialized */
2209 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2211 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2212 group_element - EL_GROUP_START + 1);
2214 /* replace element which caused too deep recursion by question mark */
2215 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2220 if (recursion_depth == 0) /* initialization */
2222 group = actual_group;
2223 group_nr = GROUP_NR(group_element);
2225 group->num_elements_resolved = 0;
2226 group->choice_pos = 0;
2228 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2229 element_info[i].in_group[group_nr] = FALSE;
2232 for (i = 0; i < actual_group->num_elements; i++)
2234 int element = actual_group->element[i];
2236 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2239 if (IS_GROUP_ELEMENT(element))
2240 ResolveGroupElementExt(element, recursion_depth + 1);
2243 group->element_resolved[group->num_elements_resolved++] = element;
2244 element_info[element].in_group[group_nr] = TRUE;
2249 void ResolveGroupElement(int group_element)
2251 ResolveGroupElementExt(group_element, 0);
2254 void InitElementPropertiesStatic()
2256 static boolean clipboard_elements_initialized = FALSE;
2258 static int ep_diggable[] =
2263 EL_SP_BUGGY_BASE_ACTIVATING,
2266 EL_INVISIBLE_SAND_ACTIVE,
2269 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2270 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2275 EL_SP_BUGGY_BASE_ACTIVE,
2282 static int ep_collectible_only[] =
2304 EL_DYNABOMB_INCREASE_NUMBER,
2305 EL_DYNABOMB_INCREASE_SIZE,
2306 EL_DYNABOMB_INCREASE_POWER,
2324 /* !!! handle separately !!! */
2325 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2331 static int ep_dont_run_into[] =
2333 /* same elements as in 'ep_dont_touch' */
2339 /* same elements as in 'ep_dont_collide_with' */
2351 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2356 EL_SP_BUGGY_BASE_ACTIVE,
2363 static int ep_dont_collide_with[] =
2365 /* same elements as in 'ep_dont_touch' */
2382 static int ep_dont_touch[] =
2392 static int ep_indestructible[] =
2396 EL_ACID_POOL_TOPLEFT,
2397 EL_ACID_POOL_TOPRIGHT,
2398 EL_ACID_POOL_BOTTOMLEFT,
2399 EL_ACID_POOL_BOTTOM,
2400 EL_ACID_POOL_BOTTOMRIGHT,
2401 EL_SP_HARDWARE_GRAY,
2402 EL_SP_HARDWARE_GREEN,
2403 EL_SP_HARDWARE_BLUE,
2405 EL_SP_HARDWARE_YELLOW,
2406 EL_SP_HARDWARE_BASE_1,
2407 EL_SP_HARDWARE_BASE_2,
2408 EL_SP_HARDWARE_BASE_3,
2409 EL_SP_HARDWARE_BASE_4,
2410 EL_SP_HARDWARE_BASE_5,
2411 EL_SP_HARDWARE_BASE_6,
2412 EL_INVISIBLE_STEELWALL,
2413 EL_INVISIBLE_STEELWALL_ACTIVE,
2414 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2415 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2416 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2417 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2418 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2419 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2420 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2421 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2422 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2423 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2424 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2425 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2427 EL_LIGHT_SWITCH_ACTIVE,
2428 EL_SIGN_EXCLAMATION,
2429 EL_SIGN_RADIOACTIVITY,
2436 EL_SIGN_ENTRY_FORBIDDEN,
2437 EL_SIGN_EMERGENCY_EXIT,
2445 EL_STEEL_EXIT_CLOSED,
2447 EL_STEEL_EXIT_OPENING,
2448 EL_STEEL_EXIT_CLOSING,
2449 EL_EM_STEEL_EXIT_CLOSED,
2450 EL_EM_STEEL_EXIT_OPEN,
2451 EL_EM_STEEL_EXIT_OPENING,
2452 EL_EM_STEEL_EXIT_CLOSING,
2453 EL_DC_STEELWALL_1_LEFT,
2454 EL_DC_STEELWALL_1_RIGHT,
2455 EL_DC_STEELWALL_1_TOP,
2456 EL_DC_STEELWALL_1_BOTTOM,
2457 EL_DC_STEELWALL_1_HORIZONTAL,
2458 EL_DC_STEELWALL_1_VERTICAL,
2459 EL_DC_STEELWALL_1_TOPLEFT,
2460 EL_DC_STEELWALL_1_TOPRIGHT,
2461 EL_DC_STEELWALL_1_BOTTOMLEFT,
2462 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2463 EL_DC_STEELWALL_1_TOPLEFT_2,
2464 EL_DC_STEELWALL_1_TOPRIGHT_2,
2465 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2466 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2467 EL_DC_STEELWALL_2_LEFT,
2468 EL_DC_STEELWALL_2_RIGHT,
2469 EL_DC_STEELWALL_2_TOP,
2470 EL_DC_STEELWALL_2_BOTTOM,
2471 EL_DC_STEELWALL_2_HORIZONTAL,
2472 EL_DC_STEELWALL_2_VERTICAL,
2473 EL_DC_STEELWALL_2_MIDDLE,
2474 EL_DC_STEELWALL_2_SINGLE,
2475 EL_STEELWALL_SLIPPERY,
2489 EL_GATE_1_GRAY_ACTIVE,
2490 EL_GATE_2_GRAY_ACTIVE,
2491 EL_GATE_3_GRAY_ACTIVE,
2492 EL_GATE_4_GRAY_ACTIVE,
2501 EL_EM_GATE_1_GRAY_ACTIVE,
2502 EL_EM_GATE_2_GRAY_ACTIVE,
2503 EL_EM_GATE_3_GRAY_ACTIVE,
2504 EL_EM_GATE_4_GRAY_ACTIVE,
2513 EL_EMC_GATE_5_GRAY_ACTIVE,
2514 EL_EMC_GATE_6_GRAY_ACTIVE,
2515 EL_EMC_GATE_7_GRAY_ACTIVE,
2516 EL_EMC_GATE_8_GRAY_ACTIVE,
2518 EL_DC_GATE_WHITE_GRAY,
2519 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2520 EL_DC_GATE_FAKE_GRAY,
2522 EL_SWITCHGATE_OPENING,
2523 EL_SWITCHGATE_CLOSED,
2524 EL_SWITCHGATE_CLOSING,
2525 EL_DC_SWITCHGATE_SWITCH_UP,
2526 EL_DC_SWITCHGATE_SWITCH_DOWN,
2528 EL_TIMEGATE_OPENING,
2530 EL_TIMEGATE_CLOSING,
2531 EL_DC_TIMEGATE_SWITCH,
2532 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2536 EL_TUBE_VERTICAL_LEFT,
2537 EL_TUBE_VERTICAL_RIGHT,
2538 EL_TUBE_HORIZONTAL_UP,
2539 EL_TUBE_HORIZONTAL_DOWN,
2544 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2545 EL_EXPANDABLE_STEELWALL_VERTICAL,
2546 EL_EXPANDABLE_STEELWALL_ANY,
2551 static int ep_slippery[] =
2565 EL_ROBOT_WHEEL_ACTIVE,
2571 EL_ACID_POOL_TOPLEFT,
2572 EL_ACID_POOL_TOPRIGHT,
2582 EL_STEELWALL_SLIPPERY,
2585 EL_EMC_WALL_SLIPPERY_1,
2586 EL_EMC_WALL_SLIPPERY_2,
2587 EL_EMC_WALL_SLIPPERY_3,
2588 EL_EMC_WALL_SLIPPERY_4,
2590 EL_EMC_MAGIC_BALL_ACTIVE,
2595 static int ep_can_change[] =
2600 static int ep_can_move[] =
2602 /* same elements as in 'pb_can_move_into_acid' */
2625 static int ep_can_fall[] =
2639 EL_QUICKSAND_FAST_FULL,
2641 EL_BD_MAGIC_WALL_FULL,
2642 EL_DC_MAGIC_WALL_FULL,
2656 static int ep_can_smash_player[] =
2682 static int ep_can_smash_enemies[] =
2691 static int ep_can_smash_everything[] =
2700 static int ep_explodes_by_fire[] =
2702 /* same elements as in 'ep_explodes_impact' */
2707 /* same elements as in 'ep_explodes_smashed' */
2717 EL_EM_DYNAMITE_ACTIVE,
2718 EL_DYNABOMB_PLAYER_1_ACTIVE,
2719 EL_DYNABOMB_PLAYER_2_ACTIVE,
2720 EL_DYNABOMB_PLAYER_3_ACTIVE,
2721 EL_DYNABOMB_PLAYER_4_ACTIVE,
2722 EL_DYNABOMB_INCREASE_NUMBER,
2723 EL_DYNABOMB_INCREASE_SIZE,
2724 EL_DYNABOMB_INCREASE_POWER,
2725 EL_SP_DISK_RED_ACTIVE,
2739 static int ep_explodes_smashed[] =
2741 /* same elements as in 'ep_explodes_impact' */
2755 static int ep_explodes_impact[] =
2764 static int ep_walkable_over[] =
2768 EL_SOKOBAN_FIELD_EMPTY,
2775 EL_EM_STEEL_EXIT_OPEN,
2776 EL_EM_STEEL_EXIT_OPENING,
2785 EL_GATE_1_GRAY_ACTIVE,
2786 EL_GATE_2_GRAY_ACTIVE,
2787 EL_GATE_3_GRAY_ACTIVE,
2788 EL_GATE_4_GRAY_ACTIVE,
2796 static int ep_walkable_inside[] =
2801 EL_TUBE_VERTICAL_LEFT,
2802 EL_TUBE_VERTICAL_RIGHT,
2803 EL_TUBE_HORIZONTAL_UP,
2804 EL_TUBE_HORIZONTAL_DOWN,
2813 static int ep_walkable_under[] =
2818 static int ep_passable_over[] =
2828 EL_EM_GATE_1_GRAY_ACTIVE,
2829 EL_EM_GATE_2_GRAY_ACTIVE,
2830 EL_EM_GATE_3_GRAY_ACTIVE,
2831 EL_EM_GATE_4_GRAY_ACTIVE,
2840 EL_EMC_GATE_5_GRAY_ACTIVE,
2841 EL_EMC_GATE_6_GRAY_ACTIVE,
2842 EL_EMC_GATE_7_GRAY_ACTIVE,
2843 EL_EMC_GATE_8_GRAY_ACTIVE,
2845 EL_DC_GATE_WHITE_GRAY,
2846 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2853 static int ep_passable_inside[] =
2859 EL_SP_PORT_HORIZONTAL,
2860 EL_SP_PORT_VERTICAL,
2862 EL_SP_GRAVITY_PORT_LEFT,
2863 EL_SP_GRAVITY_PORT_RIGHT,
2864 EL_SP_GRAVITY_PORT_UP,
2865 EL_SP_GRAVITY_PORT_DOWN,
2866 EL_SP_GRAVITY_ON_PORT_LEFT,
2867 EL_SP_GRAVITY_ON_PORT_RIGHT,
2868 EL_SP_GRAVITY_ON_PORT_UP,
2869 EL_SP_GRAVITY_ON_PORT_DOWN,
2870 EL_SP_GRAVITY_OFF_PORT_LEFT,
2871 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2872 EL_SP_GRAVITY_OFF_PORT_UP,
2873 EL_SP_GRAVITY_OFF_PORT_DOWN,
2878 static int ep_passable_under[] =
2883 static int ep_droppable[] =
2888 static int ep_explodes_1x1_old[] =
2893 static int ep_pushable[] =
2905 EL_SOKOBAN_FIELD_FULL,
2914 static int ep_explodes_cross_old[] =
2919 static int ep_protected[] =
2921 /* same elements as in 'ep_walkable_inside' */
2925 EL_TUBE_VERTICAL_LEFT,
2926 EL_TUBE_VERTICAL_RIGHT,
2927 EL_TUBE_HORIZONTAL_UP,
2928 EL_TUBE_HORIZONTAL_DOWN,
2934 /* same elements as in 'ep_passable_over' */
2943 EL_EM_GATE_1_GRAY_ACTIVE,
2944 EL_EM_GATE_2_GRAY_ACTIVE,
2945 EL_EM_GATE_3_GRAY_ACTIVE,
2946 EL_EM_GATE_4_GRAY_ACTIVE,
2955 EL_EMC_GATE_5_GRAY_ACTIVE,
2956 EL_EMC_GATE_6_GRAY_ACTIVE,
2957 EL_EMC_GATE_7_GRAY_ACTIVE,
2958 EL_EMC_GATE_8_GRAY_ACTIVE,
2960 EL_DC_GATE_WHITE_GRAY,
2961 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2965 /* same elements as in 'ep_passable_inside' */
2970 EL_SP_PORT_HORIZONTAL,
2971 EL_SP_PORT_VERTICAL,
2973 EL_SP_GRAVITY_PORT_LEFT,
2974 EL_SP_GRAVITY_PORT_RIGHT,
2975 EL_SP_GRAVITY_PORT_UP,
2976 EL_SP_GRAVITY_PORT_DOWN,
2977 EL_SP_GRAVITY_ON_PORT_LEFT,
2978 EL_SP_GRAVITY_ON_PORT_RIGHT,
2979 EL_SP_GRAVITY_ON_PORT_UP,
2980 EL_SP_GRAVITY_ON_PORT_DOWN,
2981 EL_SP_GRAVITY_OFF_PORT_LEFT,
2982 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2983 EL_SP_GRAVITY_OFF_PORT_UP,
2984 EL_SP_GRAVITY_OFF_PORT_DOWN,
2989 static int ep_throwable[] =
2994 static int ep_can_explode[] =
2996 /* same elements as in 'ep_explodes_impact' */
3001 /* same elements as in 'ep_explodes_smashed' */
3007 /* elements that can explode by explosion or by dragonfire */
3011 EL_EM_DYNAMITE_ACTIVE,
3012 EL_DYNABOMB_PLAYER_1_ACTIVE,
3013 EL_DYNABOMB_PLAYER_2_ACTIVE,
3014 EL_DYNABOMB_PLAYER_3_ACTIVE,
3015 EL_DYNABOMB_PLAYER_4_ACTIVE,
3016 EL_DYNABOMB_INCREASE_NUMBER,
3017 EL_DYNABOMB_INCREASE_SIZE,
3018 EL_DYNABOMB_INCREASE_POWER,
3019 EL_SP_DISK_RED_ACTIVE,
3027 /* elements that can explode only by explosion */
3033 static int ep_gravity_reachable[] =
3039 EL_INVISIBLE_SAND_ACTIVE,
3044 EL_SP_PORT_HORIZONTAL,
3045 EL_SP_PORT_VERTICAL,
3047 EL_SP_GRAVITY_PORT_LEFT,
3048 EL_SP_GRAVITY_PORT_RIGHT,
3049 EL_SP_GRAVITY_PORT_UP,
3050 EL_SP_GRAVITY_PORT_DOWN,
3051 EL_SP_GRAVITY_ON_PORT_LEFT,
3052 EL_SP_GRAVITY_ON_PORT_RIGHT,
3053 EL_SP_GRAVITY_ON_PORT_UP,
3054 EL_SP_GRAVITY_ON_PORT_DOWN,
3055 EL_SP_GRAVITY_OFF_PORT_LEFT,
3056 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3057 EL_SP_GRAVITY_OFF_PORT_UP,
3058 EL_SP_GRAVITY_OFF_PORT_DOWN,
3064 static int ep_player[] =
3071 EL_SOKOBAN_FIELD_PLAYER,
3077 static int ep_can_pass_magic_wall[] =
3091 static int ep_can_pass_dc_magic_wall[] =
3107 static int ep_switchable[] =
3111 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3112 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3113 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3114 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3115 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3116 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3117 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3118 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3119 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3120 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3121 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3122 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3123 EL_SWITCHGATE_SWITCH_UP,
3124 EL_SWITCHGATE_SWITCH_DOWN,
3125 EL_DC_SWITCHGATE_SWITCH_UP,
3126 EL_DC_SWITCHGATE_SWITCH_DOWN,
3128 EL_LIGHT_SWITCH_ACTIVE,
3130 EL_DC_TIMEGATE_SWITCH,
3131 EL_BALLOON_SWITCH_LEFT,
3132 EL_BALLOON_SWITCH_RIGHT,
3133 EL_BALLOON_SWITCH_UP,
3134 EL_BALLOON_SWITCH_DOWN,
3135 EL_BALLOON_SWITCH_ANY,
3136 EL_BALLOON_SWITCH_NONE,
3139 EL_EMC_MAGIC_BALL_SWITCH,
3140 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3145 static int ep_bd_element[] =
3179 static int ep_sp_element[] =
3181 /* should always be valid */
3184 /* standard classic Supaplex elements */
3191 EL_SP_HARDWARE_GRAY,
3199 EL_SP_GRAVITY_PORT_RIGHT,
3200 EL_SP_GRAVITY_PORT_DOWN,
3201 EL_SP_GRAVITY_PORT_LEFT,
3202 EL_SP_GRAVITY_PORT_UP,
3207 EL_SP_PORT_VERTICAL,
3208 EL_SP_PORT_HORIZONTAL,
3214 EL_SP_HARDWARE_BASE_1,
3215 EL_SP_HARDWARE_GREEN,
3216 EL_SP_HARDWARE_BLUE,
3218 EL_SP_HARDWARE_YELLOW,
3219 EL_SP_HARDWARE_BASE_2,
3220 EL_SP_HARDWARE_BASE_3,
3221 EL_SP_HARDWARE_BASE_4,
3222 EL_SP_HARDWARE_BASE_5,
3223 EL_SP_HARDWARE_BASE_6,
3227 /* additional elements that appeared in newer Supaplex levels */
3230 /* additional gravity port elements (not switching, but setting gravity) */
3231 EL_SP_GRAVITY_ON_PORT_LEFT,
3232 EL_SP_GRAVITY_ON_PORT_RIGHT,
3233 EL_SP_GRAVITY_ON_PORT_UP,
3234 EL_SP_GRAVITY_ON_PORT_DOWN,
3235 EL_SP_GRAVITY_OFF_PORT_LEFT,
3236 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3237 EL_SP_GRAVITY_OFF_PORT_UP,
3238 EL_SP_GRAVITY_OFF_PORT_DOWN,
3240 /* more than one Murphy in a level results in an inactive clone */
3243 /* runtime Supaplex elements */
3244 EL_SP_DISK_RED_ACTIVE,
3245 EL_SP_TERMINAL_ACTIVE,
3246 EL_SP_BUGGY_BASE_ACTIVATING,
3247 EL_SP_BUGGY_BASE_ACTIVE,
3254 static int ep_sb_element[] =
3259 EL_SOKOBAN_FIELD_EMPTY,
3260 EL_SOKOBAN_FIELD_FULL,
3261 EL_SOKOBAN_FIELD_PLAYER,
3266 EL_INVISIBLE_STEELWALL,
3271 static int ep_gem[] =
3283 static int ep_food_dark_yamyam[] =
3311 static int ep_food_penguin[] =
3325 static int ep_food_pig[] =
3337 static int ep_historic_wall[] =
3348 EL_GATE_1_GRAY_ACTIVE,
3349 EL_GATE_2_GRAY_ACTIVE,
3350 EL_GATE_3_GRAY_ACTIVE,
3351 EL_GATE_4_GRAY_ACTIVE,
3360 EL_EM_GATE_1_GRAY_ACTIVE,
3361 EL_EM_GATE_2_GRAY_ACTIVE,
3362 EL_EM_GATE_3_GRAY_ACTIVE,
3363 EL_EM_GATE_4_GRAY_ACTIVE,
3370 EL_EXPANDABLE_WALL_HORIZONTAL,
3371 EL_EXPANDABLE_WALL_VERTICAL,
3372 EL_EXPANDABLE_WALL_ANY,
3373 EL_EXPANDABLE_WALL_GROWING,
3374 EL_BD_EXPANDABLE_WALL,
3381 EL_SP_HARDWARE_GRAY,
3382 EL_SP_HARDWARE_GREEN,
3383 EL_SP_HARDWARE_BLUE,
3385 EL_SP_HARDWARE_YELLOW,
3386 EL_SP_HARDWARE_BASE_1,
3387 EL_SP_HARDWARE_BASE_2,
3388 EL_SP_HARDWARE_BASE_3,
3389 EL_SP_HARDWARE_BASE_4,
3390 EL_SP_HARDWARE_BASE_5,
3391 EL_SP_HARDWARE_BASE_6,
3393 EL_SP_TERMINAL_ACTIVE,
3396 EL_INVISIBLE_STEELWALL,
3397 EL_INVISIBLE_STEELWALL_ACTIVE,
3399 EL_INVISIBLE_WALL_ACTIVE,
3400 EL_STEELWALL_SLIPPERY,
3417 static int ep_historic_solid[] =
3421 EL_EXPANDABLE_WALL_HORIZONTAL,
3422 EL_EXPANDABLE_WALL_VERTICAL,
3423 EL_EXPANDABLE_WALL_ANY,
3424 EL_BD_EXPANDABLE_WALL,
3437 EL_QUICKSAND_FILLING,
3438 EL_QUICKSAND_EMPTYING,
3440 EL_MAGIC_WALL_ACTIVE,
3441 EL_MAGIC_WALL_EMPTYING,
3442 EL_MAGIC_WALL_FILLING,
3446 EL_BD_MAGIC_WALL_ACTIVE,
3447 EL_BD_MAGIC_WALL_EMPTYING,
3448 EL_BD_MAGIC_WALL_FULL,
3449 EL_BD_MAGIC_WALL_FILLING,
3450 EL_BD_MAGIC_WALL_DEAD,
3459 EL_SP_TERMINAL_ACTIVE,
3463 EL_INVISIBLE_WALL_ACTIVE,
3464 EL_SWITCHGATE_SWITCH_UP,
3465 EL_SWITCHGATE_SWITCH_DOWN,
3466 EL_DC_SWITCHGATE_SWITCH_UP,
3467 EL_DC_SWITCHGATE_SWITCH_DOWN,
3469 EL_TIMEGATE_SWITCH_ACTIVE,
3470 EL_DC_TIMEGATE_SWITCH,
3471 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3483 /* the following elements are a direct copy of "indestructible" elements,
3484 except "EL_ACID", which is "indestructible", but not "solid"! */
3489 EL_ACID_POOL_TOPLEFT,
3490 EL_ACID_POOL_TOPRIGHT,
3491 EL_ACID_POOL_BOTTOMLEFT,
3492 EL_ACID_POOL_BOTTOM,
3493 EL_ACID_POOL_BOTTOMRIGHT,
3494 EL_SP_HARDWARE_GRAY,
3495 EL_SP_HARDWARE_GREEN,
3496 EL_SP_HARDWARE_BLUE,
3498 EL_SP_HARDWARE_YELLOW,
3499 EL_SP_HARDWARE_BASE_1,
3500 EL_SP_HARDWARE_BASE_2,
3501 EL_SP_HARDWARE_BASE_3,
3502 EL_SP_HARDWARE_BASE_4,
3503 EL_SP_HARDWARE_BASE_5,
3504 EL_SP_HARDWARE_BASE_6,
3505 EL_INVISIBLE_STEELWALL,
3506 EL_INVISIBLE_STEELWALL_ACTIVE,
3507 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3508 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3509 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3510 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3511 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3512 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3513 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3514 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3515 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3516 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3517 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3518 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3520 EL_LIGHT_SWITCH_ACTIVE,
3521 EL_SIGN_EXCLAMATION,
3522 EL_SIGN_RADIOACTIVITY,
3529 EL_SIGN_ENTRY_FORBIDDEN,
3530 EL_SIGN_EMERGENCY_EXIT,
3538 EL_STEEL_EXIT_CLOSED,
3540 EL_DC_STEELWALL_1_LEFT,
3541 EL_DC_STEELWALL_1_RIGHT,
3542 EL_DC_STEELWALL_1_TOP,
3543 EL_DC_STEELWALL_1_BOTTOM,
3544 EL_DC_STEELWALL_1_HORIZONTAL,
3545 EL_DC_STEELWALL_1_VERTICAL,
3546 EL_DC_STEELWALL_1_TOPLEFT,
3547 EL_DC_STEELWALL_1_TOPRIGHT,
3548 EL_DC_STEELWALL_1_BOTTOMLEFT,
3549 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3550 EL_DC_STEELWALL_1_TOPLEFT_2,
3551 EL_DC_STEELWALL_1_TOPRIGHT_2,
3552 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3553 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3554 EL_DC_STEELWALL_2_LEFT,
3555 EL_DC_STEELWALL_2_RIGHT,
3556 EL_DC_STEELWALL_2_TOP,
3557 EL_DC_STEELWALL_2_BOTTOM,
3558 EL_DC_STEELWALL_2_HORIZONTAL,
3559 EL_DC_STEELWALL_2_VERTICAL,
3560 EL_DC_STEELWALL_2_MIDDLE,
3561 EL_DC_STEELWALL_2_SINGLE,
3562 EL_STEELWALL_SLIPPERY,
3576 EL_GATE_1_GRAY_ACTIVE,
3577 EL_GATE_2_GRAY_ACTIVE,
3578 EL_GATE_3_GRAY_ACTIVE,
3579 EL_GATE_4_GRAY_ACTIVE,
3588 EL_EM_GATE_1_GRAY_ACTIVE,
3589 EL_EM_GATE_2_GRAY_ACTIVE,
3590 EL_EM_GATE_3_GRAY_ACTIVE,
3591 EL_EM_GATE_4_GRAY_ACTIVE,
3593 EL_SWITCHGATE_OPENING,
3594 EL_SWITCHGATE_CLOSED,
3595 EL_SWITCHGATE_CLOSING,
3597 EL_TIMEGATE_OPENING,
3599 EL_TIMEGATE_CLOSING,
3603 EL_TUBE_VERTICAL_LEFT,
3604 EL_TUBE_VERTICAL_RIGHT,
3605 EL_TUBE_HORIZONTAL_UP,
3606 EL_TUBE_HORIZONTAL_DOWN,
3615 static int ep_classic_enemy[] =
3632 static int ep_belt[] =
3634 EL_CONVEYOR_BELT_1_LEFT,
3635 EL_CONVEYOR_BELT_1_MIDDLE,
3636 EL_CONVEYOR_BELT_1_RIGHT,
3637 EL_CONVEYOR_BELT_2_LEFT,
3638 EL_CONVEYOR_BELT_2_MIDDLE,
3639 EL_CONVEYOR_BELT_2_RIGHT,
3640 EL_CONVEYOR_BELT_3_LEFT,
3641 EL_CONVEYOR_BELT_3_MIDDLE,
3642 EL_CONVEYOR_BELT_3_RIGHT,
3643 EL_CONVEYOR_BELT_4_LEFT,
3644 EL_CONVEYOR_BELT_4_MIDDLE,
3645 EL_CONVEYOR_BELT_4_RIGHT,
3650 static int ep_belt_active[] =
3652 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3653 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3654 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3655 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3656 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3657 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3658 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3659 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3660 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3661 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3662 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3663 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3668 static int ep_belt_switch[] =
3670 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3671 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3672 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3673 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3674 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3675 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3676 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3677 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3678 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3679 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3680 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3681 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3686 static int ep_tube[] =
3693 EL_TUBE_HORIZONTAL_UP,
3694 EL_TUBE_HORIZONTAL_DOWN,
3696 EL_TUBE_VERTICAL_LEFT,
3697 EL_TUBE_VERTICAL_RIGHT,
3703 static int ep_acid_pool[] =
3705 EL_ACID_POOL_TOPLEFT,
3706 EL_ACID_POOL_TOPRIGHT,
3707 EL_ACID_POOL_BOTTOMLEFT,
3708 EL_ACID_POOL_BOTTOM,
3709 EL_ACID_POOL_BOTTOMRIGHT,
3714 static int ep_keygate[] =
3724 EL_GATE_1_GRAY_ACTIVE,
3725 EL_GATE_2_GRAY_ACTIVE,
3726 EL_GATE_3_GRAY_ACTIVE,
3727 EL_GATE_4_GRAY_ACTIVE,
3736 EL_EM_GATE_1_GRAY_ACTIVE,
3737 EL_EM_GATE_2_GRAY_ACTIVE,
3738 EL_EM_GATE_3_GRAY_ACTIVE,
3739 EL_EM_GATE_4_GRAY_ACTIVE,
3748 EL_EMC_GATE_5_GRAY_ACTIVE,
3749 EL_EMC_GATE_6_GRAY_ACTIVE,
3750 EL_EMC_GATE_7_GRAY_ACTIVE,
3751 EL_EMC_GATE_8_GRAY_ACTIVE,
3753 EL_DC_GATE_WHITE_GRAY,
3754 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3759 static int ep_amoeboid[] =
3771 static int ep_amoebalive[] =
3782 static int ep_has_editor_content[] =
3788 EL_SOKOBAN_FIELD_PLAYER,
3805 static int ep_can_turn_each_move[] =
3807 /* !!! do something with this one !!! */
3811 static int ep_can_grow[] =
3825 static int ep_active_bomb[] =
3828 EL_EM_DYNAMITE_ACTIVE,
3829 EL_DYNABOMB_PLAYER_1_ACTIVE,
3830 EL_DYNABOMB_PLAYER_2_ACTIVE,
3831 EL_DYNABOMB_PLAYER_3_ACTIVE,
3832 EL_DYNABOMB_PLAYER_4_ACTIVE,
3833 EL_SP_DISK_RED_ACTIVE,
3838 static int ep_inactive[] =
3848 EL_QUICKSAND_FAST_EMPTY,
3871 EL_GATE_1_GRAY_ACTIVE,
3872 EL_GATE_2_GRAY_ACTIVE,
3873 EL_GATE_3_GRAY_ACTIVE,
3874 EL_GATE_4_GRAY_ACTIVE,
3883 EL_EM_GATE_1_GRAY_ACTIVE,
3884 EL_EM_GATE_2_GRAY_ACTIVE,
3885 EL_EM_GATE_3_GRAY_ACTIVE,
3886 EL_EM_GATE_4_GRAY_ACTIVE,
3895 EL_EMC_GATE_5_GRAY_ACTIVE,
3896 EL_EMC_GATE_6_GRAY_ACTIVE,
3897 EL_EMC_GATE_7_GRAY_ACTIVE,
3898 EL_EMC_GATE_8_GRAY_ACTIVE,
3900 EL_DC_GATE_WHITE_GRAY,
3901 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3902 EL_DC_GATE_FAKE_GRAY,
3905 EL_INVISIBLE_STEELWALL,
3913 EL_WALL_EMERALD_YELLOW,
3914 EL_DYNABOMB_INCREASE_NUMBER,
3915 EL_DYNABOMB_INCREASE_SIZE,
3916 EL_DYNABOMB_INCREASE_POWER,
3920 EL_SOKOBAN_FIELD_EMPTY,
3921 EL_SOKOBAN_FIELD_FULL,
3922 EL_WALL_EMERALD_RED,
3923 EL_WALL_EMERALD_PURPLE,
3924 EL_ACID_POOL_TOPLEFT,
3925 EL_ACID_POOL_TOPRIGHT,
3926 EL_ACID_POOL_BOTTOMLEFT,
3927 EL_ACID_POOL_BOTTOM,
3928 EL_ACID_POOL_BOTTOMRIGHT,
3932 EL_BD_MAGIC_WALL_DEAD,
3934 EL_DC_MAGIC_WALL_DEAD,
3935 EL_AMOEBA_TO_DIAMOND,
3943 EL_SP_GRAVITY_PORT_RIGHT,
3944 EL_SP_GRAVITY_PORT_DOWN,
3945 EL_SP_GRAVITY_PORT_LEFT,
3946 EL_SP_GRAVITY_PORT_UP,
3947 EL_SP_PORT_HORIZONTAL,
3948 EL_SP_PORT_VERTICAL,
3959 EL_SP_HARDWARE_GRAY,
3960 EL_SP_HARDWARE_GREEN,
3961 EL_SP_HARDWARE_BLUE,
3963 EL_SP_HARDWARE_YELLOW,
3964 EL_SP_HARDWARE_BASE_1,
3965 EL_SP_HARDWARE_BASE_2,
3966 EL_SP_HARDWARE_BASE_3,
3967 EL_SP_HARDWARE_BASE_4,
3968 EL_SP_HARDWARE_BASE_5,
3969 EL_SP_HARDWARE_BASE_6,
3970 EL_SP_GRAVITY_ON_PORT_LEFT,
3971 EL_SP_GRAVITY_ON_PORT_RIGHT,
3972 EL_SP_GRAVITY_ON_PORT_UP,
3973 EL_SP_GRAVITY_ON_PORT_DOWN,
3974 EL_SP_GRAVITY_OFF_PORT_LEFT,
3975 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3976 EL_SP_GRAVITY_OFF_PORT_UP,
3977 EL_SP_GRAVITY_OFF_PORT_DOWN,
3978 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3979 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3980 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3981 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3982 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3983 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3984 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3985 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3986 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3987 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3988 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3989 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3990 EL_SIGN_EXCLAMATION,
3991 EL_SIGN_RADIOACTIVITY,
3998 EL_SIGN_ENTRY_FORBIDDEN,
3999 EL_SIGN_EMERGENCY_EXIT,
4007 EL_DC_STEELWALL_1_LEFT,
4008 EL_DC_STEELWALL_1_RIGHT,
4009 EL_DC_STEELWALL_1_TOP,
4010 EL_DC_STEELWALL_1_BOTTOM,
4011 EL_DC_STEELWALL_1_HORIZONTAL,
4012 EL_DC_STEELWALL_1_VERTICAL,
4013 EL_DC_STEELWALL_1_TOPLEFT,
4014 EL_DC_STEELWALL_1_TOPRIGHT,
4015 EL_DC_STEELWALL_1_BOTTOMLEFT,
4016 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4017 EL_DC_STEELWALL_1_TOPLEFT_2,
4018 EL_DC_STEELWALL_1_TOPRIGHT_2,
4019 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4020 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4021 EL_DC_STEELWALL_2_LEFT,
4022 EL_DC_STEELWALL_2_RIGHT,
4023 EL_DC_STEELWALL_2_TOP,
4024 EL_DC_STEELWALL_2_BOTTOM,
4025 EL_DC_STEELWALL_2_HORIZONTAL,
4026 EL_DC_STEELWALL_2_VERTICAL,
4027 EL_DC_STEELWALL_2_MIDDLE,
4028 EL_DC_STEELWALL_2_SINGLE,
4029 EL_STEELWALL_SLIPPERY,
4034 EL_EMC_WALL_SLIPPERY_1,
4035 EL_EMC_WALL_SLIPPERY_2,
4036 EL_EMC_WALL_SLIPPERY_3,
4037 EL_EMC_WALL_SLIPPERY_4,
4058 static int ep_em_slippery_wall[] =
4063 static int ep_gfx_crumbled[] =
4074 static int ep_editor_cascade_active[] =
4076 EL_INTERNAL_CASCADE_BD_ACTIVE,
4077 EL_INTERNAL_CASCADE_EM_ACTIVE,
4078 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4079 EL_INTERNAL_CASCADE_RND_ACTIVE,
4080 EL_INTERNAL_CASCADE_SB_ACTIVE,
4081 EL_INTERNAL_CASCADE_SP_ACTIVE,
4082 EL_INTERNAL_CASCADE_DC_ACTIVE,
4083 EL_INTERNAL_CASCADE_DX_ACTIVE,
4084 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4085 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4086 EL_INTERNAL_CASCADE_CE_ACTIVE,
4087 EL_INTERNAL_CASCADE_GE_ACTIVE,
4088 EL_INTERNAL_CASCADE_REF_ACTIVE,
4089 EL_INTERNAL_CASCADE_USER_ACTIVE,
4090 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4095 static int ep_editor_cascade_inactive[] =
4097 EL_INTERNAL_CASCADE_BD,
4098 EL_INTERNAL_CASCADE_EM,
4099 EL_INTERNAL_CASCADE_EMC,
4100 EL_INTERNAL_CASCADE_RND,
4101 EL_INTERNAL_CASCADE_SB,
4102 EL_INTERNAL_CASCADE_SP,
4103 EL_INTERNAL_CASCADE_DC,
4104 EL_INTERNAL_CASCADE_DX,
4105 EL_INTERNAL_CASCADE_CHARS,
4106 EL_INTERNAL_CASCADE_STEEL_CHARS,
4107 EL_INTERNAL_CASCADE_CE,
4108 EL_INTERNAL_CASCADE_GE,
4109 EL_INTERNAL_CASCADE_REF,
4110 EL_INTERNAL_CASCADE_USER,
4111 EL_INTERNAL_CASCADE_DYNAMIC,
4116 static int ep_obsolete[] =
4120 EL_EM_KEY_1_FILE_OBSOLETE,
4121 EL_EM_KEY_2_FILE_OBSOLETE,
4122 EL_EM_KEY_3_FILE_OBSOLETE,
4123 EL_EM_KEY_4_FILE_OBSOLETE,
4124 EL_ENVELOPE_OBSOLETE,
4133 } element_properties[] =
4135 { ep_diggable, EP_DIGGABLE },
4136 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4137 { ep_dont_run_into, EP_DONT_RUN_INTO },
4138 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4139 { ep_dont_touch, EP_DONT_TOUCH },
4140 { ep_indestructible, EP_INDESTRUCTIBLE },
4141 { ep_slippery, EP_SLIPPERY },
4142 { ep_can_change, EP_CAN_CHANGE },
4143 { ep_can_move, EP_CAN_MOVE },
4144 { ep_can_fall, EP_CAN_FALL },
4145 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4146 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4147 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4148 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4149 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4150 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4151 { ep_walkable_over, EP_WALKABLE_OVER },
4152 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4153 { ep_walkable_under, EP_WALKABLE_UNDER },
4154 { ep_passable_over, EP_PASSABLE_OVER },
4155 { ep_passable_inside, EP_PASSABLE_INSIDE },
4156 { ep_passable_under, EP_PASSABLE_UNDER },
4157 { ep_droppable, EP_DROPPABLE },
4158 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4159 { ep_pushable, EP_PUSHABLE },
4160 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4161 { ep_protected, EP_PROTECTED },
4162 { ep_throwable, EP_THROWABLE },
4163 { ep_can_explode, EP_CAN_EXPLODE },
4164 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4166 { ep_player, EP_PLAYER },
4167 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4168 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4169 { ep_switchable, EP_SWITCHABLE },
4170 { ep_bd_element, EP_BD_ELEMENT },
4171 { ep_sp_element, EP_SP_ELEMENT },
4172 { ep_sb_element, EP_SB_ELEMENT },
4174 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4175 { ep_food_penguin, EP_FOOD_PENGUIN },
4176 { ep_food_pig, EP_FOOD_PIG },
4177 { ep_historic_wall, EP_HISTORIC_WALL },
4178 { ep_historic_solid, EP_HISTORIC_SOLID },
4179 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4180 { ep_belt, EP_BELT },
4181 { ep_belt_active, EP_BELT_ACTIVE },
4182 { ep_belt_switch, EP_BELT_SWITCH },
4183 { ep_tube, EP_TUBE },
4184 { ep_acid_pool, EP_ACID_POOL },
4185 { ep_keygate, EP_KEYGATE },
4186 { ep_amoeboid, EP_AMOEBOID },
4187 { ep_amoebalive, EP_AMOEBALIVE },
4188 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4189 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4190 { ep_can_grow, EP_CAN_GROW },
4191 { ep_active_bomb, EP_ACTIVE_BOMB },
4192 { ep_inactive, EP_INACTIVE },
4194 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4196 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4198 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4199 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4201 { ep_obsolete, EP_OBSOLETE },
4208 /* always start with reliable default values (element has no properties) */
4209 /* (but never initialize clipboard elements after the very first time) */
4210 /* (to be able to use clipboard elements between several levels) */
4211 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4212 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4213 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4214 SET_PROPERTY(i, j, FALSE);
4216 /* set all base element properties from above array definitions */
4217 for (i = 0; element_properties[i].elements != NULL; i++)
4218 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4219 SET_PROPERTY((element_properties[i].elements)[j],
4220 element_properties[i].property, TRUE);
4222 /* copy properties to some elements that are only stored in level file */
4223 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4224 for (j = 0; copy_properties[j][0] != -1; j++)
4225 if (HAS_PROPERTY(copy_properties[j][0], i))
4226 for (k = 1; k <= 4; k++)
4227 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4229 /* set static element properties that are not listed in array definitions */
4230 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4231 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4233 clipboard_elements_initialized = TRUE;
4236 void InitElementPropertiesEngine(int engine_version)
4238 static int no_wall_properties[] =
4241 EP_COLLECTIBLE_ONLY,
4243 EP_DONT_COLLIDE_WITH,
4246 EP_CAN_SMASH_PLAYER,
4247 EP_CAN_SMASH_ENEMIES,
4248 EP_CAN_SMASH_EVERYTHING,
4253 EP_FOOD_DARK_YAMYAM,
4269 /* important: after initialization in InitElementPropertiesStatic(), the
4270 elements are not again initialized to a default value; therefore all
4271 changes have to make sure that they leave the element with a defined
4272 property (which means that conditional property changes must be set to
4273 a reliable default value before) */
4275 /* resolve group elements */
4276 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4277 ResolveGroupElement(EL_GROUP_START + i);
4279 /* set all special, combined or engine dependent element properties */
4280 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4282 /* do not change (already initialized) clipboard elements here */
4283 if (IS_CLIPBOARD_ELEMENT(i))
4286 /* ---------- INACTIVE ------------------------------------------------- */
4287 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4288 i <= EL_CHAR_END) ||
4289 (i >= EL_STEEL_CHAR_START &&
4290 i <= EL_STEEL_CHAR_END)));
4292 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4293 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4294 IS_WALKABLE_INSIDE(i) ||
4295 IS_WALKABLE_UNDER(i)));
4297 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4298 IS_PASSABLE_INSIDE(i) ||
4299 IS_PASSABLE_UNDER(i)));
4301 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4302 IS_PASSABLE_OVER(i)));
4304 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4305 IS_PASSABLE_INSIDE(i)));
4307 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4308 IS_PASSABLE_UNDER(i)));
4310 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4313 /* ---------- COLLECTIBLE ---------------------------------------------- */
4314 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4318 /* ---------- SNAPPABLE ------------------------------------------------ */
4319 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4320 IS_COLLECTIBLE(i) ||
4324 /* ---------- WALL ----------------------------------------------------- */
4325 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4327 for (j = 0; no_wall_properties[j] != -1; j++)
4328 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4329 i >= EL_FIRST_RUNTIME_UNREAL)
4330 SET_PROPERTY(i, EP_WALL, FALSE);
4332 if (IS_HISTORIC_WALL(i))
4333 SET_PROPERTY(i, EP_WALL, TRUE);
4335 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4336 if (engine_version < VERSION_IDENT(2,2,0,0))
4337 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4339 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4341 !IS_COLLECTIBLE(i)));
4343 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4344 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4345 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4347 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4348 IS_INDESTRUCTIBLE(i)));
4350 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4352 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4353 else if (engine_version < VERSION_IDENT(2,2,0,0))
4354 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4356 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4360 if (IS_CUSTOM_ELEMENT(i))
4362 /* these are additional properties which are initially false when set */
4364 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4366 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4367 if (DONT_COLLIDE_WITH(i))
4368 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4370 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4371 if (CAN_SMASH_EVERYTHING(i))
4372 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4373 if (CAN_SMASH_ENEMIES(i))
4374 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4377 /* ---------- CAN_SMASH ------------------------------------------------ */
4378 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4379 CAN_SMASH_ENEMIES(i) ||
4380 CAN_SMASH_EVERYTHING(i)));
4382 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4383 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4384 EXPLODES_BY_FIRE(i)));
4386 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4387 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4388 EXPLODES_SMASHED(i)));
4390 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4391 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4392 EXPLODES_IMPACT(i)));
4394 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4395 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4397 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4398 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4399 i == EL_BLACK_ORB));
4401 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4402 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4404 IS_CUSTOM_ELEMENT(i)));
4406 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4407 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4408 i == EL_SP_ELECTRON));
4410 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4411 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4412 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4413 getMoveIntoAcidProperty(&level, i));
4415 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4416 if (MAYBE_DONT_COLLIDE_WITH(i))
4417 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4418 getDontCollideWithProperty(&level, i));
4420 /* ---------- SP_PORT -------------------------------------------------- */
4421 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4422 IS_PASSABLE_INSIDE(i)));
4424 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4425 for (j = 0; j < level.num_android_clone_elements; j++)
4426 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4428 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4430 /* ---------- CAN_CHANGE ----------------------------------------------- */
4431 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4432 for (j = 0; j < element_info[i].num_change_pages; j++)
4433 if (element_info[i].change_page[j].can_change)
4434 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4436 /* ---------- HAS_ACTION ----------------------------------------------- */
4437 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4438 for (j = 0; j < element_info[i].num_change_pages; j++)
4439 if (element_info[i].change_page[j].has_action)
4440 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4442 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4443 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4446 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4447 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4448 element_info[i].crumbled[ACTION_DEFAULT] !=
4449 element_info[i].graphic[ACTION_DEFAULT]);
4451 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4452 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4453 IS_EDITOR_CASCADE_INACTIVE(i)));
4456 /* dynamically adjust element properties according to game engine version */
4458 static int ep_em_slippery_wall[] =
4463 EL_EXPANDABLE_WALL_HORIZONTAL,
4464 EL_EXPANDABLE_WALL_VERTICAL,
4465 EL_EXPANDABLE_WALL_ANY,
4466 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4467 EL_EXPANDABLE_STEELWALL_VERTICAL,
4468 EL_EXPANDABLE_STEELWALL_ANY,
4469 EL_EXPANDABLE_STEELWALL_GROWING,
4473 static int ep_em_explodes_by_fire[] =
4476 EL_EM_DYNAMITE_ACTIVE,
4481 /* special EM style gems behaviour */
4482 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4483 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4484 level.em_slippery_gems);
4486 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4487 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4488 (level.em_slippery_gems &&
4489 engine_version > VERSION_IDENT(2,0,1,0)));
4491 /* special EM style explosion behaviour regarding chain reactions */
4492 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4493 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4494 level.em_explodes_by_fire);
4497 /* this is needed because some graphics depend on element properties */
4498 if (game_status == GAME_MODE_PLAYING)
4499 InitElementGraphicInfo();
4502 void InitElementPropertiesAfterLoading(int engine_version)
4506 /* set some other uninitialized values of custom elements in older levels */
4507 if (engine_version < VERSION_IDENT(3,1,0,0))
4509 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4511 int element = EL_CUSTOM_START + i;
4513 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4515 element_info[element].explosion_delay = 17;
4516 element_info[element].ignition_delay = 8;
4521 void InitElementPropertiesGfxElement()
4525 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4527 struct ElementInfo *ei = &element_info[i];
4529 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4533 static void InitGlobal()
4538 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4540 /* check if element_name_info entry defined for each element in "main.h" */
4541 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4542 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4544 element_info[i].token_name = element_name_info[i].token_name;
4545 element_info[i].class_name = element_name_info[i].class_name;
4546 element_info[i].editor_description= element_name_info[i].editor_description;
4549 /* create hash from image config list */
4550 image_config_hash = newSetupFileHash();
4551 for (i = 0; image_config[i].token != NULL; i++)
4552 setHashEntry(image_config_hash,
4553 image_config[i].token,
4554 image_config[i].value);
4556 /* create hash from element token list */
4557 element_token_hash = newSetupFileHash();
4558 for (i = 0; element_name_info[i].token_name != NULL; i++)
4559 setHashEntry(element_token_hash,
4560 element_name_info[i].token_name,
4563 /* create hash from graphic token list */
4564 graphic_token_hash = newSetupFileHash();
4565 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4566 if (strSuffix(image_config[i].value, ".png") ||
4567 strSuffix(image_config[i].value, ".pcx") ||
4568 strSuffix(image_config[i].value, ".wav") ||
4569 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4570 setHashEntry(graphic_token_hash,
4571 image_config[i].token,
4572 int2str(graphic++, 0));
4574 /* create hash from font token list */
4575 font_token_hash = newSetupFileHash();
4576 for (i = 0; font_info[i].token_name != NULL; i++)
4577 setHashEntry(font_token_hash,
4578 font_info[i].token_name,
4581 /* set default filenames for all cloned graphics in static configuration */
4582 for (i = 0; image_config[i].token != NULL; i++)
4584 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4586 char *token = image_config[i].token;
4587 char *token_clone_from = getStringCat2(token, ".clone_from");
4588 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4590 if (token_cloned != NULL)
4592 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4594 if (value_cloned != NULL)
4596 /* set default filename in static configuration */
4597 image_config[i].value = value_cloned;
4599 /* set default filename in image config hash */
4600 setHashEntry(image_config_hash, token, value_cloned);
4604 free(token_clone_from);
4608 /* always start with reliable default values (all elements) */
4609 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4610 ActiveElement[i] = i;
4612 /* now add all entries that have an active state (active elements) */
4613 for (i = 0; element_with_active_state[i].element != -1; i++)
4615 int element = element_with_active_state[i].element;
4616 int element_active = element_with_active_state[i].element_active;
4618 ActiveElement[element] = element_active;
4621 /* always start with reliable default values (all buttons) */
4622 for (i = 0; i < NUM_IMAGE_FILES; i++)
4623 ActiveButton[i] = i;
4625 /* now add all entries that have an active state (active buttons) */
4626 for (i = 0; button_with_active_state[i].button != -1; i++)
4628 int button = button_with_active_state[i].button;
4629 int button_active = button_with_active_state[i].button_active;
4631 ActiveButton[button] = button_active;
4634 /* always start with reliable default values (all fonts) */
4635 for (i = 0; i < NUM_FONTS; i++)
4638 /* now add all entries that have an active state (active fonts) */
4639 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4641 int font = font_with_active_state[i].font_nr;
4642 int font_active = font_with_active_state[i].font_nr_active;
4644 ActiveFont[font] = font_active;
4647 global.autoplay_leveldir = NULL;
4648 global.convert_leveldir = NULL;
4649 global.create_images_dir = NULL;
4651 global.frames_per_second = 0;
4653 global.border_status = GAME_MODE_MAIN;
4655 global.use_envelope_request = FALSE;
4658 void Execute_Command(char *command)
4662 if (strEqual(command, "print graphicsinfo.conf"))
4664 Print("# You can configure additional/alternative image files here.\n");
4665 Print("# (The entries below are default and therefore commented out.)\n");
4667 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4669 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4672 for (i = 0; image_config[i].token != NULL; i++)
4673 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4674 image_config[i].value));
4678 else if (strEqual(command, "print soundsinfo.conf"))
4680 Print("# You can configure additional/alternative sound files here.\n");
4681 Print("# (The entries below are default and therefore commented out.)\n");
4683 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4685 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4688 for (i = 0; sound_config[i].token != NULL; i++)
4689 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4690 sound_config[i].value));
4694 else if (strEqual(command, "print musicinfo.conf"))
4696 Print("# You can configure additional/alternative music files here.\n");
4697 Print("# (The entries below are default and therefore commented out.)\n");
4699 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4701 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4704 for (i = 0; music_config[i].token != NULL; i++)
4705 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4706 music_config[i].value));
4710 else if (strEqual(command, "print editorsetup.conf"))
4712 Print("# You can configure your personal editor element list here.\n");
4713 Print("# (The entries below are default and therefore commented out.)\n");
4716 /* this is needed to be able to check element list for cascade elements */
4717 InitElementPropertiesStatic();
4718 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4720 PrintEditorElementList();
4724 else if (strEqual(command, "print helpanim.conf"))
4726 Print("# You can configure different element help animations here.\n");
4727 Print("# (The entries below are default and therefore commented out.)\n");
4730 for (i = 0; helpanim_config[i].token != NULL; i++)
4732 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4733 helpanim_config[i].value));
4735 if (strEqual(helpanim_config[i].token, "end"))
4741 else if (strEqual(command, "print helptext.conf"))
4743 Print("# You can configure different element help text here.\n");
4744 Print("# (The entries below are default and therefore commented out.)\n");
4747 for (i = 0; helptext_config[i].token != NULL; i++)
4748 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4749 helptext_config[i].value));
4753 else if (strPrefix(command, "dump level "))
4755 char *filename = &command[11];
4757 if (!fileExists(filename))
4758 Error(ERR_EXIT, "cannot open file '%s'", filename);
4760 LoadLevelFromFilename(&level, filename);
4765 else if (strPrefix(command, "dump tape "))
4767 char *filename = &command[10];
4769 if (!fileExists(filename))
4770 Error(ERR_EXIT, "cannot open file '%s'", filename);
4772 LoadTapeFromFilename(filename);
4777 else if (strPrefix(command, "autotest ") ||
4778 strPrefix(command, "autoplay ") ||
4779 strPrefix(command, "autoffwd "))
4781 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4783 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4784 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4785 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4787 while (*str_ptr != '\0') /* continue parsing string */
4789 /* cut leading whitespace from string, replace it by string terminator */
4790 while (*str_ptr == ' ' || *str_ptr == '\t')
4793 if (*str_ptr == '\0') /* end of string reached */
4796 if (global.autoplay_leveldir == NULL) /* read level set string */
4798 global.autoplay_leveldir = str_ptr;
4799 global.autoplay_all = TRUE; /* default: play all tapes */
4801 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4802 global.autoplay_level[i] = FALSE;
4804 else /* read level number string */
4806 int level_nr = atoi(str_ptr); /* get level_nr value */
4808 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4809 global.autoplay_level[level_nr] = TRUE;
4811 global.autoplay_all = FALSE;
4814 /* advance string pointer to the next whitespace (or end of string) */
4815 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4819 else if (strPrefix(command, "convert "))
4821 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4822 char *str_ptr = strchr(str_copy, ' ');
4824 global.convert_leveldir = str_copy;
4825 global.convert_level_nr = -1;
4827 if (str_ptr != NULL) /* level number follows */
4829 *str_ptr++ = '\0'; /* terminate leveldir string */
4830 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4833 else if (strPrefix(command, "create images "))
4835 global.create_images_dir = getStringCopy(&command[14]);
4837 if (access(global.create_images_dir, W_OK) != 0)
4838 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4839 global.create_images_dir);
4841 else if (strPrefix(command, "create CE image "))
4843 CreateCustomElementImages(&command[16]);
4849 #if defined(TARGET_SDL2)
4850 else if (strEqual(command, "SDL_ListModes"))
4852 SDL_Init(SDL_INIT_VIDEO);
4854 int num_displays = SDL_GetNumVideoDisplays();
4856 // check if there are any displays available
4857 if (num_displays < 0)
4859 Print("No displays available: %s\n", SDL_GetError());
4864 for (i = 0; i < num_displays; i++)
4866 int num_modes = SDL_GetNumDisplayModes(i);
4869 Print("Available display modes for display %d:\n", i);
4871 // check if there are any display modes available for this display
4874 Print("No display modes available for display %d: %s\n",
4880 for (j = 0; j < num_modes; j++)
4882 SDL_DisplayMode mode;
4884 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4886 Print("Cannot get display mode %d for display %d: %s\n",
4887 j, i, SDL_GetError());
4892 Print("- %d x %d\n", mode.w, mode.h);
4898 #elif defined(TARGET_SDL)
4899 else if (strEqual(command, "SDL_ListModes"))
4904 SDL_Init(SDL_INIT_VIDEO);
4906 /* get available fullscreen/hardware modes */
4907 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4909 /* check if there are any modes available */
4912 Print("No modes available!\n");
4917 /* check if our resolution is restricted */
4918 if (modes == (SDL_Rect **)-1)
4920 Print("All resolutions available.\n");
4924 Print("Available display modes:\n");
4926 for (i = 0; modes[i]; i++)
4927 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4937 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4941 static void InitSetup()
4943 LoadSetup(); /* global setup info */
4945 /* set some options from setup file */
4947 if (setup.options.verbose)
4948 options.verbose = TRUE;
4951 static void InitGameInfo()
4953 game.restart_level = FALSE;
4956 static void InitPlayerInfo()
4960 /* choose default local player */
4961 local_player = &stored_player[0];
4963 for (i = 0; i < MAX_PLAYERS; i++)
4964 stored_player[i].connected = FALSE;
4966 local_player->connected = TRUE;
4969 static void InitArtworkInfo()
4974 static char *get_string_in_brackets(char *string)
4976 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4978 sprintf(string_in_brackets, "[%s]", string);
4980 return string_in_brackets;
4983 static char *get_level_id_suffix(int id_nr)
4985 char *id_suffix = checked_malloc(1 + 3 + 1);
4987 if (id_nr < 0 || id_nr > 999)
4990 sprintf(id_suffix, ".%03d", id_nr);
4995 static void InitArtworkConfig()
4997 static char *image_id_prefix[MAX_NUM_ELEMENTS +
4999 NUM_GLOBAL_ANIM_TOKENS + 1];
5000 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5001 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5002 static char *action_id_suffix[NUM_ACTIONS + 1];
5003 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5004 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5005 static char *level_id_suffix[MAX_LEVELS + 1];
5006 static char *dummy[1] = { NULL };
5007 static char *ignore_generic_tokens[] =
5013 static char **ignore_image_tokens;
5014 static char **ignore_sound_tokens;
5015 static char **ignore_music_tokens;
5016 int num_ignore_generic_tokens;
5017 int num_ignore_image_tokens;
5018 int num_ignore_sound_tokens;
5019 int num_ignore_music_tokens;
5022 /* dynamically determine list of generic tokens to be ignored */
5023 num_ignore_generic_tokens = 0;
5024 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5025 num_ignore_generic_tokens++;
5027 /* dynamically determine list of image tokens to be ignored */
5028 num_ignore_image_tokens = num_ignore_generic_tokens;
5029 for (i = 0; image_config_vars[i].token != NULL; i++)
5030 num_ignore_image_tokens++;
5031 ignore_image_tokens =
5032 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5033 for (i = 0; i < num_ignore_generic_tokens; i++)
5034 ignore_image_tokens[i] = ignore_generic_tokens[i];
5035 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5036 ignore_image_tokens[num_ignore_generic_tokens + i] =
5037 image_config_vars[i].token;
5038 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5040 /* dynamically determine list of sound tokens to be ignored */
5041 num_ignore_sound_tokens = num_ignore_generic_tokens;
5042 ignore_sound_tokens =
5043 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5044 for (i = 0; i < num_ignore_generic_tokens; i++)
5045 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5046 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5048 /* dynamically determine list of music tokens to be ignored */
5049 num_ignore_music_tokens = num_ignore_generic_tokens;
5050 ignore_music_tokens =
5051 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5052 for (i = 0; i < num_ignore_generic_tokens; i++)
5053 ignore_music_tokens[i] = ignore_generic_tokens[i];
5054 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5056 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5057 image_id_prefix[i] = element_info[i].token_name;
5058 for (i = 0; i < NUM_FONTS; i++)
5059 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5060 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5061 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5062 global_anim_info[i].token_name;
5063 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5065 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5066 sound_id_prefix[i] = element_info[i].token_name;
5067 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5068 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5069 get_string_in_brackets(element_info[i].class_name);
5070 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5072 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5073 music_id_prefix[i] = music_prefix_info[i].prefix;
5074 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5076 for (i = 0; i < NUM_ACTIONS; i++)
5077 action_id_suffix[i] = element_action_info[i].suffix;
5078 action_id_suffix[NUM_ACTIONS] = NULL;
5080 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5081 direction_id_suffix[i] = element_direction_info[i].suffix;
5082 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5084 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5085 special_id_suffix[i] = special_suffix_info[i].suffix;
5086 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5088 for (i = 0; i < MAX_LEVELS; i++)
5089 level_id_suffix[i] = get_level_id_suffix(i);
5090 level_id_suffix[MAX_LEVELS] = NULL;
5092 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5093 image_id_prefix, action_id_suffix, direction_id_suffix,
5094 special_id_suffix, ignore_image_tokens);
5095 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5096 sound_id_prefix, action_id_suffix, dummy,
5097 special_id_suffix, ignore_sound_tokens);
5098 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5099 music_id_prefix, special_id_suffix, level_id_suffix,
5100 dummy, ignore_music_tokens);
5103 static void InitMixer()
5110 void InitGfxBuffers()
5112 static int win_xsize_last = -1;
5113 static int win_ysize_last = -1;
5115 /* create additional image buffers for double-buffering and cross-fading */
5117 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5119 /* may contain content for cross-fading -- only re-create if changed */
5120 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5121 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5123 win_xsize_last = WIN_XSIZE;
5124 win_ysize_last = WIN_YSIZE;
5127 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5128 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5129 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5130 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5131 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5133 /* initialize screen properties */
5134 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5135 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5137 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5138 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5139 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5140 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5141 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5142 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5144 /* required if door size definitions have changed */
5145 InitGraphicCompatibilityInfo_Doors();
5147 InitGfxBuffers_EM();
5148 InitGfxBuffers_SP();
5153 struct GraphicInfo *graphic_info_last = graphic_info;
5154 char *filename_font_initial = NULL;
5155 char *filename_anim_initial = NULL;
5156 Bitmap *bitmap_font_initial = NULL;
5160 /* determine settings for initial font (for displaying startup messages) */
5161 for (i = 0; image_config[i].token != NULL; i++)
5163 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5165 char font_token[128];
5168 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5169 len_font_token = strlen(font_token);
5171 if (strEqual(image_config[i].token, font_token))
5172 filename_font_initial = image_config[i].value;
5173 else if (strlen(image_config[i].token) > len_font_token &&
5174 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5176 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5177 font_initial[j].src_x = atoi(image_config[i].value);
5178 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5179 font_initial[j].src_y = atoi(image_config[i].value);
5180 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5181 font_initial[j].width = atoi(image_config[i].value);
5182 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5183 font_initial[j].height = atoi(image_config[i].value);
5188 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5190 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5191 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5194 if (filename_font_initial == NULL) /* should not happen */
5195 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5198 InitGfxCustomArtworkInfo();
5199 InitGfxOtherSettings();
5201 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5203 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5204 font_initial[j].bitmap = bitmap_font_initial;
5206 InitFontGraphicInfo();
5208 font_height = getFontHeight(FC_RED);
5210 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5211 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5212 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5215 DrawInitText("Loading graphics", 120, FC_GREEN);
5217 /* initialize settings for busy animation with default values */
5218 int parameter[NUM_GFX_ARGS];
5219 for (i = 0; i < NUM_GFX_ARGS; i++)
5220 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5221 image_config_suffix[i].token,
5222 image_config_suffix[i].type);
5224 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5225 int len_anim_token = strlen(anim_token);
5227 /* read settings for busy animation from default custom artwork config */
5228 char *gfx_config_filename = getPath3(options.graphics_directory,
5230 GRAPHICSINFO_FILENAME);
5232 if (fileExists(gfx_config_filename))
5234 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5236 if (setup_file_hash)
5238 char *filename = getHashEntry(setup_file_hash, anim_token);
5242 filename_anim_initial = getStringCopy(filename);
5244 for (j = 0; image_config_suffix[j].token != NULL; j++)
5246 int type = image_config_suffix[j].type;
5247 char *suffix = image_config_suffix[j].token;
5248 char *token = getStringCat2(anim_token, suffix);
5249 char *value = getHashEntry(setup_file_hash, token);
5251 checked_free(token);
5254 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5258 freeSetupFileHash(setup_file_hash);
5262 if (filename_anim_initial == NULL)
5264 /* read settings for busy animation from static default artwork config */
5265 for (i = 0; image_config[i].token != NULL; i++)
5267 if (strEqual(image_config[i].token, anim_token))
5268 filename_anim_initial = getStringCopy(image_config[i].value);
5269 else if (strlen(image_config[i].token) > len_anim_token &&
5270 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5272 for (j = 0; image_config_suffix[j].token != NULL; j++)
5274 if (strEqual(&image_config[i].token[len_anim_token],
5275 image_config_suffix[j].token))
5277 get_graphic_parameter_value(image_config[i].value,
5278 image_config_suffix[j].token,
5279 image_config_suffix[j].type);
5285 if (filename_anim_initial == NULL) /* should not happen */
5286 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5288 anim_initial.bitmaps =
5289 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5291 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5292 LoadCustomImage(filename_anim_initial);
5294 checked_free(filename_anim_initial);
5296 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5298 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5300 graphic_info = graphic_info_last;
5302 init.busy.width = anim_initial.width;
5303 init.busy.height = anim_initial.height;
5305 InitMenuDesignSettings_Static();
5307 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5308 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5310 /* use copy of busy animation to prevent change while reloading artwork */
5314 void InitGfxBackground()
5316 fieldbuffer = bitmap_db_field;
5317 SetDrawtoField(DRAW_BACKBUFFER);
5319 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5321 redraw_mask = REDRAW_ALL;
5324 static void InitLevelInfo()
5326 LoadLevelInfo(); /* global level info */
5327 LoadLevelSetup_LastSeries(); /* last played series info */
5328 LoadLevelSetup_SeriesInfo(); /* last played level info */
5330 if (global.autoplay_leveldir &&
5331 global.autoplay_mode != AUTOPLAY_TEST)
5333 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5334 global.autoplay_leveldir);
5335 if (leveldir_current == NULL)
5336 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5340 static void InitLevelArtworkInfo()
5342 LoadLevelArtworkInfo();
5345 static void InitImages()
5347 print_timestamp_init("InitImages");
5350 printf("::: leveldir_current->identifier == '%s'\n",
5351 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5352 printf("::: leveldir_current->graphics_path == '%s'\n",
5353 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5354 printf("::: leveldir_current->graphics_set == '%s'\n",
5355 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5356 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5357 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5360 setLevelArtworkDir(artwork.gfx_first);
5363 printf("::: leveldir_current->identifier == '%s'\n",
5364 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5365 printf("::: leveldir_current->graphics_path == '%s'\n",
5366 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5367 printf("::: leveldir_current->graphics_set == '%s'\n",
5368 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5369 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5370 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5374 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5375 leveldir_current->identifier,
5376 artwork.gfx_current_identifier,
5377 artwork.gfx_current->identifier,
5378 leveldir_current->graphics_set,
5379 leveldir_current->graphics_path);
5382 UPDATE_BUSY_STATE();
5384 ReloadCustomImages();
5385 print_timestamp_time("ReloadCustomImages");
5387 UPDATE_BUSY_STATE();
5389 LoadCustomElementDescriptions();
5390 print_timestamp_time("LoadCustomElementDescriptions");
5392 UPDATE_BUSY_STATE();
5394 LoadMenuDesignSettings();
5395 print_timestamp_time("LoadMenuDesignSettings");
5397 UPDATE_BUSY_STATE();
5399 ReinitializeGraphics();
5400 print_timestamp_time("ReinitializeGraphics");
5402 UPDATE_BUSY_STATE();
5404 print_timestamp_done("InitImages");
5407 static void InitSound(char *identifier)
5409 print_timestamp_init("InitSound");
5411 if (identifier == NULL)
5412 identifier = artwork.snd_current->identifier;
5414 /* set artwork path to send it to the sound server process */
5415 setLevelArtworkDir(artwork.snd_first);
5417 InitReloadCustomSounds(identifier);
5418 print_timestamp_time("InitReloadCustomSounds");
5420 ReinitializeSounds();
5421 print_timestamp_time("ReinitializeSounds");
5423 print_timestamp_done("InitSound");
5426 static void InitMusic(char *identifier)
5428 print_timestamp_init("InitMusic");
5430 if (identifier == NULL)
5431 identifier = artwork.mus_current->identifier;
5433 /* set artwork path to send it to the sound server process */
5434 setLevelArtworkDir(artwork.mus_first);
5436 InitReloadCustomMusic(identifier);
5437 print_timestamp_time("InitReloadCustomMusic");
5439 ReinitializeMusic();
5440 print_timestamp_time("ReinitializeMusic");
5442 print_timestamp_done("InitMusic");
5445 void InitNetworkServer()
5447 #if defined(NETWORK_AVALIABLE)
5451 if (!options.network)
5454 #if defined(NETWORK_AVALIABLE)
5455 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5457 if (!ConnectToServer(options.server_host, options.server_port))
5458 Error(ERR_EXIT, "cannot connect to network game server");
5460 SendToServer_PlayerName(setup.player_name);
5461 SendToServer_ProtocolVersion();
5464 SendToServer_NrWanted(nr_wanted);
5468 static boolean CheckArtworkConfigForCustomElements(char *filename)
5470 SetupFileHash *setup_file_hash;
5471 boolean redefined_ce_found = FALSE;
5473 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5475 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5477 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5479 char *token = HASH_ITERATION_TOKEN(itr);
5481 if (strPrefix(token, "custom_"))
5483 redefined_ce_found = TRUE;
5488 END_HASH_ITERATION(setup_file_hash, itr)
5490 freeSetupFileHash(setup_file_hash);
5493 return redefined_ce_found;
5496 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5498 char *filename_base, *filename_local;
5499 boolean redefined_ce_found = FALSE;
5501 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5504 printf("::: leveldir_current->identifier == '%s'\n",
5505 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5506 printf("::: leveldir_current->graphics_path == '%s'\n",
5507 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5508 printf("::: leveldir_current->graphics_set == '%s'\n",
5509 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5510 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5511 leveldir_current == NULL ? "[NULL]" :
5512 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5515 /* first look for special artwork configured in level series config */
5516 filename_base = getCustomArtworkLevelConfigFilename(type);
5519 printf("::: filename_base == '%s'\n", filename_base);
5522 if (fileExists(filename_base))
5523 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5525 filename_local = getCustomArtworkConfigFilename(type);
5528 printf("::: filename_local == '%s'\n", filename_local);
5531 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5532 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5535 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5538 return redefined_ce_found;
5541 static void InitOverrideArtwork()
5543 boolean redefined_ce_found = FALSE;
5545 /* to check if this level set redefines any CEs, do not use overriding */
5546 gfx.override_level_graphics = FALSE;
5547 gfx.override_level_sounds = FALSE;
5548 gfx.override_level_music = FALSE;
5550 /* now check if this level set has definitions for custom elements */
5551 if (setup.override_level_graphics == AUTO ||
5552 setup.override_level_sounds == AUTO ||
5553 setup.override_level_music == AUTO)
5554 redefined_ce_found =
5555 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5556 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5557 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5560 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5563 if (redefined_ce_found)
5565 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5566 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5567 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5568 gfx.override_level_music = (setup.override_level_music == TRUE);
5572 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5573 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5574 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5575 gfx.override_level_music = (setup.override_level_music != FALSE);
5579 printf("::: => %d, %d, %d\n",
5580 gfx.override_level_graphics,
5581 gfx.override_level_sounds,
5582 gfx.override_level_music);
5586 static char *getNewArtworkIdentifier(int type)
5588 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5589 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5590 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5591 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5592 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5593 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5594 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5595 char *leveldir_identifier = leveldir_current->identifier;
5596 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5597 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5598 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5599 char *artwork_current_identifier;
5600 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5602 /* leveldir_current may be invalid (level group, parent link) */
5603 if (!validLevelSeries(leveldir_current))
5606 /* 1st step: determine artwork set to be activated in descending order:
5607 --------------------------------------------------------------------
5608 1. setup artwork (when configured to override everything else)
5609 2. artwork set configured in "levelinfo.conf" of current level set
5610 (artwork in level directory will have priority when loading later)
5611 3. artwork in level directory (stored in artwork sub-directory)
5612 4. setup artwork (currently configured in setup menu) */
5614 if (setup_override_artwork)
5615 artwork_current_identifier = setup_artwork_set;
5616 else if (leveldir_artwork_set != NULL)
5617 artwork_current_identifier = leveldir_artwork_set;
5618 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5619 artwork_current_identifier = leveldir_identifier;
5621 artwork_current_identifier = setup_artwork_set;
5624 /* 2nd step: check if it is really needed to reload artwork set
5625 ------------------------------------------------------------ */
5627 /* ---------- reload if level set and also artwork set has changed ------- */
5628 if (leveldir_current_identifier[type] != leveldir_identifier &&
5629 (last_has_level_artwork_set[type] || has_level_artwork_set))
5630 artwork_new_identifier = artwork_current_identifier;
5632 leveldir_current_identifier[type] = leveldir_identifier;
5633 last_has_level_artwork_set[type] = has_level_artwork_set;
5635 /* ---------- reload if "override artwork" setting has changed ----------- */
5636 if (last_override_level_artwork[type] != setup_override_artwork)
5637 artwork_new_identifier = artwork_current_identifier;
5639 last_override_level_artwork[type] = setup_override_artwork;
5641 /* ---------- reload if current artwork identifier has changed ----------- */
5642 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5643 artwork_current_identifier))
5644 artwork_new_identifier = artwork_current_identifier;
5646 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5648 /* ---------- do not reload directly after starting ---------------------- */
5649 if (!initialized[type])
5650 artwork_new_identifier = NULL;
5652 initialized[type] = TRUE;
5654 return artwork_new_identifier;
5657 void ReloadCustomArtwork(int force_reload)
5659 int last_game_status = game_status; /* save current game status */
5660 char *gfx_new_identifier;
5661 char *snd_new_identifier;
5662 char *mus_new_identifier;
5663 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5664 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5665 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5666 boolean reload_needed;
5668 InitOverrideArtwork();
5670 force_reload_gfx |= AdjustGraphicsForEMC();
5672 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5673 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5674 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5676 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5677 snd_new_identifier != NULL || force_reload_snd ||
5678 mus_new_identifier != NULL || force_reload_mus);
5683 print_timestamp_init("ReloadCustomArtwork");
5685 game_status = GAME_MODE_LOADING;
5687 FadeOut(REDRAW_ALL);
5689 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5690 print_timestamp_time("ClearRectangle");
5694 if (gfx_new_identifier != NULL || force_reload_gfx)
5697 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5698 artwork.gfx_current_identifier,
5700 artwork.gfx_current->identifier,
5701 leveldir_current->graphics_set);
5705 print_timestamp_time("InitImages");
5708 if (snd_new_identifier != NULL || force_reload_snd)
5710 InitSound(snd_new_identifier);
5711 print_timestamp_time("InitSound");
5714 if (mus_new_identifier != NULL || force_reload_mus)
5716 InitMusic(mus_new_identifier);
5717 print_timestamp_time("InitMusic");
5720 game_status = last_game_status; /* restore current game status */
5722 init_last = init; /* switch to new busy animation */
5724 FadeOut(REDRAW_ALL);
5726 RedrawGlobalBorder();
5728 /* force redraw of (open or closed) door graphics */
5729 SetDoorState(DOOR_OPEN_ALL);
5730 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5732 FadeSetEnterScreen();
5733 FadeSkipNextFadeOut();
5735 print_timestamp_done("ReloadCustomArtwork");
5737 LimitScreenUpdates(FALSE);
5740 void KeyboardAutoRepeatOffUnlessAutoplay()
5742 if (global.autoplay_leveldir == NULL)
5743 KeyboardAutoRepeatOff();
5746 void DisplayExitMessage(char *format, va_list ap)
5748 // check if draw buffer and fonts for exit message are already available
5749 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5752 int font_1 = FC_RED;
5753 int font_2 = FC_YELLOW;
5754 int font_3 = FC_BLUE;
5755 int font_width = getFontWidth(font_2);
5756 int font_height = getFontHeight(font_2);
5759 int sxsize = WIN_XSIZE - 2 * sx;
5760 int sysize = WIN_YSIZE - 2 * sy;
5761 int line_length = sxsize / font_width;
5762 int max_lines = sysize / font_height;
5763 int num_lines_printed;
5767 gfx.sxsize = sxsize;
5768 gfx.sysize = sysize;
5772 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5774 DrawTextSCentered(sy, font_1, "Fatal error:");
5775 sy += 3 * font_height;;
5778 DrawTextBufferVA(sx, sy, format, ap, font_2,
5779 line_length, line_length, max_lines,
5780 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5781 sy += (num_lines_printed + 3) * font_height;
5783 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5784 sy += 3 * font_height;
5787 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5788 line_length, line_length, max_lines,
5789 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5791 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5793 redraw_mask = REDRAW_ALL;
5795 /* force drawing exit message even if screen updates are currently limited */
5796 LimitScreenUpdates(FALSE);
5800 /* deactivate toons on error message screen */
5801 setup.toons = FALSE;
5803 WaitForEventToContinue();
5807 /* ========================================================================= */
5809 /* ========================================================================= */
5813 print_timestamp_init("OpenAll");
5815 game_status = GAME_MODE_LOADING;
5819 InitGlobal(); /* initialize some global variables */
5821 print_timestamp_time("[init global stuff]");
5825 print_timestamp_time("[init setup/config stuff (1)]");
5827 if (options.execute_command)
5828 Execute_Command(options.execute_command);
5830 if (options.serveronly)
5832 #if defined(PLATFORM_UNIX)
5833 NetworkServer(options.server_port, options.serveronly);
5835 Error(ERR_WARN, "networking only supported in Unix version");
5838 exit(0); /* never reached, server loops forever */
5842 print_timestamp_time("[init setup/config stuff (2)]");
5844 print_timestamp_time("[init setup/config stuff (3)]");
5845 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5846 print_timestamp_time("[init setup/config stuff (4)]");
5847 InitArtworkConfig(); /* needed before forking sound child process */
5848 print_timestamp_time("[init setup/config stuff (5)]");
5850 print_timestamp_time("[init setup/config stuff (6)]");
5852 InitRND(NEW_RANDOMIZE);
5853 InitSimpleRandom(NEW_RANDOMIZE);
5857 print_timestamp_time("[init setup/config stuff]");
5860 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5862 InitEventFilter(FilterEvents);
5864 print_timestamp_time("[init video stuff]");
5866 InitElementPropertiesStatic();
5867 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5868 InitElementPropertiesGfxElement();
5870 print_timestamp_time("[init element properties stuff]");
5874 print_timestamp_time("InitGfx");
5877 print_timestamp_time("InitLevelInfo");
5879 InitLevelArtworkInfo();
5880 print_timestamp_time("InitLevelArtworkInfo");
5882 InitOverrideArtwork(); /* needs to know current level directory */
5883 print_timestamp_time("InitOverrideArtwork");
5885 InitImages(); /* needs to know current level directory */
5886 print_timestamp_time("InitImages");
5888 InitSound(NULL); /* needs to know current level directory */
5889 print_timestamp_time("InitSound");
5891 InitMusic(NULL); /* needs to know current level directory */
5892 print_timestamp_time("InitMusic");
5894 InitGfxBackground();
5899 if (global.autoplay_leveldir)
5904 else if (global.convert_leveldir)
5909 else if (global.create_images_dir)
5911 CreateLevelSketchImages();
5915 game_status = GAME_MODE_MAIN;
5917 FadeSetEnterScreen();
5918 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5919 FadeSkipNextFadeOut();
5921 print_timestamp_time("[post-artwork]");
5923 print_timestamp_done("OpenAll");
5927 InitNetworkServer();
5930 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5932 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5933 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5934 #if defined(PLATFORM_ANDROID)
5935 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5936 SDL_AndroidGetInternalStoragePath());
5937 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5938 SDL_AndroidGetExternalStoragePath());
5939 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5940 (SDL_AndroidGetExternalStorageState() ==
5941 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5942 SDL_AndroidGetExternalStorageState() ==
5943 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5948 void CloseAllAndExit(int exit_value)
5953 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5960 #if defined(TARGET_SDL)
5961 #if defined(TARGET_SDL2)
5963 // set a flag to tell the network server thread to quit and wait for it
5964 // using SDL_WaitThread()
5966 if (network_server) /* terminate network server */
5967 SDL_KillThread(server_thread);
5971 CloseVideoDisplay();
5972 ClosePlatformDependentStuff();
5974 if (exit_value != 0)
5976 /* fall back to default level set (current set may have caused an error) */
5977 SaveLevelSetup_LastSeries_Deactivate();
5979 /* tell user where to find error log file which may contain more details */
5980 // (error notification now directly displayed on screen inside R'n'D
5981 // NotifyUserAboutErrorFile(); /* currently only works for Windows */