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];
1350 /* this is only used for drawing font characters */
1351 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1352 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1354 /* this is only used for drawing envelope graphics */
1355 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1357 /* optional graphic for cloning all graphics settings */
1358 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1359 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1361 /* optional settings for drawing title screens and title messages */
1362 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1363 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1364 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1365 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1366 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1367 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1368 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1369 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1370 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1371 g->align = parameter[GFX_ARG_ALIGN];
1372 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1373 g->valign = parameter[GFX_ARG_VALIGN];
1374 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1375 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1377 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1378 g->class = parameter[GFX_ARG_CLASS];
1379 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1380 g->style = parameter[GFX_ARG_STYLE];
1382 /* this is only used for drawing menu buttons and text */
1383 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1384 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1385 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1386 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1389 static void set_graphic_parameters(int graphic)
1391 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1392 char **parameter_raw = image->parameter;
1393 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1394 int parameter[NUM_GFX_ARGS];
1397 /* if fallback to default artwork is done, also use the default parameters */
1398 if (image->fallback_to_default)
1399 parameter_raw = image->default_parameter;
1401 /* get integer values from string parameters */
1402 for (i = 0; i < NUM_GFX_ARGS; i++)
1403 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1404 image_config_suffix[i].token,
1405 image_config_suffix[i].type);
1407 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1409 UPDATE_BUSY_STATE();
1412 static void set_cloned_graphic_parameters(int graphic)
1414 int fallback_graphic = IMG_CHAR_EXCLAM;
1415 int max_num_images = getImageListSize();
1416 int clone_graphic = graphic_info[graphic].clone_from;
1417 int num_references_followed = 1;
1419 while (graphic_info[clone_graphic].clone_from != -1 &&
1420 num_references_followed < max_num_images)
1422 clone_graphic = graphic_info[clone_graphic].clone_from;
1424 num_references_followed++;
1427 if (num_references_followed >= max_num_images)
1429 Error(ERR_INFO_LINE, "-");
1430 Error(ERR_INFO, "warning: error found in config file:");
1431 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1432 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1433 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1434 Error(ERR_INFO, "custom graphic rejected for this element/action");
1436 if (graphic == fallback_graphic)
1437 Error(ERR_EXIT, "no fallback graphic available");
1439 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1440 Error(ERR_INFO_LINE, "-");
1442 graphic_info[graphic] = graphic_info[fallback_graphic];
1446 graphic_info[graphic] = graphic_info[clone_graphic];
1447 graphic_info[graphic].clone_from = clone_graphic;
1451 static void InitGraphicInfo()
1453 int fallback_graphic = IMG_CHAR_EXCLAM;
1454 int num_images = getImageListSize();
1457 /* use image size as default values for width and height for these images */
1458 static int full_size_graphics[] =
1461 IMG_GLOBAL_BORDER_MAIN,
1462 IMG_GLOBAL_BORDER_SCORES,
1463 IMG_GLOBAL_BORDER_EDITOR,
1464 IMG_GLOBAL_BORDER_PLAYING,
1467 IMG_BACKGROUND_ENVELOPE_1,
1468 IMG_BACKGROUND_ENVELOPE_2,
1469 IMG_BACKGROUND_ENVELOPE_3,
1470 IMG_BACKGROUND_ENVELOPE_4,
1471 IMG_BACKGROUND_REQUEST,
1474 IMG_BACKGROUND_TITLE_INITIAL,
1475 IMG_BACKGROUND_TITLE,
1476 IMG_BACKGROUND_MAIN,
1477 IMG_BACKGROUND_LEVELS,
1478 IMG_BACKGROUND_LEVELNR,
1479 IMG_BACKGROUND_SCORES,
1480 IMG_BACKGROUND_EDITOR,
1481 IMG_BACKGROUND_INFO,
1482 IMG_BACKGROUND_INFO_ELEMENTS,
1483 IMG_BACKGROUND_INFO_MUSIC,
1484 IMG_BACKGROUND_INFO_CREDITS,
1485 IMG_BACKGROUND_INFO_PROGRAM,
1486 IMG_BACKGROUND_INFO_VERSION,
1487 IMG_BACKGROUND_INFO_LEVELSET,
1488 IMG_BACKGROUND_SETUP,
1489 IMG_BACKGROUND_PLAYING,
1490 IMG_BACKGROUND_DOOR,
1491 IMG_BACKGROUND_TAPE,
1492 IMG_BACKGROUND_PANEL,
1493 IMG_BACKGROUND_PALETTE,
1494 IMG_BACKGROUND_TOOLBOX,
1496 IMG_TITLESCREEN_INITIAL_1,
1497 IMG_TITLESCREEN_INITIAL_2,
1498 IMG_TITLESCREEN_INITIAL_3,
1499 IMG_TITLESCREEN_INITIAL_4,
1500 IMG_TITLESCREEN_INITIAL_5,
1507 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1508 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1509 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1510 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1511 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1512 IMG_BACKGROUND_TITLEMESSAGE_1,
1513 IMG_BACKGROUND_TITLEMESSAGE_2,
1514 IMG_BACKGROUND_TITLEMESSAGE_3,
1515 IMG_BACKGROUND_TITLEMESSAGE_4,
1516 IMG_BACKGROUND_TITLEMESSAGE_5,
1521 checked_free(graphic_info);
1523 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1525 /* initialize "use_image_size" flag with default value */
1526 for (i = 0; i < num_images; i++)
1527 graphic_info[i].use_image_size = FALSE;
1529 /* initialize "use_image_size" flag from static configuration above */
1530 for (i = 0; full_size_graphics[i] != -1; i++)
1531 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1533 /* first set all graphic paramaters ... */
1534 for (i = 0; i < num_images; i++)
1535 set_graphic_parameters(i);
1537 /* ... then copy these parameters for cloned graphics */
1538 for (i = 0; i < num_images; i++)
1539 if (graphic_info[i].clone_from != -1)
1540 set_cloned_graphic_parameters(i);
1542 for (i = 0; i < num_images; i++)
1547 int first_frame, last_frame;
1548 int src_bitmap_width, src_bitmap_height;
1550 /* now check if no animation frames are outside of the loaded image */
1552 if (graphic_info[i].bitmap == NULL)
1553 continue; /* skip check for optional images that are undefined */
1555 /* get image size (this can differ from the standard element tile size!) */
1556 width = graphic_info[i].width;
1557 height = graphic_info[i].height;
1559 /* get final bitmap size (with scaling, but without small images) */
1560 src_bitmap_width = graphic_info[i].src_image_width;
1561 src_bitmap_height = graphic_info[i].src_image_height;
1563 /* check if first animation frame is inside specified bitmap */
1566 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1568 /* this avoids calculating wrong start position for out-of-bounds frame */
1569 src_x = graphic_info[i].src_x;
1570 src_y = graphic_info[i].src_y;
1572 if (src_x < 0 || src_y < 0 ||
1573 src_x + width > src_bitmap_width ||
1574 src_y + height > src_bitmap_height)
1576 Error(ERR_INFO_LINE, "-");
1577 Error(ERR_INFO, "warning: error found in config file:");
1578 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1579 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1580 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1582 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1583 src_x, src_y, src_bitmap_width, src_bitmap_height);
1584 Error(ERR_INFO, "custom graphic rejected for this element/action");
1586 if (i == fallback_graphic)
1587 Error(ERR_EXIT, "no fallback graphic available");
1589 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1590 Error(ERR_INFO_LINE, "-");
1592 graphic_info[i] = graphic_info[fallback_graphic];
1595 /* check if last animation frame is inside specified bitmap */
1597 last_frame = graphic_info[i].anim_frames - 1;
1598 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1600 if (src_x < 0 || src_y < 0 ||
1601 src_x + width > src_bitmap_width ||
1602 src_y + height > src_bitmap_height)
1604 Error(ERR_INFO_LINE, "-");
1605 Error(ERR_INFO, "warning: error found in config file:");
1606 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1607 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1608 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1610 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1611 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1612 Error(ERR_INFO, "::: %d, %d", width, height);
1613 Error(ERR_INFO, "custom graphic rejected for this element/action");
1615 if (i == fallback_graphic)
1616 Error(ERR_EXIT, "no fallback graphic available");
1618 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1619 Error(ERR_INFO_LINE, "-");
1621 graphic_info[i] = graphic_info[fallback_graphic];
1626 static void InitGraphicCompatibilityInfo()
1628 struct FileInfo *fi_global_door =
1629 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1630 int num_images = getImageListSize();
1633 /* the following compatibility handling is needed for the following case:
1634 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1635 graphics mainly used for door and panel graphics, like editor, tape and
1636 in-game buttons with hard-coded bitmap positions and button sizes; as
1637 these graphics now have individual definitions, redefining "global.door"
1638 to change all these graphics at once like before does not work anymore
1639 (because all those individual definitions still have their default values);
1640 to solve this, remap all those individual definitions that are not
1641 redefined to the new bitmap of "global.door" if it was redefined */
1643 /* special compatibility handling if image "global.door" was redefined */
1644 if (fi_global_door->redefined)
1646 for (i = 0; i < num_images; i++)
1648 struct FileInfo *fi = getImageListEntryFromImageID(i);
1650 /* process only those images that still use the default settings */
1653 /* process all images which default to same image as "global.door" */
1654 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1656 // printf("::: special treatment needed for token '%s'\n", fi->token);
1658 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1664 InitGraphicCompatibilityInfo_Doors();
1667 static void InitElementSoundInfo()
1669 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1670 int num_property_mappings = getSoundListPropertyMappingSize();
1673 /* set values to -1 to identify later as "uninitialized" values */
1674 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1675 for (act = 0; act < NUM_ACTIONS; act++)
1676 element_info[i].sound[act] = -1;
1678 /* initialize element/sound mapping from static configuration */
1679 for (i = 0; element_to_sound[i].element > -1; i++)
1681 int element = element_to_sound[i].element;
1682 int action = element_to_sound[i].action;
1683 int sound = element_to_sound[i].sound;
1684 boolean is_class = element_to_sound[i].is_class;
1687 action = ACTION_DEFAULT;
1690 element_info[element].sound[action] = sound;
1692 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1693 if (strEqual(element_info[j].class_name,
1694 element_info[element].class_name))
1695 element_info[j].sound[action] = sound;
1698 /* initialize element class/sound mapping from dynamic configuration */
1699 for (i = 0; i < num_property_mappings; i++)
1701 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1702 int action = property_mapping[i].ext1_index;
1703 int sound = property_mapping[i].artwork_index;
1705 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1709 action = ACTION_DEFAULT;
1711 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1712 if (strEqual(element_info[j].class_name,
1713 element_info[element_class].class_name))
1714 element_info[j].sound[action] = sound;
1717 /* initialize element/sound mapping from dynamic configuration */
1718 for (i = 0; i < num_property_mappings; i++)
1720 int element = property_mapping[i].base_index;
1721 int action = property_mapping[i].ext1_index;
1722 int sound = property_mapping[i].artwork_index;
1724 if (element >= MAX_NUM_ELEMENTS)
1728 action = ACTION_DEFAULT;
1730 element_info[element].sound[action] = sound;
1733 /* now set all '-1' values to element specific default values */
1734 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1736 for (act = 0; act < NUM_ACTIONS; act++)
1738 /* generic default action sound (defined by "[default]" directive) */
1739 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1741 /* look for special default action sound (classic game specific) */
1742 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1743 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1744 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1745 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1746 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1747 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1749 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1750 /* !!! make this better !!! */
1751 if (i == EL_EMPTY_SPACE)
1752 default_action_sound = element_info[EL_DEFAULT].sound[act];
1754 /* no sound for this specific action -- use default action sound */
1755 if (element_info[i].sound[act] == -1)
1756 element_info[i].sound[act] = default_action_sound;
1760 /* copy sound settings to some elements that are only stored in level file
1761 in native R'n'D levels, but are used by game engine in native EM levels */
1762 for (i = 0; copy_properties[i][0] != -1; i++)
1763 for (j = 1; j <= 4; j++)
1764 for (act = 0; act < NUM_ACTIONS; act++)
1765 element_info[copy_properties[i][j]].sound[act] =
1766 element_info[copy_properties[i][0]].sound[act];
1769 static void InitGameModeSoundInfo()
1773 /* set values to -1 to identify later as "uninitialized" values */
1774 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1777 /* initialize gamemode/sound mapping from static configuration */
1778 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1780 int gamemode = gamemode_to_sound[i].gamemode;
1781 int sound = gamemode_to_sound[i].sound;
1784 gamemode = GAME_MODE_DEFAULT;
1786 menu.sound[gamemode] = sound;
1789 /* now set all '-1' values to levelset specific default values */
1790 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1791 if (menu.sound[i] == -1)
1792 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1795 static void set_sound_parameters(int sound, char **parameter_raw)
1797 int parameter[NUM_SND_ARGS];
1800 /* get integer values from string parameters */
1801 for (i = 0; i < NUM_SND_ARGS; i++)
1803 get_parameter_value(parameter_raw[i],
1804 sound_config_suffix[i].token,
1805 sound_config_suffix[i].type);
1807 /* explicit loop mode setting in configuration overrides default value */
1808 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1809 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1811 /* sound volume to change the original volume when loading the sound file */
1812 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1814 /* sound priority to give certain sounds a higher or lower priority */
1815 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1818 static void InitSoundInfo()
1820 int *sound_effect_properties;
1821 int num_sounds = getSoundListSize();
1824 checked_free(sound_info);
1826 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1827 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1829 /* initialize sound effect for all elements to "no sound" */
1830 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1831 for (j = 0; j < NUM_ACTIONS; j++)
1832 element_info[i].sound[j] = SND_UNDEFINED;
1834 for (i = 0; i < num_sounds; i++)
1836 struct FileInfo *sound = getSoundListEntry(i);
1837 int len_effect_text = strlen(sound->token);
1839 sound_effect_properties[i] = ACTION_OTHER;
1840 sound_info[i].loop = FALSE; /* default: play sound only once */
1842 /* determine all loop sounds and identify certain sound classes */
1844 for (j = 0; element_action_info[j].suffix; j++)
1846 int len_action_text = strlen(element_action_info[j].suffix);
1848 if (len_action_text < len_effect_text &&
1849 strEqual(&sound->token[len_effect_text - len_action_text],
1850 element_action_info[j].suffix))
1852 sound_effect_properties[i] = element_action_info[j].value;
1853 sound_info[i].loop = element_action_info[j].is_loop_sound;
1859 /* associate elements and some selected sound actions */
1861 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1863 if (element_info[j].class_name)
1865 int len_class_text = strlen(element_info[j].class_name);
1867 if (len_class_text + 1 < len_effect_text &&
1868 strncmp(sound->token,
1869 element_info[j].class_name, len_class_text) == 0 &&
1870 sound->token[len_class_text] == '.')
1872 int sound_action_value = sound_effect_properties[i];
1874 element_info[j].sound[sound_action_value] = i;
1879 set_sound_parameters(i, sound->parameter);
1882 free(sound_effect_properties);
1885 static void InitGameModeMusicInfo()
1887 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1888 int num_property_mappings = getMusicListPropertyMappingSize();
1889 int default_levelset_music = -1;
1892 /* set values to -1 to identify later as "uninitialized" values */
1893 for (i = 0; i < MAX_LEVELS; i++)
1894 levelset.music[i] = -1;
1895 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1898 /* initialize gamemode/music mapping from static configuration */
1899 for (i = 0; gamemode_to_music[i].music > -1; i++)
1901 int gamemode = gamemode_to_music[i].gamemode;
1902 int music = gamemode_to_music[i].music;
1905 gamemode = GAME_MODE_DEFAULT;
1907 menu.music[gamemode] = music;
1910 /* initialize gamemode/music mapping from dynamic configuration */
1911 for (i = 0; i < num_property_mappings; i++)
1913 int prefix = property_mapping[i].base_index;
1914 int gamemode = property_mapping[i].ext1_index;
1915 int level = property_mapping[i].ext2_index;
1916 int music = property_mapping[i].artwork_index;
1918 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1922 gamemode = GAME_MODE_DEFAULT;
1924 /* level specific music only allowed for in-game music */
1925 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1926 gamemode = GAME_MODE_PLAYING;
1931 default_levelset_music = music;
1934 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1935 levelset.music[level] = music;
1936 if (gamemode != GAME_MODE_PLAYING)
1937 menu.music[gamemode] = music;
1940 /* now set all '-1' values to menu specific default values */
1941 /* (undefined values of "levelset.music[]" might stay at "-1" to
1942 allow dynamic selection of music files from music directory!) */
1943 for (i = 0; i < MAX_LEVELS; i++)
1944 if (levelset.music[i] == -1)
1945 levelset.music[i] = default_levelset_music;
1946 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1947 if (menu.music[i] == -1)
1948 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1951 static void set_music_parameters(int music, char **parameter_raw)
1953 int parameter[NUM_MUS_ARGS];
1956 /* get integer values from string parameters */
1957 for (i = 0; i < NUM_MUS_ARGS; i++)
1959 get_parameter_value(parameter_raw[i],
1960 music_config_suffix[i].token,
1961 music_config_suffix[i].type);
1963 /* explicit loop mode setting in configuration overrides default value */
1964 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1965 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1968 static void InitMusicInfo()
1970 int num_music = getMusicListSize();
1973 checked_free(music_info);
1975 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1977 for (i = 0; i < num_music; i++)
1979 struct FileInfo *music = getMusicListEntry(i);
1980 int len_music_text = strlen(music->token);
1982 music_info[i].loop = TRUE; /* default: play music in loop mode */
1984 /* determine all loop music */
1986 for (j = 0; music_prefix_info[j].prefix; j++)
1988 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1990 if (len_prefix_text < len_music_text &&
1991 strncmp(music->token,
1992 music_prefix_info[j].prefix, len_prefix_text) == 0)
1994 music_info[i].loop = music_prefix_info[j].is_loop_music;
2000 set_music_parameters(i, music->parameter);
2004 static void ReinitializeGraphics()
2006 print_timestamp_init("ReinitializeGraphics");
2008 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2010 InitGraphicInfo(); /* graphic properties mapping */
2011 print_timestamp_time("InitGraphicInfo");
2012 InitElementGraphicInfo(); /* element game graphic mapping */
2013 print_timestamp_time("InitElementGraphicInfo");
2014 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2015 print_timestamp_time("InitElementSpecialGraphicInfo");
2017 InitElementSmallImages(); /* scale elements to all needed sizes */
2018 print_timestamp_time("InitElementSmallImages");
2019 InitScaledImages(); /* scale all other images, if needed */
2020 print_timestamp_time("InitScaledImages");
2021 InitBitmapPointers(); /* set standard size bitmap pointers */
2022 print_timestamp_time("InitBitmapPointers");
2023 InitFontGraphicInfo(); /* initialize text drawing functions */
2024 print_timestamp_time("InitFontGraphicInfo");
2025 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2026 print_timestamp_time("InitGlobalAnimGraphicInfo");
2027 InitGlobalAnimImages(); /* initialize global animation images */
2028 print_timestamp_time("InitGlobalAnimImages");
2030 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2031 print_timestamp_time("InitGraphicInfo_EM");
2033 InitGraphicCompatibilityInfo();
2034 print_timestamp_time("InitGraphicCompatibilityInfo");
2036 SetMainBackgroundImage(IMG_BACKGROUND);
2037 print_timestamp_time("SetMainBackgroundImage");
2038 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2039 print_timestamp_time("SetDoorBackgroundImage");
2042 print_timestamp_time("InitGadgets");
2044 print_timestamp_time("InitToons");
2046 print_timestamp_time("InitDoors");
2048 print_timestamp_done("ReinitializeGraphics");
2051 static void ReinitializeSounds()
2053 InitSoundInfo(); /* sound properties mapping */
2054 InitElementSoundInfo(); /* element game sound mapping */
2055 InitGameModeSoundInfo(); /* game mode sound mapping */
2057 InitPlayLevelSound(); /* internal game sound settings */
2060 static void ReinitializeMusic()
2062 InitMusicInfo(); /* music properties mapping */
2063 InitGameModeMusicInfo(); /* game mode music mapping */
2066 static int get_special_property_bit(int element, int property_bit_nr)
2068 struct PropertyBitInfo
2074 static struct PropertyBitInfo pb_can_move_into_acid[] =
2076 /* the player may be able fall into acid when gravity is activated */
2081 { EL_SP_MURPHY, 0 },
2082 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2084 /* all elements that can move may be able to also move into acid */
2087 { EL_BUG_RIGHT, 1 },
2090 { EL_SPACESHIP, 2 },
2091 { EL_SPACESHIP_LEFT, 2 },
2092 { EL_SPACESHIP_RIGHT, 2 },
2093 { EL_SPACESHIP_UP, 2 },
2094 { EL_SPACESHIP_DOWN, 2 },
2095 { EL_BD_BUTTERFLY, 3 },
2096 { EL_BD_BUTTERFLY_LEFT, 3 },
2097 { EL_BD_BUTTERFLY_RIGHT, 3 },
2098 { EL_BD_BUTTERFLY_UP, 3 },
2099 { EL_BD_BUTTERFLY_DOWN, 3 },
2100 { EL_BD_FIREFLY, 4 },
2101 { EL_BD_FIREFLY_LEFT, 4 },
2102 { EL_BD_FIREFLY_RIGHT, 4 },
2103 { EL_BD_FIREFLY_UP, 4 },
2104 { EL_BD_FIREFLY_DOWN, 4 },
2106 { EL_YAMYAM_LEFT, 5 },
2107 { EL_YAMYAM_RIGHT, 5 },
2108 { EL_YAMYAM_UP, 5 },
2109 { EL_YAMYAM_DOWN, 5 },
2110 { EL_DARK_YAMYAM, 6 },
2113 { EL_PACMAN_LEFT, 8 },
2114 { EL_PACMAN_RIGHT, 8 },
2115 { EL_PACMAN_UP, 8 },
2116 { EL_PACMAN_DOWN, 8 },
2118 { EL_MOLE_LEFT, 9 },
2119 { EL_MOLE_RIGHT, 9 },
2121 { EL_MOLE_DOWN, 9 },
2125 { EL_SATELLITE, 13 },
2126 { EL_SP_SNIKSNAK, 14 },
2127 { EL_SP_ELECTRON, 15 },
2130 { EL_EMC_ANDROID, 18 },
2135 static struct PropertyBitInfo pb_dont_collide_with[] =
2137 { EL_SP_SNIKSNAK, 0 },
2138 { EL_SP_ELECTRON, 1 },
2146 struct PropertyBitInfo *pb_info;
2149 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2150 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2155 struct PropertyBitInfo *pb_info = NULL;
2158 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2159 if (pb_definition[i].bit_nr == property_bit_nr)
2160 pb_info = pb_definition[i].pb_info;
2162 if (pb_info == NULL)
2165 for (i = 0; pb_info[i].element != -1; i++)
2166 if (pb_info[i].element == element)
2167 return pb_info[i].bit_nr;
2172 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2173 boolean property_value)
2175 int bit_nr = get_special_property_bit(element, property_bit_nr);
2180 *bitfield |= (1 << bit_nr);
2182 *bitfield &= ~(1 << bit_nr);
2186 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2188 int bit_nr = get_special_property_bit(element, property_bit_nr);
2191 return ((*bitfield & (1 << bit_nr)) != 0);
2196 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2198 static int group_nr;
2199 static struct ElementGroupInfo *group;
2200 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2203 if (actual_group == NULL) /* not yet initialized */
2206 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2208 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2209 group_element - EL_GROUP_START + 1);
2211 /* replace element which caused too deep recursion by question mark */
2212 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2217 if (recursion_depth == 0) /* initialization */
2219 group = actual_group;
2220 group_nr = GROUP_NR(group_element);
2222 group->num_elements_resolved = 0;
2223 group->choice_pos = 0;
2225 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2226 element_info[i].in_group[group_nr] = FALSE;
2229 for (i = 0; i < actual_group->num_elements; i++)
2231 int element = actual_group->element[i];
2233 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2236 if (IS_GROUP_ELEMENT(element))
2237 ResolveGroupElementExt(element, recursion_depth + 1);
2240 group->element_resolved[group->num_elements_resolved++] = element;
2241 element_info[element].in_group[group_nr] = TRUE;
2246 void ResolveGroupElement(int group_element)
2248 ResolveGroupElementExt(group_element, 0);
2251 void InitElementPropertiesStatic()
2253 static boolean clipboard_elements_initialized = FALSE;
2255 static int ep_diggable[] =
2260 EL_SP_BUGGY_BASE_ACTIVATING,
2263 EL_INVISIBLE_SAND_ACTIVE,
2266 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2267 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2272 EL_SP_BUGGY_BASE_ACTIVE,
2279 static int ep_collectible_only[] =
2301 EL_DYNABOMB_INCREASE_NUMBER,
2302 EL_DYNABOMB_INCREASE_SIZE,
2303 EL_DYNABOMB_INCREASE_POWER,
2321 /* !!! handle separately !!! */
2322 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2328 static int ep_dont_run_into[] =
2330 /* same elements as in 'ep_dont_touch' */
2336 /* same elements as in 'ep_dont_collide_with' */
2348 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2353 EL_SP_BUGGY_BASE_ACTIVE,
2360 static int ep_dont_collide_with[] =
2362 /* same elements as in 'ep_dont_touch' */
2379 static int ep_dont_touch[] =
2389 static int ep_indestructible[] =
2393 EL_ACID_POOL_TOPLEFT,
2394 EL_ACID_POOL_TOPRIGHT,
2395 EL_ACID_POOL_BOTTOMLEFT,
2396 EL_ACID_POOL_BOTTOM,
2397 EL_ACID_POOL_BOTTOMRIGHT,
2398 EL_SP_HARDWARE_GRAY,
2399 EL_SP_HARDWARE_GREEN,
2400 EL_SP_HARDWARE_BLUE,
2402 EL_SP_HARDWARE_YELLOW,
2403 EL_SP_HARDWARE_BASE_1,
2404 EL_SP_HARDWARE_BASE_2,
2405 EL_SP_HARDWARE_BASE_3,
2406 EL_SP_HARDWARE_BASE_4,
2407 EL_SP_HARDWARE_BASE_5,
2408 EL_SP_HARDWARE_BASE_6,
2409 EL_INVISIBLE_STEELWALL,
2410 EL_INVISIBLE_STEELWALL_ACTIVE,
2411 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2412 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2413 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2414 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2415 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2416 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2417 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2418 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2419 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2420 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2421 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2422 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2424 EL_LIGHT_SWITCH_ACTIVE,
2425 EL_SIGN_EXCLAMATION,
2426 EL_SIGN_RADIOACTIVITY,
2433 EL_SIGN_ENTRY_FORBIDDEN,
2434 EL_SIGN_EMERGENCY_EXIT,
2442 EL_STEEL_EXIT_CLOSED,
2444 EL_STEEL_EXIT_OPENING,
2445 EL_STEEL_EXIT_CLOSING,
2446 EL_EM_STEEL_EXIT_CLOSED,
2447 EL_EM_STEEL_EXIT_OPEN,
2448 EL_EM_STEEL_EXIT_OPENING,
2449 EL_EM_STEEL_EXIT_CLOSING,
2450 EL_DC_STEELWALL_1_LEFT,
2451 EL_DC_STEELWALL_1_RIGHT,
2452 EL_DC_STEELWALL_1_TOP,
2453 EL_DC_STEELWALL_1_BOTTOM,
2454 EL_DC_STEELWALL_1_HORIZONTAL,
2455 EL_DC_STEELWALL_1_VERTICAL,
2456 EL_DC_STEELWALL_1_TOPLEFT,
2457 EL_DC_STEELWALL_1_TOPRIGHT,
2458 EL_DC_STEELWALL_1_BOTTOMLEFT,
2459 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2460 EL_DC_STEELWALL_1_TOPLEFT_2,
2461 EL_DC_STEELWALL_1_TOPRIGHT_2,
2462 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2463 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2464 EL_DC_STEELWALL_2_LEFT,
2465 EL_DC_STEELWALL_2_RIGHT,
2466 EL_DC_STEELWALL_2_TOP,
2467 EL_DC_STEELWALL_2_BOTTOM,
2468 EL_DC_STEELWALL_2_HORIZONTAL,
2469 EL_DC_STEELWALL_2_VERTICAL,
2470 EL_DC_STEELWALL_2_MIDDLE,
2471 EL_DC_STEELWALL_2_SINGLE,
2472 EL_STEELWALL_SLIPPERY,
2486 EL_GATE_1_GRAY_ACTIVE,
2487 EL_GATE_2_GRAY_ACTIVE,
2488 EL_GATE_3_GRAY_ACTIVE,
2489 EL_GATE_4_GRAY_ACTIVE,
2498 EL_EM_GATE_1_GRAY_ACTIVE,
2499 EL_EM_GATE_2_GRAY_ACTIVE,
2500 EL_EM_GATE_3_GRAY_ACTIVE,
2501 EL_EM_GATE_4_GRAY_ACTIVE,
2510 EL_EMC_GATE_5_GRAY_ACTIVE,
2511 EL_EMC_GATE_6_GRAY_ACTIVE,
2512 EL_EMC_GATE_7_GRAY_ACTIVE,
2513 EL_EMC_GATE_8_GRAY_ACTIVE,
2515 EL_DC_GATE_WHITE_GRAY,
2516 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2517 EL_DC_GATE_FAKE_GRAY,
2519 EL_SWITCHGATE_OPENING,
2520 EL_SWITCHGATE_CLOSED,
2521 EL_SWITCHGATE_CLOSING,
2522 EL_DC_SWITCHGATE_SWITCH_UP,
2523 EL_DC_SWITCHGATE_SWITCH_DOWN,
2525 EL_TIMEGATE_OPENING,
2527 EL_TIMEGATE_CLOSING,
2528 EL_DC_TIMEGATE_SWITCH,
2529 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2533 EL_TUBE_VERTICAL_LEFT,
2534 EL_TUBE_VERTICAL_RIGHT,
2535 EL_TUBE_HORIZONTAL_UP,
2536 EL_TUBE_HORIZONTAL_DOWN,
2541 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2542 EL_EXPANDABLE_STEELWALL_VERTICAL,
2543 EL_EXPANDABLE_STEELWALL_ANY,
2548 static int ep_slippery[] =
2562 EL_ROBOT_WHEEL_ACTIVE,
2568 EL_ACID_POOL_TOPLEFT,
2569 EL_ACID_POOL_TOPRIGHT,
2579 EL_STEELWALL_SLIPPERY,
2582 EL_EMC_WALL_SLIPPERY_1,
2583 EL_EMC_WALL_SLIPPERY_2,
2584 EL_EMC_WALL_SLIPPERY_3,
2585 EL_EMC_WALL_SLIPPERY_4,
2587 EL_EMC_MAGIC_BALL_ACTIVE,
2592 static int ep_can_change[] =
2597 static int ep_can_move[] =
2599 /* same elements as in 'pb_can_move_into_acid' */
2622 static int ep_can_fall[] =
2636 EL_QUICKSAND_FAST_FULL,
2638 EL_BD_MAGIC_WALL_FULL,
2639 EL_DC_MAGIC_WALL_FULL,
2653 static int ep_can_smash_player[] =
2679 static int ep_can_smash_enemies[] =
2688 static int ep_can_smash_everything[] =
2697 static int ep_explodes_by_fire[] =
2699 /* same elements as in 'ep_explodes_impact' */
2704 /* same elements as in 'ep_explodes_smashed' */
2714 EL_EM_DYNAMITE_ACTIVE,
2715 EL_DYNABOMB_PLAYER_1_ACTIVE,
2716 EL_DYNABOMB_PLAYER_2_ACTIVE,
2717 EL_DYNABOMB_PLAYER_3_ACTIVE,
2718 EL_DYNABOMB_PLAYER_4_ACTIVE,
2719 EL_DYNABOMB_INCREASE_NUMBER,
2720 EL_DYNABOMB_INCREASE_SIZE,
2721 EL_DYNABOMB_INCREASE_POWER,
2722 EL_SP_DISK_RED_ACTIVE,
2736 static int ep_explodes_smashed[] =
2738 /* same elements as in 'ep_explodes_impact' */
2752 static int ep_explodes_impact[] =
2761 static int ep_walkable_over[] =
2765 EL_SOKOBAN_FIELD_EMPTY,
2772 EL_EM_STEEL_EXIT_OPEN,
2773 EL_EM_STEEL_EXIT_OPENING,
2782 EL_GATE_1_GRAY_ACTIVE,
2783 EL_GATE_2_GRAY_ACTIVE,
2784 EL_GATE_3_GRAY_ACTIVE,
2785 EL_GATE_4_GRAY_ACTIVE,
2793 static int ep_walkable_inside[] =
2798 EL_TUBE_VERTICAL_LEFT,
2799 EL_TUBE_VERTICAL_RIGHT,
2800 EL_TUBE_HORIZONTAL_UP,
2801 EL_TUBE_HORIZONTAL_DOWN,
2810 static int ep_walkable_under[] =
2815 static int ep_passable_over[] =
2825 EL_EM_GATE_1_GRAY_ACTIVE,
2826 EL_EM_GATE_2_GRAY_ACTIVE,
2827 EL_EM_GATE_3_GRAY_ACTIVE,
2828 EL_EM_GATE_4_GRAY_ACTIVE,
2837 EL_EMC_GATE_5_GRAY_ACTIVE,
2838 EL_EMC_GATE_6_GRAY_ACTIVE,
2839 EL_EMC_GATE_7_GRAY_ACTIVE,
2840 EL_EMC_GATE_8_GRAY_ACTIVE,
2842 EL_DC_GATE_WHITE_GRAY,
2843 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2850 static int ep_passable_inside[] =
2856 EL_SP_PORT_HORIZONTAL,
2857 EL_SP_PORT_VERTICAL,
2859 EL_SP_GRAVITY_PORT_LEFT,
2860 EL_SP_GRAVITY_PORT_RIGHT,
2861 EL_SP_GRAVITY_PORT_UP,
2862 EL_SP_GRAVITY_PORT_DOWN,
2863 EL_SP_GRAVITY_ON_PORT_LEFT,
2864 EL_SP_GRAVITY_ON_PORT_RIGHT,
2865 EL_SP_GRAVITY_ON_PORT_UP,
2866 EL_SP_GRAVITY_ON_PORT_DOWN,
2867 EL_SP_GRAVITY_OFF_PORT_LEFT,
2868 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2869 EL_SP_GRAVITY_OFF_PORT_UP,
2870 EL_SP_GRAVITY_OFF_PORT_DOWN,
2875 static int ep_passable_under[] =
2880 static int ep_droppable[] =
2885 static int ep_explodes_1x1_old[] =
2890 static int ep_pushable[] =
2902 EL_SOKOBAN_FIELD_FULL,
2911 static int ep_explodes_cross_old[] =
2916 static int ep_protected[] =
2918 /* same elements as in 'ep_walkable_inside' */
2922 EL_TUBE_VERTICAL_LEFT,
2923 EL_TUBE_VERTICAL_RIGHT,
2924 EL_TUBE_HORIZONTAL_UP,
2925 EL_TUBE_HORIZONTAL_DOWN,
2931 /* same elements as in 'ep_passable_over' */
2940 EL_EM_GATE_1_GRAY_ACTIVE,
2941 EL_EM_GATE_2_GRAY_ACTIVE,
2942 EL_EM_GATE_3_GRAY_ACTIVE,
2943 EL_EM_GATE_4_GRAY_ACTIVE,
2952 EL_EMC_GATE_5_GRAY_ACTIVE,
2953 EL_EMC_GATE_6_GRAY_ACTIVE,
2954 EL_EMC_GATE_7_GRAY_ACTIVE,
2955 EL_EMC_GATE_8_GRAY_ACTIVE,
2957 EL_DC_GATE_WHITE_GRAY,
2958 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2962 /* same elements as in 'ep_passable_inside' */
2967 EL_SP_PORT_HORIZONTAL,
2968 EL_SP_PORT_VERTICAL,
2970 EL_SP_GRAVITY_PORT_LEFT,
2971 EL_SP_GRAVITY_PORT_RIGHT,
2972 EL_SP_GRAVITY_PORT_UP,
2973 EL_SP_GRAVITY_PORT_DOWN,
2974 EL_SP_GRAVITY_ON_PORT_LEFT,
2975 EL_SP_GRAVITY_ON_PORT_RIGHT,
2976 EL_SP_GRAVITY_ON_PORT_UP,
2977 EL_SP_GRAVITY_ON_PORT_DOWN,
2978 EL_SP_GRAVITY_OFF_PORT_LEFT,
2979 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2980 EL_SP_GRAVITY_OFF_PORT_UP,
2981 EL_SP_GRAVITY_OFF_PORT_DOWN,
2986 static int ep_throwable[] =
2991 static int ep_can_explode[] =
2993 /* same elements as in 'ep_explodes_impact' */
2998 /* same elements as in 'ep_explodes_smashed' */
3004 /* elements that can explode by explosion or by dragonfire */
3008 EL_EM_DYNAMITE_ACTIVE,
3009 EL_DYNABOMB_PLAYER_1_ACTIVE,
3010 EL_DYNABOMB_PLAYER_2_ACTIVE,
3011 EL_DYNABOMB_PLAYER_3_ACTIVE,
3012 EL_DYNABOMB_PLAYER_4_ACTIVE,
3013 EL_DYNABOMB_INCREASE_NUMBER,
3014 EL_DYNABOMB_INCREASE_SIZE,
3015 EL_DYNABOMB_INCREASE_POWER,
3016 EL_SP_DISK_RED_ACTIVE,
3024 /* elements that can explode only by explosion */
3030 static int ep_gravity_reachable[] =
3036 EL_INVISIBLE_SAND_ACTIVE,
3041 EL_SP_PORT_HORIZONTAL,
3042 EL_SP_PORT_VERTICAL,
3044 EL_SP_GRAVITY_PORT_LEFT,
3045 EL_SP_GRAVITY_PORT_RIGHT,
3046 EL_SP_GRAVITY_PORT_UP,
3047 EL_SP_GRAVITY_PORT_DOWN,
3048 EL_SP_GRAVITY_ON_PORT_LEFT,
3049 EL_SP_GRAVITY_ON_PORT_RIGHT,
3050 EL_SP_GRAVITY_ON_PORT_UP,
3051 EL_SP_GRAVITY_ON_PORT_DOWN,
3052 EL_SP_GRAVITY_OFF_PORT_LEFT,
3053 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3054 EL_SP_GRAVITY_OFF_PORT_UP,
3055 EL_SP_GRAVITY_OFF_PORT_DOWN,
3061 static int ep_player[] =
3068 EL_SOKOBAN_FIELD_PLAYER,
3074 static int ep_can_pass_magic_wall[] =
3088 static int ep_can_pass_dc_magic_wall[] =
3104 static int ep_switchable[] =
3108 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3109 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3110 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3111 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3112 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3113 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3114 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3115 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3116 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3117 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3118 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3119 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3120 EL_SWITCHGATE_SWITCH_UP,
3121 EL_SWITCHGATE_SWITCH_DOWN,
3122 EL_DC_SWITCHGATE_SWITCH_UP,
3123 EL_DC_SWITCHGATE_SWITCH_DOWN,
3125 EL_LIGHT_SWITCH_ACTIVE,
3127 EL_DC_TIMEGATE_SWITCH,
3128 EL_BALLOON_SWITCH_LEFT,
3129 EL_BALLOON_SWITCH_RIGHT,
3130 EL_BALLOON_SWITCH_UP,
3131 EL_BALLOON_SWITCH_DOWN,
3132 EL_BALLOON_SWITCH_ANY,
3133 EL_BALLOON_SWITCH_NONE,
3136 EL_EMC_MAGIC_BALL_SWITCH,
3137 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3142 static int ep_bd_element[] =
3176 static int ep_sp_element[] =
3178 /* should always be valid */
3181 /* standard classic Supaplex elements */
3188 EL_SP_HARDWARE_GRAY,
3196 EL_SP_GRAVITY_PORT_RIGHT,
3197 EL_SP_GRAVITY_PORT_DOWN,
3198 EL_SP_GRAVITY_PORT_LEFT,
3199 EL_SP_GRAVITY_PORT_UP,
3204 EL_SP_PORT_VERTICAL,
3205 EL_SP_PORT_HORIZONTAL,
3211 EL_SP_HARDWARE_BASE_1,
3212 EL_SP_HARDWARE_GREEN,
3213 EL_SP_HARDWARE_BLUE,
3215 EL_SP_HARDWARE_YELLOW,
3216 EL_SP_HARDWARE_BASE_2,
3217 EL_SP_HARDWARE_BASE_3,
3218 EL_SP_HARDWARE_BASE_4,
3219 EL_SP_HARDWARE_BASE_5,
3220 EL_SP_HARDWARE_BASE_6,
3224 /* additional elements that appeared in newer Supaplex levels */
3227 /* additional gravity port elements (not switching, but setting gravity) */
3228 EL_SP_GRAVITY_ON_PORT_LEFT,
3229 EL_SP_GRAVITY_ON_PORT_RIGHT,
3230 EL_SP_GRAVITY_ON_PORT_UP,
3231 EL_SP_GRAVITY_ON_PORT_DOWN,
3232 EL_SP_GRAVITY_OFF_PORT_LEFT,
3233 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3234 EL_SP_GRAVITY_OFF_PORT_UP,
3235 EL_SP_GRAVITY_OFF_PORT_DOWN,
3237 /* more than one Murphy in a level results in an inactive clone */
3240 /* runtime Supaplex elements */
3241 EL_SP_DISK_RED_ACTIVE,
3242 EL_SP_TERMINAL_ACTIVE,
3243 EL_SP_BUGGY_BASE_ACTIVATING,
3244 EL_SP_BUGGY_BASE_ACTIVE,
3251 static int ep_sb_element[] =
3256 EL_SOKOBAN_FIELD_EMPTY,
3257 EL_SOKOBAN_FIELD_FULL,
3258 EL_SOKOBAN_FIELD_PLAYER,
3263 EL_INVISIBLE_STEELWALL,
3268 static int ep_gem[] =
3280 static int ep_food_dark_yamyam[] =
3308 static int ep_food_penguin[] =
3322 static int ep_food_pig[] =
3334 static int ep_historic_wall[] =
3345 EL_GATE_1_GRAY_ACTIVE,
3346 EL_GATE_2_GRAY_ACTIVE,
3347 EL_GATE_3_GRAY_ACTIVE,
3348 EL_GATE_4_GRAY_ACTIVE,
3357 EL_EM_GATE_1_GRAY_ACTIVE,
3358 EL_EM_GATE_2_GRAY_ACTIVE,
3359 EL_EM_GATE_3_GRAY_ACTIVE,
3360 EL_EM_GATE_4_GRAY_ACTIVE,
3367 EL_EXPANDABLE_WALL_HORIZONTAL,
3368 EL_EXPANDABLE_WALL_VERTICAL,
3369 EL_EXPANDABLE_WALL_ANY,
3370 EL_EXPANDABLE_WALL_GROWING,
3371 EL_BD_EXPANDABLE_WALL,
3378 EL_SP_HARDWARE_GRAY,
3379 EL_SP_HARDWARE_GREEN,
3380 EL_SP_HARDWARE_BLUE,
3382 EL_SP_HARDWARE_YELLOW,
3383 EL_SP_HARDWARE_BASE_1,
3384 EL_SP_HARDWARE_BASE_2,
3385 EL_SP_HARDWARE_BASE_3,
3386 EL_SP_HARDWARE_BASE_4,
3387 EL_SP_HARDWARE_BASE_5,
3388 EL_SP_HARDWARE_BASE_6,
3390 EL_SP_TERMINAL_ACTIVE,
3393 EL_INVISIBLE_STEELWALL,
3394 EL_INVISIBLE_STEELWALL_ACTIVE,
3396 EL_INVISIBLE_WALL_ACTIVE,
3397 EL_STEELWALL_SLIPPERY,
3414 static int ep_historic_solid[] =
3418 EL_EXPANDABLE_WALL_HORIZONTAL,
3419 EL_EXPANDABLE_WALL_VERTICAL,
3420 EL_EXPANDABLE_WALL_ANY,
3421 EL_BD_EXPANDABLE_WALL,
3434 EL_QUICKSAND_FILLING,
3435 EL_QUICKSAND_EMPTYING,
3437 EL_MAGIC_WALL_ACTIVE,
3438 EL_MAGIC_WALL_EMPTYING,
3439 EL_MAGIC_WALL_FILLING,
3443 EL_BD_MAGIC_WALL_ACTIVE,
3444 EL_BD_MAGIC_WALL_EMPTYING,
3445 EL_BD_MAGIC_WALL_FULL,
3446 EL_BD_MAGIC_WALL_FILLING,
3447 EL_BD_MAGIC_WALL_DEAD,
3456 EL_SP_TERMINAL_ACTIVE,
3460 EL_INVISIBLE_WALL_ACTIVE,
3461 EL_SWITCHGATE_SWITCH_UP,
3462 EL_SWITCHGATE_SWITCH_DOWN,
3463 EL_DC_SWITCHGATE_SWITCH_UP,
3464 EL_DC_SWITCHGATE_SWITCH_DOWN,
3466 EL_TIMEGATE_SWITCH_ACTIVE,
3467 EL_DC_TIMEGATE_SWITCH,
3468 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3480 /* the following elements are a direct copy of "indestructible" elements,
3481 except "EL_ACID", which is "indestructible", but not "solid"! */
3486 EL_ACID_POOL_TOPLEFT,
3487 EL_ACID_POOL_TOPRIGHT,
3488 EL_ACID_POOL_BOTTOMLEFT,
3489 EL_ACID_POOL_BOTTOM,
3490 EL_ACID_POOL_BOTTOMRIGHT,
3491 EL_SP_HARDWARE_GRAY,
3492 EL_SP_HARDWARE_GREEN,
3493 EL_SP_HARDWARE_BLUE,
3495 EL_SP_HARDWARE_YELLOW,
3496 EL_SP_HARDWARE_BASE_1,
3497 EL_SP_HARDWARE_BASE_2,
3498 EL_SP_HARDWARE_BASE_3,
3499 EL_SP_HARDWARE_BASE_4,
3500 EL_SP_HARDWARE_BASE_5,
3501 EL_SP_HARDWARE_BASE_6,
3502 EL_INVISIBLE_STEELWALL,
3503 EL_INVISIBLE_STEELWALL_ACTIVE,
3504 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3505 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3506 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3507 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3508 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3509 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3510 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3511 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3512 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3513 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3514 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3515 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3517 EL_LIGHT_SWITCH_ACTIVE,
3518 EL_SIGN_EXCLAMATION,
3519 EL_SIGN_RADIOACTIVITY,
3526 EL_SIGN_ENTRY_FORBIDDEN,
3527 EL_SIGN_EMERGENCY_EXIT,
3535 EL_STEEL_EXIT_CLOSED,
3537 EL_DC_STEELWALL_1_LEFT,
3538 EL_DC_STEELWALL_1_RIGHT,
3539 EL_DC_STEELWALL_1_TOP,
3540 EL_DC_STEELWALL_1_BOTTOM,
3541 EL_DC_STEELWALL_1_HORIZONTAL,
3542 EL_DC_STEELWALL_1_VERTICAL,
3543 EL_DC_STEELWALL_1_TOPLEFT,
3544 EL_DC_STEELWALL_1_TOPRIGHT,
3545 EL_DC_STEELWALL_1_BOTTOMLEFT,
3546 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3547 EL_DC_STEELWALL_1_TOPLEFT_2,
3548 EL_DC_STEELWALL_1_TOPRIGHT_2,
3549 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3550 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3551 EL_DC_STEELWALL_2_LEFT,
3552 EL_DC_STEELWALL_2_RIGHT,
3553 EL_DC_STEELWALL_2_TOP,
3554 EL_DC_STEELWALL_2_BOTTOM,
3555 EL_DC_STEELWALL_2_HORIZONTAL,
3556 EL_DC_STEELWALL_2_VERTICAL,
3557 EL_DC_STEELWALL_2_MIDDLE,
3558 EL_DC_STEELWALL_2_SINGLE,
3559 EL_STEELWALL_SLIPPERY,
3573 EL_GATE_1_GRAY_ACTIVE,
3574 EL_GATE_2_GRAY_ACTIVE,
3575 EL_GATE_3_GRAY_ACTIVE,
3576 EL_GATE_4_GRAY_ACTIVE,
3585 EL_EM_GATE_1_GRAY_ACTIVE,
3586 EL_EM_GATE_2_GRAY_ACTIVE,
3587 EL_EM_GATE_3_GRAY_ACTIVE,
3588 EL_EM_GATE_4_GRAY_ACTIVE,
3590 EL_SWITCHGATE_OPENING,
3591 EL_SWITCHGATE_CLOSED,
3592 EL_SWITCHGATE_CLOSING,
3594 EL_TIMEGATE_OPENING,
3596 EL_TIMEGATE_CLOSING,
3600 EL_TUBE_VERTICAL_LEFT,
3601 EL_TUBE_VERTICAL_RIGHT,
3602 EL_TUBE_HORIZONTAL_UP,
3603 EL_TUBE_HORIZONTAL_DOWN,
3612 static int ep_classic_enemy[] =
3629 static int ep_belt[] =
3631 EL_CONVEYOR_BELT_1_LEFT,
3632 EL_CONVEYOR_BELT_1_MIDDLE,
3633 EL_CONVEYOR_BELT_1_RIGHT,
3634 EL_CONVEYOR_BELT_2_LEFT,
3635 EL_CONVEYOR_BELT_2_MIDDLE,
3636 EL_CONVEYOR_BELT_2_RIGHT,
3637 EL_CONVEYOR_BELT_3_LEFT,
3638 EL_CONVEYOR_BELT_3_MIDDLE,
3639 EL_CONVEYOR_BELT_3_RIGHT,
3640 EL_CONVEYOR_BELT_4_LEFT,
3641 EL_CONVEYOR_BELT_4_MIDDLE,
3642 EL_CONVEYOR_BELT_4_RIGHT,
3647 static int ep_belt_active[] =
3649 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3650 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3651 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3652 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3653 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3654 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3655 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3656 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3657 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3658 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3659 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3660 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3665 static int ep_belt_switch[] =
3667 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3668 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3669 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3670 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3671 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3672 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3673 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3674 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3675 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3676 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3677 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3678 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3683 static int ep_tube[] =
3690 EL_TUBE_HORIZONTAL_UP,
3691 EL_TUBE_HORIZONTAL_DOWN,
3693 EL_TUBE_VERTICAL_LEFT,
3694 EL_TUBE_VERTICAL_RIGHT,
3700 static int ep_acid_pool[] =
3702 EL_ACID_POOL_TOPLEFT,
3703 EL_ACID_POOL_TOPRIGHT,
3704 EL_ACID_POOL_BOTTOMLEFT,
3705 EL_ACID_POOL_BOTTOM,
3706 EL_ACID_POOL_BOTTOMRIGHT,
3711 static int ep_keygate[] =
3721 EL_GATE_1_GRAY_ACTIVE,
3722 EL_GATE_2_GRAY_ACTIVE,
3723 EL_GATE_3_GRAY_ACTIVE,
3724 EL_GATE_4_GRAY_ACTIVE,
3733 EL_EM_GATE_1_GRAY_ACTIVE,
3734 EL_EM_GATE_2_GRAY_ACTIVE,
3735 EL_EM_GATE_3_GRAY_ACTIVE,
3736 EL_EM_GATE_4_GRAY_ACTIVE,
3745 EL_EMC_GATE_5_GRAY_ACTIVE,
3746 EL_EMC_GATE_6_GRAY_ACTIVE,
3747 EL_EMC_GATE_7_GRAY_ACTIVE,
3748 EL_EMC_GATE_8_GRAY_ACTIVE,
3750 EL_DC_GATE_WHITE_GRAY,
3751 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3756 static int ep_amoeboid[] =
3768 static int ep_amoebalive[] =
3779 static int ep_has_editor_content[] =
3785 EL_SOKOBAN_FIELD_PLAYER,
3802 static int ep_can_turn_each_move[] =
3804 /* !!! do something with this one !!! */
3808 static int ep_can_grow[] =
3822 static int ep_active_bomb[] =
3825 EL_EM_DYNAMITE_ACTIVE,
3826 EL_DYNABOMB_PLAYER_1_ACTIVE,
3827 EL_DYNABOMB_PLAYER_2_ACTIVE,
3828 EL_DYNABOMB_PLAYER_3_ACTIVE,
3829 EL_DYNABOMB_PLAYER_4_ACTIVE,
3830 EL_SP_DISK_RED_ACTIVE,
3835 static int ep_inactive[] =
3845 EL_QUICKSAND_FAST_EMPTY,
3868 EL_GATE_1_GRAY_ACTIVE,
3869 EL_GATE_2_GRAY_ACTIVE,
3870 EL_GATE_3_GRAY_ACTIVE,
3871 EL_GATE_4_GRAY_ACTIVE,
3880 EL_EM_GATE_1_GRAY_ACTIVE,
3881 EL_EM_GATE_2_GRAY_ACTIVE,
3882 EL_EM_GATE_3_GRAY_ACTIVE,
3883 EL_EM_GATE_4_GRAY_ACTIVE,
3892 EL_EMC_GATE_5_GRAY_ACTIVE,
3893 EL_EMC_GATE_6_GRAY_ACTIVE,
3894 EL_EMC_GATE_7_GRAY_ACTIVE,
3895 EL_EMC_GATE_8_GRAY_ACTIVE,
3897 EL_DC_GATE_WHITE_GRAY,
3898 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3899 EL_DC_GATE_FAKE_GRAY,
3902 EL_INVISIBLE_STEELWALL,
3910 EL_WALL_EMERALD_YELLOW,
3911 EL_DYNABOMB_INCREASE_NUMBER,
3912 EL_DYNABOMB_INCREASE_SIZE,
3913 EL_DYNABOMB_INCREASE_POWER,
3917 EL_SOKOBAN_FIELD_EMPTY,
3918 EL_SOKOBAN_FIELD_FULL,
3919 EL_WALL_EMERALD_RED,
3920 EL_WALL_EMERALD_PURPLE,
3921 EL_ACID_POOL_TOPLEFT,
3922 EL_ACID_POOL_TOPRIGHT,
3923 EL_ACID_POOL_BOTTOMLEFT,
3924 EL_ACID_POOL_BOTTOM,
3925 EL_ACID_POOL_BOTTOMRIGHT,
3929 EL_BD_MAGIC_WALL_DEAD,
3931 EL_DC_MAGIC_WALL_DEAD,
3932 EL_AMOEBA_TO_DIAMOND,
3940 EL_SP_GRAVITY_PORT_RIGHT,
3941 EL_SP_GRAVITY_PORT_DOWN,
3942 EL_SP_GRAVITY_PORT_LEFT,
3943 EL_SP_GRAVITY_PORT_UP,
3944 EL_SP_PORT_HORIZONTAL,
3945 EL_SP_PORT_VERTICAL,
3956 EL_SP_HARDWARE_GRAY,
3957 EL_SP_HARDWARE_GREEN,
3958 EL_SP_HARDWARE_BLUE,
3960 EL_SP_HARDWARE_YELLOW,
3961 EL_SP_HARDWARE_BASE_1,
3962 EL_SP_HARDWARE_BASE_2,
3963 EL_SP_HARDWARE_BASE_3,
3964 EL_SP_HARDWARE_BASE_4,
3965 EL_SP_HARDWARE_BASE_5,
3966 EL_SP_HARDWARE_BASE_6,
3967 EL_SP_GRAVITY_ON_PORT_LEFT,
3968 EL_SP_GRAVITY_ON_PORT_RIGHT,
3969 EL_SP_GRAVITY_ON_PORT_UP,
3970 EL_SP_GRAVITY_ON_PORT_DOWN,
3971 EL_SP_GRAVITY_OFF_PORT_LEFT,
3972 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3973 EL_SP_GRAVITY_OFF_PORT_UP,
3974 EL_SP_GRAVITY_OFF_PORT_DOWN,
3975 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3976 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3977 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3978 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3979 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3980 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3981 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3982 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3983 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3984 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3985 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3986 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3987 EL_SIGN_EXCLAMATION,
3988 EL_SIGN_RADIOACTIVITY,
3995 EL_SIGN_ENTRY_FORBIDDEN,
3996 EL_SIGN_EMERGENCY_EXIT,
4004 EL_DC_STEELWALL_1_LEFT,
4005 EL_DC_STEELWALL_1_RIGHT,
4006 EL_DC_STEELWALL_1_TOP,
4007 EL_DC_STEELWALL_1_BOTTOM,
4008 EL_DC_STEELWALL_1_HORIZONTAL,
4009 EL_DC_STEELWALL_1_VERTICAL,
4010 EL_DC_STEELWALL_1_TOPLEFT,
4011 EL_DC_STEELWALL_1_TOPRIGHT,
4012 EL_DC_STEELWALL_1_BOTTOMLEFT,
4013 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4014 EL_DC_STEELWALL_1_TOPLEFT_2,
4015 EL_DC_STEELWALL_1_TOPRIGHT_2,
4016 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4017 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4018 EL_DC_STEELWALL_2_LEFT,
4019 EL_DC_STEELWALL_2_RIGHT,
4020 EL_DC_STEELWALL_2_TOP,
4021 EL_DC_STEELWALL_2_BOTTOM,
4022 EL_DC_STEELWALL_2_HORIZONTAL,
4023 EL_DC_STEELWALL_2_VERTICAL,
4024 EL_DC_STEELWALL_2_MIDDLE,
4025 EL_DC_STEELWALL_2_SINGLE,
4026 EL_STEELWALL_SLIPPERY,
4031 EL_EMC_WALL_SLIPPERY_1,
4032 EL_EMC_WALL_SLIPPERY_2,
4033 EL_EMC_WALL_SLIPPERY_3,
4034 EL_EMC_WALL_SLIPPERY_4,
4055 static int ep_em_slippery_wall[] =
4060 static int ep_gfx_crumbled[] =
4071 static int ep_editor_cascade_active[] =
4073 EL_INTERNAL_CASCADE_BD_ACTIVE,
4074 EL_INTERNAL_CASCADE_EM_ACTIVE,
4075 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4076 EL_INTERNAL_CASCADE_RND_ACTIVE,
4077 EL_INTERNAL_CASCADE_SB_ACTIVE,
4078 EL_INTERNAL_CASCADE_SP_ACTIVE,
4079 EL_INTERNAL_CASCADE_DC_ACTIVE,
4080 EL_INTERNAL_CASCADE_DX_ACTIVE,
4081 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4082 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4083 EL_INTERNAL_CASCADE_CE_ACTIVE,
4084 EL_INTERNAL_CASCADE_GE_ACTIVE,
4085 EL_INTERNAL_CASCADE_REF_ACTIVE,
4086 EL_INTERNAL_CASCADE_USER_ACTIVE,
4087 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4092 static int ep_editor_cascade_inactive[] =
4094 EL_INTERNAL_CASCADE_BD,
4095 EL_INTERNAL_CASCADE_EM,
4096 EL_INTERNAL_CASCADE_EMC,
4097 EL_INTERNAL_CASCADE_RND,
4098 EL_INTERNAL_CASCADE_SB,
4099 EL_INTERNAL_CASCADE_SP,
4100 EL_INTERNAL_CASCADE_DC,
4101 EL_INTERNAL_CASCADE_DX,
4102 EL_INTERNAL_CASCADE_CHARS,
4103 EL_INTERNAL_CASCADE_STEEL_CHARS,
4104 EL_INTERNAL_CASCADE_CE,
4105 EL_INTERNAL_CASCADE_GE,
4106 EL_INTERNAL_CASCADE_REF,
4107 EL_INTERNAL_CASCADE_USER,
4108 EL_INTERNAL_CASCADE_DYNAMIC,
4113 static int ep_obsolete[] =
4117 EL_EM_KEY_1_FILE_OBSOLETE,
4118 EL_EM_KEY_2_FILE_OBSOLETE,
4119 EL_EM_KEY_3_FILE_OBSOLETE,
4120 EL_EM_KEY_4_FILE_OBSOLETE,
4121 EL_ENVELOPE_OBSOLETE,
4130 } element_properties[] =
4132 { ep_diggable, EP_DIGGABLE },
4133 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4134 { ep_dont_run_into, EP_DONT_RUN_INTO },
4135 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4136 { ep_dont_touch, EP_DONT_TOUCH },
4137 { ep_indestructible, EP_INDESTRUCTIBLE },
4138 { ep_slippery, EP_SLIPPERY },
4139 { ep_can_change, EP_CAN_CHANGE },
4140 { ep_can_move, EP_CAN_MOVE },
4141 { ep_can_fall, EP_CAN_FALL },
4142 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4143 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4144 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4145 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4146 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4147 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4148 { ep_walkable_over, EP_WALKABLE_OVER },
4149 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4150 { ep_walkable_under, EP_WALKABLE_UNDER },
4151 { ep_passable_over, EP_PASSABLE_OVER },
4152 { ep_passable_inside, EP_PASSABLE_INSIDE },
4153 { ep_passable_under, EP_PASSABLE_UNDER },
4154 { ep_droppable, EP_DROPPABLE },
4155 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4156 { ep_pushable, EP_PUSHABLE },
4157 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4158 { ep_protected, EP_PROTECTED },
4159 { ep_throwable, EP_THROWABLE },
4160 { ep_can_explode, EP_CAN_EXPLODE },
4161 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4163 { ep_player, EP_PLAYER },
4164 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4165 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4166 { ep_switchable, EP_SWITCHABLE },
4167 { ep_bd_element, EP_BD_ELEMENT },
4168 { ep_sp_element, EP_SP_ELEMENT },
4169 { ep_sb_element, EP_SB_ELEMENT },
4171 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4172 { ep_food_penguin, EP_FOOD_PENGUIN },
4173 { ep_food_pig, EP_FOOD_PIG },
4174 { ep_historic_wall, EP_HISTORIC_WALL },
4175 { ep_historic_solid, EP_HISTORIC_SOLID },
4176 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4177 { ep_belt, EP_BELT },
4178 { ep_belt_active, EP_BELT_ACTIVE },
4179 { ep_belt_switch, EP_BELT_SWITCH },
4180 { ep_tube, EP_TUBE },
4181 { ep_acid_pool, EP_ACID_POOL },
4182 { ep_keygate, EP_KEYGATE },
4183 { ep_amoeboid, EP_AMOEBOID },
4184 { ep_amoebalive, EP_AMOEBALIVE },
4185 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4186 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4187 { ep_can_grow, EP_CAN_GROW },
4188 { ep_active_bomb, EP_ACTIVE_BOMB },
4189 { ep_inactive, EP_INACTIVE },
4191 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4193 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4195 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4196 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4198 { ep_obsolete, EP_OBSOLETE },
4205 /* always start with reliable default values (element has no properties) */
4206 /* (but never initialize clipboard elements after the very first time) */
4207 /* (to be able to use clipboard elements between several levels) */
4208 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4209 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4210 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4211 SET_PROPERTY(i, j, FALSE);
4213 /* set all base element properties from above array definitions */
4214 for (i = 0; element_properties[i].elements != NULL; i++)
4215 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4216 SET_PROPERTY((element_properties[i].elements)[j],
4217 element_properties[i].property, TRUE);
4219 /* copy properties to some elements that are only stored in level file */
4220 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4221 for (j = 0; copy_properties[j][0] != -1; j++)
4222 if (HAS_PROPERTY(copy_properties[j][0], i))
4223 for (k = 1; k <= 4; k++)
4224 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4226 /* set static element properties that are not listed in array definitions */
4227 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4228 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4230 clipboard_elements_initialized = TRUE;
4233 void InitElementPropertiesEngine(int engine_version)
4235 static int no_wall_properties[] =
4238 EP_COLLECTIBLE_ONLY,
4240 EP_DONT_COLLIDE_WITH,
4243 EP_CAN_SMASH_PLAYER,
4244 EP_CAN_SMASH_ENEMIES,
4245 EP_CAN_SMASH_EVERYTHING,
4250 EP_FOOD_DARK_YAMYAM,
4266 /* important: after initialization in InitElementPropertiesStatic(), the
4267 elements are not again initialized to a default value; therefore all
4268 changes have to make sure that they leave the element with a defined
4269 property (which means that conditional property changes must be set to
4270 a reliable default value before) */
4272 /* resolve group elements */
4273 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4274 ResolveGroupElement(EL_GROUP_START + i);
4276 /* set all special, combined or engine dependent element properties */
4277 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4279 /* do not change (already initialized) clipboard elements here */
4280 if (IS_CLIPBOARD_ELEMENT(i))
4283 /* ---------- INACTIVE ------------------------------------------------- */
4284 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4285 i <= EL_CHAR_END) ||
4286 (i >= EL_STEEL_CHAR_START &&
4287 i <= EL_STEEL_CHAR_END)));
4289 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4290 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4291 IS_WALKABLE_INSIDE(i) ||
4292 IS_WALKABLE_UNDER(i)));
4294 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4295 IS_PASSABLE_INSIDE(i) ||
4296 IS_PASSABLE_UNDER(i)));
4298 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4299 IS_PASSABLE_OVER(i)));
4301 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4302 IS_PASSABLE_INSIDE(i)));
4304 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4305 IS_PASSABLE_UNDER(i)));
4307 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4310 /* ---------- COLLECTIBLE ---------------------------------------------- */
4311 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4315 /* ---------- SNAPPABLE ------------------------------------------------ */
4316 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4317 IS_COLLECTIBLE(i) ||
4321 /* ---------- WALL ----------------------------------------------------- */
4322 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4324 for (j = 0; no_wall_properties[j] != -1; j++)
4325 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4326 i >= EL_FIRST_RUNTIME_UNREAL)
4327 SET_PROPERTY(i, EP_WALL, FALSE);
4329 if (IS_HISTORIC_WALL(i))
4330 SET_PROPERTY(i, EP_WALL, TRUE);
4332 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4333 if (engine_version < VERSION_IDENT(2,2,0,0))
4334 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4336 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4338 !IS_COLLECTIBLE(i)));
4340 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4341 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4342 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4344 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4345 IS_INDESTRUCTIBLE(i)));
4347 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4349 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4350 else if (engine_version < VERSION_IDENT(2,2,0,0))
4351 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4353 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4357 if (IS_CUSTOM_ELEMENT(i))
4359 /* these are additional properties which are initially false when set */
4361 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4363 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4364 if (DONT_COLLIDE_WITH(i))
4365 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4367 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4368 if (CAN_SMASH_EVERYTHING(i))
4369 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4370 if (CAN_SMASH_ENEMIES(i))
4371 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4374 /* ---------- CAN_SMASH ------------------------------------------------ */
4375 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4376 CAN_SMASH_ENEMIES(i) ||
4377 CAN_SMASH_EVERYTHING(i)));
4379 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4380 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4381 EXPLODES_BY_FIRE(i)));
4383 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4384 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4385 EXPLODES_SMASHED(i)));
4387 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4388 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4389 EXPLODES_IMPACT(i)));
4391 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4392 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4394 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4395 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4396 i == EL_BLACK_ORB));
4398 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4399 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4401 IS_CUSTOM_ELEMENT(i)));
4403 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4404 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4405 i == EL_SP_ELECTRON));
4407 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4408 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4409 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4410 getMoveIntoAcidProperty(&level, i));
4412 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4413 if (MAYBE_DONT_COLLIDE_WITH(i))
4414 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4415 getDontCollideWithProperty(&level, i));
4417 /* ---------- SP_PORT -------------------------------------------------- */
4418 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4419 IS_PASSABLE_INSIDE(i)));
4421 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4422 for (j = 0; j < level.num_android_clone_elements; j++)
4423 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4425 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4427 /* ---------- CAN_CHANGE ----------------------------------------------- */
4428 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4429 for (j = 0; j < element_info[i].num_change_pages; j++)
4430 if (element_info[i].change_page[j].can_change)
4431 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4433 /* ---------- HAS_ACTION ----------------------------------------------- */
4434 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4435 for (j = 0; j < element_info[i].num_change_pages; j++)
4436 if (element_info[i].change_page[j].has_action)
4437 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4439 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4440 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4443 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4444 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4445 element_info[i].crumbled[ACTION_DEFAULT] !=
4446 element_info[i].graphic[ACTION_DEFAULT]);
4448 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4449 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4450 IS_EDITOR_CASCADE_INACTIVE(i)));
4453 /* dynamically adjust element properties according to game engine version */
4455 static int ep_em_slippery_wall[] =
4460 EL_EXPANDABLE_WALL_HORIZONTAL,
4461 EL_EXPANDABLE_WALL_VERTICAL,
4462 EL_EXPANDABLE_WALL_ANY,
4463 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4464 EL_EXPANDABLE_STEELWALL_VERTICAL,
4465 EL_EXPANDABLE_STEELWALL_ANY,
4466 EL_EXPANDABLE_STEELWALL_GROWING,
4470 static int ep_em_explodes_by_fire[] =
4473 EL_EM_DYNAMITE_ACTIVE,
4478 /* special EM style gems behaviour */
4479 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4480 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4481 level.em_slippery_gems);
4483 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4484 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4485 (level.em_slippery_gems &&
4486 engine_version > VERSION_IDENT(2,0,1,0)));
4488 /* special EM style explosion behaviour regarding chain reactions */
4489 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4490 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4491 level.em_explodes_by_fire);
4494 /* this is needed because some graphics depend on element properties */
4495 if (game_status == GAME_MODE_PLAYING)
4496 InitElementGraphicInfo();
4499 void InitElementPropertiesAfterLoading(int engine_version)
4503 /* set some other uninitialized values of custom elements in older levels */
4504 if (engine_version < VERSION_IDENT(3,1,0,0))
4506 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4508 int element = EL_CUSTOM_START + i;
4510 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4512 element_info[element].explosion_delay = 17;
4513 element_info[element].ignition_delay = 8;
4518 void InitElementPropertiesGfxElement()
4522 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4524 struct ElementInfo *ei = &element_info[i];
4526 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4530 static void InitGlobal()
4535 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4537 /* check if element_name_info entry defined for each element in "main.h" */
4538 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4539 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4541 element_info[i].token_name = element_name_info[i].token_name;
4542 element_info[i].class_name = element_name_info[i].class_name;
4543 element_info[i].editor_description= element_name_info[i].editor_description;
4546 /* create hash from image config list */
4547 image_config_hash = newSetupFileHash();
4548 for (i = 0; image_config[i].token != NULL; i++)
4549 setHashEntry(image_config_hash,
4550 image_config[i].token,
4551 image_config[i].value);
4553 /* create hash from element token list */
4554 element_token_hash = newSetupFileHash();
4555 for (i = 0; element_name_info[i].token_name != NULL; i++)
4556 setHashEntry(element_token_hash,
4557 element_name_info[i].token_name,
4560 /* create hash from graphic token list */
4561 graphic_token_hash = newSetupFileHash();
4562 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4563 if (strSuffix(image_config[i].value, ".png") ||
4564 strSuffix(image_config[i].value, ".pcx") ||
4565 strSuffix(image_config[i].value, ".wav") ||
4566 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4567 setHashEntry(graphic_token_hash,
4568 image_config[i].token,
4569 int2str(graphic++, 0));
4571 /* create hash from font token list */
4572 font_token_hash = newSetupFileHash();
4573 for (i = 0; font_info[i].token_name != NULL; i++)
4574 setHashEntry(font_token_hash,
4575 font_info[i].token_name,
4578 /* set default filenames for all cloned graphics in static configuration */
4579 for (i = 0; image_config[i].token != NULL; i++)
4581 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4583 char *token = image_config[i].token;
4584 char *token_clone_from = getStringCat2(token, ".clone_from");
4585 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4587 if (token_cloned != NULL)
4589 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4591 if (value_cloned != NULL)
4593 /* set default filename in static configuration */
4594 image_config[i].value = value_cloned;
4596 /* set default filename in image config hash */
4597 setHashEntry(image_config_hash, token, value_cloned);
4601 free(token_clone_from);
4605 /* always start with reliable default values (all elements) */
4606 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4607 ActiveElement[i] = i;
4609 /* now add all entries that have an active state (active elements) */
4610 for (i = 0; element_with_active_state[i].element != -1; i++)
4612 int element = element_with_active_state[i].element;
4613 int element_active = element_with_active_state[i].element_active;
4615 ActiveElement[element] = element_active;
4618 /* always start with reliable default values (all buttons) */
4619 for (i = 0; i < NUM_IMAGE_FILES; i++)
4620 ActiveButton[i] = i;
4622 /* now add all entries that have an active state (active buttons) */
4623 for (i = 0; button_with_active_state[i].button != -1; i++)
4625 int button = button_with_active_state[i].button;
4626 int button_active = button_with_active_state[i].button_active;
4628 ActiveButton[button] = button_active;
4631 /* always start with reliable default values (all fonts) */
4632 for (i = 0; i < NUM_FONTS; i++)
4635 /* now add all entries that have an active state (active fonts) */
4636 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4638 int font = font_with_active_state[i].font_nr;
4639 int font_active = font_with_active_state[i].font_nr_active;
4641 ActiveFont[font] = font_active;
4644 global.autoplay_leveldir = NULL;
4645 global.convert_leveldir = NULL;
4646 global.create_images_dir = NULL;
4648 global.frames_per_second = 0;
4650 global.border_status = GAME_MODE_MAIN;
4652 global.use_envelope_request = FALSE;
4655 void Execute_Command(char *command)
4659 if (strEqual(command, "print graphicsinfo.conf"))
4661 Print("# You can configure additional/alternative image files here.\n");
4662 Print("# (The entries below are default and therefore commented out.)\n");
4664 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4666 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4669 for (i = 0; image_config[i].token != NULL; i++)
4670 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4671 image_config[i].value));
4675 else if (strEqual(command, "print soundsinfo.conf"))
4677 Print("# You can configure additional/alternative sound files here.\n");
4678 Print("# (The entries below are default and therefore commented out.)\n");
4680 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4682 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4685 for (i = 0; sound_config[i].token != NULL; i++)
4686 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4687 sound_config[i].value));
4691 else if (strEqual(command, "print musicinfo.conf"))
4693 Print("# You can configure additional/alternative music files here.\n");
4694 Print("# (The entries below are default and therefore commented out.)\n");
4696 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4698 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4701 for (i = 0; music_config[i].token != NULL; i++)
4702 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4703 music_config[i].value));
4707 else if (strEqual(command, "print editorsetup.conf"))
4709 Print("# You can configure your personal editor element list here.\n");
4710 Print("# (The entries below are default and therefore commented out.)\n");
4713 /* this is needed to be able to check element list for cascade elements */
4714 InitElementPropertiesStatic();
4715 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4717 PrintEditorElementList();
4721 else if (strEqual(command, "print helpanim.conf"))
4723 Print("# You can configure different element help animations here.\n");
4724 Print("# (The entries below are default and therefore commented out.)\n");
4727 for (i = 0; helpanim_config[i].token != NULL; i++)
4729 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4730 helpanim_config[i].value));
4732 if (strEqual(helpanim_config[i].token, "end"))
4738 else if (strEqual(command, "print helptext.conf"))
4740 Print("# You can configure different element help text here.\n");
4741 Print("# (The entries below are default and therefore commented out.)\n");
4744 for (i = 0; helptext_config[i].token != NULL; i++)
4745 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4746 helptext_config[i].value));
4750 else if (strPrefix(command, "dump level "))
4752 char *filename = &command[11];
4754 if (!fileExists(filename))
4755 Error(ERR_EXIT, "cannot open file '%s'", filename);
4757 LoadLevelFromFilename(&level, filename);
4762 else if (strPrefix(command, "dump tape "))
4764 char *filename = &command[10];
4766 if (!fileExists(filename))
4767 Error(ERR_EXIT, "cannot open file '%s'", filename);
4769 LoadTapeFromFilename(filename);
4774 else if (strPrefix(command, "autotest ") ||
4775 strPrefix(command, "autoplay ") ||
4776 strPrefix(command, "autoffwd "))
4778 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4780 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4781 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4782 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4784 while (*str_ptr != '\0') /* continue parsing string */
4786 /* cut leading whitespace from string, replace it by string terminator */
4787 while (*str_ptr == ' ' || *str_ptr == '\t')
4790 if (*str_ptr == '\0') /* end of string reached */
4793 if (global.autoplay_leveldir == NULL) /* read level set string */
4795 global.autoplay_leveldir = str_ptr;
4796 global.autoplay_all = TRUE; /* default: play all tapes */
4798 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4799 global.autoplay_level[i] = FALSE;
4801 else /* read level number string */
4803 int level_nr = atoi(str_ptr); /* get level_nr value */
4805 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4806 global.autoplay_level[level_nr] = TRUE;
4808 global.autoplay_all = FALSE;
4811 /* advance string pointer to the next whitespace (or end of string) */
4812 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4816 else if (strPrefix(command, "convert "))
4818 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4819 char *str_ptr = strchr(str_copy, ' ');
4821 global.convert_leveldir = str_copy;
4822 global.convert_level_nr = -1;
4824 if (str_ptr != NULL) /* level number follows */
4826 *str_ptr++ = '\0'; /* terminate leveldir string */
4827 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4830 else if (strPrefix(command, "create images "))
4832 global.create_images_dir = getStringCopy(&command[14]);
4834 if (access(global.create_images_dir, W_OK) != 0)
4835 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4836 global.create_images_dir);
4838 else if (strPrefix(command, "create CE image "))
4840 CreateCustomElementImages(&command[16]);
4846 #if defined(TARGET_SDL2)
4847 else if (strEqual(command, "SDL_ListModes"))
4849 SDL_Init(SDL_INIT_VIDEO);
4851 int num_displays = SDL_GetNumVideoDisplays();
4853 // check if there are any displays available
4854 if (num_displays < 0)
4856 Print("No displays available: %s\n", SDL_GetError());
4861 for (i = 0; i < num_displays; i++)
4863 int num_modes = SDL_GetNumDisplayModes(i);
4866 Print("Available display modes for display %d:\n", i);
4868 // check if there are any display modes available for this display
4871 Print("No display modes available for display %d: %s\n",
4877 for (j = 0; j < num_modes; j++)
4879 SDL_DisplayMode mode;
4881 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4883 Print("Cannot get display mode %d for display %d: %s\n",
4884 j, i, SDL_GetError());
4889 Print("- %d x %d\n", mode.w, mode.h);
4895 #elif defined(TARGET_SDL)
4896 else if (strEqual(command, "SDL_ListModes"))
4901 SDL_Init(SDL_INIT_VIDEO);
4903 /* get available fullscreen/hardware modes */
4904 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4906 /* check if there are any modes available */
4909 Print("No modes available!\n");
4914 /* check if our resolution is restricted */
4915 if (modes == (SDL_Rect **)-1)
4917 Print("All resolutions available.\n");
4921 Print("Available display modes:\n");
4923 for (i = 0; modes[i]; i++)
4924 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4934 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4938 static void InitSetup()
4940 LoadSetup(); /* global setup info */
4942 /* set some options from setup file */
4944 if (setup.options.verbose)
4945 options.verbose = TRUE;
4948 static void InitGameInfo()
4950 game.restart_level = FALSE;
4953 static void InitPlayerInfo()
4957 /* choose default local player */
4958 local_player = &stored_player[0];
4960 for (i = 0; i < MAX_PLAYERS; i++)
4961 stored_player[i].connected = FALSE;
4963 local_player->connected = TRUE;
4966 static void InitArtworkInfo()
4971 static char *get_string_in_brackets(char *string)
4973 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4975 sprintf(string_in_brackets, "[%s]", string);
4977 return string_in_brackets;
4980 static char *get_level_id_suffix(int id_nr)
4982 char *id_suffix = checked_malloc(1 + 3 + 1);
4984 if (id_nr < 0 || id_nr > 999)
4987 sprintf(id_suffix, ".%03d", id_nr);
4992 static void InitArtworkConfig()
4994 static char *image_id_prefix[MAX_NUM_ELEMENTS +
4996 NUM_GLOBAL_ANIM_TOKENS + 1];
4997 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4998 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4999 static char *action_id_suffix[NUM_ACTIONS + 1];
5000 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5001 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5002 static char *level_id_suffix[MAX_LEVELS + 1];
5003 static char *dummy[1] = { NULL };
5004 static char *ignore_generic_tokens[] =
5010 static char **ignore_image_tokens;
5011 static char **ignore_sound_tokens;
5012 static char **ignore_music_tokens;
5013 int num_ignore_generic_tokens;
5014 int num_ignore_image_tokens;
5015 int num_ignore_sound_tokens;
5016 int num_ignore_music_tokens;
5019 /* dynamically determine list of generic tokens to be ignored */
5020 num_ignore_generic_tokens = 0;
5021 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5022 num_ignore_generic_tokens++;
5024 /* dynamically determine list of image tokens to be ignored */
5025 num_ignore_image_tokens = num_ignore_generic_tokens;
5026 for (i = 0; image_config_vars[i].token != NULL; i++)
5027 num_ignore_image_tokens++;
5028 ignore_image_tokens =
5029 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5030 for (i = 0; i < num_ignore_generic_tokens; i++)
5031 ignore_image_tokens[i] = ignore_generic_tokens[i];
5032 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5033 ignore_image_tokens[num_ignore_generic_tokens + i] =
5034 image_config_vars[i].token;
5035 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5037 /* dynamically determine list of sound tokens to be ignored */
5038 num_ignore_sound_tokens = num_ignore_generic_tokens;
5039 ignore_sound_tokens =
5040 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5041 for (i = 0; i < num_ignore_generic_tokens; i++)
5042 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5043 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5045 /* dynamically determine list of music tokens to be ignored */
5046 num_ignore_music_tokens = num_ignore_generic_tokens;
5047 ignore_music_tokens =
5048 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5049 for (i = 0; i < num_ignore_generic_tokens; i++)
5050 ignore_music_tokens[i] = ignore_generic_tokens[i];
5051 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5053 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5054 image_id_prefix[i] = element_info[i].token_name;
5055 for (i = 0; i < NUM_FONTS; i++)
5056 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5057 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5058 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5059 global_anim_info[i].token_name;
5060 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5062 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5063 sound_id_prefix[i] = element_info[i].token_name;
5064 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5065 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5066 get_string_in_brackets(element_info[i].class_name);
5067 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5069 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5070 music_id_prefix[i] = music_prefix_info[i].prefix;
5071 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5073 for (i = 0; i < NUM_ACTIONS; i++)
5074 action_id_suffix[i] = element_action_info[i].suffix;
5075 action_id_suffix[NUM_ACTIONS] = NULL;
5077 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5078 direction_id_suffix[i] = element_direction_info[i].suffix;
5079 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5081 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5082 special_id_suffix[i] = special_suffix_info[i].suffix;
5083 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5085 for (i = 0; i < MAX_LEVELS; i++)
5086 level_id_suffix[i] = get_level_id_suffix(i);
5087 level_id_suffix[MAX_LEVELS] = NULL;
5089 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5090 image_id_prefix, action_id_suffix, direction_id_suffix,
5091 special_id_suffix, ignore_image_tokens);
5092 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5093 sound_id_prefix, action_id_suffix, dummy,
5094 special_id_suffix, ignore_sound_tokens);
5095 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5096 music_id_prefix, special_id_suffix, level_id_suffix,
5097 dummy, ignore_music_tokens);
5100 static void InitMixer()
5107 void InitGfxBuffers()
5109 static int win_xsize_last = -1;
5110 static int win_ysize_last = -1;
5112 /* create additional image buffers for double-buffering and cross-fading */
5114 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5116 /* may contain content for cross-fading -- only re-create if changed */
5117 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5118 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5120 win_xsize_last = WIN_XSIZE;
5121 win_ysize_last = WIN_YSIZE;
5124 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5125 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5126 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5127 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5128 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5130 /* initialize screen properties */
5131 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5132 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5134 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5135 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5136 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5137 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5138 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5139 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5141 /* required if door size definitions have changed */
5142 InitGraphicCompatibilityInfo_Doors();
5144 InitGfxBuffers_EM();
5145 InitGfxBuffers_SP();
5150 struct GraphicInfo *graphic_info_last = graphic_info;
5151 char *filename_font_initial = NULL;
5152 char *filename_anim_initial = NULL;
5153 Bitmap *bitmap_font_initial = NULL;
5157 /* determine settings for initial font (for displaying startup messages) */
5158 for (i = 0; image_config[i].token != NULL; i++)
5160 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5162 char font_token[128];
5165 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5166 len_font_token = strlen(font_token);
5168 if (strEqual(image_config[i].token, font_token))
5169 filename_font_initial = image_config[i].value;
5170 else if (strlen(image_config[i].token) > len_font_token &&
5171 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5173 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5174 font_initial[j].src_x = atoi(image_config[i].value);
5175 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5176 font_initial[j].src_y = atoi(image_config[i].value);
5177 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5178 font_initial[j].width = atoi(image_config[i].value);
5179 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5180 font_initial[j].height = atoi(image_config[i].value);
5185 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5187 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5188 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5191 if (filename_font_initial == NULL) /* should not happen */
5192 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5195 InitGfxCustomArtworkInfo();
5196 InitGfxOtherSettings();
5198 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5200 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5201 font_initial[j].bitmap = bitmap_font_initial;
5203 InitFontGraphicInfo();
5205 font_height = getFontHeight(FC_RED);
5207 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5208 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5209 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5212 DrawInitText("Loading graphics", 120, FC_GREEN);
5214 /* initialize settings for busy animation with default values */
5215 int parameter[NUM_GFX_ARGS];
5216 for (i = 0; i < NUM_GFX_ARGS; i++)
5217 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5218 image_config_suffix[i].token,
5219 image_config_suffix[i].type);
5221 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5222 int len_anim_token = strlen(anim_token);
5224 /* read settings for busy animation from default custom artwork config */
5225 char *gfx_config_filename = getPath3(options.graphics_directory,
5227 GRAPHICSINFO_FILENAME);
5229 if (fileExists(gfx_config_filename))
5231 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5233 if (setup_file_hash)
5235 char *filename = getHashEntry(setup_file_hash, anim_token);
5239 filename_anim_initial = getStringCopy(filename);
5241 for (j = 0; image_config_suffix[j].token != NULL; j++)
5243 int type = image_config_suffix[j].type;
5244 char *suffix = image_config_suffix[j].token;
5245 char *token = getStringCat2(anim_token, suffix);
5246 char *value = getHashEntry(setup_file_hash, token);
5248 checked_free(token);
5251 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5255 freeSetupFileHash(setup_file_hash);
5259 if (filename_anim_initial == NULL)
5261 /* read settings for busy animation from static default artwork config */
5262 for (i = 0; image_config[i].token != NULL; i++)
5264 if (strEqual(image_config[i].token, anim_token))
5265 filename_anim_initial = getStringCopy(image_config[i].value);
5266 else if (strlen(image_config[i].token) > len_anim_token &&
5267 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5269 for (j = 0; image_config_suffix[j].token != NULL; j++)
5271 if (strEqual(&image_config[i].token[len_anim_token],
5272 image_config_suffix[j].token))
5274 get_graphic_parameter_value(image_config[i].value,
5275 image_config_suffix[j].token,
5276 image_config_suffix[j].type);
5282 if (filename_anim_initial == NULL) /* should not happen */
5283 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5285 anim_initial.bitmaps =
5286 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5288 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5289 LoadCustomImage(filename_anim_initial);
5291 checked_free(filename_anim_initial);
5293 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5295 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5297 graphic_info = graphic_info_last;
5299 init.busy.width = anim_initial.width;
5300 init.busy.height = anim_initial.height;
5302 InitMenuDesignSettings_Static();
5304 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5305 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5307 /* use copy of busy animation to prevent change while reloading artwork */
5311 void InitGfxBackground()
5313 fieldbuffer = bitmap_db_field;
5314 SetDrawtoField(DRAW_BACKBUFFER);
5316 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5318 redraw_mask = REDRAW_ALL;
5321 static void InitLevelInfo()
5323 LoadLevelInfo(); /* global level info */
5324 LoadLevelSetup_LastSeries(); /* last played series info */
5325 LoadLevelSetup_SeriesInfo(); /* last played level info */
5327 if (global.autoplay_leveldir &&
5328 global.autoplay_mode != AUTOPLAY_TEST)
5330 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5331 global.autoplay_leveldir);
5332 if (leveldir_current == NULL)
5333 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5337 static void InitLevelArtworkInfo()
5339 LoadLevelArtworkInfo();
5342 static void InitImages()
5344 print_timestamp_init("InitImages");
5347 printf("::: leveldir_current->identifier == '%s'\n",
5348 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5349 printf("::: leveldir_current->graphics_path == '%s'\n",
5350 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5351 printf("::: leveldir_current->graphics_set == '%s'\n",
5352 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5353 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5354 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5357 setLevelArtworkDir(artwork.gfx_first);
5360 printf("::: leveldir_current->identifier == '%s'\n",
5361 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5362 printf("::: leveldir_current->graphics_path == '%s'\n",
5363 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5364 printf("::: leveldir_current->graphics_set == '%s'\n",
5365 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5366 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5367 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5371 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5372 leveldir_current->identifier,
5373 artwork.gfx_current_identifier,
5374 artwork.gfx_current->identifier,
5375 leveldir_current->graphics_set,
5376 leveldir_current->graphics_path);
5379 UPDATE_BUSY_STATE();
5381 ReloadCustomImages();
5382 print_timestamp_time("ReloadCustomImages");
5384 UPDATE_BUSY_STATE();
5386 LoadCustomElementDescriptions();
5387 print_timestamp_time("LoadCustomElementDescriptions");
5389 UPDATE_BUSY_STATE();
5391 LoadMenuDesignSettings();
5392 print_timestamp_time("LoadMenuDesignSettings");
5394 UPDATE_BUSY_STATE();
5396 ReinitializeGraphics();
5397 print_timestamp_time("ReinitializeGraphics");
5399 UPDATE_BUSY_STATE();
5401 print_timestamp_done("InitImages");
5404 static void InitSound(char *identifier)
5406 print_timestamp_init("InitSound");
5408 if (identifier == NULL)
5409 identifier = artwork.snd_current->identifier;
5411 /* set artwork path to send it to the sound server process */
5412 setLevelArtworkDir(artwork.snd_first);
5414 InitReloadCustomSounds(identifier);
5415 print_timestamp_time("InitReloadCustomSounds");
5417 ReinitializeSounds();
5418 print_timestamp_time("ReinitializeSounds");
5420 print_timestamp_done("InitSound");
5423 static void InitMusic(char *identifier)
5425 print_timestamp_init("InitMusic");
5427 if (identifier == NULL)
5428 identifier = artwork.mus_current->identifier;
5430 /* set artwork path to send it to the sound server process */
5431 setLevelArtworkDir(artwork.mus_first);
5433 InitReloadCustomMusic(identifier);
5434 print_timestamp_time("InitReloadCustomMusic");
5436 ReinitializeMusic();
5437 print_timestamp_time("ReinitializeMusic");
5439 print_timestamp_done("InitMusic");
5442 void InitNetworkServer()
5444 #if defined(NETWORK_AVALIABLE)
5448 if (!options.network)
5451 #if defined(NETWORK_AVALIABLE)
5452 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5454 if (!ConnectToServer(options.server_host, options.server_port))
5455 Error(ERR_EXIT, "cannot connect to network game server");
5457 SendToServer_PlayerName(setup.player_name);
5458 SendToServer_ProtocolVersion();
5461 SendToServer_NrWanted(nr_wanted);
5465 static boolean CheckArtworkConfigForCustomElements(char *filename)
5467 SetupFileHash *setup_file_hash;
5468 boolean redefined_ce_found = FALSE;
5470 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5472 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5474 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5476 char *token = HASH_ITERATION_TOKEN(itr);
5478 if (strPrefix(token, "custom_"))
5480 redefined_ce_found = TRUE;
5485 END_HASH_ITERATION(setup_file_hash, itr)
5487 freeSetupFileHash(setup_file_hash);
5490 return redefined_ce_found;
5493 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5495 char *filename_base, *filename_local;
5496 boolean redefined_ce_found = FALSE;
5498 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5501 printf("::: leveldir_current->identifier == '%s'\n",
5502 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5503 printf("::: leveldir_current->graphics_path == '%s'\n",
5504 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5505 printf("::: leveldir_current->graphics_set == '%s'\n",
5506 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5507 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5508 leveldir_current == NULL ? "[NULL]" :
5509 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5512 /* first look for special artwork configured in level series config */
5513 filename_base = getCustomArtworkLevelConfigFilename(type);
5516 printf("::: filename_base == '%s'\n", filename_base);
5519 if (fileExists(filename_base))
5520 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5522 filename_local = getCustomArtworkConfigFilename(type);
5525 printf("::: filename_local == '%s'\n", filename_local);
5528 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5529 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5532 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5535 return redefined_ce_found;
5538 static void InitOverrideArtwork()
5540 boolean redefined_ce_found = FALSE;
5542 /* to check if this level set redefines any CEs, do not use overriding */
5543 gfx.override_level_graphics = FALSE;
5544 gfx.override_level_sounds = FALSE;
5545 gfx.override_level_music = FALSE;
5547 /* now check if this level set has definitions for custom elements */
5548 if (setup.override_level_graphics == AUTO ||
5549 setup.override_level_sounds == AUTO ||
5550 setup.override_level_music == AUTO)
5551 redefined_ce_found =
5552 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5553 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5554 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5557 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5560 if (redefined_ce_found)
5562 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5563 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5564 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5565 gfx.override_level_music = (setup.override_level_music == TRUE);
5569 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5570 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5571 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5572 gfx.override_level_music = (setup.override_level_music != FALSE);
5576 printf("::: => %d, %d, %d\n",
5577 gfx.override_level_graphics,
5578 gfx.override_level_sounds,
5579 gfx.override_level_music);
5583 static char *getNewArtworkIdentifier(int type)
5585 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5586 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5587 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5588 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5589 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5590 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5591 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5592 char *leveldir_identifier = leveldir_current->identifier;
5593 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5594 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5595 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5596 char *artwork_current_identifier;
5597 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5599 /* leveldir_current may be invalid (level group, parent link) */
5600 if (!validLevelSeries(leveldir_current))
5603 /* 1st step: determine artwork set to be activated in descending order:
5604 --------------------------------------------------------------------
5605 1. setup artwork (when configured to override everything else)
5606 2. artwork set configured in "levelinfo.conf" of current level set
5607 (artwork in level directory will have priority when loading later)
5608 3. artwork in level directory (stored in artwork sub-directory)
5609 4. setup artwork (currently configured in setup menu) */
5611 if (setup_override_artwork)
5612 artwork_current_identifier = setup_artwork_set;
5613 else if (leveldir_artwork_set != NULL)
5614 artwork_current_identifier = leveldir_artwork_set;
5615 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5616 artwork_current_identifier = leveldir_identifier;
5618 artwork_current_identifier = setup_artwork_set;
5621 /* 2nd step: check if it is really needed to reload artwork set
5622 ------------------------------------------------------------ */
5624 /* ---------- reload if level set and also artwork set has changed ------- */
5625 if (leveldir_current_identifier[type] != leveldir_identifier &&
5626 (last_has_level_artwork_set[type] || has_level_artwork_set))
5627 artwork_new_identifier = artwork_current_identifier;
5629 leveldir_current_identifier[type] = leveldir_identifier;
5630 last_has_level_artwork_set[type] = has_level_artwork_set;
5632 /* ---------- reload if "override artwork" setting has changed ----------- */
5633 if (last_override_level_artwork[type] != setup_override_artwork)
5634 artwork_new_identifier = artwork_current_identifier;
5636 last_override_level_artwork[type] = setup_override_artwork;
5638 /* ---------- reload if current artwork identifier has changed ----------- */
5639 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5640 artwork_current_identifier))
5641 artwork_new_identifier = artwork_current_identifier;
5643 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5645 /* ---------- do not reload directly after starting ---------------------- */
5646 if (!initialized[type])
5647 artwork_new_identifier = NULL;
5649 initialized[type] = TRUE;
5651 return artwork_new_identifier;
5654 void ReloadCustomArtwork(int force_reload)
5656 int last_game_status = game_status; /* save current game status */
5657 char *gfx_new_identifier;
5658 char *snd_new_identifier;
5659 char *mus_new_identifier;
5660 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5661 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5662 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5663 boolean reload_needed;
5665 InitOverrideArtwork();
5667 force_reload_gfx |= AdjustGraphicsForEMC();
5669 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5670 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5671 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5673 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5674 snd_new_identifier != NULL || force_reload_snd ||
5675 mus_new_identifier != NULL || force_reload_mus);
5680 print_timestamp_init("ReloadCustomArtwork");
5682 game_status = GAME_MODE_LOADING;
5684 FadeOut(REDRAW_ALL);
5686 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5687 print_timestamp_time("ClearRectangle");
5691 if (gfx_new_identifier != NULL || force_reload_gfx)
5694 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5695 artwork.gfx_current_identifier,
5697 artwork.gfx_current->identifier,
5698 leveldir_current->graphics_set);
5702 print_timestamp_time("InitImages");
5705 if (snd_new_identifier != NULL || force_reload_snd)
5707 InitSound(snd_new_identifier);
5708 print_timestamp_time("InitSound");
5711 if (mus_new_identifier != NULL || force_reload_mus)
5713 InitMusic(mus_new_identifier);
5714 print_timestamp_time("InitMusic");
5717 game_status = last_game_status; /* restore current game status */
5719 init_last = init; /* switch to new busy animation */
5721 FadeOut(REDRAW_ALL);
5723 RedrawGlobalBorder();
5725 /* force redraw of (open or closed) door graphics */
5726 SetDoorState(DOOR_OPEN_ALL);
5727 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5729 FadeSetEnterScreen();
5730 FadeSkipNextFadeOut();
5732 print_timestamp_done("ReloadCustomArtwork");
5734 LimitScreenUpdates(FALSE);
5737 void KeyboardAutoRepeatOffUnlessAutoplay()
5739 if (global.autoplay_leveldir == NULL)
5740 KeyboardAutoRepeatOff();
5743 void DisplayExitMessage(char *format, va_list ap)
5745 // check if draw buffer and fonts for exit message are already available
5746 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5749 int font_1 = FC_RED;
5750 int font_2 = FC_YELLOW;
5751 int font_3 = FC_BLUE;
5752 int font_width = getFontWidth(font_2);
5753 int font_height = getFontHeight(font_2);
5756 int sxsize = WIN_XSIZE - 2 * sx;
5757 int sysize = WIN_YSIZE - 2 * sy;
5758 int line_length = sxsize / font_width;
5759 int max_lines = sysize / font_height;
5760 int num_lines_printed;
5764 gfx.sxsize = sxsize;
5765 gfx.sysize = sysize;
5769 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5771 DrawTextSCentered(sy, font_1, "Fatal error:");
5772 sy += 3 * font_height;;
5775 DrawTextBufferVA(sx, sy, format, ap, font_2,
5776 line_length, line_length, max_lines,
5777 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5778 sy += (num_lines_printed + 3) * font_height;
5780 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5781 sy += 3 * font_height;
5784 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5785 line_length, line_length, max_lines,
5786 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5788 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5790 redraw_mask = REDRAW_ALL;
5792 /* force drawing exit message even if screen updates are currently limited */
5793 LimitScreenUpdates(FALSE);
5797 /* deactivate toons on error message screen */
5798 setup.toons = FALSE;
5800 WaitForEventToContinue();
5804 /* ========================================================================= */
5806 /* ========================================================================= */
5810 print_timestamp_init("OpenAll");
5812 game_status = GAME_MODE_LOADING;
5816 InitGlobal(); /* initialize some global variables */
5818 print_timestamp_time("[init global stuff]");
5822 print_timestamp_time("[init setup/config stuff (1)]");
5824 if (options.execute_command)
5825 Execute_Command(options.execute_command);
5827 if (options.serveronly)
5829 #if defined(PLATFORM_UNIX)
5830 NetworkServer(options.server_port, options.serveronly);
5832 Error(ERR_WARN, "networking only supported in Unix version");
5835 exit(0); /* never reached, server loops forever */
5839 print_timestamp_time("[init setup/config stuff (2)]");
5841 print_timestamp_time("[init setup/config stuff (3)]");
5842 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5843 print_timestamp_time("[init setup/config stuff (4)]");
5844 InitArtworkConfig(); /* needed before forking sound child process */
5845 print_timestamp_time("[init setup/config stuff (5)]");
5847 print_timestamp_time("[init setup/config stuff (6)]");
5849 InitRND(NEW_RANDOMIZE);
5850 InitSimpleRandom(NEW_RANDOMIZE);
5854 print_timestamp_time("[init setup/config stuff]");
5857 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5859 InitEventFilter(FilterEvents);
5861 print_timestamp_time("[init video stuff]");
5863 InitElementPropertiesStatic();
5864 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5865 InitElementPropertiesGfxElement();
5867 print_timestamp_time("[init element properties stuff]");
5871 print_timestamp_time("InitGfx");
5874 print_timestamp_time("InitLevelInfo");
5876 InitLevelArtworkInfo();
5877 print_timestamp_time("InitLevelArtworkInfo");
5879 InitOverrideArtwork(); /* needs to know current level directory */
5880 print_timestamp_time("InitOverrideArtwork");
5882 InitImages(); /* needs to know current level directory */
5883 print_timestamp_time("InitImages");
5885 InitSound(NULL); /* needs to know current level directory */
5886 print_timestamp_time("InitSound");
5888 InitMusic(NULL); /* needs to know current level directory */
5889 print_timestamp_time("InitMusic");
5891 InitGfxBackground();
5896 if (global.autoplay_leveldir)
5901 else if (global.convert_leveldir)
5906 else if (global.create_images_dir)
5908 CreateLevelSketchImages();
5912 game_status = GAME_MODE_MAIN;
5914 FadeSetEnterScreen();
5915 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5916 FadeSkipNextFadeOut();
5918 print_timestamp_time("[post-artwork]");
5920 print_timestamp_done("OpenAll");
5924 InitNetworkServer();
5927 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5929 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5930 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5931 #if defined(PLATFORM_ANDROID)
5932 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5933 SDL_AndroidGetInternalStoragePath());
5934 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5935 SDL_AndroidGetExternalStoragePath());
5936 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5937 (SDL_AndroidGetExternalStorageState() ==
5938 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5939 SDL_AndroidGetExternalStorageState() ==
5940 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5945 void CloseAllAndExit(int exit_value)
5950 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5957 #if defined(TARGET_SDL)
5958 #if defined(TARGET_SDL2)
5960 // set a flag to tell the network server thread to quit and wait for it
5961 // using SDL_WaitThread()
5963 if (network_server) /* terminate network server */
5964 SDL_KillThread(server_thread);
5968 CloseVideoDisplay();
5969 ClosePlatformDependentStuff();
5971 if (exit_value != 0)
5973 /* fall back to default level set (current set may have caused an error) */
5974 SaveLevelSetup_LastSeries_Deactivate();
5976 /* tell user where to find error log file which may contain more details */
5977 // (error notification now directly displayed on screen inside R'n'D
5978 // NotifyUserAboutErrorFile(); /* currently only works for Windows */