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 static void InitGlobalAnimImages()
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 // create textures from images for fast GPU blitting, if possible
245 CreateImageTextures(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");
2029 InitGlobalAnimImages(); /* initialize global animation images */
2030 print_timestamp_time("InitGlobalAnimImages");
2032 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2033 print_timestamp_time("InitGraphicInfo_EM");
2035 InitGraphicCompatibilityInfo();
2036 print_timestamp_time("InitGraphicCompatibilityInfo");
2038 SetMainBackgroundImage(IMG_BACKGROUND);
2039 print_timestamp_time("SetMainBackgroundImage");
2040 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2041 print_timestamp_time("SetDoorBackgroundImage");
2044 print_timestamp_time("InitGadgets");
2046 print_timestamp_time("InitToons");
2048 print_timestamp_time("InitDoors");
2050 print_timestamp_done("ReinitializeGraphics");
2053 static void ReinitializeSounds()
2055 InitSoundInfo(); /* sound properties mapping */
2056 InitElementSoundInfo(); /* element game sound mapping */
2057 InitGameModeSoundInfo(); /* game mode sound mapping */
2059 InitPlayLevelSound(); /* internal game sound settings */
2062 static void ReinitializeMusic()
2064 InitMusicInfo(); /* music properties mapping */
2065 InitGameModeMusicInfo(); /* game mode music mapping */
2068 static int get_special_property_bit(int element, int property_bit_nr)
2070 struct PropertyBitInfo
2076 static struct PropertyBitInfo pb_can_move_into_acid[] =
2078 /* the player may be able fall into acid when gravity is activated */
2083 { EL_SP_MURPHY, 0 },
2084 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2086 /* all elements that can move may be able to also move into acid */
2089 { EL_BUG_RIGHT, 1 },
2092 { EL_SPACESHIP, 2 },
2093 { EL_SPACESHIP_LEFT, 2 },
2094 { EL_SPACESHIP_RIGHT, 2 },
2095 { EL_SPACESHIP_UP, 2 },
2096 { EL_SPACESHIP_DOWN, 2 },
2097 { EL_BD_BUTTERFLY, 3 },
2098 { EL_BD_BUTTERFLY_LEFT, 3 },
2099 { EL_BD_BUTTERFLY_RIGHT, 3 },
2100 { EL_BD_BUTTERFLY_UP, 3 },
2101 { EL_BD_BUTTERFLY_DOWN, 3 },
2102 { EL_BD_FIREFLY, 4 },
2103 { EL_BD_FIREFLY_LEFT, 4 },
2104 { EL_BD_FIREFLY_RIGHT, 4 },
2105 { EL_BD_FIREFLY_UP, 4 },
2106 { EL_BD_FIREFLY_DOWN, 4 },
2108 { EL_YAMYAM_LEFT, 5 },
2109 { EL_YAMYAM_RIGHT, 5 },
2110 { EL_YAMYAM_UP, 5 },
2111 { EL_YAMYAM_DOWN, 5 },
2112 { EL_DARK_YAMYAM, 6 },
2115 { EL_PACMAN_LEFT, 8 },
2116 { EL_PACMAN_RIGHT, 8 },
2117 { EL_PACMAN_UP, 8 },
2118 { EL_PACMAN_DOWN, 8 },
2120 { EL_MOLE_LEFT, 9 },
2121 { EL_MOLE_RIGHT, 9 },
2123 { EL_MOLE_DOWN, 9 },
2127 { EL_SATELLITE, 13 },
2128 { EL_SP_SNIKSNAK, 14 },
2129 { EL_SP_ELECTRON, 15 },
2132 { EL_EMC_ANDROID, 18 },
2137 static struct PropertyBitInfo pb_dont_collide_with[] =
2139 { EL_SP_SNIKSNAK, 0 },
2140 { EL_SP_ELECTRON, 1 },
2148 struct PropertyBitInfo *pb_info;
2151 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2152 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2157 struct PropertyBitInfo *pb_info = NULL;
2160 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2161 if (pb_definition[i].bit_nr == property_bit_nr)
2162 pb_info = pb_definition[i].pb_info;
2164 if (pb_info == NULL)
2167 for (i = 0; pb_info[i].element != -1; i++)
2168 if (pb_info[i].element == element)
2169 return pb_info[i].bit_nr;
2174 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2175 boolean property_value)
2177 int bit_nr = get_special_property_bit(element, property_bit_nr);
2182 *bitfield |= (1 << bit_nr);
2184 *bitfield &= ~(1 << bit_nr);
2188 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2190 int bit_nr = get_special_property_bit(element, property_bit_nr);
2193 return ((*bitfield & (1 << bit_nr)) != 0);
2198 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2200 static int group_nr;
2201 static struct ElementGroupInfo *group;
2202 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2205 if (actual_group == NULL) /* not yet initialized */
2208 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2210 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2211 group_element - EL_GROUP_START + 1);
2213 /* replace element which caused too deep recursion by question mark */
2214 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2219 if (recursion_depth == 0) /* initialization */
2221 group = actual_group;
2222 group_nr = GROUP_NR(group_element);
2224 group->num_elements_resolved = 0;
2225 group->choice_pos = 0;
2227 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2228 element_info[i].in_group[group_nr] = FALSE;
2231 for (i = 0; i < actual_group->num_elements; i++)
2233 int element = actual_group->element[i];
2235 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2238 if (IS_GROUP_ELEMENT(element))
2239 ResolveGroupElementExt(element, recursion_depth + 1);
2242 group->element_resolved[group->num_elements_resolved++] = element;
2243 element_info[element].in_group[group_nr] = TRUE;
2248 void ResolveGroupElement(int group_element)
2250 ResolveGroupElementExt(group_element, 0);
2253 void InitElementPropertiesStatic()
2255 static boolean clipboard_elements_initialized = FALSE;
2257 static int ep_diggable[] =
2262 EL_SP_BUGGY_BASE_ACTIVATING,
2265 EL_INVISIBLE_SAND_ACTIVE,
2268 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2269 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2274 EL_SP_BUGGY_BASE_ACTIVE,
2281 static int ep_collectible_only[] =
2303 EL_DYNABOMB_INCREASE_NUMBER,
2304 EL_DYNABOMB_INCREASE_SIZE,
2305 EL_DYNABOMB_INCREASE_POWER,
2323 /* !!! handle separately !!! */
2324 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2330 static int ep_dont_run_into[] =
2332 /* same elements as in 'ep_dont_touch' */
2338 /* same elements as in 'ep_dont_collide_with' */
2350 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2355 EL_SP_BUGGY_BASE_ACTIVE,
2362 static int ep_dont_collide_with[] =
2364 /* same elements as in 'ep_dont_touch' */
2381 static int ep_dont_touch[] =
2391 static int ep_indestructible[] =
2395 EL_ACID_POOL_TOPLEFT,
2396 EL_ACID_POOL_TOPRIGHT,
2397 EL_ACID_POOL_BOTTOMLEFT,
2398 EL_ACID_POOL_BOTTOM,
2399 EL_ACID_POOL_BOTTOMRIGHT,
2400 EL_SP_HARDWARE_GRAY,
2401 EL_SP_HARDWARE_GREEN,
2402 EL_SP_HARDWARE_BLUE,
2404 EL_SP_HARDWARE_YELLOW,
2405 EL_SP_HARDWARE_BASE_1,
2406 EL_SP_HARDWARE_BASE_2,
2407 EL_SP_HARDWARE_BASE_3,
2408 EL_SP_HARDWARE_BASE_4,
2409 EL_SP_HARDWARE_BASE_5,
2410 EL_SP_HARDWARE_BASE_6,
2411 EL_INVISIBLE_STEELWALL,
2412 EL_INVISIBLE_STEELWALL_ACTIVE,
2413 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2414 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2415 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2416 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2417 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2418 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2419 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2420 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2421 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2422 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2423 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2424 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2426 EL_LIGHT_SWITCH_ACTIVE,
2427 EL_SIGN_EXCLAMATION,
2428 EL_SIGN_RADIOACTIVITY,
2435 EL_SIGN_ENTRY_FORBIDDEN,
2436 EL_SIGN_EMERGENCY_EXIT,
2444 EL_STEEL_EXIT_CLOSED,
2446 EL_STEEL_EXIT_OPENING,
2447 EL_STEEL_EXIT_CLOSING,
2448 EL_EM_STEEL_EXIT_CLOSED,
2449 EL_EM_STEEL_EXIT_OPEN,
2450 EL_EM_STEEL_EXIT_OPENING,
2451 EL_EM_STEEL_EXIT_CLOSING,
2452 EL_DC_STEELWALL_1_LEFT,
2453 EL_DC_STEELWALL_1_RIGHT,
2454 EL_DC_STEELWALL_1_TOP,
2455 EL_DC_STEELWALL_1_BOTTOM,
2456 EL_DC_STEELWALL_1_HORIZONTAL,
2457 EL_DC_STEELWALL_1_VERTICAL,
2458 EL_DC_STEELWALL_1_TOPLEFT,
2459 EL_DC_STEELWALL_1_TOPRIGHT,
2460 EL_DC_STEELWALL_1_BOTTOMLEFT,
2461 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2462 EL_DC_STEELWALL_1_TOPLEFT_2,
2463 EL_DC_STEELWALL_1_TOPRIGHT_2,
2464 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2465 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2466 EL_DC_STEELWALL_2_LEFT,
2467 EL_DC_STEELWALL_2_RIGHT,
2468 EL_DC_STEELWALL_2_TOP,
2469 EL_DC_STEELWALL_2_BOTTOM,
2470 EL_DC_STEELWALL_2_HORIZONTAL,
2471 EL_DC_STEELWALL_2_VERTICAL,
2472 EL_DC_STEELWALL_2_MIDDLE,
2473 EL_DC_STEELWALL_2_SINGLE,
2474 EL_STEELWALL_SLIPPERY,
2488 EL_GATE_1_GRAY_ACTIVE,
2489 EL_GATE_2_GRAY_ACTIVE,
2490 EL_GATE_3_GRAY_ACTIVE,
2491 EL_GATE_4_GRAY_ACTIVE,
2500 EL_EM_GATE_1_GRAY_ACTIVE,
2501 EL_EM_GATE_2_GRAY_ACTIVE,
2502 EL_EM_GATE_3_GRAY_ACTIVE,
2503 EL_EM_GATE_4_GRAY_ACTIVE,
2512 EL_EMC_GATE_5_GRAY_ACTIVE,
2513 EL_EMC_GATE_6_GRAY_ACTIVE,
2514 EL_EMC_GATE_7_GRAY_ACTIVE,
2515 EL_EMC_GATE_8_GRAY_ACTIVE,
2517 EL_DC_GATE_WHITE_GRAY,
2518 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2519 EL_DC_GATE_FAKE_GRAY,
2521 EL_SWITCHGATE_OPENING,
2522 EL_SWITCHGATE_CLOSED,
2523 EL_SWITCHGATE_CLOSING,
2524 EL_DC_SWITCHGATE_SWITCH_UP,
2525 EL_DC_SWITCHGATE_SWITCH_DOWN,
2527 EL_TIMEGATE_OPENING,
2529 EL_TIMEGATE_CLOSING,
2530 EL_DC_TIMEGATE_SWITCH,
2531 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2535 EL_TUBE_VERTICAL_LEFT,
2536 EL_TUBE_VERTICAL_RIGHT,
2537 EL_TUBE_HORIZONTAL_UP,
2538 EL_TUBE_HORIZONTAL_DOWN,
2543 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2544 EL_EXPANDABLE_STEELWALL_VERTICAL,
2545 EL_EXPANDABLE_STEELWALL_ANY,
2550 static int ep_slippery[] =
2564 EL_ROBOT_WHEEL_ACTIVE,
2570 EL_ACID_POOL_TOPLEFT,
2571 EL_ACID_POOL_TOPRIGHT,
2581 EL_STEELWALL_SLIPPERY,
2584 EL_EMC_WALL_SLIPPERY_1,
2585 EL_EMC_WALL_SLIPPERY_2,
2586 EL_EMC_WALL_SLIPPERY_3,
2587 EL_EMC_WALL_SLIPPERY_4,
2589 EL_EMC_MAGIC_BALL_ACTIVE,
2594 static int ep_can_change[] =
2599 static int ep_can_move[] =
2601 /* same elements as in 'pb_can_move_into_acid' */
2624 static int ep_can_fall[] =
2638 EL_QUICKSAND_FAST_FULL,
2640 EL_BD_MAGIC_WALL_FULL,
2641 EL_DC_MAGIC_WALL_FULL,
2655 static int ep_can_smash_player[] =
2681 static int ep_can_smash_enemies[] =
2690 static int ep_can_smash_everything[] =
2699 static int ep_explodes_by_fire[] =
2701 /* same elements as in 'ep_explodes_impact' */
2706 /* same elements as in 'ep_explodes_smashed' */
2716 EL_EM_DYNAMITE_ACTIVE,
2717 EL_DYNABOMB_PLAYER_1_ACTIVE,
2718 EL_DYNABOMB_PLAYER_2_ACTIVE,
2719 EL_DYNABOMB_PLAYER_3_ACTIVE,
2720 EL_DYNABOMB_PLAYER_4_ACTIVE,
2721 EL_DYNABOMB_INCREASE_NUMBER,
2722 EL_DYNABOMB_INCREASE_SIZE,
2723 EL_DYNABOMB_INCREASE_POWER,
2724 EL_SP_DISK_RED_ACTIVE,
2738 static int ep_explodes_smashed[] =
2740 /* same elements as in 'ep_explodes_impact' */
2754 static int ep_explodes_impact[] =
2763 static int ep_walkable_over[] =
2767 EL_SOKOBAN_FIELD_EMPTY,
2774 EL_EM_STEEL_EXIT_OPEN,
2775 EL_EM_STEEL_EXIT_OPENING,
2784 EL_GATE_1_GRAY_ACTIVE,
2785 EL_GATE_2_GRAY_ACTIVE,
2786 EL_GATE_3_GRAY_ACTIVE,
2787 EL_GATE_4_GRAY_ACTIVE,
2795 static int ep_walkable_inside[] =
2800 EL_TUBE_VERTICAL_LEFT,
2801 EL_TUBE_VERTICAL_RIGHT,
2802 EL_TUBE_HORIZONTAL_UP,
2803 EL_TUBE_HORIZONTAL_DOWN,
2812 static int ep_walkable_under[] =
2817 static int ep_passable_over[] =
2827 EL_EM_GATE_1_GRAY_ACTIVE,
2828 EL_EM_GATE_2_GRAY_ACTIVE,
2829 EL_EM_GATE_3_GRAY_ACTIVE,
2830 EL_EM_GATE_4_GRAY_ACTIVE,
2839 EL_EMC_GATE_5_GRAY_ACTIVE,
2840 EL_EMC_GATE_6_GRAY_ACTIVE,
2841 EL_EMC_GATE_7_GRAY_ACTIVE,
2842 EL_EMC_GATE_8_GRAY_ACTIVE,
2844 EL_DC_GATE_WHITE_GRAY,
2845 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2852 static int ep_passable_inside[] =
2858 EL_SP_PORT_HORIZONTAL,
2859 EL_SP_PORT_VERTICAL,
2861 EL_SP_GRAVITY_PORT_LEFT,
2862 EL_SP_GRAVITY_PORT_RIGHT,
2863 EL_SP_GRAVITY_PORT_UP,
2864 EL_SP_GRAVITY_PORT_DOWN,
2865 EL_SP_GRAVITY_ON_PORT_LEFT,
2866 EL_SP_GRAVITY_ON_PORT_RIGHT,
2867 EL_SP_GRAVITY_ON_PORT_UP,
2868 EL_SP_GRAVITY_ON_PORT_DOWN,
2869 EL_SP_GRAVITY_OFF_PORT_LEFT,
2870 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2871 EL_SP_GRAVITY_OFF_PORT_UP,
2872 EL_SP_GRAVITY_OFF_PORT_DOWN,
2877 static int ep_passable_under[] =
2882 static int ep_droppable[] =
2887 static int ep_explodes_1x1_old[] =
2892 static int ep_pushable[] =
2904 EL_SOKOBAN_FIELD_FULL,
2913 static int ep_explodes_cross_old[] =
2918 static int ep_protected[] =
2920 /* same elements as in 'ep_walkable_inside' */
2924 EL_TUBE_VERTICAL_LEFT,
2925 EL_TUBE_VERTICAL_RIGHT,
2926 EL_TUBE_HORIZONTAL_UP,
2927 EL_TUBE_HORIZONTAL_DOWN,
2933 /* same elements as in 'ep_passable_over' */
2942 EL_EM_GATE_1_GRAY_ACTIVE,
2943 EL_EM_GATE_2_GRAY_ACTIVE,
2944 EL_EM_GATE_3_GRAY_ACTIVE,
2945 EL_EM_GATE_4_GRAY_ACTIVE,
2954 EL_EMC_GATE_5_GRAY_ACTIVE,
2955 EL_EMC_GATE_6_GRAY_ACTIVE,
2956 EL_EMC_GATE_7_GRAY_ACTIVE,
2957 EL_EMC_GATE_8_GRAY_ACTIVE,
2959 EL_DC_GATE_WHITE_GRAY,
2960 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2964 /* same elements as in 'ep_passable_inside' */
2969 EL_SP_PORT_HORIZONTAL,
2970 EL_SP_PORT_VERTICAL,
2972 EL_SP_GRAVITY_PORT_LEFT,
2973 EL_SP_GRAVITY_PORT_RIGHT,
2974 EL_SP_GRAVITY_PORT_UP,
2975 EL_SP_GRAVITY_PORT_DOWN,
2976 EL_SP_GRAVITY_ON_PORT_LEFT,
2977 EL_SP_GRAVITY_ON_PORT_RIGHT,
2978 EL_SP_GRAVITY_ON_PORT_UP,
2979 EL_SP_GRAVITY_ON_PORT_DOWN,
2980 EL_SP_GRAVITY_OFF_PORT_LEFT,
2981 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2982 EL_SP_GRAVITY_OFF_PORT_UP,
2983 EL_SP_GRAVITY_OFF_PORT_DOWN,
2988 static int ep_throwable[] =
2993 static int ep_can_explode[] =
2995 /* same elements as in 'ep_explodes_impact' */
3000 /* same elements as in 'ep_explodes_smashed' */
3006 /* elements that can explode by explosion or by dragonfire */
3010 EL_EM_DYNAMITE_ACTIVE,
3011 EL_DYNABOMB_PLAYER_1_ACTIVE,
3012 EL_DYNABOMB_PLAYER_2_ACTIVE,
3013 EL_DYNABOMB_PLAYER_3_ACTIVE,
3014 EL_DYNABOMB_PLAYER_4_ACTIVE,
3015 EL_DYNABOMB_INCREASE_NUMBER,
3016 EL_DYNABOMB_INCREASE_SIZE,
3017 EL_DYNABOMB_INCREASE_POWER,
3018 EL_SP_DISK_RED_ACTIVE,
3026 /* elements that can explode only by explosion */
3032 static int ep_gravity_reachable[] =
3038 EL_INVISIBLE_SAND_ACTIVE,
3043 EL_SP_PORT_HORIZONTAL,
3044 EL_SP_PORT_VERTICAL,
3046 EL_SP_GRAVITY_PORT_LEFT,
3047 EL_SP_GRAVITY_PORT_RIGHT,
3048 EL_SP_GRAVITY_PORT_UP,
3049 EL_SP_GRAVITY_PORT_DOWN,
3050 EL_SP_GRAVITY_ON_PORT_LEFT,
3051 EL_SP_GRAVITY_ON_PORT_RIGHT,
3052 EL_SP_GRAVITY_ON_PORT_UP,
3053 EL_SP_GRAVITY_ON_PORT_DOWN,
3054 EL_SP_GRAVITY_OFF_PORT_LEFT,
3055 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3056 EL_SP_GRAVITY_OFF_PORT_UP,
3057 EL_SP_GRAVITY_OFF_PORT_DOWN,
3063 static int ep_player[] =
3070 EL_SOKOBAN_FIELD_PLAYER,
3076 static int ep_can_pass_magic_wall[] =
3090 static int ep_can_pass_dc_magic_wall[] =
3106 static int ep_switchable[] =
3110 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3111 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3112 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3113 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3114 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3115 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3116 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3117 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3118 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3119 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3120 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3121 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3122 EL_SWITCHGATE_SWITCH_UP,
3123 EL_SWITCHGATE_SWITCH_DOWN,
3124 EL_DC_SWITCHGATE_SWITCH_UP,
3125 EL_DC_SWITCHGATE_SWITCH_DOWN,
3127 EL_LIGHT_SWITCH_ACTIVE,
3129 EL_DC_TIMEGATE_SWITCH,
3130 EL_BALLOON_SWITCH_LEFT,
3131 EL_BALLOON_SWITCH_RIGHT,
3132 EL_BALLOON_SWITCH_UP,
3133 EL_BALLOON_SWITCH_DOWN,
3134 EL_BALLOON_SWITCH_ANY,
3135 EL_BALLOON_SWITCH_NONE,
3138 EL_EMC_MAGIC_BALL_SWITCH,
3139 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3144 static int ep_bd_element[] =
3178 static int ep_sp_element[] =
3180 /* should always be valid */
3183 /* standard classic Supaplex elements */
3190 EL_SP_HARDWARE_GRAY,
3198 EL_SP_GRAVITY_PORT_RIGHT,
3199 EL_SP_GRAVITY_PORT_DOWN,
3200 EL_SP_GRAVITY_PORT_LEFT,
3201 EL_SP_GRAVITY_PORT_UP,
3206 EL_SP_PORT_VERTICAL,
3207 EL_SP_PORT_HORIZONTAL,
3213 EL_SP_HARDWARE_BASE_1,
3214 EL_SP_HARDWARE_GREEN,
3215 EL_SP_HARDWARE_BLUE,
3217 EL_SP_HARDWARE_YELLOW,
3218 EL_SP_HARDWARE_BASE_2,
3219 EL_SP_HARDWARE_BASE_3,
3220 EL_SP_HARDWARE_BASE_4,
3221 EL_SP_HARDWARE_BASE_5,
3222 EL_SP_HARDWARE_BASE_6,
3226 /* additional elements that appeared in newer Supaplex levels */
3229 /* additional gravity port elements (not switching, but setting gravity) */
3230 EL_SP_GRAVITY_ON_PORT_LEFT,
3231 EL_SP_GRAVITY_ON_PORT_RIGHT,
3232 EL_SP_GRAVITY_ON_PORT_UP,
3233 EL_SP_GRAVITY_ON_PORT_DOWN,
3234 EL_SP_GRAVITY_OFF_PORT_LEFT,
3235 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3236 EL_SP_GRAVITY_OFF_PORT_UP,
3237 EL_SP_GRAVITY_OFF_PORT_DOWN,
3239 /* more than one Murphy in a level results in an inactive clone */
3242 /* runtime Supaplex elements */
3243 EL_SP_DISK_RED_ACTIVE,
3244 EL_SP_TERMINAL_ACTIVE,
3245 EL_SP_BUGGY_BASE_ACTIVATING,
3246 EL_SP_BUGGY_BASE_ACTIVE,
3253 static int ep_sb_element[] =
3258 EL_SOKOBAN_FIELD_EMPTY,
3259 EL_SOKOBAN_FIELD_FULL,
3260 EL_SOKOBAN_FIELD_PLAYER,
3265 EL_INVISIBLE_STEELWALL,
3270 static int ep_gem[] =
3282 static int ep_food_dark_yamyam[] =
3310 static int ep_food_penguin[] =
3324 static int ep_food_pig[] =
3336 static int ep_historic_wall[] =
3347 EL_GATE_1_GRAY_ACTIVE,
3348 EL_GATE_2_GRAY_ACTIVE,
3349 EL_GATE_3_GRAY_ACTIVE,
3350 EL_GATE_4_GRAY_ACTIVE,
3359 EL_EM_GATE_1_GRAY_ACTIVE,
3360 EL_EM_GATE_2_GRAY_ACTIVE,
3361 EL_EM_GATE_3_GRAY_ACTIVE,
3362 EL_EM_GATE_4_GRAY_ACTIVE,
3369 EL_EXPANDABLE_WALL_HORIZONTAL,
3370 EL_EXPANDABLE_WALL_VERTICAL,
3371 EL_EXPANDABLE_WALL_ANY,
3372 EL_EXPANDABLE_WALL_GROWING,
3373 EL_BD_EXPANDABLE_WALL,
3380 EL_SP_HARDWARE_GRAY,
3381 EL_SP_HARDWARE_GREEN,
3382 EL_SP_HARDWARE_BLUE,
3384 EL_SP_HARDWARE_YELLOW,
3385 EL_SP_HARDWARE_BASE_1,
3386 EL_SP_HARDWARE_BASE_2,
3387 EL_SP_HARDWARE_BASE_3,
3388 EL_SP_HARDWARE_BASE_4,
3389 EL_SP_HARDWARE_BASE_5,
3390 EL_SP_HARDWARE_BASE_6,
3392 EL_SP_TERMINAL_ACTIVE,
3395 EL_INVISIBLE_STEELWALL,
3396 EL_INVISIBLE_STEELWALL_ACTIVE,
3398 EL_INVISIBLE_WALL_ACTIVE,
3399 EL_STEELWALL_SLIPPERY,
3416 static int ep_historic_solid[] =
3420 EL_EXPANDABLE_WALL_HORIZONTAL,
3421 EL_EXPANDABLE_WALL_VERTICAL,
3422 EL_EXPANDABLE_WALL_ANY,
3423 EL_BD_EXPANDABLE_WALL,
3436 EL_QUICKSAND_FILLING,
3437 EL_QUICKSAND_EMPTYING,
3439 EL_MAGIC_WALL_ACTIVE,
3440 EL_MAGIC_WALL_EMPTYING,
3441 EL_MAGIC_WALL_FILLING,
3445 EL_BD_MAGIC_WALL_ACTIVE,
3446 EL_BD_MAGIC_WALL_EMPTYING,
3447 EL_BD_MAGIC_WALL_FULL,
3448 EL_BD_MAGIC_WALL_FILLING,
3449 EL_BD_MAGIC_WALL_DEAD,
3458 EL_SP_TERMINAL_ACTIVE,
3462 EL_INVISIBLE_WALL_ACTIVE,
3463 EL_SWITCHGATE_SWITCH_UP,
3464 EL_SWITCHGATE_SWITCH_DOWN,
3465 EL_DC_SWITCHGATE_SWITCH_UP,
3466 EL_DC_SWITCHGATE_SWITCH_DOWN,
3468 EL_TIMEGATE_SWITCH_ACTIVE,
3469 EL_DC_TIMEGATE_SWITCH,
3470 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3482 /* the following elements are a direct copy of "indestructible" elements,
3483 except "EL_ACID", which is "indestructible", but not "solid"! */
3488 EL_ACID_POOL_TOPLEFT,
3489 EL_ACID_POOL_TOPRIGHT,
3490 EL_ACID_POOL_BOTTOMLEFT,
3491 EL_ACID_POOL_BOTTOM,
3492 EL_ACID_POOL_BOTTOMRIGHT,
3493 EL_SP_HARDWARE_GRAY,
3494 EL_SP_HARDWARE_GREEN,
3495 EL_SP_HARDWARE_BLUE,
3497 EL_SP_HARDWARE_YELLOW,
3498 EL_SP_HARDWARE_BASE_1,
3499 EL_SP_HARDWARE_BASE_2,
3500 EL_SP_HARDWARE_BASE_3,
3501 EL_SP_HARDWARE_BASE_4,
3502 EL_SP_HARDWARE_BASE_5,
3503 EL_SP_HARDWARE_BASE_6,
3504 EL_INVISIBLE_STEELWALL,
3505 EL_INVISIBLE_STEELWALL_ACTIVE,
3506 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3507 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3508 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3509 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3510 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3511 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3512 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3513 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3514 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3515 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3516 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3517 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3519 EL_LIGHT_SWITCH_ACTIVE,
3520 EL_SIGN_EXCLAMATION,
3521 EL_SIGN_RADIOACTIVITY,
3528 EL_SIGN_ENTRY_FORBIDDEN,
3529 EL_SIGN_EMERGENCY_EXIT,
3537 EL_STEEL_EXIT_CLOSED,
3539 EL_DC_STEELWALL_1_LEFT,
3540 EL_DC_STEELWALL_1_RIGHT,
3541 EL_DC_STEELWALL_1_TOP,
3542 EL_DC_STEELWALL_1_BOTTOM,
3543 EL_DC_STEELWALL_1_HORIZONTAL,
3544 EL_DC_STEELWALL_1_VERTICAL,
3545 EL_DC_STEELWALL_1_TOPLEFT,
3546 EL_DC_STEELWALL_1_TOPRIGHT,
3547 EL_DC_STEELWALL_1_BOTTOMLEFT,
3548 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3549 EL_DC_STEELWALL_1_TOPLEFT_2,
3550 EL_DC_STEELWALL_1_TOPRIGHT_2,
3551 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3552 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3553 EL_DC_STEELWALL_2_LEFT,
3554 EL_DC_STEELWALL_2_RIGHT,
3555 EL_DC_STEELWALL_2_TOP,
3556 EL_DC_STEELWALL_2_BOTTOM,
3557 EL_DC_STEELWALL_2_HORIZONTAL,
3558 EL_DC_STEELWALL_2_VERTICAL,
3559 EL_DC_STEELWALL_2_MIDDLE,
3560 EL_DC_STEELWALL_2_SINGLE,
3561 EL_STEELWALL_SLIPPERY,
3575 EL_GATE_1_GRAY_ACTIVE,
3576 EL_GATE_2_GRAY_ACTIVE,
3577 EL_GATE_3_GRAY_ACTIVE,
3578 EL_GATE_4_GRAY_ACTIVE,
3587 EL_EM_GATE_1_GRAY_ACTIVE,
3588 EL_EM_GATE_2_GRAY_ACTIVE,
3589 EL_EM_GATE_3_GRAY_ACTIVE,
3590 EL_EM_GATE_4_GRAY_ACTIVE,
3592 EL_SWITCHGATE_OPENING,
3593 EL_SWITCHGATE_CLOSED,
3594 EL_SWITCHGATE_CLOSING,
3596 EL_TIMEGATE_OPENING,
3598 EL_TIMEGATE_CLOSING,
3602 EL_TUBE_VERTICAL_LEFT,
3603 EL_TUBE_VERTICAL_RIGHT,
3604 EL_TUBE_HORIZONTAL_UP,
3605 EL_TUBE_HORIZONTAL_DOWN,
3614 static int ep_classic_enemy[] =
3631 static int ep_belt[] =
3633 EL_CONVEYOR_BELT_1_LEFT,
3634 EL_CONVEYOR_BELT_1_MIDDLE,
3635 EL_CONVEYOR_BELT_1_RIGHT,
3636 EL_CONVEYOR_BELT_2_LEFT,
3637 EL_CONVEYOR_BELT_2_MIDDLE,
3638 EL_CONVEYOR_BELT_2_RIGHT,
3639 EL_CONVEYOR_BELT_3_LEFT,
3640 EL_CONVEYOR_BELT_3_MIDDLE,
3641 EL_CONVEYOR_BELT_3_RIGHT,
3642 EL_CONVEYOR_BELT_4_LEFT,
3643 EL_CONVEYOR_BELT_4_MIDDLE,
3644 EL_CONVEYOR_BELT_4_RIGHT,
3649 static int ep_belt_active[] =
3651 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3652 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3653 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3654 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3655 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3656 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3657 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3658 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3659 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3660 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3661 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3662 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3667 static int ep_belt_switch[] =
3669 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3670 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3671 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3672 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3673 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3674 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3675 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3676 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3677 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3678 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3679 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3680 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3685 static int ep_tube[] =
3692 EL_TUBE_HORIZONTAL_UP,
3693 EL_TUBE_HORIZONTAL_DOWN,
3695 EL_TUBE_VERTICAL_LEFT,
3696 EL_TUBE_VERTICAL_RIGHT,
3702 static int ep_acid_pool[] =
3704 EL_ACID_POOL_TOPLEFT,
3705 EL_ACID_POOL_TOPRIGHT,
3706 EL_ACID_POOL_BOTTOMLEFT,
3707 EL_ACID_POOL_BOTTOM,
3708 EL_ACID_POOL_BOTTOMRIGHT,
3713 static int ep_keygate[] =
3723 EL_GATE_1_GRAY_ACTIVE,
3724 EL_GATE_2_GRAY_ACTIVE,
3725 EL_GATE_3_GRAY_ACTIVE,
3726 EL_GATE_4_GRAY_ACTIVE,
3735 EL_EM_GATE_1_GRAY_ACTIVE,
3736 EL_EM_GATE_2_GRAY_ACTIVE,
3737 EL_EM_GATE_3_GRAY_ACTIVE,
3738 EL_EM_GATE_4_GRAY_ACTIVE,
3747 EL_EMC_GATE_5_GRAY_ACTIVE,
3748 EL_EMC_GATE_6_GRAY_ACTIVE,
3749 EL_EMC_GATE_7_GRAY_ACTIVE,
3750 EL_EMC_GATE_8_GRAY_ACTIVE,
3752 EL_DC_GATE_WHITE_GRAY,
3753 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3758 static int ep_amoeboid[] =
3770 static int ep_amoebalive[] =
3781 static int ep_has_editor_content[] =
3787 EL_SOKOBAN_FIELD_PLAYER,
3804 static int ep_can_turn_each_move[] =
3806 /* !!! do something with this one !!! */
3810 static int ep_can_grow[] =
3824 static int ep_active_bomb[] =
3827 EL_EM_DYNAMITE_ACTIVE,
3828 EL_DYNABOMB_PLAYER_1_ACTIVE,
3829 EL_DYNABOMB_PLAYER_2_ACTIVE,
3830 EL_DYNABOMB_PLAYER_3_ACTIVE,
3831 EL_DYNABOMB_PLAYER_4_ACTIVE,
3832 EL_SP_DISK_RED_ACTIVE,
3837 static int ep_inactive[] =
3847 EL_QUICKSAND_FAST_EMPTY,
3870 EL_GATE_1_GRAY_ACTIVE,
3871 EL_GATE_2_GRAY_ACTIVE,
3872 EL_GATE_3_GRAY_ACTIVE,
3873 EL_GATE_4_GRAY_ACTIVE,
3882 EL_EM_GATE_1_GRAY_ACTIVE,
3883 EL_EM_GATE_2_GRAY_ACTIVE,
3884 EL_EM_GATE_3_GRAY_ACTIVE,
3885 EL_EM_GATE_4_GRAY_ACTIVE,
3894 EL_EMC_GATE_5_GRAY_ACTIVE,
3895 EL_EMC_GATE_6_GRAY_ACTIVE,
3896 EL_EMC_GATE_7_GRAY_ACTIVE,
3897 EL_EMC_GATE_8_GRAY_ACTIVE,
3899 EL_DC_GATE_WHITE_GRAY,
3900 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3901 EL_DC_GATE_FAKE_GRAY,
3904 EL_INVISIBLE_STEELWALL,
3912 EL_WALL_EMERALD_YELLOW,
3913 EL_DYNABOMB_INCREASE_NUMBER,
3914 EL_DYNABOMB_INCREASE_SIZE,
3915 EL_DYNABOMB_INCREASE_POWER,
3919 EL_SOKOBAN_FIELD_EMPTY,
3920 EL_SOKOBAN_FIELD_FULL,
3921 EL_WALL_EMERALD_RED,
3922 EL_WALL_EMERALD_PURPLE,
3923 EL_ACID_POOL_TOPLEFT,
3924 EL_ACID_POOL_TOPRIGHT,
3925 EL_ACID_POOL_BOTTOMLEFT,
3926 EL_ACID_POOL_BOTTOM,
3927 EL_ACID_POOL_BOTTOMRIGHT,
3931 EL_BD_MAGIC_WALL_DEAD,
3933 EL_DC_MAGIC_WALL_DEAD,
3934 EL_AMOEBA_TO_DIAMOND,
3942 EL_SP_GRAVITY_PORT_RIGHT,
3943 EL_SP_GRAVITY_PORT_DOWN,
3944 EL_SP_GRAVITY_PORT_LEFT,
3945 EL_SP_GRAVITY_PORT_UP,
3946 EL_SP_PORT_HORIZONTAL,
3947 EL_SP_PORT_VERTICAL,
3958 EL_SP_HARDWARE_GRAY,
3959 EL_SP_HARDWARE_GREEN,
3960 EL_SP_HARDWARE_BLUE,
3962 EL_SP_HARDWARE_YELLOW,
3963 EL_SP_HARDWARE_BASE_1,
3964 EL_SP_HARDWARE_BASE_2,
3965 EL_SP_HARDWARE_BASE_3,
3966 EL_SP_HARDWARE_BASE_4,
3967 EL_SP_HARDWARE_BASE_5,
3968 EL_SP_HARDWARE_BASE_6,
3969 EL_SP_GRAVITY_ON_PORT_LEFT,
3970 EL_SP_GRAVITY_ON_PORT_RIGHT,
3971 EL_SP_GRAVITY_ON_PORT_UP,
3972 EL_SP_GRAVITY_ON_PORT_DOWN,
3973 EL_SP_GRAVITY_OFF_PORT_LEFT,
3974 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3975 EL_SP_GRAVITY_OFF_PORT_UP,
3976 EL_SP_GRAVITY_OFF_PORT_DOWN,
3977 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3978 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3979 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3980 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3981 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3982 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3983 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3984 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3985 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3986 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3987 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3988 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3989 EL_SIGN_EXCLAMATION,
3990 EL_SIGN_RADIOACTIVITY,
3997 EL_SIGN_ENTRY_FORBIDDEN,
3998 EL_SIGN_EMERGENCY_EXIT,
4006 EL_DC_STEELWALL_1_LEFT,
4007 EL_DC_STEELWALL_1_RIGHT,
4008 EL_DC_STEELWALL_1_TOP,
4009 EL_DC_STEELWALL_1_BOTTOM,
4010 EL_DC_STEELWALL_1_HORIZONTAL,
4011 EL_DC_STEELWALL_1_VERTICAL,
4012 EL_DC_STEELWALL_1_TOPLEFT,
4013 EL_DC_STEELWALL_1_TOPRIGHT,
4014 EL_DC_STEELWALL_1_BOTTOMLEFT,
4015 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4016 EL_DC_STEELWALL_1_TOPLEFT_2,
4017 EL_DC_STEELWALL_1_TOPRIGHT_2,
4018 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4019 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4020 EL_DC_STEELWALL_2_LEFT,
4021 EL_DC_STEELWALL_2_RIGHT,
4022 EL_DC_STEELWALL_2_TOP,
4023 EL_DC_STEELWALL_2_BOTTOM,
4024 EL_DC_STEELWALL_2_HORIZONTAL,
4025 EL_DC_STEELWALL_2_VERTICAL,
4026 EL_DC_STEELWALL_2_MIDDLE,
4027 EL_DC_STEELWALL_2_SINGLE,
4028 EL_STEELWALL_SLIPPERY,
4033 EL_EMC_WALL_SLIPPERY_1,
4034 EL_EMC_WALL_SLIPPERY_2,
4035 EL_EMC_WALL_SLIPPERY_3,
4036 EL_EMC_WALL_SLIPPERY_4,
4057 static int ep_em_slippery_wall[] =
4062 static int ep_gfx_crumbled[] =
4073 static int ep_editor_cascade_active[] =
4075 EL_INTERNAL_CASCADE_BD_ACTIVE,
4076 EL_INTERNAL_CASCADE_EM_ACTIVE,
4077 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4078 EL_INTERNAL_CASCADE_RND_ACTIVE,
4079 EL_INTERNAL_CASCADE_SB_ACTIVE,
4080 EL_INTERNAL_CASCADE_SP_ACTIVE,
4081 EL_INTERNAL_CASCADE_DC_ACTIVE,
4082 EL_INTERNAL_CASCADE_DX_ACTIVE,
4083 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4084 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4085 EL_INTERNAL_CASCADE_CE_ACTIVE,
4086 EL_INTERNAL_CASCADE_GE_ACTIVE,
4087 EL_INTERNAL_CASCADE_REF_ACTIVE,
4088 EL_INTERNAL_CASCADE_USER_ACTIVE,
4089 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4094 static int ep_editor_cascade_inactive[] =
4096 EL_INTERNAL_CASCADE_BD,
4097 EL_INTERNAL_CASCADE_EM,
4098 EL_INTERNAL_CASCADE_EMC,
4099 EL_INTERNAL_CASCADE_RND,
4100 EL_INTERNAL_CASCADE_SB,
4101 EL_INTERNAL_CASCADE_SP,
4102 EL_INTERNAL_CASCADE_DC,
4103 EL_INTERNAL_CASCADE_DX,
4104 EL_INTERNAL_CASCADE_CHARS,
4105 EL_INTERNAL_CASCADE_STEEL_CHARS,
4106 EL_INTERNAL_CASCADE_CE,
4107 EL_INTERNAL_CASCADE_GE,
4108 EL_INTERNAL_CASCADE_REF,
4109 EL_INTERNAL_CASCADE_USER,
4110 EL_INTERNAL_CASCADE_DYNAMIC,
4115 static int ep_obsolete[] =
4119 EL_EM_KEY_1_FILE_OBSOLETE,
4120 EL_EM_KEY_2_FILE_OBSOLETE,
4121 EL_EM_KEY_3_FILE_OBSOLETE,
4122 EL_EM_KEY_4_FILE_OBSOLETE,
4123 EL_ENVELOPE_OBSOLETE,
4132 } element_properties[] =
4134 { ep_diggable, EP_DIGGABLE },
4135 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4136 { ep_dont_run_into, EP_DONT_RUN_INTO },
4137 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4138 { ep_dont_touch, EP_DONT_TOUCH },
4139 { ep_indestructible, EP_INDESTRUCTIBLE },
4140 { ep_slippery, EP_SLIPPERY },
4141 { ep_can_change, EP_CAN_CHANGE },
4142 { ep_can_move, EP_CAN_MOVE },
4143 { ep_can_fall, EP_CAN_FALL },
4144 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4145 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4146 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4147 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4148 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4149 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4150 { ep_walkable_over, EP_WALKABLE_OVER },
4151 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4152 { ep_walkable_under, EP_WALKABLE_UNDER },
4153 { ep_passable_over, EP_PASSABLE_OVER },
4154 { ep_passable_inside, EP_PASSABLE_INSIDE },
4155 { ep_passable_under, EP_PASSABLE_UNDER },
4156 { ep_droppable, EP_DROPPABLE },
4157 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4158 { ep_pushable, EP_PUSHABLE },
4159 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4160 { ep_protected, EP_PROTECTED },
4161 { ep_throwable, EP_THROWABLE },
4162 { ep_can_explode, EP_CAN_EXPLODE },
4163 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4165 { ep_player, EP_PLAYER },
4166 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4167 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4168 { ep_switchable, EP_SWITCHABLE },
4169 { ep_bd_element, EP_BD_ELEMENT },
4170 { ep_sp_element, EP_SP_ELEMENT },
4171 { ep_sb_element, EP_SB_ELEMENT },
4173 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4174 { ep_food_penguin, EP_FOOD_PENGUIN },
4175 { ep_food_pig, EP_FOOD_PIG },
4176 { ep_historic_wall, EP_HISTORIC_WALL },
4177 { ep_historic_solid, EP_HISTORIC_SOLID },
4178 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4179 { ep_belt, EP_BELT },
4180 { ep_belt_active, EP_BELT_ACTIVE },
4181 { ep_belt_switch, EP_BELT_SWITCH },
4182 { ep_tube, EP_TUBE },
4183 { ep_acid_pool, EP_ACID_POOL },
4184 { ep_keygate, EP_KEYGATE },
4185 { ep_amoeboid, EP_AMOEBOID },
4186 { ep_amoebalive, EP_AMOEBALIVE },
4187 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4188 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4189 { ep_can_grow, EP_CAN_GROW },
4190 { ep_active_bomb, EP_ACTIVE_BOMB },
4191 { ep_inactive, EP_INACTIVE },
4193 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4195 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4197 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4198 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4200 { ep_obsolete, EP_OBSOLETE },
4207 /* always start with reliable default values (element has no properties) */
4208 /* (but never initialize clipboard elements after the very first time) */
4209 /* (to be able to use clipboard elements between several levels) */
4210 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4211 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4212 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4213 SET_PROPERTY(i, j, FALSE);
4215 /* set all base element properties from above array definitions */
4216 for (i = 0; element_properties[i].elements != NULL; i++)
4217 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4218 SET_PROPERTY((element_properties[i].elements)[j],
4219 element_properties[i].property, TRUE);
4221 /* copy properties to some elements that are only stored in level file */
4222 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4223 for (j = 0; copy_properties[j][0] != -1; j++)
4224 if (HAS_PROPERTY(copy_properties[j][0], i))
4225 for (k = 1; k <= 4; k++)
4226 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4228 /* set static element properties that are not listed in array definitions */
4229 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4230 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4232 clipboard_elements_initialized = TRUE;
4235 void InitElementPropertiesEngine(int engine_version)
4237 static int no_wall_properties[] =
4240 EP_COLLECTIBLE_ONLY,
4242 EP_DONT_COLLIDE_WITH,
4245 EP_CAN_SMASH_PLAYER,
4246 EP_CAN_SMASH_ENEMIES,
4247 EP_CAN_SMASH_EVERYTHING,
4252 EP_FOOD_DARK_YAMYAM,
4268 /* important: after initialization in InitElementPropertiesStatic(), the
4269 elements are not again initialized to a default value; therefore all
4270 changes have to make sure that they leave the element with a defined
4271 property (which means that conditional property changes must be set to
4272 a reliable default value before) */
4274 /* resolve group elements */
4275 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4276 ResolveGroupElement(EL_GROUP_START + i);
4278 /* set all special, combined or engine dependent element properties */
4279 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4281 /* do not change (already initialized) clipboard elements here */
4282 if (IS_CLIPBOARD_ELEMENT(i))
4285 /* ---------- INACTIVE ------------------------------------------------- */
4286 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4287 i <= EL_CHAR_END) ||
4288 (i >= EL_STEEL_CHAR_START &&
4289 i <= EL_STEEL_CHAR_END)));
4291 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4292 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4293 IS_WALKABLE_INSIDE(i) ||
4294 IS_WALKABLE_UNDER(i)));
4296 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4297 IS_PASSABLE_INSIDE(i) ||
4298 IS_PASSABLE_UNDER(i)));
4300 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4301 IS_PASSABLE_OVER(i)));
4303 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4304 IS_PASSABLE_INSIDE(i)));
4306 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4307 IS_PASSABLE_UNDER(i)));
4309 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4312 /* ---------- COLLECTIBLE ---------------------------------------------- */
4313 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4317 /* ---------- SNAPPABLE ------------------------------------------------ */
4318 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4319 IS_COLLECTIBLE(i) ||
4323 /* ---------- WALL ----------------------------------------------------- */
4324 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4326 for (j = 0; no_wall_properties[j] != -1; j++)
4327 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4328 i >= EL_FIRST_RUNTIME_UNREAL)
4329 SET_PROPERTY(i, EP_WALL, FALSE);
4331 if (IS_HISTORIC_WALL(i))
4332 SET_PROPERTY(i, EP_WALL, TRUE);
4334 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4335 if (engine_version < VERSION_IDENT(2,2,0,0))
4336 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4338 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4340 !IS_COLLECTIBLE(i)));
4342 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4343 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4344 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4346 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4347 IS_INDESTRUCTIBLE(i)));
4349 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4351 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4352 else if (engine_version < VERSION_IDENT(2,2,0,0))
4353 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4355 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4359 if (IS_CUSTOM_ELEMENT(i))
4361 /* these are additional properties which are initially false when set */
4363 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4365 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4366 if (DONT_COLLIDE_WITH(i))
4367 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4369 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4370 if (CAN_SMASH_EVERYTHING(i))
4371 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4372 if (CAN_SMASH_ENEMIES(i))
4373 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4376 /* ---------- CAN_SMASH ------------------------------------------------ */
4377 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4378 CAN_SMASH_ENEMIES(i) ||
4379 CAN_SMASH_EVERYTHING(i)));
4381 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4382 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4383 EXPLODES_BY_FIRE(i)));
4385 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4386 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4387 EXPLODES_SMASHED(i)));
4389 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4390 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4391 EXPLODES_IMPACT(i)));
4393 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4394 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4396 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4397 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4398 i == EL_BLACK_ORB));
4400 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4401 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4403 IS_CUSTOM_ELEMENT(i)));
4405 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4406 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4407 i == EL_SP_ELECTRON));
4409 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4410 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4411 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4412 getMoveIntoAcidProperty(&level, i));
4414 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4415 if (MAYBE_DONT_COLLIDE_WITH(i))
4416 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4417 getDontCollideWithProperty(&level, i));
4419 /* ---------- SP_PORT -------------------------------------------------- */
4420 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4421 IS_PASSABLE_INSIDE(i)));
4423 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4424 for (j = 0; j < level.num_android_clone_elements; j++)
4425 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4427 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4429 /* ---------- CAN_CHANGE ----------------------------------------------- */
4430 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4431 for (j = 0; j < element_info[i].num_change_pages; j++)
4432 if (element_info[i].change_page[j].can_change)
4433 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4435 /* ---------- HAS_ACTION ----------------------------------------------- */
4436 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4437 for (j = 0; j < element_info[i].num_change_pages; j++)
4438 if (element_info[i].change_page[j].has_action)
4439 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4441 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4442 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4445 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4446 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4447 element_info[i].crumbled[ACTION_DEFAULT] !=
4448 element_info[i].graphic[ACTION_DEFAULT]);
4450 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4451 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4452 IS_EDITOR_CASCADE_INACTIVE(i)));
4455 /* dynamically adjust element properties according to game engine version */
4457 static int ep_em_slippery_wall[] =
4462 EL_EXPANDABLE_WALL_HORIZONTAL,
4463 EL_EXPANDABLE_WALL_VERTICAL,
4464 EL_EXPANDABLE_WALL_ANY,
4465 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4466 EL_EXPANDABLE_STEELWALL_VERTICAL,
4467 EL_EXPANDABLE_STEELWALL_ANY,
4468 EL_EXPANDABLE_STEELWALL_GROWING,
4472 static int ep_em_explodes_by_fire[] =
4475 EL_EM_DYNAMITE_ACTIVE,
4480 /* special EM style gems behaviour */
4481 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4482 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4483 level.em_slippery_gems);
4485 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4486 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4487 (level.em_slippery_gems &&
4488 engine_version > VERSION_IDENT(2,0,1,0)));
4490 /* special EM style explosion behaviour regarding chain reactions */
4491 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4492 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4493 level.em_explodes_by_fire);
4496 /* this is needed because some graphics depend on element properties */
4497 if (game_status == GAME_MODE_PLAYING)
4498 InitElementGraphicInfo();
4501 void InitElementPropertiesAfterLoading(int engine_version)
4505 /* set some other uninitialized values of custom elements in older levels */
4506 if (engine_version < VERSION_IDENT(3,1,0,0))
4508 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4510 int element = EL_CUSTOM_START + i;
4512 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4514 element_info[element].explosion_delay = 17;
4515 element_info[element].ignition_delay = 8;
4520 void InitElementPropertiesGfxElement()
4524 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4526 struct ElementInfo *ei = &element_info[i];
4528 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4532 static void InitGlobal()
4537 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4539 /* check if element_name_info entry defined for each element in "main.h" */
4540 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4541 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4543 element_info[i].token_name = element_name_info[i].token_name;
4544 element_info[i].class_name = element_name_info[i].class_name;
4545 element_info[i].editor_description= element_name_info[i].editor_description;
4548 /* create hash from image config list */
4549 image_config_hash = newSetupFileHash();
4550 for (i = 0; image_config[i].token != NULL; i++)
4551 setHashEntry(image_config_hash,
4552 image_config[i].token,
4553 image_config[i].value);
4555 /* create hash from element token list */
4556 element_token_hash = newSetupFileHash();
4557 for (i = 0; element_name_info[i].token_name != NULL; i++)
4558 setHashEntry(element_token_hash,
4559 element_name_info[i].token_name,
4562 /* create hash from graphic token list */
4563 graphic_token_hash = newSetupFileHash();
4564 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4565 if (strSuffix(image_config[i].value, ".png") ||
4566 strSuffix(image_config[i].value, ".pcx") ||
4567 strSuffix(image_config[i].value, ".wav") ||
4568 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4569 setHashEntry(graphic_token_hash,
4570 image_config[i].token,
4571 int2str(graphic++, 0));
4573 /* create hash from font token list */
4574 font_token_hash = newSetupFileHash();
4575 for (i = 0; font_info[i].token_name != NULL; i++)
4576 setHashEntry(font_token_hash,
4577 font_info[i].token_name,
4580 /* set default filenames for all cloned graphics in static configuration */
4581 for (i = 0; image_config[i].token != NULL; i++)
4583 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4585 char *token = image_config[i].token;
4586 char *token_clone_from = getStringCat2(token, ".clone_from");
4587 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4589 if (token_cloned != NULL)
4591 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4593 if (value_cloned != NULL)
4595 /* set default filename in static configuration */
4596 image_config[i].value = value_cloned;
4598 /* set default filename in image config hash */
4599 setHashEntry(image_config_hash, token, value_cloned);
4603 free(token_clone_from);
4607 /* always start with reliable default values (all elements) */
4608 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4609 ActiveElement[i] = i;
4611 /* now add all entries that have an active state (active elements) */
4612 for (i = 0; element_with_active_state[i].element != -1; i++)
4614 int element = element_with_active_state[i].element;
4615 int element_active = element_with_active_state[i].element_active;
4617 ActiveElement[element] = element_active;
4620 /* always start with reliable default values (all buttons) */
4621 for (i = 0; i < NUM_IMAGE_FILES; i++)
4622 ActiveButton[i] = i;
4624 /* now add all entries that have an active state (active buttons) */
4625 for (i = 0; button_with_active_state[i].button != -1; i++)
4627 int button = button_with_active_state[i].button;
4628 int button_active = button_with_active_state[i].button_active;
4630 ActiveButton[button] = button_active;
4633 /* always start with reliable default values (all fonts) */
4634 for (i = 0; i < NUM_FONTS; i++)
4637 /* now add all entries that have an active state (active fonts) */
4638 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4640 int font = font_with_active_state[i].font_nr;
4641 int font_active = font_with_active_state[i].font_nr_active;
4643 ActiveFont[font] = font_active;
4646 global.autoplay_leveldir = NULL;
4647 global.convert_leveldir = NULL;
4648 global.create_images_dir = NULL;
4650 global.frames_per_second = 0;
4652 global.border_status = GAME_MODE_MAIN;
4654 global.use_envelope_request = FALSE;
4657 void Execute_Command(char *command)
4661 if (strEqual(command, "print graphicsinfo.conf"))
4663 Print("# You can configure additional/alternative image files here.\n");
4664 Print("# (The entries below are default and therefore commented out.)\n");
4666 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4668 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4671 for (i = 0; image_config[i].token != NULL; i++)
4672 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4673 image_config[i].value));
4677 else if (strEqual(command, "print soundsinfo.conf"))
4679 Print("# You can configure additional/alternative sound files here.\n");
4680 Print("# (The entries below are default and therefore commented out.)\n");
4682 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4684 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4687 for (i = 0; sound_config[i].token != NULL; i++)
4688 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4689 sound_config[i].value));
4693 else if (strEqual(command, "print musicinfo.conf"))
4695 Print("# You can configure additional/alternative music files here.\n");
4696 Print("# (The entries below are default and therefore commented out.)\n");
4698 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4700 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4703 for (i = 0; music_config[i].token != NULL; i++)
4704 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4705 music_config[i].value));
4709 else if (strEqual(command, "print editorsetup.conf"))
4711 Print("# You can configure your personal editor element list here.\n");
4712 Print("# (The entries below are default and therefore commented out.)\n");
4715 /* this is needed to be able to check element list for cascade elements */
4716 InitElementPropertiesStatic();
4717 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4719 PrintEditorElementList();
4723 else if (strEqual(command, "print helpanim.conf"))
4725 Print("# You can configure different element help animations here.\n");
4726 Print("# (The entries below are default and therefore commented out.)\n");
4729 for (i = 0; helpanim_config[i].token != NULL; i++)
4731 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4732 helpanim_config[i].value));
4734 if (strEqual(helpanim_config[i].token, "end"))
4740 else if (strEqual(command, "print helptext.conf"))
4742 Print("# You can configure different element help text here.\n");
4743 Print("# (The entries below are default and therefore commented out.)\n");
4746 for (i = 0; helptext_config[i].token != NULL; i++)
4747 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4748 helptext_config[i].value));
4752 else if (strPrefix(command, "dump level "))
4754 char *filename = &command[11];
4756 if (!fileExists(filename))
4757 Error(ERR_EXIT, "cannot open file '%s'", filename);
4759 LoadLevelFromFilename(&level, filename);
4764 else if (strPrefix(command, "dump tape "))
4766 char *filename = &command[10];
4768 if (!fileExists(filename))
4769 Error(ERR_EXIT, "cannot open file '%s'", filename);
4771 LoadTapeFromFilename(filename);
4776 else if (strPrefix(command, "autotest ") ||
4777 strPrefix(command, "autoplay ") ||
4778 strPrefix(command, "autoffwd "))
4780 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4782 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4783 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4784 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4786 while (*str_ptr != '\0') /* continue parsing string */
4788 /* cut leading whitespace from string, replace it by string terminator */
4789 while (*str_ptr == ' ' || *str_ptr == '\t')
4792 if (*str_ptr == '\0') /* end of string reached */
4795 if (global.autoplay_leveldir == NULL) /* read level set string */
4797 global.autoplay_leveldir = str_ptr;
4798 global.autoplay_all = TRUE; /* default: play all tapes */
4800 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4801 global.autoplay_level[i] = FALSE;
4803 else /* read level number string */
4805 int level_nr = atoi(str_ptr); /* get level_nr value */
4807 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4808 global.autoplay_level[level_nr] = TRUE;
4810 global.autoplay_all = FALSE;
4813 /* advance string pointer to the next whitespace (or end of string) */
4814 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4818 else if (strPrefix(command, "convert "))
4820 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4821 char *str_ptr = strchr(str_copy, ' ');
4823 global.convert_leveldir = str_copy;
4824 global.convert_level_nr = -1;
4826 if (str_ptr != NULL) /* level number follows */
4828 *str_ptr++ = '\0'; /* terminate leveldir string */
4829 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4832 else if (strPrefix(command, "create images "))
4834 global.create_images_dir = getStringCopy(&command[14]);
4836 if (access(global.create_images_dir, W_OK) != 0)
4837 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4838 global.create_images_dir);
4840 else if (strPrefix(command, "create CE image "))
4842 CreateCustomElementImages(&command[16]);
4848 #if defined(TARGET_SDL2)
4849 else if (strEqual(command, "SDL_ListModes"))
4851 SDL_Init(SDL_INIT_VIDEO);
4853 int num_displays = SDL_GetNumVideoDisplays();
4855 // check if there are any displays available
4856 if (num_displays < 0)
4858 Print("No displays available: %s\n", SDL_GetError());
4863 for (i = 0; i < num_displays; i++)
4865 int num_modes = SDL_GetNumDisplayModes(i);
4868 Print("Available display modes for display %d:\n", i);
4870 // check if there are any display modes available for this display
4873 Print("No display modes available for display %d: %s\n",
4879 for (j = 0; j < num_modes; j++)
4881 SDL_DisplayMode mode;
4883 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4885 Print("Cannot get display mode %d for display %d: %s\n",
4886 j, i, SDL_GetError());
4891 Print("- %d x %d\n", mode.w, mode.h);
4897 #elif defined(TARGET_SDL)
4898 else if (strEqual(command, "SDL_ListModes"))
4903 SDL_Init(SDL_INIT_VIDEO);
4905 /* get available fullscreen/hardware modes */
4906 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4908 /* check if there are any modes available */
4911 Print("No modes available!\n");
4916 /* check if our resolution is restricted */
4917 if (modes == (SDL_Rect **)-1)
4919 Print("All resolutions available.\n");
4923 Print("Available display modes:\n");
4925 for (i = 0; modes[i]; i++)
4926 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4936 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4940 static void InitSetup()
4942 LoadSetup(); /* global setup info */
4944 /* set some options from setup file */
4946 if (setup.options.verbose)
4947 options.verbose = TRUE;
4950 static void InitGameInfo()
4952 game.restart_level = FALSE;
4955 static void InitPlayerInfo()
4959 /* choose default local player */
4960 local_player = &stored_player[0];
4962 for (i = 0; i < MAX_PLAYERS; i++)
4963 stored_player[i].connected = FALSE;
4965 local_player->connected = TRUE;
4968 static void InitArtworkInfo()
4973 static char *get_string_in_brackets(char *string)
4975 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4977 sprintf(string_in_brackets, "[%s]", string);
4979 return string_in_brackets;
4982 static char *get_level_id_suffix(int id_nr)
4984 char *id_suffix = checked_malloc(1 + 3 + 1);
4986 if (id_nr < 0 || id_nr > 999)
4989 sprintf(id_suffix, ".%03d", id_nr);
4994 static void InitArtworkConfig()
4996 static char *image_id_prefix[MAX_NUM_ELEMENTS +
4998 NUM_GLOBAL_ANIM_TOKENS + 1];
4999 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5000 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5001 static char *action_id_suffix[NUM_ACTIONS + 1];
5002 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5003 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5004 static char *level_id_suffix[MAX_LEVELS + 1];
5005 static char *dummy[1] = { NULL };
5006 static char *ignore_generic_tokens[] =
5012 static char **ignore_image_tokens;
5013 static char **ignore_sound_tokens;
5014 static char **ignore_music_tokens;
5015 int num_ignore_generic_tokens;
5016 int num_ignore_image_tokens;
5017 int num_ignore_sound_tokens;
5018 int num_ignore_music_tokens;
5021 /* dynamically determine list of generic tokens to be ignored */
5022 num_ignore_generic_tokens = 0;
5023 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5024 num_ignore_generic_tokens++;
5026 /* dynamically determine list of image tokens to be ignored */
5027 num_ignore_image_tokens = num_ignore_generic_tokens;
5028 for (i = 0; image_config_vars[i].token != NULL; i++)
5029 num_ignore_image_tokens++;
5030 ignore_image_tokens =
5031 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5032 for (i = 0; i < num_ignore_generic_tokens; i++)
5033 ignore_image_tokens[i] = ignore_generic_tokens[i];
5034 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5035 ignore_image_tokens[num_ignore_generic_tokens + i] =
5036 image_config_vars[i].token;
5037 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5039 /* dynamically determine list of sound tokens to be ignored */
5040 num_ignore_sound_tokens = num_ignore_generic_tokens;
5041 ignore_sound_tokens =
5042 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5043 for (i = 0; i < num_ignore_generic_tokens; i++)
5044 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5045 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5047 /* dynamically determine list of music tokens to be ignored */
5048 num_ignore_music_tokens = num_ignore_generic_tokens;
5049 ignore_music_tokens =
5050 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5051 for (i = 0; i < num_ignore_generic_tokens; i++)
5052 ignore_music_tokens[i] = ignore_generic_tokens[i];
5053 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5055 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5056 image_id_prefix[i] = element_info[i].token_name;
5057 for (i = 0; i < NUM_FONTS; i++)
5058 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5059 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5060 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5061 global_anim_info[i].token_name;
5062 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5064 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5065 sound_id_prefix[i] = element_info[i].token_name;
5066 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5067 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5068 get_string_in_brackets(element_info[i].class_name);
5069 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5071 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5072 music_id_prefix[i] = music_prefix_info[i].prefix;
5073 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5075 for (i = 0; i < NUM_ACTIONS; i++)
5076 action_id_suffix[i] = element_action_info[i].suffix;
5077 action_id_suffix[NUM_ACTIONS] = NULL;
5079 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5080 direction_id_suffix[i] = element_direction_info[i].suffix;
5081 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5083 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5084 special_id_suffix[i] = special_suffix_info[i].suffix;
5085 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5087 for (i = 0; i < MAX_LEVELS; i++)
5088 level_id_suffix[i] = get_level_id_suffix(i);
5089 level_id_suffix[MAX_LEVELS] = NULL;
5091 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5092 image_id_prefix, action_id_suffix, direction_id_suffix,
5093 special_id_suffix, ignore_image_tokens);
5094 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5095 sound_id_prefix, action_id_suffix, dummy,
5096 special_id_suffix, ignore_sound_tokens);
5097 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5098 music_id_prefix, special_id_suffix, level_id_suffix,
5099 dummy, ignore_music_tokens);
5102 static void InitMixer()
5109 void InitGfxBuffers()
5111 static int win_xsize_last = -1;
5112 static int win_ysize_last = -1;
5114 /* create additional image buffers for double-buffering and cross-fading */
5116 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5118 /* may contain content for cross-fading -- only re-create if changed */
5119 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5120 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5122 win_xsize_last = WIN_XSIZE;
5123 win_ysize_last = WIN_YSIZE;
5126 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5127 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5128 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5129 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5130 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5132 /* initialize screen properties */
5133 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5134 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5136 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5137 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5138 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5139 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5140 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5141 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5143 /* required if door size definitions have changed */
5144 InitGraphicCompatibilityInfo_Doors();
5146 InitGfxBuffers_EM();
5147 InitGfxBuffers_SP();
5152 struct GraphicInfo *graphic_info_last = graphic_info;
5153 char *filename_font_initial = NULL;
5154 char *filename_anim_initial = NULL;
5155 Bitmap *bitmap_font_initial = NULL;
5159 /* determine settings for initial font (for displaying startup messages) */
5160 for (i = 0; image_config[i].token != NULL; i++)
5162 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5164 char font_token[128];
5167 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5168 len_font_token = strlen(font_token);
5170 if (strEqual(image_config[i].token, font_token))
5171 filename_font_initial = image_config[i].value;
5172 else if (strlen(image_config[i].token) > len_font_token &&
5173 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5175 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5176 font_initial[j].src_x = atoi(image_config[i].value);
5177 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5178 font_initial[j].src_y = atoi(image_config[i].value);
5179 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5180 font_initial[j].width = atoi(image_config[i].value);
5181 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5182 font_initial[j].height = atoi(image_config[i].value);
5187 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5189 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5190 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5193 if (filename_font_initial == NULL) /* should not happen */
5194 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5197 InitGfxCustomArtworkInfo();
5198 InitGfxOtherSettings();
5200 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5202 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5203 font_initial[j].bitmap = bitmap_font_initial;
5205 InitFontGraphicInfo();
5207 font_height = getFontHeight(FC_RED);
5209 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5210 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5211 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5214 DrawInitText("Loading graphics", 120, FC_GREEN);
5216 /* initialize settings for busy animation with default values */
5217 int parameter[NUM_GFX_ARGS];
5218 for (i = 0; i < NUM_GFX_ARGS; i++)
5219 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5220 image_config_suffix[i].token,
5221 image_config_suffix[i].type);
5223 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5224 int len_anim_token = strlen(anim_token);
5226 /* read settings for busy animation from default custom artwork config */
5227 char *gfx_config_filename = getPath3(options.graphics_directory,
5229 GRAPHICSINFO_FILENAME);
5231 if (fileExists(gfx_config_filename))
5233 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5235 if (setup_file_hash)
5237 char *filename = getHashEntry(setup_file_hash, anim_token);
5241 filename_anim_initial = getStringCopy(filename);
5243 for (j = 0; image_config_suffix[j].token != NULL; j++)
5245 int type = image_config_suffix[j].type;
5246 char *suffix = image_config_suffix[j].token;
5247 char *token = getStringCat2(anim_token, suffix);
5248 char *value = getHashEntry(setup_file_hash, token);
5250 checked_free(token);
5253 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5257 freeSetupFileHash(setup_file_hash);
5261 if (filename_anim_initial == NULL)
5263 /* read settings for busy animation from static default artwork config */
5264 for (i = 0; image_config[i].token != NULL; i++)
5266 if (strEqual(image_config[i].token, anim_token))
5267 filename_anim_initial = getStringCopy(image_config[i].value);
5268 else if (strlen(image_config[i].token) > len_anim_token &&
5269 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5271 for (j = 0; image_config_suffix[j].token != NULL; j++)
5273 if (strEqual(&image_config[i].token[len_anim_token],
5274 image_config_suffix[j].token))
5276 get_graphic_parameter_value(image_config[i].value,
5277 image_config_suffix[j].token,
5278 image_config_suffix[j].type);
5284 if (filename_anim_initial == NULL) /* should not happen */
5285 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5287 anim_initial.bitmaps =
5288 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5290 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5291 LoadCustomImage(filename_anim_initial);
5293 checked_free(filename_anim_initial);
5295 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5297 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5299 graphic_info = graphic_info_last;
5301 init.busy.width = anim_initial.width;
5302 init.busy.height = anim_initial.height;
5304 InitMenuDesignSettings_Static();
5306 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5307 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5309 /* use copy of busy animation to prevent change while reloading artwork */
5313 void InitGfxBackground()
5315 fieldbuffer = bitmap_db_field;
5316 SetDrawtoField(DRAW_BACKBUFFER);
5318 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5320 redraw_mask = REDRAW_ALL;
5323 static void InitLevelInfo()
5325 LoadLevelInfo(); /* global level info */
5326 LoadLevelSetup_LastSeries(); /* last played series info */
5327 LoadLevelSetup_SeriesInfo(); /* last played level info */
5329 if (global.autoplay_leveldir &&
5330 global.autoplay_mode != AUTOPLAY_TEST)
5332 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5333 global.autoplay_leveldir);
5334 if (leveldir_current == NULL)
5335 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5339 static void InitLevelArtworkInfo()
5341 LoadLevelArtworkInfo();
5344 static void InitImages()
5346 print_timestamp_init("InitImages");
5349 printf("::: leveldir_current->identifier == '%s'\n",
5350 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5351 printf("::: leveldir_current->graphics_path == '%s'\n",
5352 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5353 printf("::: leveldir_current->graphics_set == '%s'\n",
5354 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5355 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5356 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5359 setLevelArtworkDir(artwork.gfx_first);
5362 printf("::: leveldir_current->identifier == '%s'\n",
5363 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5364 printf("::: leveldir_current->graphics_path == '%s'\n",
5365 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5366 printf("::: leveldir_current->graphics_set == '%s'\n",
5367 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5368 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5369 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5373 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5374 leveldir_current->identifier,
5375 artwork.gfx_current_identifier,
5376 artwork.gfx_current->identifier,
5377 leveldir_current->graphics_set,
5378 leveldir_current->graphics_path);
5381 UPDATE_BUSY_STATE();
5383 ReloadCustomImages();
5384 print_timestamp_time("ReloadCustomImages");
5386 UPDATE_BUSY_STATE();
5388 LoadCustomElementDescriptions();
5389 print_timestamp_time("LoadCustomElementDescriptions");
5391 UPDATE_BUSY_STATE();
5393 LoadMenuDesignSettings();
5394 print_timestamp_time("LoadMenuDesignSettings");
5396 UPDATE_BUSY_STATE();
5398 ReinitializeGraphics();
5399 print_timestamp_time("ReinitializeGraphics");
5401 UPDATE_BUSY_STATE();
5403 print_timestamp_done("InitImages");
5406 static void InitSound(char *identifier)
5408 print_timestamp_init("InitSound");
5410 if (identifier == NULL)
5411 identifier = artwork.snd_current->identifier;
5413 /* set artwork path to send it to the sound server process */
5414 setLevelArtworkDir(artwork.snd_first);
5416 InitReloadCustomSounds(identifier);
5417 print_timestamp_time("InitReloadCustomSounds");
5419 ReinitializeSounds();
5420 print_timestamp_time("ReinitializeSounds");
5422 print_timestamp_done("InitSound");
5425 static void InitMusic(char *identifier)
5427 print_timestamp_init("InitMusic");
5429 if (identifier == NULL)
5430 identifier = artwork.mus_current->identifier;
5432 /* set artwork path to send it to the sound server process */
5433 setLevelArtworkDir(artwork.mus_first);
5435 InitReloadCustomMusic(identifier);
5436 print_timestamp_time("InitReloadCustomMusic");
5438 ReinitializeMusic();
5439 print_timestamp_time("ReinitializeMusic");
5441 print_timestamp_done("InitMusic");
5444 void InitNetworkServer()
5446 #if defined(NETWORK_AVALIABLE)
5450 if (!options.network)
5453 #if defined(NETWORK_AVALIABLE)
5454 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5456 if (!ConnectToServer(options.server_host, options.server_port))
5457 Error(ERR_EXIT, "cannot connect to network game server");
5459 SendToServer_PlayerName(setup.player_name);
5460 SendToServer_ProtocolVersion();
5463 SendToServer_NrWanted(nr_wanted);
5467 static boolean CheckArtworkConfigForCustomElements(char *filename)
5469 SetupFileHash *setup_file_hash;
5470 boolean redefined_ce_found = FALSE;
5472 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5474 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5476 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5478 char *token = HASH_ITERATION_TOKEN(itr);
5480 if (strPrefix(token, "custom_"))
5482 redefined_ce_found = TRUE;
5487 END_HASH_ITERATION(setup_file_hash, itr)
5489 freeSetupFileHash(setup_file_hash);
5492 return redefined_ce_found;
5495 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5497 char *filename_base, *filename_local;
5498 boolean redefined_ce_found = FALSE;
5500 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5503 printf("::: leveldir_current->identifier == '%s'\n",
5504 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5505 printf("::: leveldir_current->graphics_path == '%s'\n",
5506 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5507 printf("::: leveldir_current->graphics_set == '%s'\n",
5508 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5509 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5510 leveldir_current == NULL ? "[NULL]" :
5511 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5514 /* first look for special artwork configured in level series config */
5515 filename_base = getCustomArtworkLevelConfigFilename(type);
5518 printf("::: filename_base == '%s'\n", filename_base);
5521 if (fileExists(filename_base))
5522 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5524 filename_local = getCustomArtworkConfigFilename(type);
5527 printf("::: filename_local == '%s'\n", filename_local);
5530 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5531 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5534 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5537 return redefined_ce_found;
5540 static void InitOverrideArtwork()
5542 boolean redefined_ce_found = FALSE;
5544 /* to check if this level set redefines any CEs, do not use overriding */
5545 gfx.override_level_graphics = FALSE;
5546 gfx.override_level_sounds = FALSE;
5547 gfx.override_level_music = FALSE;
5549 /* now check if this level set has definitions for custom elements */
5550 if (setup.override_level_graphics == AUTO ||
5551 setup.override_level_sounds == AUTO ||
5552 setup.override_level_music == AUTO)
5553 redefined_ce_found =
5554 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5555 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5556 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5559 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5562 if (redefined_ce_found)
5564 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5565 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5566 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5567 gfx.override_level_music = (setup.override_level_music == TRUE);
5571 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5572 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5573 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5574 gfx.override_level_music = (setup.override_level_music != FALSE);
5578 printf("::: => %d, %d, %d\n",
5579 gfx.override_level_graphics,
5580 gfx.override_level_sounds,
5581 gfx.override_level_music);
5585 static char *getNewArtworkIdentifier(int type)
5587 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5588 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5589 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5590 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5591 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5592 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5593 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5594 char *leveldir_identifier = leveldir_current->identifier;
5595 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5596 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5597 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5598 char *artwork_current_identifier;
5599 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5601 /* leveldir_current may be invalid (level group, parent link) */
5602 if (!validLevelSeries(leveldir_current))
5605 /* 1st step: determine artwork set to be activated in descending order:
5606 --------------------------------------------------------------------
5607 1. setup artwork (when configured to override everything else)
5608 2. artwork set configured in "levelinfo.conf" of current level set
5609 (artwork in level directory will have priority when loading later)
5610 3. artwork in level directory (stored in artwork sub-directory)
5611 4. setup artwork (currently configured in setup menu) */
5613 if (setup_override_artwork)
5614 artwork_current_identifier = setup_artwork_set;
5615 else if (leveldir_artwork_set != NULL)
5616 artwork_current_identifier = leveldir_artwork_set;
5617 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5618 artwork_current_identifier = leveldir_identifier;
5620 artwork_current_identifier = setup_artwork_set;
5623 /* 2nd step: check if it is really needed to reload artwork set
5624 ------------------------------------------------------------ */
5626 /* ---------- reload if level set and also artwork set has changed ------- */
5627 if (leveldir_current_identifier[type] != leveldir_identifier &&
5628 (last_has_level_artwork_set[type] || has_level_artwork_set))
5629 artwork_new_identifier = artwork_current_identifier;
5631 leveldir_current_identifier[type] = leveldir_identifier;
5632 last_has_level_artwork_set[type] = has_level_artwork_set;
5634 /* ---------- reload if "override artwork" setting has changed ----------- */
5635 if (last_override_level_artwork[type] != setup_override_artwork)
5636 artwork_new_identifier = artwork_current_identifier;
5638 last_override_level_artwork[type] = setup_override_artwork;
5640 /* ---------- reload if current artwork identifier has changed ----------- */
5641 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5642 artwork_current_identifier))
5643 artwork_new_identifier = artwork_current_identifier;
5645 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5647 /* ---------- do not reload directly after starting ---------------------- */
5648 if (!initialized[type])
5649 artwork_new_identifier = NULL;
5651 initialized[type] = TRUE;
5653 return artwork_new_identifier;
5656 void ReloadCustomArtwork(int force_reload)
5658 int last_game_status = game_status; /* save current game status */
5659 char *gfx_new_identifier;
5660 char *snd_new_identifier;
5661 char *mus_new_identifier;
5662 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5663 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5664 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5665 boolean reload_needed;
5667 InitOverrideArtwork();
5669 force_reload_gfx |= AdjustGraphicsForEMC();
5671 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5672 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5673 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5675 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5676 snd_new_identifier != NULL || force_reload_snd ||
5677 mus_new_identifier != NULL || force_reload_mus);
5682 print_timestamp_init("ReloadCustomArtwork");
5684 game_status = GAME_MODE_LOADING;
5686 FadeOut(REDRAW_ALL);
5688 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5689 print_timestamp_time("ClearRectangle");
5693 if (gfx_new_identifier != NULL || force_reload_gfx)
5696 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5697 artwork.gfx_current_identifier,
5699 artwork.gfx_current->identifier,
5700 leveldir_current->graphics_set);
5704 print_timestamp_time("InitImages");
5707 if (snd_new_identifier != NULL || force_reload_snd)
5709 InitSound(snd_new_identifier);
5710 print_timestamp_time("InitSound");
5713 if (mus_new_identifier != NULL || force_reload_mus)
5715 InitMusic(mus_new_identifier);
5716 print_timestamp_time("InitMusic");
5719 game_status = last_game_status; /* restore current game status */
5721 init_last = init; /* switch to new busy animation */
5723 FadeOut(REDRAW_ALL);
5725 RedrawGlobalBorder();
5727 /* force redraw of (open or closed) door graphics */
5728 SetDoorState(DOOR_OPEN_ALL);
5729 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5731 FadeSetEnterScreen();
5732 FadeSkipNextFadeOut();
5734 print_timestamp_done("ReloadCustomArtwork");
5736 LimitScreenUpdates(FALSE);
5739 void KeyboardAutoRepeatOffUnlessAutoplay()
5741 if (global.autoplay_leveldir == NULL)
5742 KeyboardAutoRepeatOff();
5745 void DisplayExitMessage(char *format, va_list ap)
5747 // check if draw buffer and fonts for exit message are already available
5748 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5751 int font_1 = FC_RED;
5752 int font_2 = FC_YELLOW;
5753 int font_3 = FC_BLUE;
5754 int font_width = getFontWidth(font_2);
5755 int font_height = getFontHeight(font_2);
5758 int sxsize = WIN_XSIZE - 2 * sx;
5759 int sysize = WIN_YSIZE - 2 * sy;
5760 int line_length = sxsize / font_width;
5761 int max_lines = sysize / font_height;
5762 int num_lines_printed;
5766 gfx.sxsize = sxsize;
5767 gfx.sysize = sysize;
5771 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5773 DrawTextSCentered(sy, font_1, "Fatal error:");
5774 sy += 3 * font_height;;
5777 DrawTextBufferVA(sx, sy, format, ap, font_2,
5778 line_length, line_length, max_lines,
5779 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5780 sy += (num_lines_printed + 3) * font_height;
5782 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5783 sy += 3 * font_height;
5786 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5787 line_length, line_length, max_lines,
5788 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5790 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5792 redraw_mask = REDRAW_ALL;
5794 /* force drawing exit message even if screen updates are currently limited */
5795 LimitScreenUpdates(FALSE);
5799 /* deactivate toons on error message screen */
5800 setup.toons = FALSE;
5802 WaitForEventToContinue();
5806 /* ========================================================================= */
5808 /* ========================================================================= */
5812 print_timestamp_init("OpenAll");
5814 game_status = GAME_MODE_LOADING;
5818 InitGlobal(); /* initialize some global variables */
5820 print_timestamp_time("[init global stuff]");
5824 print_timestamp_time("[init setup/config stuff (1)]");
5826 if (options.execute_command)
5827 Execute_Command(options.execute_command);
5829 if (options.serveronly)
5831 #if defined(PLATFORM_UNIX)
5832 NetworkServer(options.server_port, options.serveronly);
5834 Error(ERR_WARN, "networking only supported in Unix version");
5837 exit(0); /* never reached, server loops forever */
5841 print_timestamp_time("[init setup/config stuff (2)]");
5843 print_timestamp_time("[init setup/config stuff (3)]");
5844 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5845 print_timestamp_time("[init setup/config stuff (4)]");
5846 InitArtworkConfig(); /* needed before forking sound child process */
5847 print_timestamp_time("[init setup/config stuff (5)]");
5849 print_timestamp_time("[init setup/config stuff (6)]");
5851 InitRND(NEW_RANDOMIZE);
5852 InitSimpleRandom(NEW_RANDOMIZE);
5856 print_timestamp_time("[init setup/config stuff]");
5859 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5861 InitEventFilter(FilterEvents);
5863 print_timestamp_time("[init video stuff]");
5865 InitElementPropertiesStatic();
5866 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5867 InitElementPropertiesGfxElement();
5869 print_timestamp_time("[init element properties stuff]");
5873 print_timestamp_time("InitGfx");
5876 print_timestamp_time("InitLevelInfo");
5878 InitLevelArtworkInfo();
5879 print_timestamp_time("InitLevelArtworkInfo");
5881 InitOverrideArtwork(); /* needs to know current level directory */
5882 print_timestamp_time("InitOverrideArtwork");
5884 InitImages(); /* needs to know current level directory */
5885 print_timestamp_time("InitImages");
5887 InitSound(NULL); /* needs to know current level directory */
5888 print_timestamp_time("InitSound");
5890 InitMusic(NULL); /* needs to know current level directory */
5891 print_timestamp_time("InitMusic");
5893 InitGfxBackground();
5898 if (global.autoplay_leveldir)
5903 else if (global.convert_leveldir)
5908 else if (global.create_images_dir)
5910 CreateLevelSketchImages();
5914 game_status = GAME_MODE_MAIN;
5916 FadeSetEnterScreen();
5917 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5918 FadeSkipNextFadeOut();
5920 print_timestamp_time("[post-artwork]");
5922 print_timestamp_done("OpenAll");
5926 InitNetworkServer();
5929 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5931 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5932 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5933 #if defined(PLATFORM_ANDROID)
5934 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5935 SDL_AndroidGetInternalStoragePath());
5936 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5937 SDL_AndroidGetExternalStoragePath());
5938 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5939 (SDL_AndroidGetExternalStorageState() ==
5940 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5941 SDL_AndroidGetExternalStorageState() ==
5942 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5947 void CloseAllAndExit(int exit_value)
5952 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5959 #if defined(TARGET_SDL)
5960 #if defined(TARGET_SDL2)
5962 // set a flag to tell the network server thread to quit and wait for it
5963 // using SDL_WaitThread()
5965 if (network_server) /* terminate network server */
5966 SDL_KillThread(server_thread);
5970 CloseVideoDisplay();
5971 ClosePlatformDependentStuff();
5973 if (exit_value != 0)
5975 /* fall back to default level set (current set may have caused an error) */
5976 SaveLevelSetup_LastSeries_Deactivate();
5978 /* tell user where to find error log file which may contain more details */
5979 // (error notification now directly displayed on screen inside R'n'D
5980 // NotifyUserAboutErrorFile(); /* currently only works for Windows */