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; 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_ANIMS; i++)
541 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS; 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_ANIMS; i++)
547 global_anim_info[i].graphic[0][GFX_SPECIAL_ARG_DEFAULT] =
548 IMG_GLOBAL_ANIM_1 + i;
550 /* initialize global animation definitions from dynamic configuration */
551 for (i = 0; i < num_property_mappings; i++)
553 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
554 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
555 int special = property_mapping[i].ext3_index;
556 int graphic = property_mapping[i].artwork_index;
558 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIMS)
561 /* map animation part to first part, if not specified */
565 /* map animation screen to default, if not specified */
566 if (!IS_SPECIAL_GFX_ARG(special))
567 special = GFX_SPECIAL_ARG_DEFAULT;
569 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
573 printf("::: InitGlobalAnimGraphicInfo\n");
575 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
576 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS; j++)
577 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
578 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
579 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
580 printf("::: %d, %d, %d => %d\n",
581 i, j, k, global_anim_info[i].graphic[j][k]);
585 void InitElementGraphicInfo()
587 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
588 int num_property_mappings = getImageListPropertyMappingSize();
591 if (graphic_info == NULL) /* still at startup phase */
594 /* set values to -1 to identify later as "uninitialized" values */
595 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
597 for (act = 0; act < NUM_ACTIONS; act++)
599 element_info[i].graphic[act] = -1;
600 element_info[i].crumbled[act] = -1;
602 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
604 element_info[i].direction_graphic[act][dir] = -1;
605 element_info[i].direction_crumbled[act][dir] = -1;
612 /* initialize normal element/graphic mapping from static configuration */
613 for (i = 0; element_to_graphic[i].element > -1; i++)
615 int element = element_to_graphic[i].element;
616 int action = element_to_graphic[i].action;
617 int direction = element_to_graphic[i].direction;
618 boolean crumbled = element_to_graphic[i].crumbled;
619 int graphic = element_to_graphic[i].graphic;
620 int base_graphic = el2baseimg(element);
622 if (graphic_info[graphic].bitmap == NULL)
625 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
628 boolean base_redefined =
629 getImageListEntryFromImageID(base_graphic)->redefined;
630 boolean act_dir_redefined =
631 getImageListEntryFromImageID(graphic)->redefined;
633 /* if the base graphic ("emerald", for example) has been redefined,
634 but not the action graphic ("emerald.falling", for example), do not
635 use an existing (in this case considered obsolete) action graphic
636 anymore, but use the automatically determined default graphic */
637 if (base_redefined && !act_dir_redefined)
642 action = ACTION_DEFAULT;
647 element_info[element].direction_crumbled[action][direction] = graphic;
649 element_info[element].crumbled[action] = graphic;
654 element_info[element].direction_graphic[action][direction] = graphic;
656 element_info[element].graphic[action] = graphic;
660 /* initialize normal element/graphic mapping from dynamic configuration */
661 for (i = 0; i < num_property_mappings; i++)
663 int element = property_mapping[i].base_index;
664 int action = property_mapping[i].ext1_index;
665 int direction = property_mapping[i].ext2_index;
666 int special = property_mapping[i].ext3_index;
667 int graphic = property_mapping[i].artwork_index;
668 boolean crumbled = FALSE;
670 if (special == GFX_SPECIAL_ARG_CRUMBLED)
676 if (graphic_info[graphic].bitmap == NULL)
679 if (element >= MAX_NUM_ELEMENTS || special != -1)
683 action = ACTION_DEFAULT;
688 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
689 element_info[element].direction_crumbled[action][dir] = -1;
692 element_info[element].direction_crumbled[action][direction] = graphic;
694 element_info[element].crumbled[action] = graphic;
699 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
700 element_info[element].direction_graphic[action][dir] = -1;
703 element_info[element].direction_graphic[action][direction] = graphic;
705 element_info[element].graphic[action] = graphic;
709 /* now copy all graphics that are defined to be cloned from other graphics */
710 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
712 int graphic = element_info[i].graphic[ACTION_DEFAULT];
713 int crumbled_like, diggable_like;
718 crumbled_like = graphic_info[graphic].crumbled_like;
719 diggable_like = graphic_info[graphic].diggable_like;
721 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
723 for (act = 0; act < NUM_ACTIONS; act++)
724 element_info[i].crumbled[act] =
725 element_info[crumbled_like].crumbled[act];
726 for (act = 0; act < NUM_ACTIONS; act++)
727 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
728 element_info[i].direction_crumbled[act][dir] =
729 element_info[crumbled_like].direction_crumbled[act][dir];
732 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
734 element_info[i].graphic[ACTION_DIGGING] =
735 element_info[diggable_like].graphic[ACTION_DIGGING];
736 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
737 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
738 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
742 /* set hardcoded definitions for some runtime elements without graphic */
743 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
745 /* set hardcoded definitions for some internal elements without graphic */
746 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
748 if (IS_EDITOR_CASCADE_INACTIVE(i))
749 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
750 else if (IS_EDITOR_CASCADE_ACTIVE(i))
751 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
754 /* now set all undefined/invalid graphics to -1 to set to default after it */
755 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
757 for (act = 0; act < NUM_ACTIONS; act++)
761 graphic = element_info[i].graphic[act];
762 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
763 element_info[i].graphic[act] = -1;
765 graphic = element_info[i].crumbled[act];
766 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
767 element_info[i].crumbled[act] = -1;
769 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
771 graphic = element_info[i].direction_graphic[act][dir];
772 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
773 element_info[i].direction_graphic[act][dir] = -1;
775 graphic = element_info[i].direction_crumbled[act][dir];
776 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
777 element_info[i].direction_crumbled[act][dir] = -1;
784 /* adjust graphics with 2nd tile for movement according to direction
785 (do this before correcting '-1' values to minimize calculations) */
786 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
788 for (act = 0; act < NUM_ACTIONS; act++)
790 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
792 int graphic = element_info[i].direction_graphic[act][dir];
793 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
795 if (act == ACTION_FALLING) /* special case */
796 graphic = element_info[i].graphic[act];
799 graphic_info[graphic].double_movement &&
800 graphic_info[graphic].swap_double_tiles != 0)
802 struct GraphicInfo *g = &graphic_info[graphic];
803 int src_x_front = g->src_x;
804 int src_y_front = g->src_y;
805 int src_x_back = g->src_x + g->offset2_x;
806 int src_y_back = g->src_y + g->offset2_y;
807 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
809 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
810 src_y_front < src_y_back);
811 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
812 boolean swap_movement_tiles_autodetected =
813 (!frames_are_ordered_diagonally &&
814 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
815 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
816 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
817 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
820 /* swap frontside and backside graphic tile coordinates, if needed */
821 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
823 /* get current (wrong) backside tile coordinates */
824 getFixedGraphicSourceExt(graphic, 0, &dummy,
825 &src_x_back, &src_y_back, TRUE);
827 /* set frontside tile coordinates to backside tile coordinates */
828 g->src_x = src_x_back;
829 g->src_y = src_y_back;
831 /* invert tile offset to point to new backside tile coordinates */
835 /* do not swap front and backside tiles again after correction */
836 g->swap_double_tiles = 0;
845 /* now set all '-1' values to element specific default values */
846 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
848 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
849 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
850 int default_direction_graphic[NUM_DIRECTIONS_FULL];
851 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
853 if (default_graphic == -1)
854 default_graphic = IMG_UNKNOWN;
856 if (default_crumbled == -1)
857 default_crumbled = default_graphic;
859 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
861 default_direction_graphic[dir] =
862 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
863 default_direction_crumbled[dir] =
864 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
866 if (default_direction_graphic[dir] == -1)
867 default_direction_graphic[dir] = default_graphic;
869 if (default_direction_crumbled[dir] == -1)
870 default_direction_crumbled[dir] = default_direction_graphic[dir];
873 for (act = 0; act < NUM_ACTIONS; act++)
875 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
876 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
877 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
878 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
879 act == ACTION_TURNING_FROM_RIGHT ||
880 act == ACTION_TURNING_FROM_UP ||
881 act == ACTION_TURNING_FROM_DOWN);
883 /* generic default action graphic (defined by "[default]" directive) */
884 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
885 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
886 int default_remove_graphic = IMG_EMPTY;
888 if (act_remove && default_action_graphic != -1)
889 default_remove_graphic = default_action_graphic;
891 /* look for special default action graphic (classic game specific) */
892 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
893 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
894 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
895 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
896 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
897 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
899 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
900 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
901 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
902 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
903 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
904 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
906 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
907 /* !!! make this better !!! */
908 if (i == EL_EMPTY_SPACE)
910 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
911 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
914 if (default_action_graphic == -1)
915 default_action_graphic = default_graphic;
917 if (default_action_crumbled == -1)
918 default_action_crumbled = default_action_graphic;
920 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
922 /* use action graphic as the default direction graphic, if undefined */
923 int default_action_direction_graphic = element_info[i].graphic[act];
924 int default_action_direction_crumbled = element_info[i].crumbled[act];
926 /* no graphic for current action -- use default direction graphic */
927 if (default_action_direction_graphic == -1)
928 default_action_direction_graphic =
929 (act_remove ? default_remove_graphic :
931 element_info[i].direction_graphic[ACTION_TURNING][dir] :
932 default_action_graphic != default_graphic ?
933 default_action_graphic :
934 default_direction_graphic[dir]);
936 if (element_info[i].direction_graphic[act][dir] == -1)
937 element_info[i].direction_graphic[act][dir] =
938 default_action_direction_graphic;
940 if (default_action_direction_crumbled == -1)
941 default_action_direction_crumbled =
942 element_info[i].direction_graphic[act][dir];
944 if (element_info[i].direction_crumbled[act][dir] == -1)
945 element_info[i].direction_crumbled[act][dir] =
946 default_action_direction_crumbled;
949 /* no graphic for this specific action -- use default action graphic */
950 if (element_info[i].graphic[act] == -1)
951 element_info[i].graphic[act] =
952 (act_remove ? default_remove_graphic :
953 act_turning ? element_info[i].graphic[ACTION_TURNING] :
954 default_action_graphic);
956 if (element_info[i].crumbled[act] == -1)
957 element_info[i].crumbled[act] = element_info[i].graphic[act];
964 void InitElementSpecialGraphicInfo()
966 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
967 int num_property_mappings = getImageListPropertyMappingSize();
970 /* always start with reliable default values */
971 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
972 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
973 element_info[i].special_graphic[j] =
974 element_info[i].graphic[ACTION_DEFAULT];
976 /* initialize special element/graphic mapping from static configuration */
977 for (i = 0; element_to_special_graphic[i].element > -1; i++)
979 int element = element_to_special_graphic[i].element;
980 int special = element_to_special_graphic[i].special;
981 int graphic = element_to_special_graphic[i].graphic;
982 int base_graphic = el2baseimg(element);
983 boolean base_redefined =
984 getImageListEntryFromImageID(base_graphic)->redefined;
985 boolean special_redefined =
986 getImageListEntryFromImageID(graphic)->redefined;
988 /* if the base graphic ("emerald", for example) has been redefined,
989 but not the special graphic ("emerald.EDITOR", for example), do not
990 use an existing (in this case considered obsolete) special graphic
991 anymore, but use the automatically created (down-scaled) graphic */
992 if (base_redefined && !special_redefined)
995 element_info[element].special_graphic[special] = graphic;
998 /* initialize special element/graphic mapping from dynamic configuration */
999 for (i = 0; i < num_property_mappings; i++)
1001 int element = property_mapping[i].base_index;
1002 int action = property_mapping[i].ext1_index;
1003 int direction = property_mapping[i].ext2_index;
1004 int special = property_mapping[i].ext3_index;
1005 int graphic = property_mapping[i].artwork_index;
1007 /* for action ".active", replace element with active element, if exists */
1008 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1010 element = ELEMENT_ACTIVE(element);
1014 if (element >= MAX_NUM_ELEMENTS)
1017 /* do not change special graphic if action or direction was specified */
1018 if (action != -1 || direction != -1)
1021 if (IS_SPECIAL_GFX_ARG(special))
1022 element_info[element].special_graphic[special] = graphic;
1025 /* now set all undefined/invalid graphics to default */
1026 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1027 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1028 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1029 element_info[i].special_graphic[j] =
1030 element_info[i].graphic[ACTION_DEFAULT];
1033 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1035 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1036 return get_parameter_value(value_raw, suffix, type);
1038 if (strEqual(value_raw, ARG_UNDEFINED))
1039 return ARG_UNDEFINED_VALUE;
1041 if (type == TYPE_ELEMENT)
1043 char *value = getHashEntry(element_token_hash, value_raw);
1047 Error(ERR_INFO_LINE, "-");
1048 Error(ERR_INFO, "warning: error found in config file:");
1049 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1050 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1051 Error(ERR_INFO, "custom graphic rejected for this element/action");
1052 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1053 Error(ERR_INFO_LINE, "-");
1056 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1058 else if (type == TYPE_GRAPHIC)
1060 char *value = getHashEntry(graphic_token_hash, value_raw);
1061 int fallback_graphic = IMG_CHAR_EXCLAM;
1065 Error(ERR_INFO_LINE, "-");
1066 Error(ERR_INFO, "warning: error found in config file:");
1067 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1068 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1069 Error(ERR_INFO, "custom graphic rejected for this element/action");
1070 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1071 Error(ERR_INFO_LINE, "-");
1074 return (value != NULL ? atoi(value) : fallback_graphic);
1080 static int get_scaled_graphic_width(int graphic)
1082 int original_width = getOriginalImageWidthFromImageID(graphic);
1083 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1085 return original_width * scale_up_factor;
1088 static int get_scaled_graphic_height(int graphic)
1090 int original_height = getOriginalImageHeightFromImageID(graphic);
1091 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1093 return original_height * scale_up_factor;
1096 static void set_graphic_parameters_ext(int graphic, int *parameter,
1097 Bitmap **src_bitmaps)
1099 struct GraphicInfo *g = &graphic_info[graphic];
1100 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1101 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1102 int anim_frames_per_line = 1;
1104 /* always start with reliable default values */
1105 g->src_image_width = 0;
1106 g->src_image_height = 0;
1109 g->width = TILEX; /* default for element graphics */
1110 g->height = TILEY; /* default for element graphics */
1111 g->offset_x = 0; /* one or both of these values ... */
1112 g->offset_y = 0; /* ... will be corrected later */
1113 g->offset2_x = 0; /* one or both of these values ... */
1114 g->offset2_y = 0; /* ... will be corrected later */
1115 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1116 g->crumbled_like = -1; /* do not use clone element */
1117 g->diggable_like = -1; /* do not use clone element */
1118 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1119 g->scale_up_factor = 1; /* default: no scaling up */
1120 g->tile_size = TILESIZE; /* default: standard tile size */
1121 g->clone_from = -1; /* do not use clone graphic */
1122 g->anim_delay_fixed = 0;
1123 g->anim_delay_random = 0;
1124 g->post_delay_fixed = 0;
1125 g->post_delay_random = 0;
1126 g->fade_mode = FADE_MODE_DEFAULT;
1130 g->align = ALIGN_CENTER; /* default for title screens */
1131 g->valign = VALIGN_MIDDLE; /* default for title screens */
1132 g->sort_priority = 0; /* default for title screens */
1134 g->style = STYLE_DEFAULT;
1136 g->bitmaps = src_bitmaps;
1137 g->bitmap = src_bitmap;
1139 /* optional zoom factor for scaling up the image to a larger size */
1140 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1141 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1142 if (g->scale_up_factor < 1)
1143 g->scale_up_factor = 1; /* no scaling */
1145 /* optional tile size for using non-standard image size */
1146 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1148 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1151 // CHECK: should tile sizes less than standard tile size be allowed?
1152 if (g->tile_size < TILESIZE)
1153 g->tile_size = TILESIZE; /* standard tile size */
1156 // when setting tile size, also set width and height accordingly
1157 g->width = g->tile_size;
1158 g->height = g->tile_size;
1161 if (g->use_image_size)
1163 /* set new default bitmap size (with scaling, but without small images) */
1164 g->width = get_scaled_graphic_width(graphic);
1165 g->height = get_scaled_graphic_height(graphic);
1168 /* optional width and height of each animation frame */
1169 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1170 g->width = parameter[GFX_ARG_WIDTH];
1171 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1172 g->height = parameter[GFX_ARG_HEIGHT];
1174 /* optional x and y tile position of animation frame sequence */
1175 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1176 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1177 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1178 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1180 /* optional x and y pixel position of animation frame sequence */
1181 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1182 g->src_x = parameter[GFX_ARG_X];
1183 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1184 g->src_y = parameter[GFX_ARG_Y];
1190 Error(ERR_INFO_LINE, "-");
1191 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1192 g->width, getTokenFromImageID(graphic), TILEX);
1193 Error(ERR_INFO_LINE, "-");
1195 g->width = TILEX; /* will be checked to be inside bitmap later */
1200 Error(ERR_INFO_LINE, "-");
1201 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1202 g->height, getTokenFromImageID(graphic), TILEY);
1203 Error(ERR_INFO_LINE, "-");
1205 g->height = TILEY; /* will be checked to be inside bitmap later */
1211 /* get final bitmap size (with scaling, but without small images) */
1212 int src_image_width = get_scaled_graphic_width(graphic);
1213 int src_image_height = get_scaled_graphic_height(graphic);
1215 if (src_image_width == 0 || src_image_height == 0)
1217 /* only happens when loaded outside artwork system (like "global.busy") */
1218 src_image_width = src_bitmap->width;
1219 src_image_height = src_bitmap->height;
1222 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1224 anim_frames_per_row = src_image_width / g->tile_size;
1225 anim_frames_per_col = src_image_height / g->tile_size;
1229 anim_frames_per_row = src_image_width / g->width;
1230 anim_frames_per_col = src_image_height / g->height;
1233 g->src_image_width = src_image_width;
1234 g->src_image_height = src_image_height;
1237 /* correct x or y offset dependent of vertical or horizontal frame order */
1238 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1240 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1241 parameter[GFX_ARG_OFFSET] : g->height);
1242 anim_frames_per_line = anim_frames_per_col;
1244 else /* frames are ordered horizontally */
1246 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1247 parameter[GFX_ARG_OFFSET] : g->width);
1248 anim_frames_per_line = anim_frames_per_row;
1251 /* optionally, the x and y offset of frames can be specified directly */
1252 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1253 g->offset_x = parameter[GFX_ARG_XOFFSET];
1254 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1255 g->offset_y = parameter[GFX_ARG_YOFFSET];
1257 /* optionally, moving animations may have separate start and end graphics */
1258 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1260 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1261 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1263 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1264 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1265 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1266 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1267 else /* frames are ordered horizontally */
1268 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1269 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1271 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1272 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1273 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1274 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1275 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1277 /* optionally, the second movement tile can be specified as start tile */
1278 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1279 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1281 /* automatically determine correct number of frames, if not defined */
1282 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1283 g->anim_frames = parameter[GFX_ARG_FRAMES];
1284 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1285 g->anim_frames = anim_frames_per_row;
1286 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1287 g->anim_frames = anim_frames_per_col;
1291 if (g->anim_frames == 0) /* frames must be at least 1 */
1294 g->anim_frames_per_line =
1295 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1296 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1298 g->anim_delay = parameter[GFX_ARG_DELAY];
1299 if (g->anim_delay == 0) /* delay must be at least 1 */
1302 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1304 /* automatically determine correct start frame, if not defined */
1305 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1306 g->anim_start_frame = 0;
1307 else if (g->anim_mode & ANIM_REVERSE)
1308 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1310 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1312 /* animation synchronized with global frame counter, not move position */
1313 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1315 /* optional element for cloning crumble graphics */
1316 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1317 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1319 /* optional element for cloning digging graphics */
1320 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1321 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1323 /* optional border size for "crumbling" diggable graphics */
1324 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1325 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1327 /* this is only used for player "boring" and "sleeping" actions */
1328 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1329 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1330 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1331 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1332 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1333 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1334 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1335 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1337 /* this is only used for toon animations */
1338 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1339 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1340 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1341 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1342 g->direction = parameter[GFX_ARG_DIRECTION];
1343 g->position = parameter[GFX_ARG_POSITION];
1345 /* this is only used for drawing font characters */
1346 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1347 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1349 /* this is only used for drawing envelope graphics */
1350 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1352 /* optional graphic for cloning all graphics settings */
1353 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1354 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1356 /* optional settings for drawing title screens and title messages */
1357 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1358 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1359 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1360 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1361 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1362 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1363 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1364 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1365 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1366 g->align = parameter[GFX_ARG_ALIGN];
1367 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1368 g->valign = parameter[GFX_ARG_VALIGN];
1369 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1370 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1372 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1373 g->class = parameter[GFX_ARG_CLASS];
1374 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1375 g->style = parameter[GFX_ARG_STYLE];
1377 /* this is only used for drawing menu buttons and text */
1378 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1379 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1380 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1381 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1384 static void set_graphic_parameters(int graphic)
1386 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1387 char **parameter_raw = image->parameter;
1388 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1389 int parameter[NUM_GFX_ARGS];
1392 /* if fallback to default artwork is done, also use the default parameters */
1393 if (image->fallback_to_default)
1394 parameter_raw = image->default_parameter;
1396 /* get integer values from string parameters */
1397 for (i = 0; i < NUM_GFX_ARGS; i++)
1398 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1399 image_config_suffix[i].token,
1400 image_config_suffix[i].type);
1402 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1404 UPDATE_BUSY_STATE();
1407 static void set_cloned_graphic_parameters(int graphic)
1409 int fallback_graphic = IMG_CHAR_EXCLAM;
1410 int max_num_images = getImageListSize();
1411 int clone_graphic = graphic_info[graphic].clone_from;
1412 int num_references_followed = 1;
1414 while (graphic_info[clone_graphic].clone_from != -1 &&
1415 num_references_followed < max_num_images)
1417 clone_graphic = graphic_info[clone_graphic].clone_from;
1419 num_references_followed++;
1422 if (num_references_followed >= max_num_images)
1424 Error(ERR_INFO_LINE, "-");
1425 Error(ERR_INFO, "warning: error found in config file:");
1426 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1427 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1428 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1429 Error(ERR_INFO, "custom graphic rejected for this element/action");
1431 if (graphic == fallback_graphic)
1432 Error(ERR_EXIT, "no fallback graphic available");
1434 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1435 Error(ERR_INFO_LINE, "-");
1437 graphic_info[graphic] = graphic_info[fallback_graphic];
1441 graphic_info[graphic] = graphic_info[clone_graphic];
1442 graphic_info[graphic].clone_from = clone_graphic;
1446 static void InitGraphicInfo()
1448 int fallback_graphic = IMG_CHAR_EXCLAM;
1449 int num_images = getImageListSize();
1452 /* use image size as default values for width and height for these images */
1453 static int full_size_graphics[] =
1456 IMG_GLOBAL_BORDER_MAIN,
1457 IMG_GLOBAL_BORDER_SCORES,
1458 IMG_GLOBAL_BORDER_EDITOR,
1459 IMG_GLOBAL_BORDER_PLAYING,
1462 IMG_BACKGROUND_ENVELOPE_1,
1463 IMG_BACKGROUND_ENVELOPE_2,
1464 IMG_BACKGROUND_ENVELOPE_3,
1465 IMG_BACKGROUND_ENVELOPE_4,
1466 IMG_BACKGROUND_REQUEST,
1469 IMG_BACKGROUND_TITLE_INITIAL,
1470 IMG_BACKGROUND_TITLE,
1471 IMG_BACKGROUND_MAIN,
1472 IMG_BACKGROUND_LEVELS,
1473 IMG_BACKGROUND_LEVELNR,
1474 IMG_BACKGROUND_SCORES,
1475 IMG_BACKGROUND_EDITOR,
1476 IMG_BACKGROUND_INFO,
1477 IMG_BACKGROUND_INFO_ELEMENTS,
1478 IMG_BACKGROUND_INFO_MUSIC,
1479 IMG_BACKGROUND_INFO_CREDITS,
1480 IMG_BACKGROUND_INFO_PROGRAM,
1481 IMG_BACKGROUND_INFO_VERSION,
1482 IMG_BACKGROUND_INFO_LEVELSET,
1483 IMG_BACKGROUND_SETUP,
1484 IMG_BACKGROUND_PLAYING,
1485 IMG_BACKGROUND_DOOR,
1486 IMG_BACKGROUND_TAPE,
1487 IMG_BACKGROUND_PANEL,
1488 IMG_BACKGROUND_PALETTE,
1489 IMG_BACKGROUND_TOOLBOX,
1491 IMG_TITLESCREEN_INITIAL_1,
1492 IMG_TITLESCREEN_INITIAL_2,
1493 IMG_TITLESCREEN_INITIAL_3,
1494 IMG_TITLESCREEN_INITIAL_4,
1495 IMG_TITLESCREEN_INITIAL_5,
1502 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1503 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1504 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1505 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1506 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1507 IMG_BACKGROUND_TITLEMESSAGE_1,
1508 IMG_BACKGROUND_TITLEMESSAGE_2,
1509 IMG_BACKGROUND_TITLEMESSAGE_3,
1510 IMG_BACKGROUND_TITLEMESSAGE_4,
1511 IMG_BACKGROUND_TITLEMESSAGE_5,
1516 checked_free(graphic_info);
1518 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1520 /* initialize "use_image_size" flag with default value */
1521 for (i = 0; i < num_images; i++)
1522 graphic_info[i].use_image_size = FALSE;
1524 /* initialize "use_image_size" flag from static configuration above */
1525 for (i = 0; full_size_graphics[i] != -1; i++)
1526 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1528 /* first set all graphic paramaters ... */
1529 for (i = 0; i < num_images; i++)
1530 set_graphic_parameters(i);
1532 /* ... then copy these parameters for cloned graphics */
1533 for (i = 0; i < num_images; i++)
1534 if (graphic_info[i].clone_from != -1)
1535 set_cloned_graphic_parameters(i);
1537 for (i = 0; i < num_images; i++)
1542 int first_frame, last_frame;
1543 int src_bitmap_width, src_bitmap_height;
1545 /* now check if no animation frames are outside of the loaded image */
1547 if (graphic_info[i].bitmap == NULL)
1548 continue; /* skip check for optional images that are undefined */
1550 /* get image size (this can differ from the standard element tile size!) */
1551 width = graphic_info[i].width;
1552 height = graphic_info[i].height;
1554 /* get final bitmap size (with scaling, but without small images) */
1555 src_bitmap_width = graphic_info[i].src_image_width;
1556 src_bitmap_height = graphic_info[i].src_image_height;
1558 /* check if first animation frame is inside specified bitmap */
1561 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1563 /* this avoids calculating wrong start position for out-of-bounds frame */
1564 src_x = graphic_info[i].src_x;
1565 src_y = graphic_info[i].src_y;
1567 if (src_x < 0 || src_y < 0 ||
1568 src_x + width > src_bitmap_width ||
1569 src_y + height > src_bitmap_height)
1571 Error(ERR_INFO_LINE, "-");
1572 Error(ERR_INFO, "warning: error found in config file:");
1573 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1574 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1575 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1577 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1578 src_x, src_y, src_bitmap_width, src_bitmap_height);
1579 Error(ERR_INFO, "custom graphic rejected for this element/action");
1581 if (i == fallback_graphic)
1582 Error(ERR_EXIT, "no fallback graphic available");
1584 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1585 Error(ERR_INFO_LINE, "-");
1587 graphic_info[i] = graphic_info[fallback_graphic];
1590 /* check if last animation frame is inside specified bitmap */
1592 last_frame = graphic_info[i].anim_frames - 1;
1593 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1595 if (src_x < 0 || src_y < 0 ||
1596 src_x + width > src_bitmap_width ||
1597 src_y + height > src_bitmap_height)
1599 Error(ERR_INFO_LINE, "-");
1600 Error(ERR_INFO, "warning: error found in config file:");
1601 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1602 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1603 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1605 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1606 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1607 Error(ERR_INFO, "::: %d, %d", width, height);
1608 Error(ERR_INFO, "custom graphic rejected for this element/action");
1610 if (i == fallback_graphic)
1611 Error(ERR_EXIT, "no fallback graphic available");
1613 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1614 Error(ERR_INFO_LINE, "-");
1616 graphic_info[i] = graphic_info[fallback_graphic];
1621 static void InitGraphicCompatibilityInfo()
1623 struct FileInfo *fi_global_door =
1624 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1625 int num_images = getImageListSize();
1628 /* the following compatibility handling is needed for the following case:
1629 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1630 graphics mainly used for door and panel graphics, like editor, tape and
1631 in-game buttons with hard-coded bitmap positions and button sizes; as
1632 these graphics now have individual definitions, redefining "global.door"
1633 to change all these graphics at once like before does not work anymore
1634 (because all those individual definitions still have their default values);
1635 to solve this, remap all those individual definitions that are not
1636 redefined to the new bitmap of "global.door" if it was redefined */
1638 /* special compatibility handling if image "global.door" was redefined */
1639 if (fi_global_door->redefined)
1641 for (i = 0; i < num_images; i++)
1643 struct FileInfo *fi = getImageListEntryFromImageID(i);
1645 /* process only those images that still use the default settings */
1648 /* process all images which default to same image as "global.door" */
1649 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1651 // printf("::: special treatment needed for token '%s'\n", fi->token);
1653 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1659 InitGraphicCompatibilityInfo_Doors();
1662 static void InitElementSoundInfo()
1664 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1665 int num_property_mappings = getSoundListPropertyMappingSize();
1668 /* set values to -1 to identify later as "uninitialized" values */
1669 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1670 for (act = 0; act < NUM_ACTIONS; act++)
1671 element_info[i].sound[act] = -1;
1673 /* initialize element/sound mapping from static configuration */
1674 for (i = 0; element_to_sound[i].element > -1; i++)
1676 int element = element_to_sound[i].element;
1677 int action = element_to_sound[i].action;
1678 int sound = element_to_sound[i].sound;
1679 boolean is_class = element_to_sound[i].is_class;
1682 action = ACTION_DEFAULT;
1685 element_info[element].sound[action] = sound;
1687 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1688 if (strEqual(element_info[j].class_name,
1689 element_info[element].class_name))
1690 element_info[j].sound[action] = sound;
1693 /* initialize element class/sound mapping from dynamic configuration */
1694 for (i = 0; i < num_property_mappings; i++)
1696 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1697 int action = property_mapping[i].ext1_index;
1698 int sound = property_mapping[i].artwork_index;
1700 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1704 action = ACTION_DEFAULT;
1706 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1707 if (strEqual(element_info[j].class_name,
1708 element_info[element_class].class_name))
1709 element_info[j].sound[action] = sound;
1712 /* initialize element/sound mapping from dynamic configuration */
1713 for (i = 0; i < num_property_mappings; i++)
1715 int element = property_mapping[i].base_index;
1716 int action = property_mapping[i].ext1_index;
1717 int sound = property_mapping[i].artwork_index;
1719 if (element >= MAX_NUM_ELEMENTS)
1723 action = ACTION_DEFAULT;
1725 element_info[element].sound[action] = sound;
1728 /* now set all '-1' values to element specific default values */
1729 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1731 for (act = 0; act < NUM_ACTIONS; act++)
1733 /* generic default action sound (defined by "[default]" directive) */
1734 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1736 /* look for special default action sound (classic game specific) */
1737 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1738 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1739 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1740 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1741 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1742 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1744 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1745 /* !!! make this better !!! */
1746 if (i == EL_EMPTY_SPACE)
1747 default_action_sound = element_info[EL_DEFAULT].sound[act];
1749 /* no sound for this specific action -- use default action sound */
1750 if (element_info[i].sound[act] == -1)
1751 element_info[i].sound[act] = default_action_sound;
1755 /* copy sound settings to some elements that are only stored in level file
1756 in native R'n'D levels, but are used by game engine in native EM levels */
1757 for (i = 0; copy_properties[i][0] != -1; i++)
1758 for (j = 1; j <= 4; j++)
1759 for (act = 0; act < NUM_ACTIONS; act++)
1760 element_info[copy_properties[i][j]].sound[act] =
1761 element_info[copy_properties[i][0]].sound[act];
1764 static void InitGameModeSoundInfo()
1768 /* set values to -1 to identify later as "uninitialized" values */
1769 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1772 /* initialize gamemode/sound mapping from static configuration */
1773 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1775 int gamemode = gamemode_to_sound[i].gamemode;
1776 int sound = gamemode_to_sound[i].sound;
1779 gamemode = GAME_MODE_DEFAULT;
1781 menu.sound[gamemode] = sound;
1784 /* now set all '-1' values to levelset specific default values */
1785 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1786 if (menu.sound[i] == -1)
1787 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1790 static void set_sound_parameters(int sound, char **parameter_raw)
1792 int parameter[NUM_SND_ARGS];
1795 /* get integer values from string parameters */
1796 for (i = 0; i < NUM_SND_ARGS; i++)
1798 get_parameter_value(parameter_raw[i],
1799 sound_config_suffix[i].token,
1800 sound_config_suffix[i].type);
1802 /* explicit loop mode setting in configuration overrides default value */
1803 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1804 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1806 /* sound volume to change the original volume when loading the sound file */
1807 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1809 /* sound priority to give certain sounds a higher or lower priority */
1810 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1813 static void InitSoundInfo()
1815 int *sound_effect_properties;
1816 int num_sounds = getSoundListSize();
1819 checked_free(sound_info);
1821 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1822 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1824 /* initialize sound effect for all elements to "no sound" */
1825 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1826 for (j = 0; j < NUM_ACTIONS; j++)
1827 element_info[i].sound[j] = SND_UNDEFINED;
1829 for (i = 0; i < num_sounds; i++)
1831 struct FileInfo *sound = getSoundListEntry(i);
1832 int len_effect_text = strlen(sound->token);
1834 sound_effect_properties[i] = ACTION_OTHER;
1835 sound_info[i].loop = FALSE; /* default: play sound only once */
1837 /* determine all loop sounds and identify certain sound classes */
1839 for (j = 0; element_action_info[j].suffix; j++)
1841 int len_action_text = strlen(element_action_info[j].suffix);
1843 if (len_action_text < len_effect_text &&
1844 strEqual(&sound->token[len_effect_text - len_action_text],
1845 element_action_info[j].suffix))
1847 sound_effect_properties[i] = element_action_info[j].value;
1848 sound_info[i].loop = element_action_info[j].is_loop_sound;
1854 /* associate elements and some selected sound actions */
1856 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1858 if (element_info[j].class_name)
1860 int len_class_text = strlen(element_info[j].class_name);
1862 if (len_class_text + 1 < len_effect_text &&
1863 strncmp(sound->token,
1864 element_info[j].class_name, len_class_text) == 0 &&
1865 sound->token[len_class_text] == '.')
1867 int sound_action_value = sound_effect_properties[i];
1869 element_info[j].sound[sound_action_value] = i;
1874 set_sound_parameters(i, sound->parameter);
1877 free(sound_effect_properties);
1880 static void InitGameModeMusicInfo()
1882 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1883 int num_property_mappings = getMusicListPropertyMappingSize();
1884 int default_levelset_music = -1;
1887 /* set values to -1 to identify later as "uninitialized" values */
1888 for (i = 0; i < MAX_LEVELS; i++)
1889 levelset.music[i] = -1;
1890 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1893 /* initialize gamemode/music mapping from static configuration */
1894 for (i = 0; gamemode_to_music[i].music > -1; i++)
1896 int gamemode = gamemode_to_music[i].gamemode;
1897 int music = gamemode_to_music[i].music;
1900 gamemode = GAME_MODE_DEFAULT;
1902 menu.music[gamemode] = music;
1905 /* initialize gamemode/music mapping from dynamic configuration */
1906 for (i = 0; i < num_property_mappings; i++)
1908 int prefix = property_mapping[i].base_index;
1909 int gamemode = property_mapping[i].ext1_index;
1910 int level = property_mapping[i].ext2_index;
1911 int music = property_mapping[i].artwork_index;
1913 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1917 gamemode = GAME_MODE_DEFAULT;
1919 /* level specific music only allowed for in-game music */
1920 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1921 gamemode = GAME_MODE_PLAYING;
1926 default_levelset_music = music;
1929 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1930 levelset.music[level] = music;
1931 if (gamemode != GAME_MODE_PLAYING)
1932 menu.music[gamemode] = music;
1935 /* now set all '-1' values to menu specific default values */
1936 /* (undefined values of "levelset.music[]" might stay at "-1" to
1937 allow dynamic selection of music files from music directory!) */
1938 for (i = 0; i < MAX_LEVELS; i++)
1939 if (levelset.music[i] == -1)
1940 levelset.music[i] = default_levelset_music;
1941 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1942 if (menu.music[i] == -1)
1943 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1946 static void set_music_parameters(int music, char **parameter_raw)
1948 int parameter[NUM_MUS_ARGS];
1951 /* get integer values from string parameters */
1952 for (i = 0; i < NUM_MUS_ARGS; i++)
1954 get_parameter_value(parameter_raw[i],
1955 music_config_suffix[i].token,
1956 music_config_suffix[i].type);
1958 /* explicit loop mode setting in configuration overrides default value */
1959 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1960 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1963 static void InitMusicInfo()
1965 int num_music = getMusicListSize();
1968 checked_free(music_info);
1970 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1972 for (i = 0; i < num_music; i++)
1974 struct FileInfo *music = getMusicListEntry(i);
1975 int len_music_text = strlen(music->token);
1977 music_info[i].loop = TRUE; /* default: play music in loop mode */
1979 /* determine all loop music */
1981 for (j = 0; music_prefix_info[j].prefix; j++)
1983 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1985 if (len_prefix_text < len_music_text &&
1986 strncmp(music->token,
1987 music_prefix_info[j].prefix, len_prefix_text) == 0)
1989 music_info[i].loop = music_prefix_info[j].is_loop_music;
1995 set_music_parameters(i, music->parameter);
1999 static void ReinitializeGraphics()
2001 print_timestamp_init("ReinitializeGraphics");
2003 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2005 InitGraphicInfo(); /* graphic properties mapping */
2006 print_timestamp_time("InitGraphicInfo");
2007 InitElementGraphicInfo(); /* element game graphic mapping */
2008 print_timestamp_time("InitElementGraphicInfo");
2009 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2010 print_timestamp_time("InitElementSpecialGraphicInfo");
2012 InitElementSmallImages(); /* scale elements to all needed sizes */
2013 print_timestamp_time("InitElementSmallImages");
2014 InitScaledImages(); /* scale all other images, if needed */
2015 print_timestamp_time("InitScaledImages");
2016 InitBitmapPointers(); /* set standard size bitmap pointers */
2017 print_timestamp_time("InitBitmapPointers");
2018 InitFontGraphicInfo(); /* initialize text drawing functions */
2019 print_timestamp_time("InitFontGraphicInfo");
2020 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2021 print_timestamp_time("InitGlobalAnimGraphicInfo");
2022 InitGlobalAnimImages(); /* initialize global animation images */
2023 print_timestamp_time("InitGlobalAnimImages");
2025 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2026 print_timestamp_time("InitGraphicInfo_EM");
2028 InitGraphicCompatibilityInfo();
2029 print_timestamp_time("InitGraphicCompatibilityInfo");
2031 SetMainBackgroundImage(IMG_BACKGROUND);
2032 print_timestamp_time("SetMainBackgroundImage");
2033 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2034 print_timestamp_time("SetDoorBackgroundImage");
2037 print_timestamp_time("InitGadgets");
2039 print_timestamp_time("InitToons");
2041 print_timestamp_time("InitDoors");
2043 print_timestamp_done("ReinitializeGraphics");
2046 static void ReinitializeSounds()
2048 InitSoundInfo(); /* sound properties mapping */
2049 InitElementSoundInfo(); /* element game sound mapping */
2050 InitGameModeSoundInfo(); /* game mode sound mapping */
2052 InitPlayLevelSound(); /* internal game sound settings */
2055 static void ReinitializeMusic()
2057 InitMusicInfo(); /* music properties mapping */
2058 InitGameModeMusicInfo(); /* game mode music mapping */
2061 static int get_special_property_bit(int element, int property_bit_nr)
2063 struct PropertyBitInfo
2069 static struct PropertyBitInfo pb_can_move_into_acid[] =
2071 /* the player may be able fall into acid when gravity is activated */
2076 { EL_SP_MURPHY, 0 },
2077 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2079 /* all elements that can move may be able to also move into acid */
2082 { EL_BUG_RIGHT, 1 },
2085 { EL_SPACESHIP, 2 },
2086 { EL_SPACESHIP_LEFT, 2 },
2087 { EL_SPACESHIP_RIGHT, 2 },
2088 { EL_SPACESHIP_UP, 2 },
2089 { EL_SPACESHIP_DOWN, 2 },
2090 { EL_BD_BUTTERFLY, 3 },
2091 { EL_BD_BUTTERFLY_LEFT, 3 },
2092 { EL_BD_BUTTERFLY_RIGHT, 3 },
2093 { EL_BD_BUTTERFLY_UP, 3 },
2094 { EL_BD_BUTTERFLY_DOWN, 3 },
2095 { EL_BD_FIREFLY, 4 },
2096 { EL_BD_FIREFLY_LEFT, 4 },
2097 { EL_BD_FIREFLY_RIGHT, 4 },
2098 { EL_BD_FIREFLY_UP, 4 },
2099 { EL_BD_FIREFLY_DOWN, 4 },
2101 { EL_YAMYAM_LEFT, 5 },
2102 { EL_YAMYAM_RIGHT, 5 },
2103 { EL_YAMYAM_UP, 5 },
2104 { EL_YAMYAM_DOWN, 5 },
2105 { EL_DARK_YAMYAM, 6 },
2108 { EL_PACMAN_LEFT, 8 },
2109 { EL_PACMAN_RIGHT, 8 },
2110 { EL_PACMAN_UP, 8 },
2111 { EL_PACMAN_DOWN, 8 },
2113 { EL_MOLE_LEFT, 9 },
2114 { EL_MOLE_RIGHT, 9 },
2116 { EL_MOLE_DOWN, 9 },
2120 { EL_SATELLITE, 13 },
2121 { EL_SP_SNIKSNAK, 14 },
2122 { EL_SP_ELECTRON, 15 },
2125 { EL_EMC_ANDROID, 18 },
2130 static struct PropertyBitInfo pb_dont_collide_with[] =
2132 { EL_SP_SNIKSNAK, 0 },
2133 { EL_SP_ELECTRON, 1 },
2141 struct PropertyBitInfo *pb_info;
2144 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2145 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2150 struct PropertyBitInfo *pb_info = NULL;
2153 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2154 if (pb_definition[i].bit_nr == property_bit_nr)
2155 pb_info = pb_definition[i].pb_info;
2157 if (pb_info == NULL)
2160 for (i = 0; pb_info[i].element != -1; i++)
2161 if (pb_info[i].element == element)
2162 return pb_info[i].bit_nr;
2167 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2168 boolean property_value)
2170 int bit_nr = get_special_property_bit(element, property_bit_nr);
2175 *bitfield |= (1 << bit_nr);
2177 *bitfield &= ~(1 << bit_nr);
2181 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2183 int bit_nr = get_special_property_bit(element, property_bit_nr);
2186 return ((*bitfield & (1 << bit_nr)) != 0);
2191 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2193 static int group_nr;
2194 static struct ElementGroupInfo *group;
2195 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2198 if (actual_group == NULL) /* not yet initialized */
2201 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2203 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2204 group_element - EL_GROUP_START + 1);
2206 /* replace element which caused too deep recursion by question mark */
2207 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2212 if (recursion_depth == 0) /* initialization */
2214 group = actual_group;
2215 group_nr = GROUP_NR(group_element);
2217 group->num_elements_resolved = 0;
2218 group->choice_pos = 0;
2220 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2221 element_info[i].in_group[group_nr] = FALSE;
2224 for (i = 0; i < actual_group->num_elements; i++)
2226 int element = actual_group->element[i];
2228 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2231 if (IS_GROUP_ELEMENT(element))
2232 ResolveGroupElementExt(element, recursion_depth + 1);
2235 group->element_resolved[group->num_elements_resolved++] = element;
2236 element_info[element].in_group[group_nr] = TRUE;
2241 void ResolveGroupElement(int group_element)
2243 ResolveGroupElementExt(group_element, 0);
2246 void InitElementPropertiesStatic()
2248 static boolean clipboard_elements_initialized = FALSE;
2250 static int ep_diggable[] =
2255 EL_SP_BUGGY_BASE_ACTIVATING,
2258 EL_INVISIBLE_SAND_ACTIVE,
2261 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2262 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2267 EL_SP_BUGGY_BASE_ACTIVE,
2274 static int ep_collectible_only[] =
2296 EL_DYNABOMB_INCREASE_NUMBER,
2297 EL_DYNABOMB_INCREASE_SIZE,
2298 EL_DYNABOMB_INCREASE_POWER,
2316 /* !!! handle separately !!! */
2317 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2323 static int ep_dont_run_into[] =
2325 /* same elements as in 'ep_dont_touch' */
2331 /* same elements as in 'ep_dont_collide_with' */
2343 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2348 EL_SP_BUGGY_BASE_ACTIVE,
2355 static int ep_dont_collide_with[] =
2357 /* same elements as in 'ep_dont_touch' */
2374 static int ep_dont_touch[] =
2384 static int ep_indestructible[] =
2388 EL_ACID_POOL_TOPLEFT,
2389 EL_ACID_POOL_TOPRIGHT,
2390 EL_ACID_POOL_BOTTOMLEFT,
2391 EL_ACID_POOL_BOTTOM,
2392 EL_ACID_POOL_BOTTOMRIGHT,
2393 EL_SP_HARDWARE_GRAY,
2394 EL_SP_HARDWARE_GREEN,
2395 EL_SP_HARDWARE_BLUE,
2397 EL_SP_HARDWARE_YELLOW,
2398 EL_SP_HARDWARE_BASE_1,
2399 EL_SP_HARDWARE_BASE_2,
2400 EL_SP_HARDWARE_BASE_3,
2401 EL_SP_HARDWARE_BASE_4,
2402 EL_SP_HARDWARE_BASE_5,
2403 EL_SP_HARDWARE_BASE_6,
2404 EL_INVISIBLE_STEELWALL,
2405 EL_INVISIBLE_STEELWALL_ACTIVE,
2406 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2407 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2408 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2409 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2410 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2411 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2412 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2413 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2414 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2415 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2416 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2417 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2419 EL_LIGHT_SWITCH_ACTIVE,
2420 EL_SIGN_EXCLAMATION,
2421 EL_SIGN_RADIOACTIVITY,
2428 EL_SIGN_ENTRY_FORBIDDEN,
2429 EL_SIGN_EMERGENCY_EXIT,
2437 EL_STEEL_EXIT_CLOSED,
2439 EL_STEEL_EXIT_OPENING,
2440 EL_STEEL_EXIT_CLOSING,
2441 EL_EM_STEEL_EXIT_CLOSED,
2442 EL_EM_STEEL_EXIT_OPEN,
2443 EL_EM_STEEL_EXIT_OPENING,
2444 EL_EM_STEEL_EXIT_CLOSING,
2445 EL_DC_STEELWALL_1_LEFT,
2446 EL_DC_STEELWALL_1_RIGHT,
2447 EL_DC_STEELWALL_1_TOP,
2448 EL_DC_STEELWALL_1_BOTTOM,
2449 EL_DC_STEELWALL_1_HORIZONTAL,
2450 EL_DC_STEELWALL_1_VERTICAL,
2451 EL_DC_STEELWALL_1_TOPLEFT,
2452 EL_DC_STEELWALL_1_TOPRIGHT,
2453 EL_DC_STEELWALL_1_BOTTOMLEFT,
2454 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2455 EL_DC_STEELWALL_1_TOPLEFT_2,
2456 EL_DC_STEELWALL_1_TOPRIGHT_2,
2457 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2458 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2459 EL_DC_STEELWALL_2_LEFT,
2460 EL_DC_STEELWALL_2_RIGHT,
2461 EL_DC_STEELWALL_2_TOP,
2462 EL_DC_STEELWALL_2_BOTTOM,
2463 EL_DC_STEELWALL_2_HORIZONTAL,
2464 EL_DC_STEELWALL_2_VERTICAL,
2465 EL_DC_STEELWALL_2_MIDDLE,
2466 EL_DC_STEELWALL_2_SINGLE,
2467 EL_STEELWALL_SLIPPERY,
2481 EL_GATE_1_GRAY_ACTIVE,
2482 EL_GATE_2_GRAY_ACTIVE,
2483 EL_GATE_3_GRAY_ACTIVE,
2484 EL_GATE_4_GRAY_ACTIVE,
2493 EL_EM_GATE_1_GRAY_ACTIVE,
2494 EL_EM_GATE_2_GRAY_ACTIVE,
2495 EL_EM_GATE_3_GRAY_ACTIVE,
2496 EL_EM_GATE_4_GRAY_ACTIVE,
2505 EL_EMC_GATE_5_GRAY_ACTIVE,
2506 EL_EMC_GATE_6_GRAY_ACTIVE,
2507 EL_EMC_GATE_7_GRAY_ACTIVE,
2508 EL_EMC_GATE_8_GRAY_ACTIVE,
2510 EL_DC_GATE_WHITE_GRAY,
2511 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2512 EL_DC_GATE_FAKE_GRAY,
2514 EL_SWITCHGATE_OPENING,
2515 EL_SWITCHGATE_CLOSED,
2516 EL_SWITCHGATE_CLOSING,
2517 EL_DC_SWITCHGATE_SWITCH_UP,
2518 EL_DC_SWITCHGATE_SWITCH_DOWN,
2520 EL_TIMEGATE_OPENING,
2522 EL_TIMEGATE_CLOSING,
2523 EL_DC_TIMEGATE_SWITCH,
2524 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2528 EL_TUBE_VERTICAL_LEFT,
2529 EL_TUBE_VERTICAL_RIGHT,
2530 EL_TUBE_HORIZONTAL_UP,
2531 EL_TUBE_HORIZONTAL_DOWN,
2536 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2537 EL_EXPANDABLE_STEELWALL_VERTICAL,
2538 EL_EXPANDABLE_STEELWALL_ANY,
2543 static int ep_slippery[] =
2557 EL_ROBOT_WHEEL_ACTIVE,
2563 EL_ACID_POOL_TOPLEFT,
2564 EL_ACID_POOL_TOPRIGHT,
2574 EL_STEELWALL_SLIPPERY,
2577 EL_EMC_WALL_SLIPPERY_1,
2578 EL_EMC_WALL_SLIPPERY_2,
2579 EL_EMC_WALL_SLIPPERY_3,
2580 EL_EMC_WALL_SLIPPERY_4,
2582 EL_EMC_MAGIC_BALL_ACTIVE,
2587 static int ep_can_change[] =
2592 static int ep_can_move[] =
2594 /* same elements as in 'pb_can_move_into_acid' */
2617 static int ep_can_fall[] =
2631 EL_QUICKSAND_FAST_FULL,
2633 EL_BD_MAGIC_WALL_FULL,
2634 EL_DC_MAGIC_WALL_FULL,
2648 static int ep_can_smash_player[] =
2674 static int ep_can_smash_enemies[] =
2683 static int ep_can_smash_everything[] =
2692 static int ep_explodes_by_fire[] =
2694 /* same elements as in 'ep_explodes_impact' */
2699 /* same elements as in 'ep_explodes_smashed' */
2709 EL_EM_DYNAMITE_ACTIVE,
2710 EL_DYNABOMB_PLAYER_1_ACTIVE,
2711 EL_DYNABOMB_PLAYER_2_ACTIVE,
2712 EL_DYNABOMB_PLAYER_3_ACTIVE,
2713 EL_DYNABOMB_PLAYER_4_ACTIVE,
2714 EL_DYNABOMB_INCREASE_NUMBER,
2715 EL_DYNABOMB_INCREASE_SIZE,
2716 EL_DYNABOMB_INCREASE_POWER,
2717 EL_SP_DISK_RED_ACTIVE,
2731 static int ep_explodes_smashed[] =
2733 /* same elements as in 'ep_explodes_impact' */
2747 static int ep_explodes_impact[] =
2756 static int ep_walkable_over[] =
2760 EL_SOKOBAN_FIELD_EMPTY,
2767 EL_EM_STEEL_EXIT_OPEN,
2768 EL_EM_STEEL_EXIT_OPENING,
2777 EL_GATE_1_GRAY_ACTIVE,
2778 EL_GATE_2_GRAY_ACTIVE,
2779 EL_GATE_3_GRAY_ACTIVE,
2780 EL_GATE_4_GRAY_ACTIVE,
2788 static int ep_walkable_inside[] =
2793 EL_TUBE_VERTICAL_LEFT,
2794 EL_TUBE_VERTICAL_RIGHT,
2795 EL_TUBE_HORIZONTAL_UP,
2796 EL_TUBE_HORIZONTAL_DOWN,
2805 static int ep_walkable_under[] =
2810 static int ep_passable_over[] =
2820 EL_EM_GATE_1_GRAY_ACTIVE,
2821 EL_EM_GATE_2_GRAY_ACTIVE,
2822 EL_EM_GATE_3_GRAY_ACTIVE,
2823 EL_EM_GATE_4_GRAY_ACTIVE,
2832 EL_EMC_GATE_5_GRAY_ACTIVE,
2833 EL_EMC_GATE_6_GRAY_ACTIVE,
2834 EL_EMC_GATE_7_GRAY_ACTIVE,
2835 EL_EMC_GATE_8_GRAY_ACTIVE,
2837 EL_DC_GATE_WHITE_GRAY,
2838 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2845 static int ep_passable_inside[] =
2851 EL_SP_PORT_HORIZONTAL,
2852 EL_SP_PORT_VERTICAL,
2854 EL_SP_GRAVITY_PORT_LEFT,
2855 EL_SP_GRAVITY_PORT_RIGHT,
2856 EL_SP_GRAVITY_PORT_UP,
2857 EL_SP_GRAVITY_PORT_DOWN,
2858 EL_SP_GRAVITY_ON_PORT_LEFT,
2859 EL_SP_GRAVITY_ON_PORT_RIGHT,
2860 EL_SP_GRAVITY_ON_PORT_UP,
2861 EL_SP_GRAVITY_ON_PORT_DOWN,
2862 EL_SP_GRAVITY_OFF_PORT_LEFT,
2863 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2864 EL_SP_GRAVITY_OFF_PORT_UP,
2865 EL_SP_GRAVITY_OFF_PORT_DOWN,
2870 static int ep_passable_under[] =
2875 static int ep_droppable[] =
2880 static int ep_explodes_1x1_old[] =
2885 static int ep_pushable[] =
2897 EL_SOKOBAN_FIELD_FULL,
2906 static int ep_explodes_cross_old[] =
2911 static int ep_protected[] =
2913 /* same elements as in 'ep_walkable_inside' */
2917 EL_TUBE_VERTICAL_LEFT,
2918 EL_TUBE_VERTICAL_RIGHT,
2919 EL_TUBE_HORIZONTAL_UP,
2920 EL_TUBE_HORIZONTAL_DOWN,
2926 /* same elements as in 'ep_passable_over' */
2935 EL_EM_GATE_1_GRAY_ACTIVE,
2936 EL_EM_GATE_2_GRAY_ACTIVE,
2937 EL_EM_GATE_3_GRAY_ACTIVE,
2938 EL_EM_GATE_4_GRAY_ACTIVE,
2947 EL_EMC_GATE_5_GRAY_ACTIVE,
2948 EL_EMC_GATE_6_GRAY_ACTIVE,
2949 EL_EMC_GATE_7_GRAY_ACTIVE,
2950 EL_EMC_GATE_8_GRAY_ACTIVE,
2952 EL_DC_GATE_WHITE_GRAY,
2953 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2957 /* same elements as in 'ep_passable_inside' */
2962 EL_SP_PORT_HORIZONTAL,
2963 EL_SP_PORT_VERTICAL,
2965 EL_SP_GRAVITY_PORT_LEFT,
2966 EL_SP_GRAVITY_PORT_RIGHT,
2967 EL_SP_GRAVITY_PORT_UP,
2968 EL_SP_GRAVITY_PORT_DOWN,
2969 EL_SP_GRAVITY_ON_PORT_LEFT,
2970 EL_SP_GRAVITY_ON_PORT_RIGHT,
2971 EL_SP_GRAVITY_ON_PORT_UP,
2972 EL_SP_GRAVITY_ON_PORT_DOWN,
2973 EL_SP_GRAVITY_OFF_PORT_LEFT,
2974 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2975 EL_SP_GRAVITY_OFF_PORT_UP,
2976 EL_SP_GRAVITY_OFF_PORT_DOWN,
2981 static int ep_throwable[] =
2986 static int ep_can_explode[] =
2988 /* same elements as in 'ep_explodes_impact' */
2993 /* same elements as in 'ep_explodes_smashed' */
2999 /* elements that can explode by explosion or by dragonfire */
3003 EL_EM_DYNAMITE_ACTIVE,
3004 EL_DYNABOMB_PLAYER_1_ACTIVE,
3005 EL_DYNABOMB_PLAYER_2_ACTIVE,
3006 EL_DYNABOMB_PLAYER_3_ACTIVE,
3007 EL_DYNABOMB_PLAYER_4_ACTIVE,
3008 EL_DYNABOMB_INCREASE_NUMBER,
3009 EL_DYNABOMB_INCREASE_SIZE,
3010 EL_DYNABOMB_INCREASE_POWER,
3011 EL_SP_DISK_RED_ACTIVE,
3019 /* elements that can explode only by explosion */
3025 static int ep_gravity_reachable[] =
3031 EL_INVISIBLE_SAND_ACTIVE,
3036 EL_SP_PORT_HORIZONTAL,
3037 EL_SP_PORT_VERTICAL,
3039 EL_SP_GRAVITY_PORT_LEFT,
3040 EL_SP_GRAVITY_PORT_RIGHT,
3041 EL_SP_GRAVITY_PORT_UP,
3042 EL_SP_GRAVITY_PORT_DOWN,
3043 EL_SP_GRAVITY_ON_PORT_LEFT,
3044 EL_SP_GRAVITY_ON_PORT_RIGHT,
3045 EL_SP_GRAVITY_ON_PORT_UP,
3046 EL_SP_GRAVITY_ON_PORT_DOWN,
3047 EL_SP_GRAVITY_OFF_PORT_LEFT,
3048 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3049 EL_SP_GRAVITY_OFF_PORT_UP,
3050 EL_SP_GRAVITY_OFF_PORT_DOWN,
3056 static int ep_player[] =
3063 EL_SOKOBAN_FIELD_PLAYER,
3069 static int ep_can_pass_magic_wall[] =
3083 static int ep_can_pass_dc_magic_wall[] =
3099 static int ep_switchable[] =
3103 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3104 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3105 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3106 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3107 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3108 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3109 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3110 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3111 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3112 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3113 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3114 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3115 EL_SWITCHGATE_SWITCH_UP,
3116 EL_SWITCHGATE_SWITCH_DOWN,
3117 EL_DC_SWITCHGATE_SWITCH_UP,
3118 EL_DC_SWITCHGATE_SWITCH_DOWN,
3120 EL_LIGHT_SWITCH_ACTIVE,
3122 EL_DC_TIMEGATE_SWITCH,
3123 EL_BALLOON_SWITCH_LEFT,
3124 EL_BALLOON_SWITCH_RIGHT,
3125 EL_BALLOON_SWITCH_UP,
3126 EL_BALLOON_SWITCH_DOWN,
3127 EL_BALLOON_SWITCH_ANY,
3128 EL_BALLOON_SWITCH_NONE,
3131 EL_EMC_MAGIC_BALL_SWITCH,
3132 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3137 static int ep_bd_element[] =
3171 static int ep_sp_element[] =
3173 /* should always be valid */
3176 /* standard classic Supaplex elements */
3183 EL_SP_HARDWARE_GRAY,
3191 EL_SP_GRAVITY_PORT_RIGHT,
3192 EL_SP_GRAVITY_PORT_DOWN,
3193 EL_SP_GRAVITY_PORT_LEFT,
3194 EL_SP_GRAVITY_PORT_UP,
3199 EL_SP_PORT_VERTICAL,
3200 EL_SP_PORT_HORIZONTAL,
3206 EL_SP_HARDWARE_BASE_1,
3207 EL_SP_HARDWARE_GREEN,
3208 EL_SP_HARDWARE_BLUE,
3210 EL_SP_HARDWARE_YELLOW,
3211 EL_SP_HARDWARE_BASE_2,
3212 EL_SP_HARDWARE_BASE_3,
3213 EL_SP_HARDWARE_BASE_4,
3214 EL_SP_HARDWARE_BASE_5,
3215 EL_SP_HARDWARE_BASE_6,
3219 /* additional elements that appeared in newer Supaplex levels */
3222 /* additional gravity port elements (not switching, but setting gravity) */
3223 EL_SP_GRAVITY_ON_PORT_LEFT,
3224 EL_SP_GRAVITY_ON_PORT_RIGHT,
3225 EL_SP_GRAVITY_ON_PORT_UP,
3226 EL_SP_GRAVITY_ON_PORT_DOWN,
3227 EL_SP_GRAVITY_OFF_PORT_LEFT,
3228 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3229 EL_SP_GRAVITY_OFF_PORT_UP,
3230 EL_SP_GRAVITY_OFF_PORT_DOWN,
3232 /* more than one Murphy in a level results in an inactive clone */
3235 /* runtime Supaplex elements */
3236 EL_SP_DISK_RED_ACTIVE,
3237 EL_SP_TERMINAL_ACTIVE,
3238 EL_SP_BUGGY_BASE_ACTIVATING,
3239 EL_SP_BUGGY_BASE_ACTIVE,
3246 static int ep_sb_element[] =
3251 EL_SOKOBAN_FIELD_EMPTY,
3252 EL_SOKOBAN_FIELD_FULL,
3253 EL_SOKOBAN_FIELD_PLAYER,
3258 EL_INVISIBLE_STEELWALL,
3263 static int ep_gem[] =
3275 static int ep_food_dark_yamyam[] =
3303 static int ep_food_penguin[] =
3317 static int ep_food_pig[] =
3329 static int ep_historic_wall[] =
3340 EL_GATE_1_GRAY_ACTIVE,
3341 EL_GATE_2_GRAY_ACTIVE,
3342 EL_GATE_3_GRAY_ACTIVE,
3343 EL_GATE_4_GRAY_ACTIVE,
3352 EL_EM_GATE_1_GRAY_ACTIVE,
3353 EL_EM_GATE_2_GRAY_ACTIVE,
3354 EL_EM_GATE_3_GRAY_ACTIVE,
3355 EL_EM_GATE_4_GRAY_ACTIVE,
3362 EL_EXPANDABLE_WALL_HORIZONTAL,
3363 EL_EXPANDABLE_WALL_VERTICAL,
3364 EL_EXPANDABLE_WALL_ANY,
3365 EL_EXPANDABLE_WALL_GROWING,
3366 EL_BD_EXPANDABLE_WALL,
3373 EL_SP_HARDWARE_GRAY,
3374 EL_SP_HARDWARE_GREEN,
3375 EL_SP_HARDWARE_BLUE,
3377 EL_SP_HARDWARE_YELLOW,
3378 EL_SP_HARDWARE_BASE_1,
3379 EL_SP_HARDWARE_BASE_2,
3380 EL_SP_HARDWARE_BASE_3,
3381 EL_SP_HARDWARE_BASE_4,
3382 EL_SP_HARDWARE_BASE_5,
3383 EL_SP_HARDWARE_BASE_6,
3385 EL_SP_TERMINAL_ACTIVE,
3388 EL_INVISIBLE_STEELWALL,
3389 EL_INVISIBLE_STEELWALL_ACTIVE,
3391 EL_INVISIBLE_WALL_ACTIVE,
3392 EL_STEELWALL_SLIPPERY,
3409 static int ep_historic_solid[] =
3413 EL_EXPANDABLE_WALL_HORIZONTAL,
3414 EL_EXPANDABLE_WALL_VERTICAL,
3415 EL_EXPANDABLE_WALL_ANY,
3416 EL_BD_EXPANDABLE_WALL,
3429 EL_QUICKSAND_FILLING,
3430 EL_QUICKSAND_EMPTYING,
3432 EL_MAGIC_WALL_ACTIVE,
3433 EL_MAGIC_WALL_EMPTYING,
3434 EL_MAGIC_WALL_FILLING,
3438 EL_BD_MAGIC_WALL_ACTIVE,
3439 EL_BD_MAGIC_WALL_EMPTYING,
3440 EL_BD_MAGIC_WALL_FULL,
3441 EL_BD_MAGIC_WALL_FILLING,
3442 EL_BD_MAGIC_WALL_DEAD,
3451 EL_SP_TERMINAL_ACTIVE,
3455 EL_INVISIBLE_WALL_ACTIVE,
3456 EL_SWITCHGATE_SWITCH_UP,
3457 EL_SWITCHGATE_SWITCH_DOWN,
3458 EL_DC_SWITCHGATE_SWITCH_UP,
3459 EL_DC_SWITCHGATE_SWITCH_DOWN,
3461 EL_TIMEGATE_SWITCH_ACTIVE,
3462 EL_DC_TIMEGATE_SWITCH,
3463 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3475 /* the following elements are a direct copy of "indestructible" elements,
3476 except "EL_ACID", which is "indestructible", but not "solid"! */
3481 EL_ACID_POOL_TOPLEFT,
3482 EL_ACID_POOL_TOPRIGHT,
3483 EL_ACID_POOL_BOTTOMLEFT,
3484 EL_ACID_POOL_BOTTOM,
3485 EL_ACID_POOL_BOTTOMRIGHT,
3486 EL_SP_HARDWARE_GRAY,
3487 EL_SP_HARDWARE_GREEN,
3488 EL_SP_HARDWARE_BLUE,
3490 EL_SP_HARDWARE_YELLOW,
3491 EL_SP_HARDWARE_BASE_1,
3492 EL_SP_HARDWARE_BASE_2,
3493 EL_SP_HARDWARE_BASE_3,
3494 EL_SP_HARDWARE_BASE_4,
3495 EL_SP_HARDWARE_BASE_5,
3496 EL_SP_HARDWARE_BASE_6,
3497 EL_INVISIBLE_STEELWALL,
3498 EL_INVISIBLE_STEELWALL_ACTIVE,
3499 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3500 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3501 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3502 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3503 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3504 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3505 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3506 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3507 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3508 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3509 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3510 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3512 EL_LIGHT_SWITCH_ACTIVE,
3513 EL_SIGN_EXCLAMATION,
3514 EL_SIGN_RADIOACTIVITY,
3521 EL_SIGN_ENTRY_FORBIDDEN,
3522 EL_SIGN_EMERGENCY_EXIT,
3530 EL_STEEL_EXIT_CLOSED,
3532 EL_DC_STEELWALL_1_LEFT,
3533 EL_DC_STEELWALL_1_RIGHT,
3534 EL_DC_STEELWALL_1_TOP,
3535 EL_DC_STEELWALL_1_BOTTOM,
3536 EL_DC_STEELWALL_1_HORIZONTAL,
3537 EL_DC_STEELWALL_1_VERTICAL,
3538 EL_DC_STEELWALL_1_TOPLEFT,
3539 EL_DC_STEELWALL_1_TOPRIGHT,
3540 EL_DC_STEELWALL_1_BOTTOMLEFT,
3541 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3542 EL_DC_STEELWALL_1_TOPLEFT_2,
3543 EL_DC_STEELWALL_1_TOPRIGHT_2,
3544 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3545 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3546 EL_DC_STEELWALL_2_LEFT,
3547 EL_DC_STEELWALL_2_RIGHT,
3548 EL_DC_STEELWALL_2_TOP,
3549 EL_DC_STEELWALL_2_BOTTOM,
3550 EL_DC_STEELWALL_2_HORIZONTAL,
3551 EL_DC_STEELWALL_2_VERTICAL,
3552 EL_DC_STEELWALL_2_MIDDLE,
3553 EL_DC_STEELWALL_2_SINGLE,
3554 EL_STEELWALL_SLIPPERY,
3568 EL_GATE_1_GRAY_ACTIVE,
3569 EL_GATE_2_GRAY_ACTIVE,
3570 EL_GATE_3_GRAY_ACTIVE,
3571 EL_GATE_4_GRAY_ACTIVE,
3580 EL_EM_GATE_1_GRAY_ACTIVE,
3581 EL_EM_GATE_2_GRAY_ACTIVE,
3582 EL_EM_GATE_3_GRAY_ACTIVE,
3583 EL_EM_GATE_4_GRAY_ACTIVE,
3585 EL_SWITCHGATE_OPENING,
3586 EL_SWITCHGATE_CLOSED,
3587 EL_SWITCHGATE_CLOSING,
3589 EL_TIMEGATE_OPENING,
3591 EL_TIMEGATE_CLOSING,
3595 EL_TUBE_VERTICAL_LEFT,
3596 EL_TUBE_VERTICAL_RIGHT,
3597 EL_TUBE_HORIZONTAL_UP,
3598 EL_TUBE_HORIZONTAL_DOWN,
3607 static int ep_classic_enemy[] =
3624 static int ep_belt[] =
3626 EL_CONVEYOR_BELT_1_LEFT,
3627 EL_CONVEYOR_BELT_1_MIDDLE,
3628 EL_CONVEYOR_BELT_1_RIGHT,
3629 EL_CONVEYOR_BELT_2_LEFT,
3630 EL_CONVEYOR_BELT_2_MIDDLE,
3631 EL_CONVEYOR_BELT_2_RIGHT,
3632 EL_CONVEYOR_BELT_3_LEFT,
3633 EL_CONVEYOR_BELT_3_MIDDLE,
3634 EL_CONVEYOR_BELT_3_RIGHT,
3635 EL_CONVEYOR_BELT_4_LEFT,
3636 EL_CONVEYOR_BELT_4_MIDDLE,
3637 EL_CONVEYOR_BELT_4_RIGHT,
3642 static int ep_belt_active[] =
3644 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3645 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3646 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3647 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3648 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3649 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3650 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3651 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3652 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3653 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3654 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3655 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3660 static int ep_belt_switch[] =
3662 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3663 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3664 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3665 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3666 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3667 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3668 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3669 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3670 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3671 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3672 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3673 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3678 static int ep_tube[] =
3685 EL_TUBE_HORIZONTAL_UP,
3686 EL_TUBE_HORIZONTAL_DOWN,
3688 EL_TUBE_VERTICAL_LEFT,
3689 EL_TUBE_VERTICAL_RIGHT,
3695 static int ep_acid_pool[] =
3697 EL_ACID_POOL_TOPLEFT,
3698 EL_ACID_POOL_TOPRIGHT,
3699 EL_ACID_POOL_BOTTOMLEFT,
3700 EL_ACID_POOL_BOTTOM,
3701 EL_ACID_POOL_BOTTOMRIGHT,
3706 static int ep_keygate[] =
3716 EL_GATE_1_GRAY_ACTIVE,
3717 EL_GATE_2_GRAY_ACTIVE,
3718 EL_GATE_3_GRAY_ACTIVE,
3719 EL_GATE_4_GRAY_ACTIVE,
3728 EL_EM_GATE_1_GRAY_ACTIVE,
3729 EL_EM_GATE_2_GRAY_ACTIVE,
3730 EL_EM_GATE_3_GRAY_ACTIVE,
3731 EL_EM_GATE_4_GRAY_ACTIVE,
3740 EL_EMC_GATE_5_GRAY_ACTIVE,
3741 EL_EMC_GATE_6_GRAY_ACTIVE,
3742 EL_EMC_GATE_7_GRAY_ACTIVE,
3743 EL_EMC_GATE_8_GRAY_ACTIVE,
3745 EL_DC_GATE_WHITE_GRAY,
3746 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3751 static int ep_amoeboid[] =
3763 static int ep_amoebalive[] =
3774 static int ep_has_editor_content[] =
3780 EL_SOKOBAN_FIELD_PLAYER,
3797 static int ep_can_turn_each_move[] =
3799 /* !!! do something with this one !!! */
3803 static int ep_can_grow[] =
3817 static int ep_active_bomb[] =
3820 EL_EM_DYNAMITE_ACTIVE,
3821 EL_DYNABOMB_PLAYER_1_ACTIVE,
3822 EL_DYNABOMB_PLAYER_2_ACTIVE,
3823 EL_DYNABOMB_PLAYER_3_ACTIVE,
3824 EL_DYNABOMB_PLAYER_4_ACTIVE,
3825 EL_SP_DISK_RED_ACTIVE,
3830 static int ep_inactive[] =
3840 EL_QUICKSAND_FAST_EMPTY,
3863 EL_GATE_1_GRAY_ACTIVE,
3864 EL_GATE_2_GRAY_ACTIVE,
3865 EL_GATE_3_GRAY_ACTIVE,
3866 EL_GATE_4_GRAY_ACTIVE,
3875 EL_EM_GATE_1_GRAY_ACTIVE,
3876 EL_EM_GATE_2_GRAY_ACTIVE,
3877 EL_EM_GATE_3_GRAY_ACTIVE,
3878 EL_EM_GATE_4_GRAY_ACTIVE,
3887 EL_EMC_GATE_5_GRAY_ACTIVE,
3888 EL_EMC_GATE_6_GRAY_ACTIVE,
3889 EL_EMC_GATE_7_GRAY_ACTIVE,
3890 EL_EMC_GATE_8_GRAY_ACTIVE,
3892 EL_DC_GATE_WHITE_GRAY,
3893 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3894 EL_DC_GATE_FAKE_GRAY,
3897 EL_INVISIBLE_STEELWALL,
3905 EL_WALL_EMERALD_YELLOW,
3906 EL_DYNABOMB_INCREASE_NUMBER,
3907 EL_DYNABOMB_INCREASE_SIZE,
3908 EL_DYNABOMB_INCREASE_POWER,
3912 EL_SOKOBAN_FIELD_EMPTY,
3913 EL_SOKOBAN_FIELD_FULL,
3914 EL_WALL_EMERALD_RED,
3915 EL_WALL_EMERALD_PURPLE,
3916 EL_ACID_POOL_TOPLEFT,
3917 EL_ACID_POOL_TOPRIGHT,
3918 EL_ACID_POOL_BOTTOMLEFT,
3919 EL_ACID_POOL_BOTTOM,
3920 EL_ACID_POOL_BOTTOMRIGHT,
3924 EL_BD_MAGIC_WALL_DEAD,
3926 EL_DC_MAGIC_WALL_DEAD,
3927 EL_AMOEBA_TO_DIAMOND,
3935 EL_SP_GRAVITY_PORT_RIGHT,
3936 EL_SP_GRAVITY_PORT_DOWN,
3937 EL_SP_GRAVITY_PORT_LEFT,
3938 EL_SP_GRAVITY_PORT_UP,
3939 EL_SP_PORT_HORIZONTAL,
3940 EL_SP_PORT_VERTICAL,
3951 EL_SP_HARDWARE_GRAY,
3952 EL_SP_HARDWARE_GREEN,
3953 EL_SP_HARDWARE_BLUE,
3955 EL_SP_HARDWARE_YELLOW,
3956 EL_SP_HARDWARE_BASE_1,
3957 EL_SP_HARDWARE_BASE_2,
3958 EL_SP_HARDWARE_BASE_3,
3959 EL_SP_HARDWARE_BASE_4,
3960 EL_SP_HARDWARE_BASE_5,
3961 EL_SP_HARDWARE_BASE_6,
3962 EL_SP_GRAVITY_ON_PORT_LEFT,
3963 EL_SP_GRAVITY_ON_PORT_RIGHT,
3964 EL_SP_GRAVITY_ON_PORT_UP,
3965 EL_SP_GRAVITY_ON_PORT_DOWN,
3966 EL_SP_GRAVITY_OFF_PORT_LEFT,
3967 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3968 EL_SP_GRAVITY_OFF_PORT_UP,
3969 EL_SP_GRAVITY_OFF_PORT_DOWN,
3970 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3971 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3972 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3973 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3974 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3975 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3976 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3977 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3978 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3979 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3980 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3981 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3982 EL_SIGN_EXCLAMATION,
3983 EL_SIGN_RADIOACTIVITY,
3990 EL_SIGN_ENTRY_FORBIDDEN,
3991 EL_SIGN_EMERGENCY_EXIT,
3999 EL_DC_STEELWALL_1_LEFT,
4000 EL_DC_STEELWALL_1_RIGHT,
4001 EL_DC_STEELWALL_1_TOP,
4002 EL_DC_STEELWALL_1_BOTTOM,
4003 EL_DC_STEELWALL_1_HORIZONTAL,
4004 EL_DC_STEELWALL_1_VERTICAL,
4005 EL_DC_STEELWALL_1_TOPLEFT,
4006 EL_DC_STEELWALL_1_TOPRIGHT,
4007 EL_DC_STEELWALL_1_BOTTOMLEFT,
4008 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4009 EL_DC_STEELWALL_1_TOPLEFT_2,
4010 EL_DC_STEELWALL_1_TOPRIGHT_2,
4011 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4012 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4013 EL_DC_STEELWALL_2_LEFT,
4014 EL_DC_STEELWALL_2_RIGHT,
4015 EL_DC_STEELWALL_2_TOP,
4016 EL_DC_STEELWALL_2_BOTTOM,
4017 EL_DC_STEELWALL_2_HORIZONTAL,
4018 EL_DC_STEELWALL_2_VERTICAL,
4019 EL_DC_STEELWALL_2_MIDDLE,
4020 EL_DC_STEELWALL_2_SINGLE,
4021 EL_STEELWALL_SLIPPERY,
4026 EL_EMC_WALL_SLIPPERY_1,
4027 EL_EMC_WALL_SLIPPERY_2,
4028 EL_EMC_WALL_SLIPPERY_3,
4029 EL_EMC_WALL_SLIPPERY_4,
4050 static int ep_em_slippery_wall[] =
4055 static int ep_gfx_crumbled[] =
4066 static int ep_editor_cascade_active[] =
4068 EL_INTERNAL_CASCADE_BD_ACTIVE,
4069 EL_INTERNAL_CASCADE_EM_ACTIVE,
4070 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4071 EL_INTERNAL_CASCADE_RND_ACTIVE,
4072 EL_INTERNAL_CASCADE_SB_ACTIVE,
4073 EL_INTERNAL_CASCADE_SP_ACTIVE,
4074 EL_INTERNAL_CASCADE_DC_ACTIVE,
4075 EL_INTERNAL_CASCADE_DX_ACTIVE,
4076 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4077 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4078 EL_INTERNAL_CASCADE_CE_ACTIVE,
4079 EL_INTERNAL_CASCADE_GE_ACTIVE,
4080 EL_INTERNAL_CASCADE_REF_ACTIVE,
4081 EL_INTERNAL_CASCADE_USER_ACTIVE,
4082 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4087 static int ep_editor_cascade_inactive[] =
4089 EL_INTERNAL_CASCADE_BD,
4090 EL_INTERNAL_CASCADE_EM,
4091 EL_INTERNAL_CASCADE_EMC,
4092 EL_INTERNAL_CASCADE_RND,
4093 EL_INTERNAL_CASCADE_SB,
4094 EL_INTERNAL_CASCADE_SP,
4095 EL_INTERNAL_CASCADE_DC,
4096 EL_INTERNAL_CASCADE_DX,
4097 EL_INTERNAL_CASCADE_CHARS,
4098 EL_INTERNAL_CASCADE_STEEL_CHARS,
4099 EL_INTERNAL_CASCADE_CE,
4100 EL_INTERNAL_CASCADE_GE,
4101 EL_INTERNAL_CASCADE_REF,
4102 EL_INTERNAL_CASCADE_USER,
4103 EL_INTERNAL_CASCADE_DYNAMIC,
4108 static int ep_obsolete[] =
4112 EL_EM_KEY_1_FILE_OBSOLETE,
4113 EL_EM_KEY_2_FILE_OBSOLETE,
4114 EL_EM_KEY_3_FILE_OBSOLETE,
4115 EL_EM_KEY_4_FILE_OBSOLETE,
4116 EL_ENVELOPE_OBSOLETE,
4125 } element_properties[] =
4127 { ep_diggable, EP_DIGGABLE },
4128 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4129 { ep_dont_run_into, EP_DONT_RUN_INTO },
4130 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4131 { ep_dont_touch, EP_DONT_TOUCH },
4132 { ep_indestructible, EP_INDESTRUCTIBLE },
4133 { ep_slippery, EP_SLIPPERY },
4134 { ep_can_change, EP_CAN_CHANGE },
4135 { ep_can_move, EP_CAN_MOVE },
4136 { ep_can_fall, EP_CAN_FALL },
4137 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4138 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4139 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4140 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4141 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4142 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4143 { ep_walkable_over, EP_WALKABLE_OVER },
4144 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4145 { ep_walkable_under, EP_WALKABLE_UNDER },
4146 { ep_passable_over, EP_PASSABLE_OVER },
4147 { ep_passable_inside, EP_PASSABLE_INSIDE },
4148 { ep_passable_under, EP_PASSABLE_UNDER },
4149 { ep_droppable, EP_DROPPABLE },
4150 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4151 { ep_pushable, EP_PUSHABLE },
4152 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4153 { ep_protected, EP_PROTECTED },
4154 { ep_throwable, EP_THROWABLE },
4155 { ep_can_explode, EP_CAN_EXPLODE },
4156 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4158 { ep_player, EP_PLAYER },
4159 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4160 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4161 { ep_switchable, EP_SWITCHABLE },
4162 { ep_bd_element, EP_BD_ELEMENT },
4163 { ep_sp_element, EP_SP_ELEMENT },
4164 { ep_sb_element, EP_SB_ELEMENT },
4166 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4167 { ep_food_penguin, EP_FOOD_PENGUIN },
4168 { ep_food_pig, EP_FOOD_PIG },
4169 { ep_historic_wall, EP_HISTORIC_WALL },
4170 { ep_historic_solid, EP_HISTORIC_SOLID },
4171 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4172 { ep_belt, EP_BELT },
4173 { ep_belt_active, EP_BELT_ACTIVE },
4174 { ep_belt_switch, EP_BELT_SWITCH },
4175 { ep_tube, EP_TUBE },
4176 { ep_acid_pool, EP_ACID_POOL },
4177 { ep_keygate, EP_KEYGATE },
4178 { ep_amoeboid, EP_AMOEBOID },
4179 { ep_amoebalive, EP_AMOEBALIVE },
4180 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4181 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4182 { ep_can_grow, EP_CAN_GROW },
4183 { ep_active_bomb, EP_ACTIVE_BOMB },
4184 { ep_inactive, EP_INACTIVE },
4186 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4188 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4190 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4191 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4193 { ep_obsolete, EP_OBSOLETE },
4200 /* always start with reliable default values (element has no properties) */
4201 /* (but never initialize clipboard elements after the very first time) */
4202 /* (to be able to use clipboard elements between several levels) */
4203 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4204 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4205 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4206 SET_PROPERTY(i, j, FALSE);
4208 /* set all base element properties from above array definitions */
4209 for (i = 0; element_properties[i].elements != NULL; i++)
4210 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4211 SET_PROPERTY((element_properties[i].elements)[j],
4212 element_properties[i].property, TRUE);
4214 /* copy properties to some elements that are only stored in level file */
4215 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4216 for (j = 0; copy_properties[j][0] != -1; j++)
4217 if (HAS_PROPERTY(copy_properties[j][0], i))
4218 for (k = 1; k <= 4; k++)
4219 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4221 /* set static element properties that are not listed in array definitions */
4222 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4223 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4225 clipboard_elements_initialized = TRUE;
4228 void InitElementPropertiesEngine(int engine_version)
4230 static int no_wall_properties[] =
4233 EP_COLLECTIBLE_ONLY,
4235 EP_DONT_COLLIDE_WITH,
4238 EP_CAN_SMASH_PLAYER,
4239 EP_CAN_SMASH_ENEMIES,
4240 EP_CAN_SMASH_EVERYTHING,
4245 EP_FOOD_DARK_YAMYAM,
4261 /* important: after initialization in InitElementPropertiesStatic(), the
4262 elements are not again initialized to a default value; therefore all
4263 changes have to make sure that they leave the element with a defined
4264 property (which means that conditional property changes must be set to
4265 a reliable default value before) */
4267 /* resolve group elements */
4268 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4269 ResolveGroupElement(EL_GROUP_START + i);
4271 /* set all special, combined or engine dependent element properties */
4272 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4274 /* do not change (already initialized) clipboard elements here */
4275 if (IS_CLIPBOARD_ELEMENT(i))
4278 /* ---------- INACTIVE ------------------------------------------------- */
4279 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4280 i <= EL_CHAR_END) ||
4281 (i >= EL_STEEL_CHAR_START &&
4282 i <= EL_STEEL_CHAR_END)));
4284 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4285 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4286 IS_WALKABLE_INSIDE(i) ||
4287 IS_WALKABLE_UNDER(i)));
4289 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4290 IS_PASSABLE_INSIDE(i) ||
4291 IS_PASSABLE_UNDER(i)));
4293 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4294 IS_PASSABLE_OVER(i)));
4296 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4297 IS_PASSABLE_INSIDE(i)));
4299 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4300 IS_PASSABLE_UNDER(i)));
4302 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4305 /* ---------- COLLECTIBLE ---------------------------------------------- */
4306 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4310 /* ---------- SNAPPABLE ------------------------------------------------ */
4311 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4312 IS_COLLECTIBLE(i) ||
4316 /* ---------- WALL ----------------------------------------------------- */
4317 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4319 for (j = 0; no_wall_properties[j] != -1; j++)
4320 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4321 i >= EL_FIRST_RUNTIME_UNREAL)
4322 SET_PROPERTY(i, EP_WALL, FALSE);
4324 if (IS_HISTORIC_WALL(i))
4325 SET_PROPERTY(i, EP_WALL, TRUE);
4327 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4328 if (engine_version < VERSION_IDENT(2,2,0,0))
4329 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4331 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4333 !IS_COLLECTIBLE(i)));
4335 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4336 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4337 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4339 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4340 IS_INDESTRUCTIBLE(i)));
4342 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4344 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4345 else if (engine_version < VERSION_IDENT(2,2,0,0))
4346 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4348 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4352 if (IS_CUSTOM_ELEMENT(i))
4354 /* these are additional properties which are initially false when set */
4356 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4358 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4359 if (DONT_COLLIDE_WITH(i))
4360 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4362 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4363 if (CAN_SMASH_EVERYTHING(i))
4364 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4365 if (CAN_SMASH_ENEMIES(i))
4366 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4369 /* ---------- CAN_SMASH ------------------------------------------------ */
4370 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4371 CAN_SMASH_ENEMIES(i) ||
4372 CAN_SMASH_EVERYTHING(i)));
4374 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4375 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4376 EXPLODES_BY_FIRE(i)));
4378 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4379 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4380 EXPLODES_SMASHED(i)));
4382 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4383 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4384 EXPLODES_IMPACT(i)));
4386 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4387 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4389 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4390 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4391 i == EL_BLACK_ORB));
4393 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4394 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4396 IS_CUSTOM_ELEMENT(i)));
4398 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4399 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4400 i == EL_SP_ELECTRON));
4402 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4403 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4404 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4405 getMoveIntoAcidProperty(&level, i));
4407 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4408 if (MAYBE_DONT_COLLIDE_WITH(i))
4409 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4410 getDontCollideWithProperty(&level, i));
4412 /* ---------- SP_PORT -------------------------------------------------- */
4413 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4414 IS_PASSABLE_INSIDE(i)));
4416 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4417 for (j = 0; j < level.num_android_clone_elements; j++)
4418 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4420 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4422 /* ---------- CAN_CHANGE ----------------------------------------------- */
4423 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4424 for (j = 0; j < element_info[i].num_change_pages; j++)
4425 if (element_info[i].change_page[j].can_change)
4426 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4428 /* ---------- HAS_ACTION ----------------------------------------------- */
4429 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4430 for (j = 0; j < element_info[i].num_change_pages; j++)
4431 if (element_info[i].change_page[j].has_action)
4432 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4434 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4435 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4438 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4439 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4440 element_info[i].crumbled[ACTION_DEFAULT] !=
4441 element_info[i].graphic[ACTION_DEFAULT]);
4443 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4444 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4445 IS_EDITOR_CASCADE_INACTIVE(i)));
4448 /* dynamically adjust element properties according to game engine version */
4450 static int ep_em_slippery_wall[] =
4455 EL_EXPANDABLE_WALL_HORIZONTAL,
4456 EL_EXPANDABLE_WALL_VERTICAL,
4457 EL_EXPANDABLE_WALL_ANY,
4458 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4459 EL_EXPANDABLE_STEELWALL_VERTICAL,
4460 EL_EXPANDABLE_STEELWALL_ANY,
4461 EL_EXPANDABLE_STEELWALL_GROWING,
4465 static int ep_em_explodes_by_fire[] =
4468 EL_EM_DYNAMITE_ACTIVE,
4473 /* special EM style gems behaviour */
4474 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4475 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4476 level.em_slippery_gems);
4478 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4479 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4480 (level.em_slippery_gems &&
4481 engine_version > VERSION_IDENT(2,0,1,0)));
4483 /* special EM style explosion behaviour regarding chain reactions */
4484 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4485 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4486 level.em_explodes_by_fire);
4489 /* this is needed because some graphics depend on element properties */
4490 if (game_status == GAME_MODE_PLAYING)
4491 InitElementGraphicInfo();
4494 void InitElementPropertiesAfterLoading(int engine_version)
4498 /* set some other uninitialized values of custom elements in older levels */
4499 if (engine_version < VERSION_IDENT(3,1,0,0))
4501 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4503 int element = EL_CUSTOM_START + i;
4505 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4507 element_info[element].explosion_delay = 17;
4508 element_info[element].ignition_delay = 8;
4513 void InitElementPropertiesGfxElement()
4517 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4519 struct ElementInfo *ei = &element_info[i];
4521 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4525 static void InitGlobal()
4530 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4532 /* check if element_name_info entry defined for each element in "main.h" */
4533 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4534 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4536 element_info[i].token_name = element_name_info[i].token_name;
4537 element_info[i].class_name = element_name_info[i].class_name;
4538 element_info[i].editor_description= element_name_info[i].editor_description;
4541 /* create hash from image config list */
4542 image_config_hash = newSetupFileHash();
4543 for (i = 0; image_config[i].token != NULL; i++)
4544 setHashEntry(image_config_hash,
4545 image_config[i].token,
4546 image_config[i].value);
4548 /* create hash from element token list */
4549 element_token_hash = newSetupFileHash();
4550 for (i = 0; element_name_info[i].token_name != NULL; i++)
4551 setHashEntry(element_token_hash,
4552 element_name_info[i].token_name,
4555 /* create hash from graphic token list */
4556 graphic_token_hash = newSetupFileHash();
4557 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4558 if (strSuffix(image_config[i].value, ".png") ||
4559 strSuffix(image_config[i].value, ".pcx") ||
4560 strSuffix(image_config[i].value, ".wav") ||
4561 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4562 setHashEntry(graphic_token_hash,
4563 image_config[i].token,
4564 int2str(graphic++, 0));
4566 /* create hash from font token list */
4567 font_token_hash = newSetupFileHash();
4568 for (i = 0; font_info[i].token_name != NULL; i++)
4569 setHashEntry(font_token_hash,
4570 font_info[i].token_name,
4573 /* set default filenames for all cloned graphics in static configuration */
4574 for (i = 0; image_config[i].token != NULL; i++)
4576 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4578 char *token = image_config[i].token;
4579 char *token_clone_from = getStringCat2(token, ".clone_from");
4580 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4582 if (token_cloned != NULL)
4584 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4586 if (value_cloned != NULL)
4588 /* set default filename in static configuration */
4589 image_config[i].value = value_cloned;
4591 /* set default filename in image config hash */
4592 setHashEntry(image_config_hash, token, value_cloned);
4596 free(token_clone_from);
4600 /* always start with reliable default values (all elements) */
4601 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4602 ActiveElement[i] = i;
4604 /* now add all entries that have an active state (active elements) */
4605 for (i = 0; element_with_active_state[i].element != -1; i++)
4607 int element = element_with_active_state[i].element;
4608 int element_active = element_with_active_state[i].element_active;
4610 ActiveElement[element] = element_active;
4613 /* always start with reliable default values (all buttons) */
4614 for (i = 0; i < NUM_IMAGE_FILES; i++)
4615 ActiveButton[i] = i;
4617 /* now add all entries that have an active state (active buttons) */
4618 for (i = 0; button_with_active_state[i].button != -1; i++)
4620 int button = button_with_active_state[i].button;
4621 int button_active = button_with_active_state[i].button_active;
4623 ActiveButton[button] = button_active;
4626 /* always start with reliable default values (all fonts) */
4627 for (i = 0; i < NUM_FONTS; i++)
4630 /* now add all entries that have an active state (active fonts) */
4631 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4633 int font = font_with_active_state[i].font_nr;
4634 int font_active = font_with_active_state[i].font_nr_active;
4636 ActiveFont[font] = font_active;
4639 global.autoplay_leveldir = NULL;
4640 global.convert_leveldir = NULL;
4641 global.create_images_dir = NULL;
4643 global.frames_per_second = 0;
4645 global.border_status = GAME_MODE_MAIN;
4647 global.use_envelope_request = FALSE;
4650 void Execute_Command(char *command)
4654 if (strEqual(command, "print graphicsinfo.conf"))
4656 Print("# You can configure additional/alternative image files here.\n");
4657 Print("# (The entries below are default and therefore commented out.)\n");
4659 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4661 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4664 for (i = 0; image_config[i].token != NULL; i++)
4665 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4666 image_config[i].value));
4670 else if (strEqual(command, "print soundsinfo.conf"))
4672 Print("# You can configure additional/alternative sound files here.\n");
4673 Print("# (The entries below are default and therefore commented out.)\n");
4675 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4677 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4680 for (i = 0; sound_config[i].token != NULL; i++)
4681 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4682 sound_config[i].value));
4686 else if (strEqual(command, "print musicinfo.conf"))
4688 Print("# You can configure additional/alternative music files here.\n");
4689 Print("# (The entries below are default and therefore commented out.)\n");
4691 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4693 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4696 for (i = 0; music_config[i].token != NULL; i++)
4697 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4698 music_config[i].value));
4702 else if (strEqual(command, "print editorsetup.conf"))
4704 Print("# You can configure your personal editor element list here.\n");
4705 Print("# (The entries below are default and therefore commented out.)\n");
4708 /* this is needed to be able to check element list for cascade elements */
4709 InitElementPropertiesStatic();
4710 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4712 PrintEditorElementList();
4716 else if (strEqual(command, "print helpanim.conf"))
4718 Print("# You can configure different element help animations here.\n");
4719 Print("# (The entries below are default and therefore commented out.)\n");
4722 for (i = 0; helpanim_config[i].token != NULL; i++)
4724 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4725 helpanim_config[i].value));
4727 if (strEqual(helpanim_config[i].token, "end"))
4733 else if (strEqual(command, "print helptext.conf"))
4735 Print("# You can configure different element help text here.\n");
4736 Print("# (The entries below are default and therefore commented out.)\n");
4739 for (i = 0; helptext_config[i].token != NULL; i++)
4740 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4741 helptext_config[i].value));
4745 else if (strPrefix(command, "dump level "))
4747 char *filename = &command[11];
4749 if (!fileExists(filename))
4750 Error(ERR_EXIT, "cannot open file '%s'", filename);
4752 LoadLevelFromFilename(&level, filename);
4757 else if (strPrefix(command, "dump tape "))
4759 char *filename = &command[10];
4761 if (!fileExists(filename))
4762 Error(ERR_EXIT, "cannot open file '%s'", filename);
4764 LoadTapeFromFilename(filename);
4769 else if (strPrefix(command, "autotest ") ||
4770 strPrefix(command, "autoplay ") ||
4771 strPrefix(command, "autoffwd "))
4773 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4775 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4776 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4777 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4779 while (*str_ptr != '\0') /* continue parsing string */
4781 /* cut leading whitespace from string, replace it by string terminator */
4782 while (*str_ptr == ' ' || *str_ptr == '\t')
4785 if (*str_ptr == '\0') /* end of string reached */
4788 if (global.autoplay_leveldir == NULL) /* read level set string */
4790 global.autoplay_leveldir = str_ptr;
4791 global.autoplay_all = TRUE; /* default: play all tapes */
4793 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4794 global.autoplay_level[i] = FALSE;
4796 else /* read level number string */
4798 int level_nr = atoi(str_ptr); /* get level_nr value */
4800 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4801 global.autoplay_level[level_nr] = TRUE;
4803 global.autoplay_all = FALSE;
4806 /* advance string pointer to the next whitespace (or end of string) */
4807 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4811 else if (strPrefix(command, "convert "))
4813 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4814 char *str_ptr = strchr(str_copy, ' ');
4816 global.convert_leveldir = str_copy;
4817 global.convert_level_nr = -1;
4819 if (str_ptr != NULL) /* level number follows */
4821 *str_ptr++ = '\0'; /* terminate leveldir string */
4822 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4825 else if (strPrefix(command, "create images "))
4827 global.create_images_dir = getStringCopy(&command[14]);
4829 if (access(global.create_images_dir, W_OK) != 0)
4830 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4831 global.create_images_dir);
4833 else if (strPrefix(command, "create CE image "))
4835 CreateCustomElementImages(&command[16]);
4841 #if defined(TARGET_SDL2)
4842 else if (strEqual(command, "SDL_ListModes"))
4844 SDL_Init(SDL_INIT_VIDEO);
4846 int num_displays = SDL_GetNumVideoDisplays();
4848 // check if there are any displays available
4849 if (num_displays < 0)
4851 Print("No displays available: %s\n", SDL_GetError());
4856 for (i = 0; i < num_displays; i++)
4858 int num_modes = SDL_GetNumDisplayModes(i);
4861 Print("Available display modes for display %d:\n", i);
4863 // check if there are any display modes available for this display
4866 Print("No display modes available for display %d: %s\n",
4872 for (j = 0; j < num_modes; j++)
4874 SDL_DisplayMode mode;
4876 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4878 Print("Cannot get display mode %d for display %d: %s\n",
4879 j, i, SDL_GetError());
4884 Print("- %d x %d\n", mode.w, mode.h);
4890 #elif defined(TARGET_SDL)
4891 else if (strEqual(command, "SDL_ListModes"))
4896 SDL_Init(SDL_INIT_VIDEO);
4898 /* get available fullscreen/hardware modes */
4899 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4901 /* check if there are any modes available */
4904 Print("No modes available!\n");
4909 /* check if our resolution is restricted */
4910 if (modes == (SDL_Rect **)-1)
4912 Print("All resolutions available.\n");
4916 Print("Available display modes:\n");
4918 for (i = 0; modes[i]; i++)
4919 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4929 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4933 static void InitSetup()
4935 LoadSetup(); /* global setup info */
4937 /* set some options from setup file */
4939 if (setup.options.verbose)
4940 options.verbose = TRUE;
4943 static void InitGameInfo()
4945 game.restart_level = FALSE;
4948 static void InitPlayerInfo()
4952 /* choose default local player */
4953 local_player = &stored_player[0];
4955 for (i = 0; i < MAX_PLAYERS; i++)
4956 stored_player[i].connected = FALSE;
4958 local_player->connected = TRUE;
4961 static void InitArtworkInfo()
4966 static char *get_string_in_brackets(char *string)
4968 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4970 sprintf(string_in_brackets, "[%s]", string);
4972 return string_in_brackets;
4975 static char *get_level_id_suffix(int id_nr)
4977 char *id_suffix = checked_malloc(1 + 3 + 1);
4979 if (id_nr < 0 || id_nr > 999)
4982 sprintf(id_suffix, ".%03d", id_nr);
4987 static void InitArtworkConfig()
4989 static char *image_id_prefix[MAX_NUM_ELEMENTS +
4991 NUM_GLOBAL_ANIMS + 1];
4992 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4993 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4994 static char *action_id_suffix[NUM_ACTIONS + 1];
4995 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4996 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4997 static char *level_id_suffix[MAX_LEVELS + 1];
4998 static char *dummy[1] = { NULL };
4999 static char *ignore_generic_tokens[] =
5005 static char **ignore_image_tokens;
5006 static char **ignore_sound_tokens;
5007 static char **ignore_music_tokens;
5008 int num_ignore_generic_tokens;
5009 int num_ignore_image_tokens;
5010 int num_ignore_sound_tokens;
5011 int num_ignore_music_tokens;
5014 /* dynamically determine list of generic tokens to be ignored */
5015 num_ignore_generic_tokens = 0;
5016 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5017 num_ignore_generic_tokens++;
5019 /* dynamically determine list of image tokens to be ignored */
5020 num_ignore_image_tokens = num_ignore_generic_tokens;
5021 for (i = 0; image_config_vars[i].token != NULL; i++)
5022 num_ignore_image_tokens++;
5023 ignore_image_tokens =
5024 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5025 for (i = 0; i < num_ignore_generic_tokens; i++)
5026 ignore_image_tokens[i] = ignore_generic_tokens[i];
5027 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5028 ignore_image_tokens[num_ignore_generic_tokens + i] =
5029 image_config_vars[i].token;
5030 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5032 /* dynamically determine list of sound tokens to be ignored */
5033 num_ignore_sound_tokens = num_ignore_generic_tokens;
5034 ignore_sound_tokens =
5035 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5036 for (i = 0; i < num_ignore_generic_tokens; i++)
5037 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5038 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5040 /* dynamically determine list of music tokens to be ignored */
5041 num_ignore_music_tokens = num_ignore_generic_tokens;
5042 ignore_music_tokens =
5043 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5044 for (i = 0; i < num_ignore_generic_tokens; i++)
5045 ignore_music_tokens[i] = ignore_generic_tokens[i];
5046 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5048 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5049 image_id_prefix[i] = element_info[i].token_name;
5050 for (i = 0; i < NUM_FONTS; i++)
5051 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5052 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
5053 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5054 global_anim_info[i].token_name;
5055 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIMS] = NULL;
5057 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5058 sound_id_prefix[i] = element_info[i].token_name;
5059 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5060 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5061 get_string_in_brackets(element_info[i].class_name);
5062 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5064 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5065 music_id_prefix[i] = music_prefix_info[i].prefix;
5066 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5068 for (i = 0; i < NUM_ACTIONS; i++)
5069 action_id_suffix[i] = element_action_info[i].suffix;
5070 action_id_suffix[NUM_ACTIONS] = NULL;
5072 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5073 direction_id_suffix[i] = element_direction_info[i].suffix;
5074 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5076 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5077 special_id_suffix[i] = special_suffix_info[i].suffix;
5078 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5080 for (i = 0; i < MAX_LEVELS; i++)
5081 level_id_suffix[i] = get_level_id_suffix(i);
5082 level_id_suffix[MAX_LEVELS] = NULL;
5084 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5085 image_id_prefix, action_id_suffix, direction_id_suffix,
5086 special_id_suffix, ignore_image_tokens);
5087 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5088 sound_id_prefix, action_id_suffix, dummy,
5089 special_id_suffix, ignore_sound_tokens);
5090 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5091 music_id_prefix, special_id_suffix, level_id_suffix,
5092 dummy, ignore_music_tokens);
5095 static void InitMixer()
5102 void InitGfxBuffers()
5104 static int win_xsize_last = -1;
5105 static int win_ysize_last = -1;
5107 /* create additional image buffers for double-buffering and cross-fading */
5109 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5111 /* may contain content for cross-fading -- only re-create if changed */
5112 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5113 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5115 win_xsize_last = WIN_XSIZE;
5116 win_ysize_last = WIN_YSIZE;
5119 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5120 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5121 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5122 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5123 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5125 /* initialize screen properties */
5126 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5127 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5129 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5130 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5131 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5132 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5133 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5134 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5136 /* required if door size definitions have changed */
5137 InitGraphicCompatibilityInfo_Doors();
5139 InitGfxBuffers_EM();
5140 InitGfxBuffers_SP();
5145 struct GraphicInfo *graphic_info_last = graphic_info;
5146 char *filename_font_initial = NULL;
5147 char *filename_anim_initial = NULL;
5148 Bitmap *bitmap_font_initial = NULL;
5152 /* determine settings for initial font (for displaying startup messages) */
5153 for (i = 0; image_config[i].token != NULL; i++)
5155 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5157 char font_token[128];
5160 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5161 len_font_token = strlen(font_token);
5163 if (strEqual(image_config[i].token, font_token))
5164 filename_font_initial = image_config[i].value;
5165 else if (strlen(image_config[i].token) > len_font_token &&
5166 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5168 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5169 font_initial[j].src_x = atoi(image_config[i].value);
5170 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5171 font_initial[j].src_y = atoi(image_config[i].value);
5172 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5173 font_initial[j].width = atoi(image_config[i].value);
5174 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5175 font_initial[j].height = atoi(image_config[i].value);
5180 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5182 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5183 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5186 if (filename_font_initial == NULL) /* should not happen */
5187 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5190 InitGfxCustomArtworkInfo();
5191 InitGfxOtherSettings();
5193 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5195 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5196 font_initial[j].bitmap = bitmap_font_initial;
5198 InitFontGraphicInfo();
5200 font_height = getFontHeight(FC_RED);
5202 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5203 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5204 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5207 DrawInitText("Loading graphics", 120, FC_GREEN);
5209 /* initialize settings for busy animation with default values */
5210 int parameter[NUM_GFX_ARGS];
5211 for (i = 0; i < NUM_GFX_ARGS; i++)
5212 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5213 image_config_suffix[i].token,
5214 image_config_suffix[i].type);
5216 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5217 int len_anim_token = strlen(anim_token);
5219 /* read settings for busy animation from default custom artwork config */
5220 char *gfx_config_filename = getPath3(options.graphics_directory,
5222 GRAPHICSINFO_FILENAME);
5224 if (fileExists(gfx_config_filename))
5226 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5228 if (setup_file_hash)
5230 char *filename = getHashEntry(setup_file_hash, anim_token);
5234 filename_anim_initial = getStringCopy(filename);
5236 for (j = 0; image_config_suffix[j].token != NULL; j++)
5238 int type = image_config_suffix[j].type;
5239 char *suffix = image_config_suffix[j].token;
5240 char *token = getStringCat2(anim_token, suffix);
5241 char *value = getHashEntry(setup_file_hash, token);
5243 checked_free(token);
5246 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5250 freeSetupFileHash(setup_file_hash);
5254 if (filename_anim_initial == NULL)
5256 /* read settings for busy animation from static default artwork config */
5257 for (i = 0; image_config[i].token != NULL; i++)
5259 if (strEqual(image_config[i].token, anim_token))
5260 filename_anim_initial = getStringCopy(image_config[i].value);
5261 else if (strlen(image_config[i].token) > len_anim_token &&
5262 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5264 for (j = 0; image_config_suffix[j].token != NULL; j++)
5266 if (strEqual(&image_config[i].token[len_anim_token],
5267 image_config_suffix[j].token))
5269 get_graphic_parameter_value(image_config[i].value,
5270 image_config_suffix[j].token,
5271 image_config_suffix[j].type);
5277 if (filename_anim_initial == NULL) /* should not happen */
5278 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5280 anim_initial.bitmaps =
5281 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5283 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5284 LoadCustomImage(filename_anim_initial);
5286 checked_free(filename_anim_initial);
5288 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5290 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5292 graphic_info = graphic_info_last;
5294 init.busy.width = anim_initial.width;
5295 init.busy.height = anim_initial.height;
5297 InitMenuDesignSettings_Static();
5299 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5300 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5302 /* use copy of busy animation to prevent change while reloading artwork */
5306 void InitGfxBackground()
5308 fieldbuffer = bitmap_db_field;
5309 SetDrawtoField(DRAW_BACKBUFFER);
5311 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5313 redraw_mask = REDRAW_ALL;
5316 static void InitLevelInfo()
5318 LoadLevelInfo(); /* global level info */
5319 LoadLevelSetup_LastSeries(); /* last played series info */
5320 LoadLevelSetup_SeriesInfo(); /* last played level info */
5322 if (global.autoplay_leveldir &&
5323 global.autoplay_mode != AUTOPLAY_TEST)
5325 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5326 global.autoplay_leveldir);
5327 if (leveldir_current == NULL)
5328 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5332 static void InitLevelArtworkInfo()
5334 LoadLevelArtworkInfo();
5337 static void InitImages()
5339 print_timestamp_init("InitImages");
5342 printf("::: leveldir_current->identifier == '%s'\n",
5343 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5344 printf("::: leveldir_current->graphics_path == '%s'\n",
5345 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5346 printf("::: leveldir_current->graphics_set == '%s'\n",
5347 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5348 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5349 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5352 setLevelArtworkDir(artwork.gfx_first);
5355 printf("::: leveldir_current->identifier == '%s'\n",
5356 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5357 printf("::: leveldir_current->graphics_path == '%s'\n",
5358 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5359 printf("::: leveldir_current->graphics_set == '%s'\n",
5360 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5361 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5362 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5366 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5367 leveldir_current->identifier,
5368 artwork.gfx_current_identifier,
5369 artwork.gfx_current->identifier,
5370 leveldir_current->graphics_set,
5371 leveldir_current->graphics_path);
5374 UPDATE_BUSY_STATE();
5376 ReloadCustomImages();
5377 print_timestamp_time("ReloadCustomImages");
5379 UPDATE_BUSY_STATE();
5381 LoadCustomElementDescriptions();
5382 print_timestamp_time("LoadCustomElementDescriptions");
5384 UPDATE_BUSY_STATE();
5386 LoadMenuDesignSettings();
5387 print_timestamp_time("LoadMenuDesignSettings");
5389 UPDATE_BUSY_STATE();
5391 ReinitializeGraphics();
5392 print_timestamp_time("ReinitializeGraphics");
5394 UPDATE_BUSY_STATE();
5396 print_timestamp_done("InitImages");
5399 static void InitSound(char *identifier)
5401 print_timestamp_init("InitSound");
5403 if (identifier == NULL)
5404 identifier = artwork.snd_current->identifier;
5406 /* set artwork path to send it to the sound server process */
5407 setLevelArtworkDir(artwork.snd_first);
5409 InitReloadCustomSounds(identifier);
5410 print_timestamp_time("InitReloadCustomSounds");
5412 ReinitializeSounds();
5413 print_timestamp_time("ReinitializeSounds");
5415 print_timestamp_done("InitSound");
5418 static void InitMusic(char *identifier)
5420 print_timestamp_init("InitMusic");
5422 if (identifier == NULL)
5423 identifier = artwork.mus_current->identifier;
5425 /* set artwork path to send it to the sound server process */
5426 setLevelArtworkDir(artwork.mus_first);
5428 InitReloadCustomMusic(identifier);
5429 print_timestamp_time("InitReloadCustomMusic");
5431 ReinitializeMusic();
5432 print_timestamp_time("ReinitializeMusic");
5434 print_timestamp_done("InitMusic");
5437 void InitNetworkServer()
5439 #if defined(NETWORK_AVALIABLE)
5443 if (!options.network)
5446 #if defined(NETWORK_AVALIABLE)
5447 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5449 if (!ConnectToServer(options.server_host, options.server_port))
5450 Error(ERR_EXIT, "cannot connect to network game server");
5452 SendToServer_PlayerName(setup.player_name);
5453 SendToServer_ProtocolVersion();
5456 SendToServer_NrWanted(nr_wanted);
5460 static boolean CheckArtworkConfigForCustomElements(char *filename)
5462 SetupFileHash *setup_file_hash;
5463 boolean redefined_ce_found = FALSE;
5465 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5467 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5469 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5471 char *token = HASH_ITERATION_TOKEN(itr);
5473 if (strPrefix(token, "custom_"))
5475 redefined_ce_found = TRUE;
5480 END_HASH_ITERATION(setup_file_hash, itr)
5482 freeSetupFileHash(setup_file_hash);
5485 return redefined_ce_found;
5488 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5490 char *filename_base, *filename_local;
5491 boolean redefined_ce_found = FALSE;
5493 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5496 printf("::: leveldir_current->identifier == '%s'\n",
5497 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5498 printf("::: leveldir_current->graphics_path == '%s'\n",
5499 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5500 printf("::: leveldir_current->graphics_set == '%s'\n",
5501 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5502 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5503 leveldir_current == NULL ? "[NULL]" :
5504 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5507 /* first look for special artwork configured in level series config */
5508 filename_base = getCustomArtworkLevelConfigFilename(type);
5511 printf("::: filename_base == '%s'\n", filename_base);
5514 if (fileExists(filename_base))
5515 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5517 filename_local = getCustomArtworkConfigFilename(type);
5520 printf("::: filename_local == '%s'\n", filename_local);
5523 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5524 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5527 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5530 return redefined_ce_found;
5533 static void InitOverrideArtwork()
5535 boolean redefined_ce_found = FALSE;
5537 /* to check if this level set redefines any CEs, do not use overriding */
5538 gfx.override_level_graphics = FALSE;
5539 gfx.override_level_sounds = FALSE;
5540 gfx.override_level_music = FALSE;
5542 /* now check if this level set has definitions for custom elements */
5543 if (setup.override_level_graphics == AUTO ||
5544 setup.override_level_sounds == AUTO ||
5545 setup.override_level_music == AUTO)
5546 redefined_ce_found =
5547 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5548 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5549 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5552 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5555 if (redefined_ce_found)
5557 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5558 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5559 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5560 gfx.override_level_music = (setup.override_level_music == TRUE);
5564 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5565 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5566 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5567 gfx.override_level_music = (setup.override_level_music != FALSE);
5571 printf("::: => %d, %d, %d\n",
5572 gfx.override_level_graphics,
5573 gfx.override_level_sounds,
5574 gfx.override_level_music);
5578 static char *getNewArtworkIdentifier(int type)
5580 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5581 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5582 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5583 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5584 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5585 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5586 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5587 char *leveldir_identifier = leveldir_current->identifier;
5588 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5589 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5590 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5591 char *artwork_current_identifier;
5592 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5594 /* leveldir_current may be invalid (level group, parent link) */
5595 if (!validLevelSeries(leveldir_current))
5598 /* 1st step: determine artwork set to be activated in descending order:
5599 --------------------------------------------------------------------
5600 1. setup artwork (when configured to override everything else)
5601 2. artwork set configured in "levelinfo.conf" of current level set
5602 (artwork in level directory will have priority when loading later)
5603 3. artwork in level directory (stored in artwork sub-directory)
5604 4. setup artwork (currently configured in setup menu) */
5606 if (setup_override_artwork)
5607 artwork_current_identifier = setup_artwork_set;
5608 else if (leveldir_artwork_set != NULL)
5609 artwork_current_identifier = leveldir_artwork_set;
5610 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5611 artwork_current_identifier = leveldir_identifier;
5613 artwork_current_identifier = setup_artwork_set;
5616 /* 2nd step: check if it is really needed to reload artwork set
5617 ------------------------------------------------------------ */
5619 /* ---------- reload if level set and also artwork set has changed ------- */
5620 if (leveldir_current_identifier[type] != leveldir_identifier &&
5621 (last_has_level_artwork_set[type] || has_level_artwork_set))
5622 artwork_new_identifier = artwork_current_identifier;
5624 leveldir_current_identifier[type] = leveldir_identifier;
5625 last_has_level_artwork_set[type] = has_level_artwork_set;
5627 /* ---------- reload if "override artwork" setting has changed ----------- */
5628 if (last_override_level_artwork[type] != setup_override_artwork)
5629 artwork_new_identifier = artwork_current_identifier;
5631 last_override_level_artwork[type] = setup_override_artwork;
5633 /* ---------- reload if current artwork identifier has changed ----------- */
5634 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5635 artwork_current_identifier))
5636 artwork_new_identifier = artwork_current_identifier;
5638 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5640 /* ---------- do not reload directly after starting ---------------------- */
5641 if (!initialized[type])
5642 artwork_new_identifier = NULL;
5644 initialized[type] = TRUE;
5646 return artwork_new_identifier;
5649 void ReloadCustomArtwork(int force_reload)
5651 int last_game_status = game_status; /* save current game status */
5652 char *gfx_new_identifier;
5653 char *snd_new_identifier;
5654 char *mus_new_identifier;
5655 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5656 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5657 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5658 boolean reload_needed;
5660 InitOverrideArtwork();
5662 force_reload_gfx |= AdjustGraphicsForEMC();
5664 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5665 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5666 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5668 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5669 snd_new_identifier != NULL || force_reload_snd ||
5670 mus_new_identifier != NULL || force_reload_mus);
5675 print_timestamp_init("ReloadCustomArtwork");
5677 game_status = GAME_MODE_LOADING;
5679 FadeOut(REDRAW_ALL);
5681 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5682 print_timestamp_time("ClearRectangle");
5686 if (gfx_new_identifier != NULL || force_reload_gfx)
5689 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5690 artwork.gfx_current_identifier,
5692 artwork.gfx_current->identifier,
5693 leveldir_current->graphics_set);
5697 print_timestamp_time("InitImages");
5700 if (snd_new_identifier != NULL || force_reload_snd)
5702 InitSound(snd_new_identifier);
5703 print_timestamp_time("InitSound");
5706 if (mus_new_identifier != NULL || force_reload_mus)
5708 InitMusic(mus_new_identifier);
5709 print_timestamp_time("InitMusic");
5712 game_status = last_game_status; /* restore current game status */
5714 init_last = init; /* switch to new busy animation */
5716 FadeOut(REDRAW_ALL);
5718 RedrawGlobalBorder();
5720 /* force redraw of (open or closed) door graphics */
5721 SetDoorState(DOOR_OPEN_ALL);
5722 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5724 FadeSetEnterScreen();
5725 FadeSkipNextFadeOut();
5727 print_timestamp_done("ReloadCustomArtwork");
5729 LimitScreenUpdates(FALSE);
5732 void KeyboardAutoRepeatOffUnlessAutoplay()
5734 if (global.autoplay_leveldir == NULL)
5735 KeyboardAutoRepeatOff();
5738 void DisplayExitMessage(char *format, va_list ap)
5740 // check if draw buffer and fonts for exit message are already available
5741 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5744 int font_1 = FC_RED;
5745 int font_2 = FC_YELLOW;
5746 int font_3 = FC_BLUE;
5747 int font_width = getFontWidth(font_2);
5748 int font_height = getFontHeight(font_2);
5751 int sxsize = WIN_XSIZE - 2 * sx;
5752 int sysize = WIN_YSIZE - 2 * sy;
5753 int line_length = sxsize / font_width;
5754 int max_lines = sysize / font_height;
5755 int num_lines_printed;
5759 gfx.sxsize = sxsize;
5760 gfx.sysize = sysize;
5764 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5766 DrawTextSCentered(sy, font_1, "Fatal error:");
5767 sy += 3 * font_height;;
5770 DrawTextBufferVA(sx, sy, format, ap, font_2,
5771 line_length, line_length, max_lines,
5772 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5773 sy += (num_lines_printed + 3) * font_height;
5775 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5776 sy += 3 * font_height;
5779 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5780 line_length, line_length, max_lines,
5781 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5783 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5785 redraw_mask = REDRAW_ALL;
5787 /* force drawing exit message even if screen updates are currently limited */
5788 LimitScreenUpdates(FALSE);
5792 /* deactivate toons on error message screen */
5793 setup.toons = FALSE;
5795 WaitForEventToContinue();
5799 /* ========================================================================= */
5801 /* ========================================================================= */
5805 print_timestamp_init("OpenAll");
5807 game_status = GAME_MODE_LOADING;
5811 InitGlobal(); /* initialize some global variables */
5813 print_timestamp_time("[init global stuff]");
5817 print_timestamp_time("[init setup/config stuff (1)]");
5819 if (options.execute_command)
5820 Execute_Command(options.execute_command);
5822 if (options.serveronly)
5824 #if defined(PLATFORM_UNIX)
5825 NetworkServer(options.server_port, options.serveronly);
5827 Error(ERR_WARN, "networking only supported in Unix version");
5830 exit(0); /* never reached, server loops forever */
5834 print_timestamp_time("[init setup/config stuff (2)]");
5836 print_timestamp_time("[init setup/config stuff (3)]");
5837 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5838 print_timestamp_time("[init setup/config stuff (4)]");
5839 InitArtworkConfig(); /* needed before forking sound child process */
5840 print_timestamp_time("[init setup/config stuff (5)]");
5842 print_timestamp_time("[init setup/config stuff (6)]");
5844 InitRND(NEW_RANDOMIZE);
5845 InitSimpleRandom(NEW_RANDOMIZE);
5849 print_timestamp_time("[init setup/config stuff]");
5852 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5854 InitEventFilter(FilterEvents);
5856 print_timestamp_time("[init video stuff]");
5858 InitElementPropertiesStatic();
5859 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5860 InitElementPropertiesGfxElement();
5862 print_timestamp_time("[init element properties stuff]");
5866 print_timestamp_time("InitGfx");
5869 print_timestamp_time("InitLevelInfo");
5871 InitLevelArtworkInfo();
5872 print_timestamp_time("InitLevelArtworkInfo");
5874 InitOverrideArtwork(); /* needs to know current level directory */
5875 print_timestamp_time("InitOverrideArtwork");
5877 InitImages(); /* needs to know current level directory */
5878 print_timestamp_time("InitImages");
5880 InitSound(NULL); /* needs to know current level directory */
5881 print_timestamp_time("InitSound");
5883 InitMusic(NULL); /* needs to know current level directory */
5884 print_timestamp_time("InitMusic");
5886 InitGfxBackground();
5891 if (global.autoplay_leveldir)
5896 else if (global.convert_leveldir)
5901 else if (global.create_images_dir)
5903 CreateLevelSketchImages();
5907 game_status = GAME_MODE_MAIN;
5909 FadeSetEnterScreen();
5910 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5911 FadeSkipNextFadeOut();
5913 print_timestamp_time("[post-artwork]");
5915 print_timestamp_done("OpenAll");
5919 InitNetworkServer();
5922 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5924 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5925 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5926 #if defined(PLATFORM_ANDROID)
5927 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5928 SDL_AndroidGetInternalStoragePath());
5929 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5930 SDL_AndroidGetExternalStoragePath());
5931 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5932 (SDL_AndroidGetExternalStorageState() ==
5933 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5934 SDL_AndroidGetExternalStorageState() ==
5935 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5940 void CloseAllAndExit(int exit_value)
5945 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5952 #if defined(TARGET_SDL)
5953 #if defined(TARGET_SDL2)
5955 // set a flag to tell the network server thread to quit and wait for it
5956 // using SDL_WaitThread()
5958 if (network_server) /* terminate network server */
5959 SDL_KillThread(server_thread);
5963 CloseVideoDisplay();
5964 ClosePlatformDependentStuff();
5966 if (exit_value != 0)
5968 /* fall back to default level set (current set may have caused an error) */
5969 SaveLevelSetup_LastSeries_Deactivate();
5971 /* tell user where to find error log file which may contain more details */
5972 // (error notification now directly displayed on screen inside R'n'D
5973 // NotifyUserAboutErrorFile(); /* currently only works for Windows */