1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" /* include auto-generated data structure definitions */
28 #include "conf_esg.c" /* include auto-generated data structure definitions */
29 #include "conf_e2s.c" /* include auto-generated data structure definitions */
30 #include "conf_fnt.c" /* include auto-generated data structure definitions */
31 #include "conf_g2s.c" /* include auto-generated data structure definitions */
32 #include "conf_g2m.c" /* include auto-generated data structure definitions */
33 #include "conf_act.c" /* include auto-generated data structure definitions */
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
89 struct GraphicInfo *graphic_info_last = graphic_info;
91 static unsigned int action_delay = 0;
92 unsigned int action_delay_value = GameFrameDelay;
93 int sync_frame = FrameCounter;
96 if (game_status != GAME_MODE_LOADING)
99 if (anim_initial.bitmap == NULL || window == NULL)
102 if (!DelayReached(&action_delay, action_delay_value))
105 if (init_last.busy.x == -1)
106 init_last.busy.x = WIN_XSIZE / 2;
107 if (init_last.busy.y == -1)
108 init_last.busy.y = WIN_YSIZE / 2;
110 x = ALIGNED_TEXT_XPOS(&init_last.busy);
111 y = ALIGNED_TEXT_YPOS(&init_last.busy);
113 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
115 if (sync_frame % anim_initial.anim_delay == 0)
119 int width = graphic_info[graphic].width;
120 int height = graphic_info[graphic].height;
121 int frame = getGraphicAnimationFrame(graphic, sync_frame);
123 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
124 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
127 graphic_info = graphic_info_last;
134 FreeLevelEditorGadgets();
143 static boolean gadgets_initialized = FALSE;
145 if (gadgets_initialized)
148 CreateLevelEditorGadgets();
152 CreateScreenGadgets();
154 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
156 gadgets_initialized = TRUE;
159 inline static void InitElementSmallImagesScaledUp(int graphic)
161 struct GraphicInfo *g = &graphic_info[graphic];
163 // create small and game tile sized bitmaps (and scale up, if needed)
164 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
167 void InitElementSmallImages()
169 print_timestamp_init("InitElementSmallImages");
171 static int special_graphics[] =
173 IMG_EDITOR_ELEMENT_BORDER,
174 IMG_EDITOR_ELEMENT_BORDER_INPUT,
175 IMG_EDITOR_CASCADE_LIST,
176 IMG_EDITOR_CASCADE_LIST_ACTIVE,
179 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
180 int num_property_mappings = getImageListPropertyMappingSize();
183 print_timestamp_time("getImageListPropertyMapping/Size");
185 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
186 /* initialize normal images from static configuration */
187 for (i = 0; element_to_graphic[i].element > -1; i++)
188 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
189 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
191 /* initialize special images from static configuration */
192 for (i = 0; element_to_special_graphic[i].element > -1; i++)
193 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
194 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
196 /* initialize images from dynamic configuration (may be elements or other) */
197 for (i = 0; i < num_property_mappings; i++)
198 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
199 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
201 /* initialize special images from above list (non-element images) */
202 for (i = 0; special_graphics[i] > -1; i++)
203 InitElementSmallImagesScaledUp(special_graphics[i]);
204 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
206 print_timestamp_done("InitElementSmallImages");
209 void InitScaledImages()
213 /* scale normal images from static configuration, if not already scaled */
214 for (i = 0; i < NUM_IMAGE_FILES; i++)
215 ScaleImage(i, graphic_info[i].scale_up_factor);
218 void InitBitmapPointers()
220 int num_images = getImageListSize();
223 // standard size bitmap may have changed -- update default bitmap pointer
224 for (i = 0; i < num_images; i++)
225 if (graphic_info[i].bitmaps)
226 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
229 void InitImageTextures()
233 FreeAllImageTextures();
235 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
237 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
239 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
241 int graphic = global_anim_info[i].graphic[j][k];
243 if (graphic == IMG_UNDEFINED)
246 CreateImageTextures(graphic);
253 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
254 void SetBitmaps_EM(Bitmap **em_bitmap)
256 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
257 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
262 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
263 void SetBitmaps_SP(Bitmap **sp_bitmap)
265 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
269 static int getFontBitmapID(int font_nr)
273 /* (special case: do not use special font for GAME_MODE_LOADING) */
274 if (game_status >= GAME_MODE_TITLE_INITIAL &&
275 game_status <= GAME_MODE_PSEUDO_PREVIEW)
276 special = game_status;
277 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
278 special = GFX_SPECIAL_ARG_MAIN;
281 return font_info[font_nr].special_bitmap_id[special];
286 static int getFontFromToken(char *token)
288 char *value = getHashEntry(font_token_hash, token);
293 /* if font not found, use reliable default value */
294 return FONT_INITIAL_1;
297 void InitFontGraphicInfo()
299 static struct FontBitmapInfo *font_bitmap_info = NULL;
300 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
301 int num_property_mappings = getImageListPropertyMappingSize();
302 int num_font_bitmaps = NUM_FONTS;
305 if (graphic_info == NULL) /* still at startup phase */
307 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
308 getFontBitmapID, getFontFromToken);
313 /* ---------- initialize font graphic definitions ---------- */
315 /* always start with reliable default values (normal font graphics) */
316 for (i = 0; i < NUM_FONTS; i++)
317 font_info[i].graphic = IMG_FONT_INITIAL_1;
319 /* initialize normal font/graphic mapping from static configuration */
320 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
322 int font_nr = font_to_graphic[i].font_nr;
323 int special = font_to_graphic[i].special;
324 int graphic = font_to_graphic[i].graphic;
329 font_info[font_nr].graphic = graphic;
332 /* always start with reliable default values (special font graphics) */
333 for (i = 0; i < NUM_FONTS; i++)
335 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
337 font_info[i].special_graphic[j] = font_info[i].graphic;
338 font_info[i].special_bitmap_id[j] = i;
342 /* initialize special font/graphic mapping from static configuration */
343 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
345 int font_nr = font_to_graphic[i].font_nr;
346 int special = font_to_graphic[i].special;
347 int graphic = font_to_graphic[i].graphic;
348 int base_graphic = font2baseimg(font_nr);
350 if (IS_SPECIAL_GFX_ARG(special))
352 boolean base_redefined =
353 getImageListEntryFromImageID(base_graphic)->redefined;
354 boolean special_redefined =
355 getImageListEntryFromImageID(graphic)->redefined;
356 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
358 /* if the base font ("font.title_1", for example) has been redefined,
359 but not the special font ("font.title_1.LEVELS", for example), do not
360 use an existing (in this case considered obsolete) special font
361 anymore, but use the automatically determined default font */
362 /* special case: cloned special fonts must be explicitly redefined,
363 but are not automatically redefined by redefining base font */
364 if (base_redefined && !special_redefined && !special_cloned)
367 font_info[font_nr].special_graphic[special] = graphic;
368 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
373 /* initialize special font/graphic mapping from dynamic configuration */
374 for (i = 0; i < num_property_mappings; i++)
376 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
377 int special = property_mapping[i].ext3_index;
378 int graphic = property_mapping[i].artwork_index;
383 if (IS_SPECIAL_GFX_ARG(special))
385 font_info[font_nr].special_graphic[special] = graphic;
386 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
391 /* correct special font/graphic mapping for cloned fonts for downwards
392 compatibility of PREVIEW fonts -- this is only needed for implicit
393 redefinition of special font by redefined base font, and only if other
394 fonts are cloned from this special font (like in the "Zelda" level set) */
395 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
397 int font_nr = font_to_graphic[i].font_nr;
398 int special = font_to_graphic[i].special;
399 int graphic = font_to_graphic[i].graphic;
401 if (IS_SPECIAL_GFX_ARG(special))
403 boolean special_redefined =
404 getImageListEntryFromImageID(graphic)->redefined;
405 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
407 if (special_cloned && !special_redefined)
411 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
413 int font_nr2 = font_to_graphic[j].font_nr;
414 int special2 = font_to_graphic[j].special;
415 int graphic2 = font_to_graphic[j].graphic;
417 if (IS_SPECIAL_GFX_ARG(special2) &&
418 graphic2 == graphic_info[graphic].clone_from)
420 font_info[font_nr].special_graphic[special] =
421 font_info[font_nr2].special_graphic[special2];
422 font_info[font_nr].special_bitmap_id[special] =
423 font_info[font_nr2].special_bitmap_id[special2];
430 /* reset non-redefined ".active" font graphics if normal font is redefined */
431 /* (this different treatment is needed because normal and active fonts are
432 independently defined ("active" is not a property of font definitions!) */
433 for (i = 0; i < NUM_FONTS; i++)
435 int font_nr_base = i;
436 int font_nr_active = FONT_ACTIVE(font_nr_base);
438 /* check only those fonts with exist as normal and ".active" variant */
439 if (font_nr_base != font_nr_active)
441 int base_graphic = font_info[font_nr_base].graphic;
442 int active_graphic = font_info[font_nr_active].graphic;
443 boolean base_redefined =
444 getImageListEntryFromImageID(base_graphic)->redefined;
445 boolean active_redefined =
446 getImageListEntryFromImageID(active_graphic)->redefined;
448 /* if the base font ("font.menu_1", for example) has been redefined,
449 but not the active font ("font.menu_1.active", for example), do not
450 use an existing (in this case considered obsolete) active font
451 anymore, but use the automatically determined default font */
452 if (base_redefined && !active_redefined)
453 font_info[font_nr_active].graphic = base_graphic;
455 /* now also check each "special" font (which may be the same as above) */
456 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
458 int base_graphic = font_info[font_nr_base].special_graphic[j];
459 int active_graphic = font_info[font_nr_active].special_graphic[j];
460 boolean base_redefined =
461 getImageListEntryFromImageID(base_graphic)->redefined;
462 boolean active_redefined =
463 getImageListEntryFromImageID(active_graphic)->redefined;
465 /* same as above, but check special graphic definitions, for example:
466 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
467 if (base_redefined && !active_redefined)
469 font_info[font_nr_active].special_graphic[j] =
470 font_info[font_nr_base].special_graphic[j];
471 font_info[font_nr_active].special_bitmap_id[j] =
472 font_info[font_nr_base].special_bitmap_id[j];
478 /* ---------- initialize font bitmap array ---------- */
480 if (font_bitmap_info != NULL)
481 FreeFontInfo(font_bitmap_info);
484 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
486 /* ---------- initialize font bitmap definitions ---------- */
488 for (i = 0; i < NUM_FONTS; i++)
490 if (i < NUM_INITIAL_FONTS)
492 font_bitmap_info[i] = font_initial[i];
496 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
498 int font_bitmap_id = font_info[i].special_bitmap_id[j];
499 int graphic = font_info[i].special_graphic[j];
501 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
502 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
504 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
505 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
508 /* copy font relevant information from graphics information */
509 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
510 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
511 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
512 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
513 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
515 font_bitmap_info[font_bitmap_id].draw_xoffset =
516 graphic_info[graphic].draw_xoffset;
517 font_bitmap_info[font_bitmap_id].draw_yoffset =
518 graphic_info[graphic].draw_yoffset;
520 font_bitmap_info[font_bitmap_id].num_chars =
521 graphic_info[graphic].anim_frames;
522 font_bitmap_info[font_bitmap_id].num_chars_per_line =
523 graphic_info[graphic].anim_frames_per_line;
527 InitFontInfo(font_bitmap_info, num_font_bitmaps,
528 getFontBitmapID, getFontFromToken);
531 void InitGlobalAnimGraphicInfo()
533 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
534 int num_property_mappings = getImageListPropertyMappingSize();
537 if (graphic_info == NULL) /* still at startup phase */
540 /* always start with reliable default values (no global animations) */
541 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
542 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
543 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
544 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
546 /* initialize global animation definitions from static configuration */
547 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
549 int j = GLOBAL_ANIM_ID_PART_BASE;
550 int k = GFX_SPECIAL_ARG_DEFAULT;
552 global_anim_info[i].graphic[j][k] = IMG_GLOBAL_ANIM_1_GFX + i;
555 /* initialize global animation definitions from dynamic configuration */
556 for (i = 0; i < num_property_mappings; i++)
558 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
559 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
560 int special = property_mapping[i].ext3_index;
561 int graphic = property_mapping[i].artwork_index;
563 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
566 /* set animation part to base part, if not specified */
567 if (!IS_GLOBAL_ANIM_PART(part_nr))
568 part_nr = GLOBAL_ANIM_ID_PART_BASE;
570 /* set animation screen to default, if not specified */
571 if (!IS_SPECIAL_GFX_ARG(special))
572 special = GFX_SPECIAL_ARG_DEFAULT;
574 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
578 printf("::: InitGlobalAnimGraphicInfo\n");
580 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
581 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
582 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
583 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
584 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
585 printf("::: - anim %d, part %d, mode %d => %d\n",
586 i, j, k, global_anim_info[i].graphic[j][k]);
590 void InitElementGraphicInfo()
592 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
593 int num_property_mappings = getImageListPropertyMappingSize();
596 if (graphic_info == NULL) /* still at startup phase */
599 /* set values to -1 to identify later as "uninitialized" values */
600 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
602 for (act = 0; act < NUM_ACTIONS; act++)
604 element_info[i].graphic[act] = -1;
605 element_info[i].crumbled[act] = -1;
607 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
609 element_info[i].direction_graphic[act][dir] = -1;
610 element_info[i].direction_crumbled[act][dir] = -1;
617 /* initialize normal element/graphic mapping from static configuration */
618 for (i = 0; element_to_graphic[i].element > -1; i++)
620 int element = element_to_graphic[i].element;
621 int action = element_to_graphic[i].action;
622 int direction = element_to_graphic[i].direction;
623 boolean crumbled = element_to_graphic[i].crumbled;
624 int graphic = element_to_graphic[i].graphic;
625 int base_graphic = el2baseimg(element);
627 if (graphic_info[graphic].bitmap == NULL)
630 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
633 boolean base_redefined =
634 getImageListEntryFromImageID(base_graphic)->redefined;
635 boolean act_dir_redefined =
636 getImageListEntryFromImageID(graphic)->redefined;
638 /* if the base graphic ("emerald", for example) has been redefined,
639 but not the action graphic ("emerald.falling", for example), do not
640 use an existing (in this case considered obsolete) action graphic
641 anymore, but use the automatically determined default graphic */
642 if (base_redefined && !act_dir_redefined)
647 action = ACTION_DEFAULT;
652 element_info[element].direction_crumbled[action][direction] = graphic;
654 element_info[element].crumbled[action] = graphic;
659 element_info[element].direction_graphic[action][direction] = graphic;
661 element_info[element].graphic[action] = graphic;
665 /* initialize normal element/graphic mapping from dynamic configuration */
666 for (i = 0; i < num_property_mappings; i++)
668 int element = property_mapping[i].base_index;
669 int action = property_mapping[i].ext1_index;
670 int direction = property_mapping[i].ext2_index;
671 int special = property_mapping[i].ext3_index;
672 int graphic = property_mapping[i].artwork_index;
673 boolean crumbled = FALSE;
675 if (special == GFX_SPECIAL_ARG_CRUMBLED)
681 if (graphic_info[graphic].bitmap == NULL)
684 if (element >= MAX_NUM_ELEMENTS || special != -1)
688 action = ACTION_DEFAULT;
693 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
694 element_info[element].direction_crumbled[action][dir] = -1;
697 element_info[element].direction_crumbled[action][direction] = graphic;
699 element_info[element].crumbled[action] = graphic;
704 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
705 element_info[element].direction_graphic[action][dir] = -1;
708 element_info[element].direction_graphic[action][direction] = graphic;
710 element_info[element].graphic[action] = graphic;
714 /* now copy all graphics that are defined to be cloned from other graphics */
715 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
717 int graphic = element_info[i].graphic[ACTION_DEFAULT];
718 int crumbled_like, diggable_like;
723 crumbled_like = graphic_info[graphic].crumbled_like;
724 diggable_like = graphic_info[graphic].diggable_like;
726 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
728 for (act = 0; act < NUM_ACTIONS; act++)
729 element_info[i].crumbled[act] =
730 element_info[crumbled_like].crumbled[act];
731 for (act = 0; act < NUM_ACTIONS; act++)
732 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
733 element_info[i].direction_crumbled[act][dir] =
734 element_info[crumbled_like].direction_crumbled[act][dir];
737 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
739 element_info[i].graphic[ACTION_DIGGING] =
740 element_info[diggable_like].graphic[ACTION_DIGGING];
741 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
742 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
743 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
747 /* set hardcoded definitions for some runtime elements without graphic */
748 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
750 /* set hardcoded definitions for some internal elements without graphic */
751 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
753 if (IS_EDITOR_CASCADE_INACTIVE(i))
754 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
755 else if (IS_EDITOR_CASCADE_ACTIVE(i))
756 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
759 /* now set all undefined/invalid graphics to -1 to set to default after it */
760 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
762 for (act = 0; act < NUM_ACTIONS; act++)
766 graphic = element_info[i].graphic[act];
767 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
768 element_info[i].graphic[act] = -1;
770 graphic = element_info[i].crumbled[act];
771 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
772 element_info[i].crumbled[act] = -1;
774 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
776 graphic = element_info[i].direction_graphic[act][dir];
777 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
778 element_info[i].direction_graphic[act][dir] = -1;
780 graphic = element_info[i].direction_crumbled[act][dir];
781 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
782 element_info[i].direction_crumbled[act][dir] = -1;
789 /* adjust graphics with 2nd tile for movement according to direction
790 (do this before correcting '-1' values to minimize calculations) */
791 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
793 for (act = 0; act < NUM_ACTIONS; act++)
795 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
797 int graphic = element_info[i].direction_graphic[act][dir];
798 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
800 if (act == ACTION_FALLING) /* special case */
801 graphic = element_info[i].graphic[act];
804 graphic_info[graphic].double_movement &&
805 graphic_info[graphic].swap_double_tiles != 0)
807 struct GraphicInfo *g = &graphic_info[graphic];
808 int src_x_front = g->src_x;
809 int src_y_front = g->src_y;
810 int src_x_back = g->src_x + g->offset2_x;
811 int src_y_back = g->src_y + g->offset2_y;
812 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
814 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
815 src_y_front < src_y_back);
816 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
817 boolean swap_movement_tiles_autodetected =
818 (!frames_are_ordered_diagonally &&
819 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
820 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
821 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
822 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
825 /* swap frontside and backside graphic tile coordinates, if needed */
826 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
828 /* get current (wrong) backside tile coordinates */
829 getFixedGraphicSourceExt(graphic, 0, &dummy,
830 &src_x_back, &src_y_back, TRUE);
832 /* set frontside tile coordinates to backside tile coordinates */
833 g->src_x = src_x_back;
834 g->src_y = src_y_back;
836 /* invert tile offset to point to new backside tile coordinates */
840 /* do not swap front and backside tiles again after correction */
841 g->swap_double_tiles = 0;
850 /* now set all '-1' values to element specific default values */
851 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
853 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
854 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
855 int default_direction_graphic[NUM_DIRECTIONS_FULL];
856 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
858 if (default_graphic == -1)
859 default_graphic = IMG_UNKNOWN;
861 if (default_crumbled == -1)
862 default_crumbled = default_graphic;
864 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
866 default_direction_graphic[dir] =
867 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
868 default_direction_crumbled[dir] =
869 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
871 if (default_direction_graphic[dir] == -1)
872 default_direction_graphic[dir] = default_graphic;
874 if (default_direction_crumbled[dir] == -1)
875 default_direction_crumbled[dir] = default_direction_graphic[dir];
878 for (act = 0; act < NUM_ACTIONS; act++)
880 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
881 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
882 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
883 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
884 act == ACTION_TURNING_FROM_RIGHT ||
885 act == ACTION_TURNING_FROM_UP ||
886 act == ACTION_TURNING_FROM_DOWN);
888 /* generic default action graphic (defined by "[default]" directive) */
889 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
890 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
891 int default_remove_graphic = IMG_EMPTY;
893 if (act_remove && default_action_graphic != -1)
894 default_remove_graphic = default_action_graphic;
896 /* look for special default action graphic (classic game specific) */
897 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
898 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
899 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
900 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
901 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
902 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
904 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
905 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
906 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
907 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
908 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
909 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
911 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
912 /* !!! make this better !!! */
913 if (i == EL_EMPTY_SPACE)
915 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
916 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
919 if (default_action_graphic == -1)
920 default_action_graphic = default_graphic;
922 if (default_action_crumbled == -1)
923 default_action_crumbled = default_action_graphic;
925 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
927 /* use action graphic as the default direction graphic, if undefined */
928 int default_action_direction_graphic = element_info[i].graphic[act];
929 int default_action_direction_crumbled = element_info[i].crumbled[act];
931 /* no graphic for current action -- use default direction graphic */
932 if (default_action_direction_graphic == -1)
933 default_action_direction_graphic =
934 (act_remove ? default_remove_graphic :
936 element_info[i].direction_graphic[ACTION_TURNING][dir] :
937 default_action_graphic != default_graphic ?
938 default_action_graphic :
939 default_direction_graphic[dir]);
941 if (element_info[i].direction_graphic[act][dir] == -1)
942 element_info[i].direction_graphic[act][dir] =
943 default_action_direction_graphic;
945 if (default_action_direction_crumbled == -1)
946 default_action_direction_crumbled =
947 element_info[i].direction_graphic[act][dir];
949 if (element_info[i].direction_crumbled[act][dir] == -1)
950 element_info[i].direction_crumbled[act][dir] =
951 default_action_direction_crumbled;
954 /* no graphic for this specific action -- use default action graphic */
955 if (element_info[i].graphic[act] == -1)
956 element_info[i].graphic[act] =
957 (act_remove ? default_remove_graphic :
958 act_turning ? element_info[i].graphic[ACTION_TURNING] :
959 default_action_graphic);
961 if (element_info[i].crumbled[act] == -1)
962 element_info[i].crumbled[act] = element_info[i].graphic[act];
969 void InitElementSpecialGraphicInfo()
971 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
972 int num_property_mappings = getImageListPropertyMappingSize();
975 /* always start with reliable default values */
976 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
977 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
978 element_info[i].special_graphic[j] =
979 element_info[i].graphic[ACTION_DEFAULT];
981 /* initialize special element/graphic mapping from static configuration */
982 for (i = 0; element_to_special_graphic[i].element > -1; i++)
984 int element = element_to_special_graphic[i].element;
985 int special = element_to_special_graphic[i].special;
986 int graphic = element_to_special_graphic[i].graphic;
987 int base_graphic = el2baseimg(element);
988 boolean base_redefined =
989 getImageListEntryFromImageID(base_graphic)->redefined;
990 boolean special_redefined =
991 getImageListEntryFromImageID(graphic)->redefined;
993 /* if the base graphic ("emerald", for example) has been redefined,
994 but not the special graphic ("emerald.EDITOR", for example), do not
995 use an existing (in this case considered obsolete) special graphic
996 anymore, but use the automatically created (down-scaled) graphic */
997 if (base_redefined && !special_redefined)
1000 element_info[element].special_graphic[special] = graphic;
1003 /* initialize special element/graphic mapping from dynamic configuration */
1004 for (i = 0; i < num_property_mappings; i++)
1006 int element = property_mapping[i].base_index;
1007 int action = property_mapping[i].ext1_index;
1008 int direction = property_mapping[i].ext2_index;
1009 int special = property_mapping[i].ext3_index;
1010 int graphic = property_mapping[i].artwork_index;
1012 /* for action ".active", replace element with active element, if exists */
1013 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1015 element = ELEMENT_ACTIVE(element);
1019 if (element >= MAX_NUM_ELEMENTS)
1022 /* do not change special graphic if action or direction was specified */
1023 if (action != -1 || direction != -1)
1026 if (IS_SPECIAL_GFX_ARG(special))
1027 element_info[element].special_graphic[special] = graphic;
1030 /* now set all undefined/invalid graphics to default */
1031 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1032 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1033 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1034 element_info[i].special_graphic[j] =
1035 element_info[i].graphic[ACTION_DEFAULT];
1038 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1040 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1041 return get_parameter_value(value_raw, suffix, type);
1043 if (strEqual(value_raw, ARG_UNDEFINED))
1044 return ARG_UNDEFINED_VALUE;
1046 if (type == TYPE_ELEMENT)
1048 char *value = getHashEntry(element_token_hash, value_raw);
1052 Error(ERR_INFO_LINE, "-");
1053 Error(ERR_INFO, "warning: error found in config file:");
1054 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1055 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1056 Error(ERR_INFO, "custom graphic rejected for this element/action");
1057 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1058 Error(ERR_INFO_LINE, "-");
1061 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1063 else if (type == TYPE_GRAPHIC)
1065 char *value = getHashEntry(graphic_token_hash, value_raw);
1066 int fallback_graphic = IMG_CHAR_EXCLAM;
1070 Error(ERR_INFO_LINE, "-");
1071 Error(ERR_INFO, "warning: error found in config file:");
1072 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1073 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1074 Error(ERR_INFO, "custom graphic rejected for this element/action");
1075 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1076 Error(ERR_INFO_LINE, "-");
1079 return (value != NULL ? atoi(value) : fallback_graphic);
1085 static int get_scaled_graphic_width(int graphic)
1087 int original_width = getOriginalImageWidthFromImageID(graphic);
1088 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1090 return original_width * scale_up_factor;
1093 static int get_scaled_graphic_height(int graphic)
1095 int original_height = getOriginalImageHeightFromImageID(graphic);
1096 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1098 return original_height * scale_up_factor;
1101 static void set_graphic_parameters_ext(int graphic, int *parameter,
1102 Bitmap **src_bitmaps)
1104 struct GraphicInfo *g = &graphic_info[graphic];
1105 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1106 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1107 int anim_frames_per_line = 1;
1109 /* always start with reliable default values */
1110 g->src_image_width = 0;
1111 g->src_image_height = 0;
1114 g->width = TILEX; /* default for element graphics */
1115 g->height = TILEY; /* default for element graphics */
1116 g->offset_x = 0; /* one or both of these values ... */
1117 g->offset_y = 0; /* ... will be corrected later */
1118 g->offset2_x = 0; /* one or both of these values ... */
1119 g->offset2_y = 0; /* ... will be corrected later */
1120 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1121 g->crumbled_like = -1; /* do not use clone element */
1122 g->diggable_like = -1; /* do not use clone element */
1123 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1124 g->scale_up_factor = 1; /* default: no scaling up */
1125 g->tile_size = TILESIZE; /* default: standard tile size */
1126 g->clone_from = -1; /* do not use clone graphic */
1127 g->anim_delay_fixed = 0;
1128 g->anim_delay_random = 0;
1129 g->post_delay_fixed = 0;
1130 g->post_delay_random = 0;
1131 g->fade_mode = FADE_MODE_DEFAULT;
1135 g->align = ALIGN_CENTER; /* default for title screens */
1136 g->valign = VALIGN_MIDDLE; /* default for title screens */
1137 g->sort_priority = 0; /* default for title screens */
1139 g->style = STYLE_DEFAULT;
1141 g->bitmaps = src_bitmaps;
1142 g->bitmap = src_bitmap;
1144 /* optional zoom factor for scaling up the image to a larger size */
1145 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1146 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1147 if (g->scale_up_factor < 1)
1148 g->scale_up_factor = 1; /* no scaling */
1150 /* optional tile size for using non-standard image size */
1151 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1153 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1156 // CHECK: should tile sizes less than standard tile size be allowed?
1157 if (g->tile_size < TILESIZE)
1158 g->tile_size = TILESIZE; /* standard tile size */
1161 // when setting tile size, also set width and height accordingly
1162 g->width = g->tile_size;
1163 g->height = g->tile_size;
1166 if (g->use_image_size)
1168 /* set new default bitmap size (with scaling, but without small images) */
1169 g->width = get_scaled_graphic_width(graphic);
1170 g->height = get_scaled_graphic_height(graphic);
1173 /* optional width and height of each animation frame */
1174 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1175 g->width = parameter[GFX_ARG_WIDTH];
1176 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1177 g->height = parameter[GFX_ARG_HEIGHT];
1179 /* optional x and y tile position of animation frame sequence */
1180 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1181 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1182 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1183 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1185 /* optional x and y pixel position of animation frame sequence */
1186 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1187 g->src_x = parameter[GFX_ARG_X];
1188 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1189 g->src_y = parameter[GFX_ARG_Y];
1195 Error(ERR_INFO_LINE, "-");
1196 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1197 g->width, getTokenFromImageID(graphic), TILEX);
1198 Error(ERR_INFO_LINE, "-");
1200 g->width = TILEX; /* will be checked to be inside bitmap later */
1205 Error(ERR_INFO_LINE, "-");
1206 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1207 g->height, getTokenFromImageID(graphic), TILEY);
1208 Error(ERR_INFO_LINE, "-");
1210 g->height = TILEY; /* will be checked to be inside bitmap later */
1216 /* get final bitmap size (with scaling, but without small images) */
1217 int src_image_width = get_scaled_graphic_width(graphic);
1218 int src_image_height = get_scaled_graphic_height(graphic);
1220 if (src_image_width == 0 || src_image_height == 0)
1222 /* only happens when loaded outside artwork system (like "global.busy") */
1223 src_image_width = src_bitmap->width;
1224 src_image_height = src_bitmap->height;
1227 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1229 anim_frames_per_row = src_image_width / g->tile_size;
1230 anim_frames_per_col = src_image_height / g->tile_size;
1234 anim_frames_per_row = src_image_width / g->width;
1235 anim_frames_per_col = src_image_height / g->height;
1238 g->src_image_width = src_image_width;
1239 g->src_image_height = src_image_height;
1242 /* correct x or y offset dependent of vertical or horizontal frame order */
1243 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1245 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1246 parameter[GFX_ARG_OFFSET] : g->height);
1247 anim_frames_per_line = anim_frames_per_col;
1249 else /* frames are ordered horizontally */
1251 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1252 parameter[GFX_ARG_OFFSET] : g->width);
1253 anim_frames_per_line = anim_frames_per_row;
1256 /* optionally, the x and y offset of frames can be specified directly */
1257 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1258 g->offset_x = parameter[GFX_ARG_XOFFSET];
1259 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1260 g->offset_y = parameter[GFX_ARG_YOFFSET];
1262 /* optionally, moving animations may have separate start and end graphics */
1263 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1265 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1266 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1268 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1269 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1270 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1271 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1272 else /* frames are ordered horizontally */
1273 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1274 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1276 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1277 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1278 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1279 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1280 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1282 /* optionally, the second movement tile can be specified as start tile */
1283 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1284 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1286 /* automatically determine correct number of frames, if not defined */
1287 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1288 g->anim_frames = parameter[GFX_ARG_FRAMES];
1289 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1290 g->anim_frames = anim_frames_per_row;
1291 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1292 g->anim_frames = anim_frames_per_col;
1296 if (g->anim_frames == 0) /* frames must be at least 1 */
1299 g->anim_frames_per_line =
1300 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1301 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1303 g->anim_delay = parameter[GFX_ARG_DELAY];
1304 if (g->anim_delay == 0) /* delay must be at least 1 */
1307 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1309 /* automatically determine correct start frame, if not defined */
1310 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1311 g->anim_start_frame = 0;
1312 else if (g->anim_mode & ANIM_REVERSE)
1313 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1315 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1317 /* animation synchronized with global frame counter, not move position */
1318 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1320 /* optional element for cloning crumble graphics */
1321 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1322 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1324 /* optional element for cloning digging graphics */
1325 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1326 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1328 /* optional border size for "crumbling" diggable graphics */
1329 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1330 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1332 /* this is only used for player "boring" and "sleeping" actions */
1333 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1334 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1335 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1336 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1337 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1338 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1339 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1340 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1342 /* this is only used for toon animations */
1343 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1344 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1345 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1346 g->step_frames = parameter[GFX_ARG_STEP_FRAMES];
1347 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1348 g->direction = parameter[GFX_ARG_DIRECTION];
1349 g->position = parameter[GFX_ARG_POSITION];
1350 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1351 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1353 /* this is only used for drawing font characters */
1354 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1355 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1357 /* this is only used for drawing envelope graphics */
1358 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1360 /* optional graphic for cloning all graphics settings */
1361 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1362 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1364 /* optional settings for drawing title screens and title messages */
1365 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1366 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1367 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1368 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1369 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1370 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1371 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1372 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1373 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1374 g->align = parameter[GFX_ARG_ALIGN];
1375 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1376 g->valign = parameter[GFX_ARG_VALIGN];
1377 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1378 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1380 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1381 g->class = parameter[GFX_ARG_CLASS];
1382 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1383 g->style = parameter[GFX_ARG_STYLE];
1385 /* this is only used for drawing menu buttons and text */
1386 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1387 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1388 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1389 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1392 static void set_graphic_parameters(int graphic)
1394 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1395 char **parameter_raw = image->parameter;
1396 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1397 int parameter[NUM_GFX_ARGS];
1400 /* if fallback to default artwork is done, also use the default parameters */
1401 if (image->fallback_to_default)
1402 parameter_raw = image->default_parameter;
1404 /* get integer values from string parameters */
1405 for (i = 0; i < NUM_GFX_ARGS; i++)
1406 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1407 image_config_suffix[i].token,
1408 image_config_suffix[i].type);
1410 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1412 UPDATE_BUSY_STATE();
1415 static void set_cloned_graphic_parameters(int graphic)
1417 int fallback_graphic = IMG_CHAR_EXCLAM;
1418 int max_num_images = getImageListSize();
1419 int clone_graphic = graphic_info[graphic].clone_from;
1420 int num_references_followed = 1;
1422 while (graphic_info[clone_graphic].clone_from != -1 &&
1423 num_references_followed < max_num_images)
1425 clone_graphic = graphic_info[clone_graphic].clone_from;
1427 num_references_followed++;
1430 if (num_references_followed >= max_num_images)
1432 Error(ERR_INFO_LINE, "-");
1433 Error(ERR_INFO, "warning: error found in config file:");
1434 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1435 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1436 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1437 Error(ERR_INFO, "custom graphic rejected for this element/action");
1439 if (graphic == fallback_graphic)
1440 Error(ERR_EXIT, "no fallback graphic available");
1442 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1443 Error(ERR_INFO_LINE, "-");
1445 graphic_info[graphic] = graphic_info[fallback_graphic];
1449 graphic_info[graphic] = graphic_info[clone_graphic];
1450 graphic_info[graphic].clone_from = clone_graphic;
1454 static void InitGraphicInfo()
1456 int fallback_graphic = IMG_CHAR_EXCLAM;
1457 int num_images = getImageListSize();
1460 /* use image size as default values for width and height for these images */
1461 static int full_size_graphics[] =
1464 IMG_GLOBAL_BORDER_MAIN,
1465 IMG_GLOBAL_BORDER_SCORES,
1466 IMG_GLOBAL_BORDER_EDITOR,
1467 IMG_GLOBAL_BORDER_PLAYING,
1470 IMG_BACKGROUND_ENVELOPE_1,
1471 IMG_BACKGROUND_ENVELOPE_2,
1472 IMG_BACKGROUND_ENVELOPE_3,
1473 IMG_BACKGROUND_ENVELOPE_4,
1474 IMG_BACKGROUND_REQUEST,
1477 IMG_BACKGROUND_TITLE_INITIAL,
1478 IMG_BACKGROUND_TITLE,
1479 IMG_BACKGROUND_MAIN,
1480 IMG_BACKGROUND_LEVELS,
1481 IMG_BACKGROUND_LEVELNR,
1482 IMG_BACKGROUND_SCORES,
1483 IMG_BACKGROUND_EDITOR,
1484 IMG_BACKGROUND_INFO,
1485 IMG_BACKGROUND_INFO_ELEMENTS,
1486 IMG_BACKGROUND_INFO_MUSIC,
1487 IMG_BACKGROUND_INFO_CREDITS,
1488 IMG_BACKGROUND_INFO_PROGRAM,
1489 IMG_BACKGROUND_INFO_VERSION,
1490 IMG_BACKGROUND_INFO_LEVELSET,
1491 IMG_BACKGROUND_SETUP,
1492 IMG_BACKGROUND_PLAYING,
1493 IMG_BACKGROUND_DOOR,
1494 IMG_BACKGROUND_TAPE,
1495 IMG_BACKGROUND_PANEL,
1496 IMG_BACKGROUND_PALETTE,
1497 IMG_BACKGROUND_TOOLBOX,
1499 IMG_TITLESCREEN_INITIAL_1,
1500 IMG_TITLESCREEN_INITIAL_2,
1501 IMG_TITLESCREEN_INITIAL_3,
1502 IMG_TITLESCREEN_INITIAL_4,
1503 IMG_TITLESCREEN_INITIAL_5,
1510 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1511 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1512 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1513 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1514 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1515 IMG_BACKGROUND_TITLEMESSAGE_1,
1516 IMG_BACKGROUND_TITLEMESSAGE_2,
1517 IMG_BACKGROUND_TITLEMESSAGE_3,
1518 IMG_BACKGROUND_TITLEMESSAGE_4,
1519 IMG_BACKGROUND_TITLEMESSAGE_5,
1524 checked_free(graphic_info);
1526 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1528 /* initialize "use_image_size" flag with default value */
1529 for (i = 0; i < num_images; i++)
1530 graphic_info[i].use_image_size = FALSE;
1532 /* initialize "use_image_size" flag from static configuration above */
1533 for (i = 0; full_size_graphics[i] != -1; i++)
1534 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1536 /* first set all graphic paramaters ... */
1537 for (i = 0; i < num_images; i++)
1538 set_graphic_parameters(i);
1540 /* ... then copy these parameters for cloned graphics */
1541 for (i = 0; i < num_images; i++)
1542 if (graphic_info[i].clone_from != -1)
1543 set_cloned_graphic_parameters(i);
1545 for (i = 0; i < num_images; i++)
1550 int first_frame, last_frame;
1551 int src_bitmap_width, src_bitmap_height;
1553 /* now check if no animation frames are outside of the loaded image */
1555 if (graphic_info[i].bitmap == NULL)
1556 continue; /* skip check for optional images that are undefined */
1558 /* get image size (this can differ from the standard element tile size!) */
1559 width = graphic_info[i].width;
1560 height = graphic_info[i].height;
1562 /* get final bitmap size (with scaling, but without small images) */
1563 src_bitmap_width = graphic_info[i].src_image_width;
1564 src_bitmap_height = graphic_info[i].src_image_height;
1566 /* check if first animation frame is inside specified bitmap */
1569 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1571 /* this avoids calculating wrong start position for out-of-bounds frame */
1572 src_x = graphic_info[i].src_x;
1573 src_y = graphic_info[i].src_y;
1575 if (src_x < 0 || src_y < 0 ||
1576 src_x + width > src_bitmap_width ||
1577 src_y + height > src_bitmap_height)
1579 Error(ERR_INFO_LINE, "-");
1580 Error(ERR_INFO, "warning: error found in config file:");
1581 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1582 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1583 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1585 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1586 src_x, src_y, src_bitmap_width, src_bitmap_height);
1587 Error(ERR_INFO, "custom graphic rejected for this element/action");
1589 if (i == fallback_graphic)
1590 Error(ERR_EXIT, "no fallback graphic available");
1592 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1593 Error(ERR_INFO_LINE, "-");
1595 graphic_info[i] = graphic_info[fallback_graphic];
1598 /* check if last animation frame is inside specified bitmap */
1600 last_frame = graphic_info[i].anim_frames - 1;
1601 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1603 if (src_x < 0 || src_y < 0 ||
1604 src_x + width > src_bitmap_width ||
1605 src_y + height > src_bitmap_height)
1607 Error(ERR_INFO_LINE, "-");
1608 Error(ERR_INFO, "warning: error found in config file:");
1609 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1610 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1611 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1613 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1614 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1615 Error(ERR_INFO, "::: %d, %d", width, height);
1616 Error(ERR_INFO, "custom graphic rejected for this element/action");
1618 if (i == fallback_graphic)
1619 Error(ERR_EXIT, "no fallback graphic available");
1621 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1622 Error(ERR_INFO_LINE, "-");
1624 graphic_info[i] = graphic_info[fallback_graphic];
1629 static void InitGraphicCompatibilityInfo()
1631 struct FileInfo *fi_global_door =
1632 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1633 int num_images = getImageListSize();
1636 /* the following compatibility handling is needed for the following case:
1637 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1638 graphics mainly used for door and panel graphics, like editor, tape and
1639 in-game buttons with hard-coded bitmap positions and button sizes; as
1640 these graphics now have individual definitions, redefining "global.door"
1641 to change all these graphics at once like before does not work anymore
1642 (because all those individual definitions still have their default values);
1643 to solve this, remap all those individual definitions that are not
1644 redefined to the new bitmap of "global.door" if it was redefined */
1646 /* special compatibility handling if image "global.door" was redefined */
1647 if (fi_global_door->redefined)
1649 for (i = 0; i < num_images; i++)
1651 struct FileInfo *fi = getImageListEntryFromImageID(i);
1653 /* process only those images that still use the default settings */
1656 /* process all images which default to same image as "global.door" */
1657 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1659 // printf("::: special treatment needed for token '%s'\n", fi->token);
1661 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1667 InitGraphicCompatibilityInfo_Doors();
1670 static void InitElementSoundInfo()
1672 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1673 int num_property_mappings = getSoundListPropertyMappingSize();
1676 /* set values to -1 to identify later as "uninitialized" values */
1677 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1678 for (act = 0; act < NUM_ACTIONS; act++)
1679 element_info[i].sound[act] = -1;
1681 /* initialize element/sound mapping from static configuration */
1682 for (i = 0; element_to_sound[i].element > -1; i++)
1684 int element = element_to_sound[i].element;
1685 int action = element_to_sound[i].action;
1686 int sound = element_to_sound[i].sound;
1687 boolean is_class = element_to_sound[i].is_class;
1690 action = ACTION_DEFAULT;
1693 element_info[element].sound[action] = sound;
1695 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1696 if (strEqual(element_info[j].class_name,
1697 element_info[element].class_name))
1698 element_info[j].sound[action] = sound;
1701 /* initialize element class/sound mapping from dynamic configuration */
1702 for (i = 0; i < num_property_mappings; i++)
1704 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1705 int action = property_mapping[i].ext1_index;
1706 int sound = property_mapping[i].artwork_index;
1708 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1712 action = ACTION_DEFAULT;
1714 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1715 if (strEqual(element_info[j].class_name,
1716 element_info[element_class].class_name))
1717 element_info[j].sound[action] = sound;
1720 /* initialize element/sound mapping from dynamic configuration */
1721 for (i = 0; i < num_property_mappings; i++)
1723 int element = property_mapping[i].base_index;
1724 int action = property_mapping[i].ext1_index;
1725 int sound = property_mapping[i].artwork_index;
1727 if (element >= MAX_NUM_ELEMENTS)
1731 action = ACTION_DEFAULT;
1733 element_info[element].sound[action] = sound;
1736 /* now set all '-1' values to element specific default values */
1737 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1739 for (act = 0; act < NUM_ACTIONS; act++)
1741 /* generic default action sound (defined by "[default]" directive) */
1742 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1744 /* look for special default action sound (classic game specific) */
1745 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1746 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1747 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1748 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1749 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1750 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1752 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1753 /* !!! make this better !!! */
1754 if (i == EL_EMPTY_SPACE)
1755 default_action_sound = element_info[EL_DEFAULT].sound[act];
1757 /* no sound for this specific action -- use default action sound */
1758 if (element_info[i].sound[act] == -1)
1759 element_info[i].sound[act] = default_action_sound;
1763 /* copy sound settings to some elements that are only stored in level file
1764 in native R'n'D levels, but are used by game engine in native EM levels */
1765 for (i = 0; copy_properties[i][0] != -1; i++)
1766 for (j = 1; j <= 4; j++)
1767 for (act = 0; act < NUM_ACTIONS; act++)
1768 element_info[copy_properties[i][j]].sound[act] =
1769 element_info[copy_properties[i][0]].sound[act];
1772 static void InitGameModeSoundInfo()
1776 /* set values to -1 to identify later as "uninitialized" values */
1777 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1780 /* initialize gamemode/sound mapping from static configuration */
1781 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1783 int gamemode = gamemode_to_sound[i].gamemode;
1784 int sound = gamemode_to_sound[i].sound;
1787 gamemode = GAME_MODE_DEFAULT;
1789 menu.sound[gamemode] = sound;
1792 /* now set all '-1' values to levelset specific default values */
1793 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1794 if (menu.sound[i] == -1)
1795 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1798 static void set_sound_parameters(int sound, char **parameter_raw)
1800 int parameter[NUM_SND_ARGS];
1803 /* get integer values from string parameters */
1804 for (i = 0; i < NUM_SND_ARGS; i++)
1806 get_parameter_value(parameter_raw[i],
1807 sound_config_suffix[i].token,
1808 sound_config_suffix[i].type);
1810 /* explicit loop mode setting in configuration overrides default value */
1811 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1812 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1814 /* sound volume to change the original volume when loading the sound file */
1815 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1817 /* sound priority to give certain sounds a higher or lower priority */
1818 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1821 static void InitSoundInfo()
1823 int *sound_effect_properties;
1824 int num_sounds = getSoundListSize();
1827 checked_free(sound_info);
1829 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1830 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1832 /* initialize sound effect for all elements to "no sound" */
1833 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1834 for (j = 0; j < NUM_ACTIONS; j++)
1835 element_info[i].sound[j] = SND_UNDEFINED;
1837 for (i = 0; i < num_sounds; i++)
1839 struct FileInfo *sound = getSoundListEntry(i);
1840 int len_effect_text = strlen(sound->token);
1842 sound_effect_properties[i] = ACTION_OTHER;
1843 sound_info[i].loop = FALSE; /* default: play sound only once */
1845 /* determine all loop sounds and identify certain sound classes */
1847 for (j = 0; element_action_info[j].suffix; j++)
1849 int len_action_text = strlen(element_action_info[j].suffix);
1851 if (len_action_text < len_effect_text &&
1852 strEqual(&sound->token[len_effect_text - len_action_text],
1853 element_action_info[j].suffix))
1855 sound_effect_properties[i] = element_action_info[j].value;
1856 sound_info[i].loop = element_action_info[j].is_loop_sound;
1862 /* associate elements and some selected sound actions */
1864 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1866 if (element_info[j].class_name)
1868 int len_class_text = strlen(element_info[j].class_name);
1870 if (len_class_text + 1 < len_effect_text &&
1871 strncmp(sound->token,
1872 element_info[j].class_name, len_class_text) == 0 &&
1873 sound->token[len_class_text] == '.')
1875 int sound_action_value = sound_effect_properties[i];
1877 element_info[j].sound[sound_action_value] = i;
1882 set_sound_parameters(i, sound->parameter);
1885 free(sound_effect_properties);
1888 static void InitGameModeMusicInfo()
1890 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1891 int num_property_mappings = getMusicListPropertyMappingSize();
1892 int default_levelset_music = -1;
1895 /* set values to -1 to identify later as "uninitialized" values */
1896 for (i = 0; i < MAX_LEVELS; i++)
1897 levelset.music[i] = -1;
1898 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1901 /* initialize gamemode/music mapping from static configuration */
1902 for (i = 0; gamemode_to_music[i].music > -1; i++)
1904 int gamemode = gamemode_to_music[i].gamemode;
1905 int music = gamemode_to_music[i].music;
1908 gamemode = GAME_MODE_DEFAULT;
1910 menu.music[gamemode] = music;
1913 /* initialize gamemode/music mapping from dynamic configuration */
1914 for (i = 0; i < num_property_mappings; i++)
1916 int prefix = property_mapping[i].base_index;
1917 int gamemode = property_mapping[i].ext1_index;
1918 int level = property_mapping[i].ext2_index;
1919 int music = property_mapping[i].artwork_index;
1921 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1925 gamemode = GAME_MODE_DEFAULT;
1927 /* level specific music only allowed for in-game music */
1928 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1929 gamemode = GAME_MODE_PLAYING;
1934 default_levelset_music = music;
1937 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1938 levelset.music[level] = music;
1939 if (gamemode != GAME_MODE_PLAYING)
1940 menu.music[gamemode] = music;
1943 /* now set all '-1' values to menu specific default values */
1944 /* (undefined values of "levelset.music[]" might stay at "-1" to
1945 allow dynamic selection of music files from music directory!) */
1946 for (i = 0; i < MAX_LEVELS; i++)
1947 if (levelset.music[i] == -1)
1948 levelset.music[i] = default_levelset_music;
1949 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1950 if (menu.music[i] == -1)
1951 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1954 static void set_music_parameters(int music, char **parameter_raw)
1956 int parameter[NUM_MUS_ARGS];
1959 /* get integer values from string parameters */
1960 for (i = 0; i < NUM_MUS_ARGS; i++)
1962 get_parameter_value(parameter_raw[i],
1963 music_config_suffix[i].token,
1964 music_config_suffix[i].type);
1966 /* explicit loop mode setting in configuration overrides default value */
1967 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1968 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1971 static void InitMusicInfo()
1973 int num_music = getMusicListSize();
1976 checked_free(music_info);
1978 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1980 for (i = 0; i < num_music; i++)
1982 struct FileInfo *music = getMusicListEntry(i);
1983 int len_music_text = strlen(music->token);
1985 music_info[i].loop = TRUE; /* default: play music in loop mode */
1987 /* determine all loop music */
1989 for (j = 0; music_prefix_info[j].prefix; j++)
1991 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1993 if (len_prefix_text < len_music_text &&
1994 strncmp(music->token,
1995 music_prefix_info[j].prefix, len_prefix_text) == 0)
1997 music_info[i].loop = music_prefix_info[j].is_loop_music;
2003 set_music_parameters(i, music->parameter);
2007 static void ReinitializeGraphics()
2009 print_timestamp_init("ReinitializeGraphics");
2011 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2013 InitGraphicInfo(); /* graphic properties mapping */
2014 print_timestamp_time("InitGraphicInfo");
2015 InitElementGraphicInfo(); /* element game graphic mapping */
2016 print_timestamp_time("InitElementGraphicInfo");
2017 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2018 print_timestamp_time("InitElementSpecialGraphicInfo");
2020 InitElementSmallImages(); /* scale elements to all needed sizes */
2021 print_timestamp_time("InitElementSmallImages");
2022 InitScaledImages(); /* scale all other images, if needed */
2023 print_timestamp_time("InitScaledImages");
2024 InitBitmapPointers(); /* set standard size bitmap pointers */
2025 print_timestamp_time("InitBitmapPointers");
2026 InitFontGraphicInfo(); /* initialize text drawing functions */
2027 print_timestamp_time("InitFontGraphicInfo");
2028 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2029 print_timestamp_time("InitGlobalAnimGraphicInfo");
2031 InitImageTextures(); /* create textures for certain images */
2032 print_timestamp_time("InitImageTextures");
2034 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2035 print_timestamp_time("InitGraphicInfo_EM");
2037 InitGraphicCompatibilityInfo();
2038 print_timestamp_time("InitGraphicCompatibilityInfo");
2040 SetMainBackgroundImage(IMG_BACKGROUND);
2041 print_timestamp_time("SetMainBackgroundImage");
2042 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2043 print_timestamp_time("SetDoorBackgroundImage");
2046 print_timestamp_time("InitGadgets");
2048 print_timestamp_time("InitToons");
2050 print_timestamp_time("InitDoors");
2052 print_timestamp_done("ReinitializeGraphics");
2055 static void ReinitializeSounds()
2057 InitSoundInfo(); /* sound properties mapping */
2058 InitElementSoundInfo(); /* element game sound mapping */
2059 InitGameModeSoundInfo(); /* game mode sound mapping */
2061 InitPlayLevelSound(); /* internal game sound settings */
2064 static void ReinitializeMusic()
2066 InitMusicInfo(); /* music properties mapping */
2067 InitGameModeMusicInfo(); /* game mode music mapping */
2070 static int get_special_property_bit(int element, int property_bit_nr)
2072 struct PropertyBitInfo
2078 static struct PropertyBitInfo pb_can_move_into_acid[] =
2080 /* the player may be able fall into acid when gravity is activated */
2085 { EL_SP_MURPHY, 0 },
2086 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2088 /* all elements that can move may be able to also move into acid */
2091 { EL_BUG_RIGHT, 1 },
2094 { EL_SPACESHIP, 2 },
2095 { EL_SPACESHIP_LEFT, 2 },
2096 { EL_SPACESHIP_RIGHT, 2 },
2097 { EL_SPACESHIP_UP, 2 },
2098 { EL_SPACESHIP_DOWN, 2 },
2099 { EL_BD_BUTTERFLY, 3 },
2100 { EL_BD_BUTTERFLY_LEFT, 3 },
2101 { EL_BD_BUTTERFLY_RIGHT, 3 },
2102 { EL_BD_BUTTERFLY_UP, 3 },
2103 { EL_BD_BUTTERFLY_DOWN, 3 },
2104 { EL_BD_FIREFLY, 4 },
2105 { EL_BD_FIREFLY_LEFT, 4 },
2106 { EL_BD_FIREFLY_RIGHT, 4 },
2107 { EL_BD_FIREFLY_UP, 4 },
2108 { EL_BD_FIREFLY_DOWN, 4 },
2110 { EL_YAMYAM_LEFT, 5 },
2111 { EL_YAMYAM_RIGHT, 5 },
2112 { EL_YAMYAM_UP, 5 },
2113 { EL_YAMYAM_DOWN, 5 },
2114 { EL_DARK_YAMYAM, 6 },
2117 { EL_PACMAN_LEFT, 8 },
2118 { EL_PACMAN_RIGHT, 8 },
2119 { EL_PACMAN_UP, 8 },
2120 { EL_PACMAN_DOWN, 8 },
2122 { EL_MOLE_LEFT, 9 },
2123 { EL_MOLE_RIGHT, 9 },
2125 { EL_MOLE_DOWN, 9 },
2129 { EL_SATELLITE, 13 },
2130 { EL_SP_SNIKSNAK, 14 },
2131 { EL_SP_ELECTRON, 15 },
2134 { EL_EMC_ANDROID, 18 },
2139 static struct PropertyBitInfo pb_dont_collide_with[] =
2141 { EL_SP_SNIKSNAK, 0 },
2142 { EL_SP_ELECTRON, 1 },
2150 struct PropertyBitInfo *pb_info;
2153 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2154 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2159 struct PropertyBitInfo *pb_info = NULL;
2162 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2163 if (pb_definition[i].bit_nr == property_bit_nr)
2164 pb_info = pb_definition[i].pb_info;
2166 if (pb_info == NULL)
2169 for (i = 0; pb_info[i].element != -1; i++)
2170 if (pb_info[i].element == element)
2171 return pb_info[i].bit_nr;
2176 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2177 boolean property_value)
2179 int bit_nr = get_special_property_bit(element, property_bit_nr);
2184 *bitfield |= (1 << bit_nr);
2186 *bitfield &= ~(1 << bit_nr);
2190 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2192 int bit_nr = get_special_property_bit(element, property_bit_nr);
2195 return ((*bitfield & (1 << bit_nr)) != 0);
2200 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2202 static int group_nr;
2203 static struct ElementGroupInfo *group;
2204 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2207 if (actual_group == NULL) /* not yet initialized */
2210 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2212 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2213 group_element - EL_GROUP_START + 1);
2215 /* replace element which caused too deep recursion by question mark */
2216 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2221 if (recursion_depth == 0) /* initialization */
2223 group = actual_group;
2224 group_nr = GROUP_NR(group_element);
2226 group->num_elements_resolved = 0;
2227 group->choice_pos = 0;
2229 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2230 element_info[i].in_group[group_nr] = FALSE;
2233 for (i = 0; i < actual_group->num_elements; i++)
2235 int element = actual_group->element[i];
2237 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2240 if (IS_GROUP_ELEMENT(element))
2241 ResolveGroupElementExt(element, recursion_depth + 1);
2244 group->element_resolved[group->num_elements_resolved++] = element;
2245 element_info[element].in_group[group_nr] = TRUE;
2250 void ResolveGroupElement(int group_element)
2252 ResolveGroupElementExt(group_element, 0);
2255 void InitElementPropertiesStatic()
2257 static boolean clipboard_elements_initialized = FALSE;
2259 static int ep_diggable[] =
2264 EL_SP_BUGGY_BASE_ACTIVATING,
2267 EL_INVISIBLE_SAND_ACTIVE,
2270 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2271 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2276 EL_SP_BUGGY_BASE_ACTIVE,
2283 static int ep_collectible_only[] =
2305 EL_DYNABOMB_INCREASE_NUMBER,
2306 EL_DYNABOMB_INCREASE_SIZE,
2307 EL_DYNABOMB_INCREASE_POWER,
2325 /* !!! handle separately !!! */
2326 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2332 static int ep_dont_run_into[] =
2334 /* same elements as in 'ep_dont_touch' */
2340 /* same elements as in 'ep_dont_collide_with' */
2352 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2357 EL_SP_BUGGY_BASE_ACTIVE,
2364 static int ep_dont_collide_with[] =
2366 /* same elements as in 'ep_dont_touch' */
2383 static int ep_dont_touch[] =
2393 static int ep_indestructible[] =
2397 EL_ACID_POOL_TOPLEFT,
2398 EL_ACID_POOL_TOPRIGHT,
2399 EL_ACID_POOL_BOTTOMLEFT,
2400 EL_ACID_POOL_BOTTOM,
2401 EL_ACID_POOL_BOTTOMRIGHT,
2402 EL_SP_HARDWARE_GRAY,
2403 EL_SP_HARDWARE_GREEN,
2404 EL_SP_HARDWARE_BLUE,
2406 EL_SP_HARDWARE_YELLOW,
2407 EL_SP_HARDWARE_BASE_1,
2408 EL_SP_HARDWARE_BASE_2,
2409 EL_SP_HARDWARE_BASE_3,
2410 EL_SP_HARDWARE_BASE_4,
2411 EL_SP_HARDWARE_BASE_5,
2412 EL_SP_HARDWARE_BASE_6,
2413 EL_INVISIBLE_STEELWALL,
2414 EL_INVISIBLE_STEELWALL_ACTIVE,
2415 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2416 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2417 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2418 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2419 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2420 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2421 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2422 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2423 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2424 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2425 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2426 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2428 EL_LIGHT_SWITCH_ACTIVE,
2429 EL_SIGN_EXCLAMATION,
2430 EL_SIGN_RADIOACTIVITY,
2437 EL_SIGN_ENTRY_FORBIDDEN,
2438 EL_SIGN_EMERGENCY_EXIT,
2446 EL_STEEL_EXIT_CLOSED,
2448 EL_STEEL_EXIT_OPENING,
2449 EL_STEEL_EXIT_CLOSING,
2450 EL_EM_STEEL_EXIT_CLOSED,
2451 EL_EM_STEEL_EXIT_OPEN,
2452 EL_EM_STEEL_EXIT_OPENING,
2453 EL_EM_STEEL_EXIT_CLOSING,
2454 EL_DC_STEELWALL_1_LEFT,
2455 EL_DC_STEELWALL_1_RIGHT,
2456 EL_DC_STEELWALL_1_TOP,
2457 EL_DC_STEELWALL_1_BOTTOM,
2458 EL_DC_STEELWALL_1_HORIZONTAL,
2459 EL_DC_STEELWALL_1_VERTICAL,
2460 EL_DC_STEELWALL_1_TOPLEFT,
2461 EL_DC_STEELWALL_1_TOPRIGHT,
2462 EL_DC_STEELWALL_1_BOTTOMLEFT,
2463 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2464 EL_DC_STEELWALL_1_TOPLEFT_2,
2465 EL_DC_STEELWALL_1_TOPRIGHT_2,
2466 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2467 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2468 EL_DC_STEELWALL_2_LEFT,
2469 EL_DC_STEELWALL_2_RIGHT,
2470 EL_DC_STEELWALL_2_TOP,
2471 EL_DC_STEELWALL_2_BOTTOM,
2472 EL_DC_STEELWALL_2_HORIZONTAL,
2473 EL_DC_STEELWALL_2_VERTICAL,
2474 EL_DC_STEELWALL_2_MIDDLE,
2475 EL_DC_STEELWALL_2_SINGLE,
2476 EL_STEELWALL_SLIPPERY,
2490 EL_GATE_1_GRAY_ACTIVE,
2491 EL_GATE_2_GRAY_ACTIVE,
2492 EL_GATE_3_GRAY_ACTIVE,
2493 EL_GATE_4_GRAY_ACTIVE,
2502 EL_EM_GATE_1_GRAY_ACTIVE,
2503 EL_EM_GATE_2_GRAY_ACTIVE,
2504 EL_EM_GATE_3_GRAY_ACTIVE,
2505 EL_EM_GATE_4_GRAY_ACTIVE,
2514 EL_EMC_GATE_5_GRAY_ACTIVE,
2515 EL_EMC_GATE_6_GRAY_ACTIVE,
2516 EL_EMC_GATE_7_GRAY_ACTIVE,
2517 EL_EMC_GATE_8_GRAY_ACTIVE,
2519 EL_DC_GATE_WHITE_GRAY,
2520 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2521 EL_DC_GATE_FAKE_GRAY,
2523 EL_SWITCHGATE_OPENING,
2524 EL_SWITCHGATE_CLOSED,
2525 EL_SWITCHGATE_CLOSING,
2526 EL_DC_SWITCHGATE_SWITCH_UP,
2527 EL_DC_SWITCHGATE_SWITCH_DOWN,
2529 EL_TIMEGATE_OPENING,
2531 EL_TIMEGATE_CLOSING,
2532 EL_DC_TIMEGATE_SWITCH,
2533 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2537 EL_TUBE_VERTICAL_LEFT,
2538 EL_TUBE_VERTICAL_RIGHT,
2539 EL_TUBE_HORIZONTAL_UP,
2540 EL_TUBE_HORIZONTAL_DOWN,
2545 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2546 EL_EXPANDABLE_STEELWALL_VERTICAL,
2547 EL_EXPANDABLE_STEELWALL_ANY,
2552 static int ep_slippery[] =
2566 EL_ROBOT_WHEEL_ACTIVE,
2572 EL_ACID_POOL_TOPLEFT,
2573 EL_ACID_POOL_TOPRIGHT,
2583 EL_STEELWALL_SLIPPERY,
2586 EL_EMC_WALL_SLIPPERY_1,
2587 EL_EMC_WALL_SLIPPERY_2,
2588 EL_EMC_WALL_SLIPPERY_3,
2589 EL_EMC_WALL_SLIPPERY_4,
2591 EL_EMC_MAGIC_BALL_ACTIVE,
2596 static int ep_can_change[] =
2601 static int ep_can_move[] =
2603 /* same elements as in 'pb_can_move_into_acid' */
2626 static int ep_can_fall[] =
2640 EL_QUICKSAND_FAST_FULL,
2642 EL_BD_MAGIC_WALL_FULL,
2643 EL_DC_MAGIC_WALL_FULL,
2657 static int ep_can_smash_player[] =
2683 static int ep_can_smash_enemies[] =
2692 static int ep_can_smash_everything[] =
2701 static int ep_explodes_by_fire[] =
2703 /* same elements as in 'ep_explodes_impact' */
2708 /* same elements as in 'ep_explodes_smashed' */
2718 EL_EM_DYNAMITE_ACTIVE,
2719 EL_DYNABOMB_PLAYER_1_ACTIVE,
2720 EL_DYNABOMB_PLAYER_2_ACTIVE,
2721 EL_DYNABOMB_PLAYER_3_ACTIVE,
2722 EL_DYNABOMB_PLAYER_4_ACTIVE,
2723 EL_DYNABOMB_INCREASE_NUMBER,
2724 EL_DYNABOMB_INCREASE_SIZE,
2725 EL_DYNABOMB_INCREASE_POWER,
2726 EL_SP_DISK_RED_ACTIVE,
2740 static int ep_explodes_smashed[] =
2742 /* same elements as in 'ep_explodes_impact' */
2756 static int ep_explodes_impact[] =
2765 static int ep_walkable_over[] =
2769 EL_SOKOBAN_FIELD_EMPTY,
2776 EL_EM_STEEL_EXIT_OPEN,
2777 EL_EM_STEEL_EXIT_OPENING,
2786 EL_GATE_1_GRAY_ACTIVE,
2787 EL_GATE_2_GRAY_ACTIVE,
2788 EL_GATE_3_GRAY_ACTIVE,
2789 EL_GATE_4_GRAY_ACTIVE,
2797 static int ep_walkable_inside[] =
2802 EL_TUBE_VERTICAL_LEFT,
2803 EL_TUBE_VERTICAL_RIGHT,
2804 EL_TUBE_HORIZONTAL_UP,
2805 EL_TUBE_HORIZONTAL_DOWN,
2814 static int ep_walkable_under[] =
2819 static int ep_passable_over[] =
2829 EL_EM_GATE_1_GRAY_ACTIVE,
2830 EL_EM_GATE_2_GRAY_ACTIVE,
2831 EL_EM_GATE_3_GRAY_ACTIVE,
2832 EL_EM_GATE_4_GRAY_ACTIVE,
2841 EL_EMC_GATE_5_GRAY_ACTIVE,
2842 EL_EMC_GATE_6_GRAY_ACTIVE,
2843 EL_EMC_GATE_7_GRAY_ACTIVE,
2844 EL_EMC_GATE_8_GRAY_ACTIVE,
2846 EL_DC_GATE_WHITE_GRAY,
2847 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2854 static int ep_passable_inside[] =
2860 EL_SP_PORT_HORIZONTAL,
2861 EL_SP_PORT_VERTICAL,
2863 EL_SP_GRAVITY_PORT_LEFT,
2864 EL_SP_GRAVITY_PORT_RIGHT,
2865 EL_SP_GRAVITY_PORT_UP,
2866 EL_SP_GRAVITY_PORT_DOWN,
2867 EL_SP_GRAVITY_ON_PORT_LEFT,
2868 EL_SP_GRAVITY_ON_PORT_RIGHT,
2869 EL_SP_GRAVITY_ON_PORT_UP,
2870 EL_SP_GRAVITY_ON_PORT_DOWN,
2871 EL_SP_GRAVITY_OFF_PORT_LEFT,
2872 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2873 EL_SP_GRAVITY_OFF_PORT_UP,
2874 EL_SP_GRAVITY_OFF_PORT_DOWN,
2879 static int ep_passable_under[] =
2884 static int ep_droppable[] =
2889 static int ep_explodes_1x1_old[] =
2894 static int ep_pushable[] =
2906 EL_SOKOBAN_FIELD_FULL,
2915 static int ep_explodes_cross_old[] =
2920 static int ep_protected[] =
2922 /* same elements as in 'ep_walkable_inside' */
2926 EL_TUBE_VERTICAL_LEFT,
2927 EL_TUBE_VERTICAL_RIGHT,
2928 EL_TUBE_HORIZONTAL_UP,
2929 EL_TUBE_HORIZONTAL_DOWN,
2935 /* same elements as in 'ep_passable_over' */
2944 EL_EM_GATE_1_GRAY_ACTIVE,
2945 EL_EM_GATE_2_GRAY_ACTIVE,
2946 EL_EM_GATE_3_GRAY_ACTIVE,
2947 EL_EM_GATE_4_GRAY_ACTIVE,
2956 EL_EMC_GATE_5_GRAY_ACTIVE,
2957 EL_EMC_GATE_6_GRAY_ACTIVE,
2958 EL_EMC_GATE_7_GRAY_ACTIVE,
2959 EL_EMC_GATE_8_GRAY_ACTIVE,
2961 EL_DC_GATE_WHITE_GRAY,
2962 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2966 /* same elements as in 'ep_passable_inside' */
2971 EL_SP_PORT_HORIZONTAL,
2972 EL_SP_PORT_VERTICAL,
2974 EL_SP_GRAVITY_PORT_LEFT,
2975 EL_SP_GRAVITY_PORT_RIGHT,
2976 EL_SP_GRAVITY_PORT_UP,
2977 EL_SP_GRAVITY_PORT_DOWN,
2978 EL_SP_GRAVITY_ON_PORT_LEFT,
2979 EL_SP_GRAVITY_ON_PORT_RIGHT,
2980 EL_SP_GRAVITY_ON_PORT_UP,
2981 EL_SP_GRAVITY_ON_PORT_DOWN,
2982 EL_SP_GRAVITY_OFF_PORT_LEFT,
2983 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2984 EL_SP_GRAVITY_OFF_PORT_UP,
2985 EL_SP_GRAVITY_OFF_PORT_DOWN,
2990 static int ep_throwable[] =
2995 static int ep_can_explode[] =
2997 /* same elements as in 'ep_explodes_impact' */
3002 /* same elements as in 'ep_explodes_smashed' */
3008 /* elements that can explode by explosion or by dragonfire */
3012 EL_EM_DYNAMITE_ACTIVE,
3013 EL_DYNABOMB_PLAYER_1_ACTIVE,
3014 EL_DYNABOMB_PLAYER_2_ACTIVE,
3015 EL_DYNABOMB_PLAYER_3_ACTIVE,
3016 EL_DYNABOMB_PLAYER_4_ACTIVE,
3017 EL_DYNABOMB_INCREASE_NUMBER,
3018 EL_DYNABOMB_INCREASE_SIZE,
3019 EL_DYNABOMB_INCREASE_POWER,
3020 EL_SP_DISK_RED_ACTIVE,
3028 /* elements that can explode only by explosion */
3034 static int ep_gravity_reachable[] =
3040 EL_INVISIBLE_SAND_ACTIVE,
3045 EL_SP_PORT_HORIZONTAL,
3046 EL_SP_PORT_VERTICAL,
3048 EL_SP_GRAVITY_PORT_LEFT,
3049 EL_SP_GRAVITY_PORT_RIGHT,
3050 EL_SP_GRAVITY_PORT_UP,
3051 EL_SP_GRAVITY_PORT_DOWN,
3052 EL_SP_GRAVITY_ON_PORT_LEFT,
3053 EL_SP_GRAVITY_ON_PORT_RIGHT,
3054 EL_SP_GRAVITY_ON_PORT_UP,
3055 EL_SP_GRAVITY_ON_PORT_DOWN,
3056 EL_SP_GRAVITY_OFF_PORT_LEFT,
3057 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3058 EL_SP_GRAVITY_OFF_PORT_UP,
3059 EL_SP_GRAVITY_OFF_PORT_DOWN,
3065 static int ep_player[] =
3072 EL_SOKOBAN_FIELD_PLAYER,
3078 static int ep_can_pass_magic_wall[] =
3092 static int ep_can_pass_dc_magic_wall[] =
3108 static int ep_switchable[] =
3112 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3113 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3114 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3115 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3116 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3117 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3118 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3119 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3120 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3121 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3122 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3123 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3124 EL_SWITCHGATE_SWITCH_UP,
3125 EL_SWITCHGATE_SWITCH_DOWN,
3126 EL_DC_SWITCHGATE_SWITCH_UP,
3127 EL_DC_SWITCHGATE_SWITCH_DOWN,
3129 EL_LIGHT_SWITCH_ACTIVE,
3131 EL_DC_TIMEGATE_SWITCH,
3132 EL_BALLOON_SWITCH_LEFT,
3133 EL_BALLOON_SWITCH_RIGHT,
3134 EL_BALLOON_SWITCH_UP,
3135 EL_BALLOON_SWITCH_DOWN,
3136 EL_BALLOON_SWITCH_ANY,
3137 EL_BALLOON_SWITCH_NONE,
3140 EL_EMC_MAGIC_BALL_SWITCH,
3141 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3146 static int ep_bd_element[] =
3180 static int ep_sp_element[] =
3182 /* should always be valid */
3185 /* standard classic Supaplex elements */
3192 EL_SP_HARDWARE_GRAY,
3200 EL_SP_GRAVITY_PORT_RIGHT,
3201 EL_SP_GRAVITY_PORT_DOWN,
3202 EL_SP_GRAVITY_PORT_LEFT,
3203 EL_SP_GRAVITY_PORT_UP,
3208 EL_SP_PORT_VERTICAL,
3209 EL_SP_PORT_HORIZONTAL,
3215 EL_SP_HARDWARE_BASE_1,
3216 EL_SP_HARDWARE_GREEN,
3217 EL_SP_HARDWARE_BLUE,
3219 EL_SP_HARDWARE_YELLOW,
3220 EL_SP_HARDWARE_BASE_2,
3221 EL_SP_HARDWARE_BASE_3,
3222 EL_SP_HARDWARE_BASE_4,
3223 EL_SP_HARDWARE_BASE_5,
3224 EL_SP_HARDWARE_BASE_6,
3228 /* additional elements that appeared in newer Supaplex levels */
3231 /* additional gravity port elements (not switching, but setting gravity) */
3232 EL_SP_GRAVITY_ON_PORT_LEFT,
3233 EL_SP_GRAVITY_ON_PORT_RIGHT,
3234 EL_SP_GRAVITY_ON_PORT_UP,
3235 EL_SP_GRAVITY_ON_PORT_DOWN,
3236 EL_SP_GRAVITY_OFF_PORT_LEFT,
3237 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3238 EL_SP_GRAVITY_OFF_PORT_UP,
3239 EL_SP_GRAVITY_OFF_PORT_DOWN,
3241 /* more than one Murphy in a level results in an inactive clone */
3244 /* runtime Supaplex elements */
3245 EL_SP_DISK_RED_ACTIVE,
3246 EL_SP_TERMINAL_ACTIVE,
3247 EL_SP_BUGGY_BASE_ACTIVATING,
3248 EL_SP_BUGGY_BASE_ACTIVE,
3255 static int ep_sb_element[] =
3260 EL_SOKOBAN_FIELD_EMPTY,
3261 EL_SOKOBAN_FIELD_FULL,
3262 EL_SOKOBAN_FIELD_PLAYER,
3267 EL_INVISIBLE_STEELWALL,
3272 static int ep_gem[] =
3284 static int ep_food_dark_yamyam[] =
3312 static int ep_food_penguin[] =
3326 static int ep_food_pig[] =
3338 static int ep_historic_wall[] =
3349 EL_GATE_1_GRAY_ACTIVE,
3350 EL_GATE_2_GRAY_ACTIVE,
3351 EL_GATE_3_GRAY_ACTIVE,
3352 EL_GATE_4_GRAY_ACTIVE,
3361 EL_EM_GATE_1_GRAY_ACTIVE,
3362 EL_EM_GATE_2_GRAY_ACTIVE,
3363 EL_EM_GATE_3_GRAY_ACTIVE,
3364 EL_EM_GATE_4_GRAY_ACTIVE,
3371 EL_EXPANDABLE_WALL_HORIZONTAL,
3372 EL_EXPANDABLE_WALL_VERTICAL,
3373 EL_EXPANDABLE_WALL_ANY,
3374 EL_EXPANDABLE_WALL_GROWING,
3375 EL_BD_EXPANDABLE_WALL,
3382 EL_SP_HARDWARE_GRAY,
3383 EL_SP_HARDWARE_GREEN,
3384 EL_SP_HARDWARE_BLUE,
3386 EL_SP_HARDWARE_YELLOW,
3387 EL_SP_HARDWARE_BASE_1,
3388 EL_SP_HARDWARE_BASE_2,
3389 EL_SP_HARDWARE_BASE_3,
3390 EL_SP_HARDWARE_BASE_4,
3391 EL_SP_HARDWARE_BASE_5,
3392 EL_SP_HARDWARE_BASE_6,
3394 EL_SP_TERMINAL_ACTIVE,
3397 EL_INVISIBLE_STEELWALL,
3398 EL_INVISIBLE_STEELWALL_ACTIVE,
3400 EL_INVISIBLE_WALL_ACTIVE,
3401 EL_STEELWALL_SLIPPERY,
3418 static int ep_historic_solid[] =
3422 EL_EXPANDABLE_WALL_HORIZONTAL,
3423 EL_EXPANDABLE_WALL_VERTICAL,
3424 EL_EXPANDABLE_WALL_ANY,
3425 EL_BD_EXPANDABLE_WALL,
3438 EL_QUICKSAND_FILLING,
3439 EL_QUICKSAND_EMPTYING,
3441 EL_MAGIC_WALL_ACTIVE,
3442 EL_MAGIC_WALL_EMPTYING,
3443 EL_MAGIC_WALL_FILLING,
3447 EL_BD_MAGIC_WALL_ACTIVE,
3448 EL_BD_MAGIC_WALL_EMPTYING,
3449 EL_BD_MAGIC_WALL_FULL,
3450 EL_BD_MAGIC_WALL_FILLING,
3451 EL_BD_MAGIC_WALL_DEAD,
3460 EL_SP_TERMINAL_ACTIVE,
3464 EL_INVISIBLE_WALL_ACTIVE,
3465 EL_SWITCHGATE_SWITCH_UP,
3466 EL_SWITCHGATE_SWITCH_DOWN,
3467 EL_DC_SWITCHGATE_SWITCH_UP,
3468 EL_DC_SWITCHGATE_SWITCH_DOWN,
3470 EL_TIMEGATE_SWITCH_ACTIVE,
3471 EL_DC_TIMEGATE_SWITCH,
3472 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3484 /* the following elements are a direct copy of "indestructible" elements,
3485 except "EL_ACID", which is "indestructible", but not "solid"! */
3490 EL_ACID_POOL_TOPLEFT,
3491 EL_ACID_POOL_TOPRIGHT,
3492 EL_ACID_POOL_BOTTOMLEFT,
3493 EL_ACID_POOL_BOTTOM,
3494 EL_ACID_POOL_BOTTOMRIGHT,
3495 EL_SP_HARDWARE_GRAY,
3496 EL_SP_HARDWARE_GREEN,
3497 EL_SP_HARDWARE_BLUE,
3499 EL_SP_HARDWARE_YELLOW,
3500 EL_SP_HARDWARE_BASE_1,
3501 EL_SP_HARDWARE_BASE_2,
3502 EL_SP_HARDWARE_BASE_3,
3503 EL_SP_HARDWARE_BASE_4,
3504 EL_SP_HARDWARE_BASE_5,
3505 EL_SP_HARDWARE_BASE_6,
3506 EL_INVISIBLE_STEELWALL,
3507 EL_INVISIBLE_STEELWALL_ACTIVE,
3508 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3509 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3510 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3511 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3512 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3513 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3514 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3515 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3516 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3517 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3518 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3519 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3521 EL_LIGHT_SWITCH_ACTIVE,
3522 EL_SIGN_EXCLAMATION,
3523 EL_SIGN_RADIOACTIVITY,
3530 EL_SIGN_ENTRY_FORBIDDEN,
3531 EL_SIGN_EMERGENCY_EXIT,
3539 EL_STEEL_EXIT_CLOSED,
3541 EL_DC_STEELWALL_1_LEFT,
3542 EL_DC_STEELWALL_1_RIGHT,
3543 EL_DC_STEELWALL_1_TOP,
3544 EL_DC_STEELWALL_1_BOTTOM,
3545 EL_DC_STEELWALL_1_HORIZONTAL,
3546 EL_DC_STEELWALL_1_VERTICAL,
3547 EL_DC_STEELWALL_1_TOPLEFT,
3548 EL_DC_STEELWALL_1_TOPRIGHT,
3549 EL_DC_STEELWALL_1_BOTTOMLEFT,
3550 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3551 EL_DC_STEELWALL_1_TOPLEFT_2,
3552 EL_DC_STEELWALL_1_TOPRIGHT_2,
3553 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3554 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3555 EL_DC_STEELWALL_2_LEFT,
3556 EL_DC_STEELWALL_2_RIGHT,
3557 EL_DC_STEELWALL_2_TOP,
3558 EL_DC_STEELWALL_2_BOTTOM,
3559 EL_DC_STEELWALL_2_HORIZONTAL,
3560 EL_DC_STEELWALL_2_VERTICAL,
3561 EL_DC_STEELWALL_2_MIDDLE,
3562 EL_DC_STEELWALL_2_SINGLE,
3563 EL_STEELWALL_SLIPPERY,
3577 EL_GATE_1_GRAY_ACTIVE,
3578 EL_GATE_2_GRAY_ACTIVE,
3579 EL_GATE_3_GRAY_ACTIVE,
3580 EL_GATE_4_GRAY_ACTIVE,
3589 EL_EM_GATE_1_GRAY_ACTIVE,
3590 EL_EM_GATE_2_GRAY_ACTIVE,
3591 EL_EM_GATE_3_GRAY_ACTIVE,
3592 EL_EM_GATE_4_GRAY_ACTIVE,
3594 EL_SWITCHGATE_OPENING,
3595 EL_SWITCHGATE_CLOSED,
3596 EL_SWITCHGATE_CLOSING,
3598 EL_TIMEGATE_OPENING,
3600 EL_TIMEGATE_CLOSING,
3604 EL_TUBE_VERTICAL_LEFT,
3605 EL_TUBE_VERTICAL_RIGHT,
3606 EL_TUBE_HORIZONTAL_UP,
3607 EL_TUBE_HORIZONTAL_DOWN,
3616 static int ep_classic_enemy[] =
3633 static int ep_belt[] =
3635 EL_CONVEYOR_BELT_1_LEFT,
3636 EL_CONVEYOR_BELT_1_MIDDLE,
3637 EL_CONVEYOR_BELT_1_RIGHT,
3638 EL_CONVEYOR_BELT_2_LEFT,
3639 EL_CONVEYOR_BELT_2_MIDDLE,
3640 EL_CONVEYOR_BELT_2_RIGHT,
3641 EL_CONVEYOR_BELT_3_LEFT,
3642 EL_CONVEYOR_BELT_3_MIDDLE,
3643 EL_CONVEYOR_BELT_3_RIGHT,
3644 EL_CONVEYOR_BELT_4_LEFT,
3645 EL_CONVEYOR_BELT_4_MIDDLE,
3646 EL_CONVEYOR_BELT_4_RIGHT,
3651 static int ep_belt_active[] =
3653 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3654 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3655 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3656 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3657 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3658 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3659 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3660 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3661 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3662 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3663 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3664 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3669 static int ep_belt_switch[] =
3671 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3672 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3673 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3674 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3675 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3676 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3677 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3678 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3679 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3680 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3681 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3682 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3687 static int ep_tube[] =
3694 EL_TUBE_HORIZONTAL_UP,
3695 EL_TUBE_HORIZONTAL_DOWN,
3697 EL_TUBE_VERTICAL_LEFT,
3698 EL_TUBE_VERTICAL_RIGHT,
3704 static int ep_acid_pool[] =
3706 EL_ACID_POOL_TOPLEFT,
3707 EL_ACID_POOL_TOPRIGHT,
3708 EL_ACID_POOL_BOTTOMLEFT,
3709 EL_ACID_POOL_BOTTOM,
3710 EL_ACID_POOL_BOTTOMRIGHT,
3715 static int ep_keygate[] =
3725 EL_GATE_1_GRAY_ACTIVE,
3726 EL_GATE_2_GRAY_ACTIVE,
3727 EL_GATE_3_GRAY_ACTIVE,
3728 EL_GATE_4_GRAY_ACTIVE,
3737 EL_EM_GATE_1_GRAY_ACTIVE,
3738 EL_EM_GATE_2_GRAY_ACTIVE,
3739 EL_EM_GATE_3_GRAY_ACTIVE,
3740 EL_EM_GATE_4_GRAY_ACTIVE,
3749 EL_EMC_GATE_5_GRAY_ACTIVE,
3750 EL_EMC_GATE_6_GRAY_ACTIVE,
3751 EL_EMC_GATE_7_GRAY_ACTIVE,
3752 EL_EMC_GATE_8_GRAY_ACTIVE,
3754 EL_DC_GATE_WHITE_GRAY,
3755 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3760 static int ep_amoeboid[] =
3772 static int ep_amoebalive[] =
3783 static int ep_has_editor_content[] =
3789 EL_SOKOBAN_FIELD_PLAYER,
3806 static int ep_can_turn_each_move[] =
3808 /* !!! do something with this one !!! */
3812 static int ep_can_grow[] =
3826 static int ep_active_bomb[] =
3829 EL_EM_DYNAMITE_ACTIVE,
3830 EL_DYNABOMB_PLAYER_1_ACTIVE,
3831 EL_DYNABOMB_PLAYER_2_ACTIVE,
3832 EL_DYNABOMB_PLAYER_3_ACTIVE,
3833 EL_DYNABOMB_PLAYER_4_ACTIVE,
3834 EL_SP_DISK_RED_ACTIVE,
3839 static int ep_inactive[] =
3849 EL_QUICKSAND_FAST_EMPTY,
3872 EL_GATE_1_GRAY_ACTIVE,
3873 EL_GATE_2_GRAY_ACTIVE,
3874 EL_GATE_3_GRAY_ACTIVE,
3875 EL_GATE_4_GRAY_ACTIVE,
3884 EL_EM_GATE_1_GRAY_ACTIVE,
3885 EL_EM_GATE_2_GRAY_ACTIVE,
3886 EL_EM_GATE_3_GRAY_ACTIVE,
3887 EL_EM_GATE_4_GRAY_ACTIVE,
3896 EL_EMC_GATE_5_GRAY_ACTIVE,
3897 EL_EMC_GATE_6_GRAY_ACTIVE,
3898 EL_EMC_GATE_7_GRAY_ACTIVE,
3899 EL_EMC_GATE_8_GRAY_ACTIVE,
3901 EL_DC_GATE_WHITE_GRAY,
3902 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3903 EL_DC_GATE_FAKE_GRAY,
3906 EL_INVISIBLE_STEELWALL,
3914 EL_WALL_EMERALD_YELLOW,
3915 EL_DYNABOMB_INCREASE_NUMBER,
3916 EL_DYNABOMB_INCREASE_SIZE,
3917 EL_DYNABOMB_INCREASE_POWER,
3921 EL_SOKOBAN_FIELD_EMPTY,
3922 EL_SOKOBAN_FIELD_FULL,
3923 EL_WALL_EMERALD_RED,
3924 EL_WALL_EMERALD_PURPLE,
3925 EL_ACID_POOL_TOPLEFT,
3926 EL_ACID_POOL_TOPRIGHT,
3927 EL_ACID_POOL_BOTTOMLEFT,
3928 EL_ACID_POOL_BOTTOM,
3929 EL_ACID_POOL_BOTTOMRIGHT,
3933 EL_BD_MAGIC_WALL_DEAD,
3935 EL_DC_MAGIC_WALL_DEAD,
3936 EL_AMOEBA_TO_DIAMOND,
3944 EL_SP_GRAVITY_PORT_RIGHT,
3945 EL_SP_GRAVITY_PORT_DOWN,
3946 EL_SP_GRAVITY_PORT_LEFT,
3947 EL_SP_GRAVITY_PORT_UP,
3948 EL_SP_PORT_HORIZONTAL,
3949 EL_SP_PORT_VERTICAL,
3960 EL_SP_HARDWARE_GRAY,
3961 EL_SP_HARDWARE_GREEN,
3962 EL_SP_HARDWARE_BLUE,
3964 EL_SP_HARDWARE_YELLOW,
3965 EL_SP_HARDWARE_BASE_1,
3966 EL_SP_HARDWARE_BASE_2,
3967 EL_SP_HARDWARE_BASE_3,
3968 EL_SP_HARDWARE_BASE_4,
3969 EL_SP_HARDWARE_BASE_5,
3970 EL_SP_HARDWARE_BASE_6,
3971 EL_SP_GRAVITY_ON_PORT_LEFT,
3972 EL_SP_GRAVITY_ON_PORT_RIGHT,
3973 EL_SP_GRAVITY_ON_PORT_UP,
3974 EL_SP_GRAVITY_ON_PORT_DOWN,
3975 EL_SP_GRAVITY_OFF_PORT_LEFT,
3976 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3977 EL_SP_GRAVITY_OFF_PORT_UP,
3978 EL_SP_GRAVITY_OFF_PORT_DOWN,
3979 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3980 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3981 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3982 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3983 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3984 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3985 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3986 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3987 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3988 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3989 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3990 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3991 EL_SIGN_EXCLAMATION,
3992 EL_SIGN_RADIOACTIVITY,
3999 EL_SIGN_ENTRY_FORBIDDEN,
4000 EL_SIGN_EMERGENCY_EXIT,
4008 EL_DC_STEELWALL_1_LEFT,
4009 EL_DC_STEELWALL_1_RIGHT,
4010 EL_DC_STEELWALL_1_TOP,
4011 EL_DC_STEELWALL_1_BOTTOM,
4012 EL_DC_STEELWALL_1_HORIZONTAL,
4013 EL_DC_STEELWALL_1_VERTICAL,
4014 EL_DC_STEELWALL_1_TOPLEFT,
4015 EL_DC_STEELWALL_1_TOPRIGHT,
4016 EL_DC_STEELWALL_1_BOTTOMLEFT,
4017 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4018 EL_DC_STEELWALL_1_TOPLEFT_2,
4019 EL_DC_STEELWALL_1_TOPRIGHT_2,
4020 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4021 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4022 EL_DC_STEELWALL_2_LEFT,
4023 EL_DC_STEELWALL_2_RIGHT,
4024 EL_DC_STEELWALL_2_TOP,
4025 EL_DC_STEELWALL_2_BOTTOM,
4026 EL_DC_STEELWALL_2_HORIZONTAL,
4027 EL_DC_STEELWALL_2_VERTICAL,
4028 EL_DC_STEELWALL_2_MIDDLE,
4029 EL_DC_STEELWALL_2_SINGLE,
4030 EL_STEELWALL_SLIPPERY,
4035 EL_EMC_WALL_SLIPPERY_1,
4036 EL_EMC_WALL_SLIPPERY_2,
4037 EL_EMC_WALL_SLIPPERY_3,
4038 EL_EMC_WALL_SLIPPERY_4,
4059 static int ep_em_slippery_wall[] =
4064 static int ep_gfx_crumbled[] =
4075 static int ep_editor_cascade_active[] =
4077 EL_INTERNAL_CASCADE_BD_ACTIVE,
4078 EL_INTERNAL_CASCADE_EM_ACTIVE,
4079 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4080 EL_INTERNAL_CASCADE_RND_ACTIVE,
4081 EL_INTERNAL_CASCADE_SB_ACTIVE,
4082 EL_INTERNAL_CASCADE_SP_ACTIVE,
4083 EL_INTERNAL_CASCADE_DC_ACTIVE,
4084 EL_INTERNAL_CASCADE_DX_ACTIVE,
4085 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4086 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4087 EL_INTERNAL_CASCADE_CE_ACTIVE,
4088 EL_INTERNAL_CASCADE_GE_ACTIVE,
4089 EL_INTERNAL_CASCADE_REF_ACTIVE,
4090 EL_INTERNAL_CASCADE_USER_ACTIVE,
4091 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4096 static int ep_editor_cascade_inactive[] =
4098 EL_INTERNAL_CASCADE_BD,
4099 EL_INTERNAL_CASCADE_EM,
4100 EL_INTERNAL_CASCADE_EMC,
4101 EL_INTERNAL_CASCADE_RND,
4102 EL_INTERNAL_CASCADE_SB,
4103 EL_INTERNAL_CASCADE_SP,
4104 EL_INTERNAL_CASCADE_DC,
4105 EL_INTERNAL_CASCADE_DX,
4106 EL_INTERNAL_CASCADE_CHARS,
4107 EL_INTERNAL_CASCADE_STEEL_CHARS,
4108 EL_INTERNAL_CASCADE_CE,
4109 EL_INTERNAL_CASCADE_GE,
4110 EL_INTERNAL_CASCADE_REF,
4111 EL_INTERNAL_CASCADE_USER,
4112 EL_INTERNAL_CASCADE_DYNAMIC,
4117 static int ep_obsolete[] =
4121 EL_EM_KEY_1_FILE_OBSOLETE,
4122 EL_EM_KEY_2_FILE_OBSOLETE,
4123 EL_EM_KEY_3_FILE_OBSOLETE,
4124 EL_EM_KEY_4_FILE_OBSOLETE,
4125 EL_ENVELOPE_OBSOLETE,
4134 } element_properties[] =
4136 { ep_diggable, EP_DIGGABLE },
4137 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4138 { ep_dont_run_into, EP_DONT_RUN_INTO },
4139 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4140 { ep_dont_touch, EP_DONT_TOUCH },
4141 { ep_indestructible, EP_INDESTRUCTIBLE },
4142 { ep_slippery, EP_SLIPPERY },
4143 { ep_can_change, EP_CAN_CHANGE },
4144 { ep_can_move, EP_CAN_MOVE },
4145 { ep_can_fall, EP_CAN_FALL },
4146 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4147 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4148 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4149 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4150 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4151 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4152 { ep_walkable_over, EP_WALKABLE_OVER },
4153 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4154 { ep_walkable_under, EP_WALKABLE_UNDER },
4155 { ep_passable_over, EP_PASSABLE_OVER },
4156 { ep_passable_inside, EP_PASSABLE_INSIDE },
4157 { ep_passable_under, EP_PASSABLE_UNDER },
4158 { ep_droppable, EP_DROPPABLE },
4159 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4160 { ep_pushable, EP_PUSHABLE },
4161 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4162 { ep_protected, EP_PROTECTED },
4163 { ep_throwable, EP_THROWABLE },
4164 { ep_can_explode, EP_CAN_EXPLODE },
4165 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4167 { ep_player, EP_PLAYER },
4168 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4169 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4170 { ep_switchable, EP_SWITCHABLE },
4171 { ep_bd_element, EP_BD_ELEMENT },
4172 { ep_sp_element, EP_SP_ELEMENT },
4173 { ep_sb_element, EP_SB_ELEMENT },
4175 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4176 { ep_food_penguin, EP_FOOD_PENGUIN },
4177 { ep_food_pig, EP_FOOD_PIG },
4178 { ep_historic_wall, EP_HISTORIC_WALL },
4179 { ep_historic_solid, EP_HISTORIC_SOLID },
4180 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4181 { ep_belt, EP_BELT },
4182 { ep_belt_active, EP_BELT_ACTIVE },
4183 { ep_belt_switch, EP_BELT_SWITCH },
4184 { ep_tube, EP_TUBE },
4185 { ep_acid_pool, EP_ACID_POOL },
4186 { ep_keygate, EP_KEYGATE },
4187 { ep_amoeboid, EP_AMOEBOID },
4188 { ep_amoebalive, EP_AMOEBALIVE },
4189 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4190 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4191 { ep_can_grow, EP_CAN_GROW },
4192 { ep_active_bomb, EP_ACTIVE_BOMB },
4193 { ep_inactive, EP_INACTIVE },
4195 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4197 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4199 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4200 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4202 { ep_obsolete, EP_OBSOLETE },
4209 /* always start with reliable default values (element has no properties) */
4210 /* (but never initialize clipboard elements after the very first time) */
4211 /* (to be able to use clipboard elements between several levels) */
4212 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4213 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4214 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4215 SET_PROPERTY(i, j, FALSE);
4217 /* set all base element properties from above array definitions */
4218 for (i = 0; element_properties[i].elements != NULL; i++)
4219 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4220 SET_PROPERTY((element_properties[i].elements)[j],
4221 element_properties[i].property, TRUE);
4223 /* copy properties to some elements that are only stored in level file */
4224 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4225 for (j = 0; copy_properties[j][0] != -1; j++)
4226 if (HAS_PROPERTY(copy_properties[j][0], i))
4227 for (k = 1; k <= 4; k++)
4228 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4230 /* set static element properties that are not listed in array definitions */
4231 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4232 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4234 clipboard_elements_initialized = TRUE;
4237 void InitElementPropertiesEngine(int engine_version)
4239 static int no_wall_properties[] =
4242 EP_COLLECTIBLE_ONLY,
4244 EP_DONT_COLLIDE_WITH,
4247 EP_CAN_SMASH_PLAYER,
4248 EP_CAN_SMASH_ENEMIES,
4249 EP_CAN_SMASH_EVERYTHING,
4254 EP_FOOD_DARK_YAMYAM,
4270 /* important: after initialization in InitElementPropertiesStatic(), the
4271 elements are not again initialized to a default value; therefore all
4272 changes have to make sure that they leave the element with a defined
4273 property (which means that conditional property changes must be set to
4274 a reliable default value before) */
4276 /* resolve group elements */
4277 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4278 ResolveGroupElement(EL_GROUP_START + i);
4280 /* set all special, combined or engine dependent element properties */
4281 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4283 /* do not change (already initialized) clipboard elements here */
4284 if (IS_CLIPBOARD_ELEMENT(i))
4287 /* ---------- INACTIVE ------------------------------------------------- */
4288 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4289 i <= EL_CHAR_END) ||
4290 (i >= EL_STEEL_CHAR_START &&
4291 i <= EL_STEEL_CHAR_END)));
4293 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4294 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4295 IS_WALKABLE_INSIDE(i) ||
4296 IS_WALKABLE_UNDER(i)));
4298 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4299 IS_PASSABLE_INSIDE(i) ||
4300 IS_PASSABLE_UNDER(i)));
4302 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4303 IS_PASSABLE_OVER(i)));
4305 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4306 IS_PASSABLE_INSIDE(i)));
4308 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4309 IS_PASSABLE_UNDER(i)));
4311 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4314 /* ---------- COLLECTIBLE ---------------------------------------------- */
4315 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4319 /* ---------- SNAPPABLE ------------------------------------------------ */
4320 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4321 IS_COLLECTIBLE(i) ||
4325 /* ---------- WALL ----------------------------------------------------- */
4326 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4328 for (j = 0; no_wall_properties[j] != -1; j++)
4329 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4330 i >= EL_FIRST_RUNTIME_UNREAL)
4331 SET_PROPERTY(i, EP_WALL, FALSE);
4333 if (IS_HISTORIC_WALL(i))
4334 SET_PROPERTY(i, EP_WALL, TRUE);
4336 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4337 if (engine_version < VERSION_IDENT(2,2,0,0))
4338 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4340 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4342 !IS_COLLECTIBLE(i)));
4344 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4345 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4346 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4348 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4349 IS_INDESTRUCTIBLE(i)));
4351 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4353 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4354 else if (engine_version < VERSION_IDENT(2,2,0,0))
4355 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4357 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4361 if (IS_CUSTOM_ELEMENT(i))
4363 /* these are additional properties which are initially false when set */
4365 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4367 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4368 if (DONT_COLLIDE_WITH(i))
4369 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4371 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4372 if (CAN_SMASH_EVERYTHING(i))
4373 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4374 if (CAN_SMASH_ENEMIES(i))
4375 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4378 /* ---------- CAN_SMASH ------------------------------------------------ */
4379 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4380 CAN_SMASH_ENEMIES(i) ||
4381 CAN_SMASH_EVERYTHING(i)));
4383 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4384 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4385 EXPLODES_BY_FIRE(i)));
4387 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4388 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4389 EXPLODES_SMASHED(i)));
4391 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4392 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4393 EXPLODES_IMPACT(i)));
4395 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4396 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4398 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4399 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4400 i == EL_BLACK_ORB));
4402 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4403 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4405 IS_CUSTOM_ELEMENT(i)));
4407 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4408 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4409 i == EL_SP_ELECTRON));
4411 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4412 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4413 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4414 getMoveIntoAcidProperty(&level, i));
4416 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4417 if (MAYBE_DONT_COLLIDE_WITH(i))
4418 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4419 getDontCollideWithProperty(&level, i));
4421 /* ---------- SP_PORT -------------------------------------------------- */
4422 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4423 IS_PASSABLE_INSIDE(i)));
4425 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4426 for (j = 0; j < level.num_android_clone_elements; j++)
4427 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4429 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4431 /* ---------- CAN_CHANGE ----------------------------------------------- */
4432 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4433 for (j = 0; j < element_info[i].num_change_pages; j++)
4434 if (element_info[i].change_page[j].can_change)
4435 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4437 /* ---------- HAS_ACTION ----------------------------------------------- */
4438 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4439 for (j = 0; j < element_info[i].num_change_pages; j++)
4440 if (element_info[i].change_page[j].has_action)
4441 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4443 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4444 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4447 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4448 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4449 element_info[i].crumbled[ACTION_DEFAULT] !=
4450 element_info[i].graphic[ACTION_DEFAULT]);
4452 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4453 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4454 IS_EDITOR_CASCADE_INACTIVE(i)));
4457 /* dynamically adjust element properties according to game engine version */
4459 static int ep_em_slippery_wall[] =
4464 EL_EXPANDABLE_WALL_HORIZONTAL,
4465 EL_EXPANDABLE_WALL_VERTICAL,
4466 EL_EXPANDABLE_WALL_ANY,
4467 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4468 EL_EXPANDABLE_STEELWALL_VERTICAL,
4469 EL_EXPANDABLE_STEELWALL_ANY,
4470 EL_EXPANDABLE_STEELWALL_GROWING,
4474 static int ep_em_explodes_by_fire[] =
4477 EL_EM_DYNAMITE_ACTIVE,
4482 /* special EM style gems behaviour */
4483 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4484 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4485 level.em_slippery_gems);
4487 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4488 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4489 (level.em_slippery_gems &&
4490 engine_version > VERSION_IDENT(2,0,1,0)));
4492 /* special EM style explosion behaviour regarding chain reactions */
4493 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4494 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4495 level.em_explodes_by_fire);
4498 /* this is needed because some graphics depend on element properties */
4499 if (game_status == GAME_MODE_PLAYING)
4500 InitElementGraphicInfo();
4503 void InitElementPropertiesAfterLoading(int engine_version)
4507 /* set some other uninitialized values of custom elements in older levels */
4508 if (engine_version < VERSION_IDENT(3,1,0,0))
4510 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4512 int element = EL_CUSTOM_START + i;
4514 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4516 element_info[element].explosion_delay = 17;
4517 element_info[element].ignition_delay = 8;
4522 void InitElementPropertiesGfxElement()
4526 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4528 struct ElementInfo *ei = &element_info[i];
4530 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4534 static void InitGlobal()
4539 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4541 /* check if element_name_info entry defined for each element in "main.h" */
4542 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4543 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4545 element_info[i].token_name = element_name_info[i].token_name;
4546 element_info[i].class_name = element_name_info[i].class_name;
4547 element_info[i].editor_description= element_name_info[i].editor_description;
4550 /* create hash from image config list */
4551 image_config_hash = newSetupFileHash();
4552 for (i = 0; image_config[i].token != NULL; i++)
4553 setHashEntry(image_config_hash,
4554 image_config[i].token,
4555 image_config[i].value);
4557 /* create hash from element token list */
4558 element_token_hash = newSetupFileHash();
4559 for (i = 0; element_name_info[i].token_name != NULL; i++)
4560 setHashEntry(element_token_hash,
4561 element_name_info[i].token_name,
4564 /* create hash from graphic token list */
4565 graphic_token_hash = newSetupFileHash();
4566 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4567 if (strSuffix(image_config[i].value, ".png") ||
4568 strSuffix(image_config[i].value, ".pcx") ||
4569 strSuffix(image_config[i].value, ".wav") ||
4570 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4571 setHashEntry(graphic_token_hash,
4572 image_config[i].token,
4573 int2str(graphic++, 0));
4575 /* create hash from font token list */
4576 font_token_hash = newSetupFileHash();
4577 for (i = 0; font_info[i].token_name != NULL; i++)
4578 setHashEntry(font_token_hash,
4579 font_info[i].token_name,
4582 /* set default filenames for all cloned graphics in static configuration */
4583 for (i = 0; image_config[i].token != NULL; i++)
4585 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4587 char *token = image_config[i].token;
4588 char *token_clone_from = getStringCat2(token, ".clone_from");
4589 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4591 if (token_cloned != NULL)
4593 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4595 if (value_cloned != NULL)
4597 /* set default filename in static configuration */
4598 image_config[i].value = value_cloned;
4600 /* set default filename in image config hash */
4601 setHashEntry(image_config_hash, token, value_cloned);
4605 free(token_clone_from);
4609 /* always start with reliable default values (all elements) */
4610 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4611 ActiveElement[i] = i;
4613 /* now add all entries that have an active state (active elements) */
4614 for (i = 0; element_with_active_state[i].element != -1; i++)
4616 int element = element_with_active_state[i].element;
4617 int element_active = element_with_active_state[i].element_active;
4619 ActiveElement[element] = element_active;
4622 /* always start with reliable default values (all buttons) */
4623 for (i = 0; i < NUM_IMAGE_FILES; i++)
4624 ActiveButton[i] = i;
4626 /* now add all entries that have an active state (active buttons) */
4627 for (i = 0; button_with_active_state[i].button != -1; i++)
4629 int button = button_with_active_state[i].button;
4630 int button_active = button_with_active_state[i].button_active;
4632 ActiveButton[button] = button_active;
4635 /* always start with reliable default values (all fonts) */
4636 for (i = 0; i < NUM_FONTS; i++)
4639 /* now add all entries that have an active state (active fonts) */
4640 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4642 int font = font_with_active_state[i].font_nr;
4643 int font_active = font_with_active_state[i].font_nr_active;
4645 ActiveFont[font] = font_active;
4648 global.autoplay_leveldir = NULL;
4649 global.convert_leveldir = NULL;
4650 global.create_images_dir = NULL;
4652 global.frames_per_second = 0;
4654 global.border_status = GAME_MODE_MAIN;
4656 global.use_envelope_request = FALSE;
4659 void Execute_Command(char *command)
4663 if (strEqual(command, "print graphicsinfo.conf"))
4665 Print("# You can configure additional/alternative image files here.\n");
4666 Print("# (The entries below are default and therefore commented out.)\n");
4668 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4670 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4673 for (i = 0; image_config[i].token != NULL; i++)
4674 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4675 image_config[i].value));
4679 else if (strEqual(command, "print soundsinfo.conf"))
4681 Print("# You can configure additional/alternative sound files here.\n");
4682 Print("# (The entries below are default and therefore commented out.)\n");
4684 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4686 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4689 for (i = 0; sound_config[i].token != NULL; i++)
4690 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4691 sound_config[i].value));
4695 else if (strEqual(command, "print musicinfo.conf"))
4697 Print("# You can configure additional/alternative music files here.\n");
4698 Print("# (The entries below are default and therefore commented out.)\n");
4700 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4702 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4705 for (i = 0; music_config[i].token != NULL; i++)
4706 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4707 music_config[i].value));
4711 else if (strEqual(command, "print editorsetup.conf"))
4713 Print("# You can configure your personal editor element list here.\n");
4714 Print("# (The entries below are default and therefore commented out.)\n");
4717 /* this is needed to be able to check element list for cascade elements */
4718 InitElementPropertiesStatic();
4719 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4721 PrintEditorElementList();
4725 else if (strEqual(command, "print helpanim.conf"))
4727 Print("# You can configure different element help animations here.\n");
4728 Print("# (The entries below are default and therefore commented out.)\n");
4731 for (i = 0; helpanim_config[i].token != NULL; i++)
4733 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4734 helpanim_config[i].value));
4736 if (strEqual(helpanim_config[i].token, "end"))
4742 else if (strEqual(command, "print helptext.conf"))
4744 Print("# You can configure different element help text here.\n");
4745 Print("# (The entries below are default and therefore commented out.)\n");
4748 for (i = 0; helptext_config[i].token != NULL; i++)
4749 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4750 helptext_config[i].value));
4754 else if (strPrefix(command, "dump level "))
4756 char *filename = &command[11];
4758 if (!fileExists(filename))
4759 Error(ERR_EXIT, "cannot open file '%s'", filename);
4761 LoadLevelFromFilename(&level, filename);
4766 else if (strPrefix(command, "dump tape "))
4768 char *filename = &command[10];
4770 if (!fileExists(filename))
4771 Error(ERR_EXIT, "cannot open file '%s'", filename);
4773 LoadTapeFromFilename(filename);
4778 else if (strPrefix(command, "autotest ") ||
4779 strPrefix(command, "autoplay ") ||
4780 strPrefix(command, "autoffwd "))
4782 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4784 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4785 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4786 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4788 while (*str_ptr != '\0') /* continue parsing string */
4790 /* cut leading whitespace from string, replace it by string terminator */
4791 while (*str_ptr == ' ' || *str_ptr == '\t')
4794 if (*str_ptr == '\0') /* end of string reached */
4797 if (global.autoplay_leveldir == NULL) /* read level set string */
4799 global.autoplay_leveldir = str_ptr;
4800 global.autoplay_all = TRUE; /* default: play all tapes */
4802 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4803 global.autoplay_level[i] = FALSE;
4805 else /* read level number string */
4807 int level_nr = atoi(str_ptr); /* get level_nr value */
4809 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4810 global.autoplay_level[level_nr] = TRUE;
4812 global.autoplay_all = FALSE;
4815 /* advance string pointer to the next whitespace (or end of string) */
4816 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4820 else if (strPrefix(command, "convert "))
4822 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4823 char *str_ptr = strchr(str_copy, ' ');
4825 global.convert_leveldir = str_copy;
4826 global.convert_level_nr = -1;
4828 if (str_ptr != NULL) /* level number follows */
4830 *str_ptr++ = '\0'; /* terminate leveldir string */
4831 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4834 else if (strPrefix(command, "create images "))
4836 global.create_images_dir = getStringCopy(&command[14]);
4838 if (access(global.create_images_dir, W_OK) != 0)
4839 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4840 global.create_images_dir);
4842 else if (strPrefix(command, "create CE image "))
4844 CreateCustomElementImages(&command[16]);
4850 #if defined(TARGET_SDL2)
4851 else if (strEqual(command, "SDL_ListModes"))
4853 SDL_Init(SDL_INIT_VIDEO);
4855 int num_displays = SDL_GetNumVideoDisplays();
4857 // check if there are any displays available
4858 if (num_displays < 0)
4860 Print("No displays available: %s\n", SDL_GetError());
4865 for (i = 0; i < num_displays; i++)
4867 int num_modes = SDL_GetNumDisplayModes(i);
4870 Print("Available display modes for display %d:\n", i);
4872 // check if there are any display modes available for this display
4875 Print("No display modes available for display %d: %s\n",
4881 for (j = 0; j < num_modes; j++)
4883 SDL_DisplayMode mode;
4885 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4887 Print("Cannot get display mode %d for display %d: %s\n",
4888 j, i, SDL_GetError());
4893 Print("- %d x %d\n", mode.w, mode.h);
4899 #elif defined(TARGET_SDL)
4900 else if (strEqual(command, "SDL_ListModes"))
4905 SDL_Init(SDL_INIT_VIDEO);
4907 /* get available fullscreen/hardware modes */
4908 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4910 /* check if there are any modes available */
4913 Print("No modes available!\n");
4918 /* check if our resolution is restricted */
4919 if (modes == (SDL_Rect **)-1)
4921 Print("All resolutions available.\n");
4925 Print("Available display modes:\n");
4927 for (i = 0; modes[i]; i++)
4928 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4938 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4942 static void InitSetup()
4944 LoadSetup(); /* global setup info */
4946 /* set some options from setup file */
4948 if (setup.options.verbose)
4949 options.verbose = TRUE;
4952 static void InitGameInfo()
4954 game.restart_level = FALSE;
4957 static void InitPlayerInfo()
4961 /* choose default local player */
4962 local_player = &stored_player[0];
4964 for (i = 0; i < MAX_PLAYERS; i++)
4965 stored_player[i].connected = FALSE;
4967 local_player->connected = TRUE;
4970 static void InitArtworkInfo()
4975 static char *get_string_in_brackets(char *string)
4977 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4979 sprintf(string_in_brackets, "[%s]", string);
4981 return string_in_brackets;
4984 static char *get_level_id_suffix(int id_nr)
4986 char *id_suffix = checked_malloc(1 + 3 + 1);
4988 if (id_nr < 0 || id_nr > 999)
4991 sprintf(id_suffix, ".%03d", id_nr);
4996 static void InitArtworkConfig()
4998 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5000 NUM_GLOBAL_ANIM_TOKENS + 1];
5001 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5002 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5003 static char *action_id_suffix[NUM_ACTIONS + 1];
5004 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5005 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5006 static char *level_id_suffix[MAX_LEVELS + 1];
5007 static char *dummy[1] = { NULL };
5008 static char *ignore_generic_tokens[] =
5014 static char **ignore_image_tokens;
5015 static char **ignore_sound_tokens;
5016 static char **ignore_music_tokens;
5017 int num_ignore_generic_tokens;
5018 int num_ignore_image_tokens;
5019 int num_ignore_sound_tokens;
5020 int num_ignore_music_tokens;
5023 /* dynamically determine list of generic tokens to be ignored */
5024 num_ignore_generic_tokens = 0;
5025 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5026 num_ignore_generic_tokens++;
5028 /* dynamically determine list of image tokens to be ignored */
5029 num_ignore_image_tokens = num_ignore_generic_tokens;
5030 for (i = 0; image_config_vars[i].token != NULL; i++)
5031 num_ignore_image_tokens++;
5032 ignore_image_tokens =
5033 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5034 for (i = 0; i < num_ignore_generic_tokens; i++)
5035 ignore_image_tokens[i] = ignore_generic_tokens[i];
5036 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5037 ignore_image_tokens[num_ignore_generic_tokens + i] =
5038 image_config_vars[i].token;
5039 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5041 /* dynamically determine list of sound tokens to be ignored */
5042 num_ignore_sound_tokens = num_ignore_generic_tokens;
5043 ignore_sound_tokens =
5044 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5045 for (i = 0; i < num_ignore_generic_tokens; i++)
5046 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5047 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5049 /* dynamically determine list of music tokens to be ignored */
5050 num_ignore_music_tokens = num_ignore_generic_tokens;
5051 ignore_music_tokens =
5052 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5053 for (i = 0; i < num_ignore_generic_tokens; i++)
5054 ignore_music_tokens[i] = ignore_generic_tokens[i];
5055 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5057 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5058 image_id_prefix[i] = element_info[i].token_name;
5059 for (i = 0; i < NUM_FONTS; i++)
5060 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5061 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5062 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5063 global_anim_info[i].token_name;
5064 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5066 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5067 sound_id_prefix[i] = element_info[i].token_name;
5068 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5069 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5070 get_string_in_brackets(element_info[i].class_name);
5071 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5073 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5074 music_id_prefix[i] = music_prefix_info[i].prefix;
5075 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5077 for (i = 0; i < NUM_ACTIONS; i++)
5078 action_id_suffix[i] = element_action_info[i].suffix;
5079 action_id_suffix[NUM_ACTIONS] = NULL;
5081 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5082 direction_id_suffix[i] = element_direction_info[i].suffix;
5083 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5085 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5086 special_id_suffix[i] = special_suffix_info[i].suffix;
5087 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5089 for (i = 0; i < MAX_LEVELS; i++)
5090 level_id_suffix[i] = get_level_id_suffix(i);
5091 level_id_suffix[MAX_LEVELS] = NULL;
5093 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5094 image_id_prefix, action_id_suffix, direction_id_suffix,
5095 special_id_suffix, ignore_image_tokens);
5096 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5097 sound_id_prefix, action_id_suffix, dummy,
5098 special_id_suffix, ignore_sound_tokens);
5099 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5100 music_id_prefix, special_id_suffix, level_id_suffix,
5101 dummy, ignore_music_tokens);
5104 static void InitMixer()
5111 void InitGfxBuffers()
5113 static int win_xsize_last = -1;
5114 static int win_ysize_last = -1;
5116 /* create additional image buffers for double-buffering and cross-fading */
5118 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5120 /* may contain content for cross-fading -- only re-create if changed */
5121 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5122 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5124 win_xsize_last = WIN_XSIZE;
5125 win_ysize_last = WIN_YSIZE;
5128 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5129 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5130 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5131 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5132 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5134 /* initialize screen properties */
5135 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5136 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5138 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5139 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5140 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5141 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5142 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5143 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5145 /* required if door size definitions have changed */
5146 InitGraphicCompatibilityInfo_Doors();
5148 InitGfxBuffers_EM();
5149 InitGfxBuffers_SP();
5154 struct GraphicInfo *graphic_info_last = graphic_info;
5155 char *filename_font_initial = NULL;
5156 char *filename_anim_initial = NULL;
5157 Bitmap *bitmap_font_initial = NULL;
5161 /* determine settings for initial font (for displaying startup messages) */
5162 for (i = 0; image_config[i].token != NULL; i++)
5164 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5166 char font_token[128];
5169 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5170 len_font_token = strlen(font_token);
5172 if (strEqual(image_config[i].token, font_token))
5173 filename_font_initial = image_config[i].value;
5174 else if (strlen(image_config[i].token) > len_font_token &&
5175 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5177 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5178 font_initial[j].src_x = atoi(image_config[i].value);
5179 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5180 font_initial[j].src_y = atoi(image_config[i].value);
5181 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5182 font_initial[j].width = atoi(image_config[i].value);
5183 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5184 font_initial[j].height = atoi(image_config[i].value);
5189 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5191 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5192 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5195 if (filename_font_initial == NULL) /* should not happen */
5196 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5199 InitGfxCustomArtworkInfo();
5200 InitGfxOtherSettings();
5202 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5204 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5205 font_initial[j].bitmap = bitmap_font_initial;
5207 InitFontGraphicInfo();
5209 font_height = getFontHeight(FC_RED);
5211 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5212 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5213 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5216 DrawInitText("Loading graphics", 120, FC_GREEN);
5218 /* initialize settings for busy animation with default values */
5219 int parameter[NUM_GFX_ARGS];
5220 for (i = 0; i < NUM_GFX_ARGS; i++)
5221 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5222 image_config_suffix[i].token,
5223 image_config_suffix[i].type);
5225 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5226 int len_anim_token = strlen(anim_token);
5228 /* read settings for busy animation from default custom artwork config */
5229 char *gfx_config_filename = getPath3(options.graphics_directory,
5231 GRAPHICSINFO_FILENAME);
5233 if (fileExists(gfx_config_filename))
5235 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5237 if (setup_file_hash)
5239 char *filename = getHashEntry(setup_file_hash, anim_token);
5243 filename_anim_initial = getStringCopy(filename);
5245 for (j = 0; image_config_suffix[j].token != NULL; j++)
5247 int type = image_config_suffix[j].type;
5248 char *suffix = image_config_suffix[j].token;
5249 char *token = getStringCat2(anim_token, suffix);
5250 char *value = getHashEntry(setup_file_hash, token);
5252 checked_free(token);
5255 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5259 freeSetupFileHash(setup_file_hash);
5263 if (filename_anim_initial == NULL)
5265 /* read settings for busy animation from static default artwork config */
5266 for (i = 0; image_config[i].token != NULL; i++)
5268 if (strEqual(image_config[i].token, anim_token))
5269 filename_anim_initial = getStringCopy(image_config[i].value);
5270 else if (strlen(image_config[i].token) > len_anim_token &&
5271 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5273 for (j = 0; image_config_suffix[j].token != NULL; j++)
5275 if (strEqual(&image_config[i].token[len_anim_token],
5276 image_config_suffix[j].token))
5278 get_graphic_parameter_value(image_config[i].value,
5279 image_config_suffix[j].token,
5280 image_config_suffix[j].type);
5286 if (filename_anim_initial == NULL) /* should not happen */
5287 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5289 anim_initial.bitmaps =
5290 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5292 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5293 LoadCustomImage(filename_anim_initial);
5295 checked_free(filename_anim_initial);
5297 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5299 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5301 graphic_info = graphic_info_last;
5303 init.busy.width = anim_initial.width;
5304 init.busy.height = anim_initial.height;
5306 InitMenuDesignSettings_Static();
5308 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5309 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5311 /* use copy of busy animation to prevent change while reloading artwork */
5315 void InitGfxBackground()
5317 fieldbuffer = bitmap_db_field;
5318 SetDrawtoField(DRAW_BACKBUFFER);
5320 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5322 redraw_mask = REDRAW_ALL;
5325 static void InitLevelInfo()
5327 LoadLevelInfo(); /* global level info */
5328 LoadLevelSetup_LastSeries(); /* last played series info */
5329 LoadLevelSetup_SeriesInfo(); /* last played level info */
5331 if (global.autoplay_leveldir &&
5332 global.autoplay_mode != AUTOPLAY_TEST)
5334 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5335 global.autoplay_leveldir);
5336 if (leveldir_current == NULL)
5337 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5341 static void InitLevelArtworkInfo()
5343 LoadLevelArtworkInfo();
5346 static void InitImages()
5348 print_timestamp_init("InitImages");
5351 printf("::: leveldir_current->identifier == '%s'\n",
5352 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5353 printf("::: leveldir_current->graphics_path == '%s'\n",
5354 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5355 printf("::: leveldir_current->graphics_set == '%s'\n",
5356 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5357 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5358 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5361 setLevelArtworkDir(artwork.gfx_first);
5364 printf("::: leveldir_current->identifier == '%s'\n",
5365 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5366 printf("::: leveldir_current->graphics_path == '%s'\n",
5367 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5368 printf("::: leveldir_current->graphics_set == '%s'\n",
5369 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5370 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5371 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5375 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5376 leveldir_current->identifier,
5377 artwork.gfx_current_identifier,
5378 artwork.gfx_current->identifier,
5379 leveldir_current->graphics_set,
5380 leveldir_current->graphics_path);
5383 UPDATE_BUSY_STATE();
5385 ReloadCustomImages();
5386 print_timestamp_time("ReloadCustomImages");
5388 UPDATE_BUSY_STATE();
5390 LoadCustomElementDescriptions();
5391 print_timestamp_time("LoadCustomElementDescriptions");
5393 UPDATE_BUSY_STATE();
5395 LoadMenuDesignSettings();
5396 print_timestamp_time("LoadMenuDesignSettings");
5398 UPDATE_BUSY_STATE();
5400 ReinitializeGraphics();
5401 print_timestamp_time("ReinitializeGraphics");
5403 UPDATE_BUSY_STATE();
5405 print_timestamp_done("InitImages");
5408 static void InitSound(char *identifier)
5410 print_timestamp_init("InitSound");
5412 if (identifier == NULL)
5413 identifier = artwork.snd_current->identifier;
5415 /* set artwork path to send it to the sound server process */
5416 setLevelArtworkDir(artwork.snd_first);
5418 InitReloadCustomSounds(identifier);
5419 print_timestamp_time("InitReloadCustomSounds");
5421 ReinitializeSounds();
5422 print_timestamp_time("ReinitializeSounds");
5424 print_timestamp_done("InitSound");
5427 static void InitMusic(char *identifier)
5429 print_timestamp_init("InitMusic");
5431 if (identifier == NULL)
5432 identifier = artwork.mus_current->identifier;
5434 /* set artwork path to send it to the sound server process */
5435 setLevelArtworkDir(artwork.mus_first);
5437 InitReloadCustomMusic(identifier);
5438 print_timestamp_time("InitReloadCustomMusic");
5440 ReinitializeMusic();
5441 print_timestamp_time("ReinitializeMusic");
5443 print_timestamp_done("InitMusic");
5446 void InitNetworkServer()
5448 #if defined(NETWORK_AVALIABLE)
5452 if (!options.network)
5455 #if defined(NETWORK_AVALIABLE)
5456 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5458 if (!ConnectToServer(options.server_host, options.server_port))
5459 Error(ERR_EXIT, "cannot connect to network game server");
5461 SendToServer_PlayerName(setup.player_name);
5462 SendToServer_ProtocolVersion();
5465 SendToServer_NrWanted(nr_wanted);
5469 static boolean CheckArtworkConfigForCustomElements(char *filename)
5471 SetupFileHash *setup_file_hash;
5472 boolean redefined_ce_found = FALSE;
5474 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5476 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5478 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5480 char *token = HASH_ITERATION_TOKEN(itr);
5482 if (strPrefix(token, "custom_"))
5484 redefined_ce_found = TRUE;
5489 END_HASH_ITERATION(setup_file_hash, itr)
5491 freeSetupFileHash(setup_file_hash);
5494 return redefined_ce_found;
5497 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5499 char *filename_base, *filename_local;
5500 boolean redefined_ce_found = FALSE;
5502 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5505 printf("::: leveldir_current->identifier == '%s'\n",
5506 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5507 printf("::: leveldir_current->graphics_path == '%s'\n",
5508 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5509 printf("::: leveldir_current->graphics_set == '%s'\n",
5510 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5511 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5512 leveldir_current == NULL ? "[NULL]" :
5513 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5516 /* first look for special artwork configured in level series config */
5517 filename_base = getCustomArtworkLevelConfigFilename(type);
5520 printf("::: filename_base == '%s'\n", filename_base);
5523 if (fileExists(filename_base))
5524 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5526 filename_local = getCustomArtworkConfigFilename(type);
5529 printf("::: filename_local == '%s'\n", filename_local);
5532 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5533 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5536 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5539 return redefined_ce_found;
5542 static void InitOverrideArtwork()
5544 boolean redefined_ce_found = FALSE;
5546 /* to check if this level set redefines any CEs, do not use overriding */
5547 gfx.override_level_graphics = FALSE;
5548 gfx.override_level_sounds = FALSE;
5549 gfx.override_level_music = FALSE;
5551 /* now check if this level set has definitions for custom elements */
5552 if (setup.override_level_graphics == AUTO ||
5553 setup.override_level_sounds == AUTO ||
5554 setup.override_level_music == AUTO)
5555 redefined_ce_found =
5556 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5557 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5558 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5561 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5564 if (redefined_ce_found)
5566 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5567 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5568 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5569 gfx.override_level_music = (setup.override_level_music == TRUE);
5573 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5574 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5575 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5576 gfx.override_level_music = (setup.override_level_music != FALSE);
5580 printf("::: => %d, %d, %d\n",
5581 gfx.override_level_graphics,
5582 gfx.override_level_sounds,
5583 gfx.override_level_music);
5587 static char *getNewArtworkIdentifier(int type)
5589 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5590 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5591 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5592 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5593 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5594 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5595 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5596 char *leveldir_identifier = leveldir_current->identifier;
5597 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5598 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5599 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5600 char *artwork_current_identifier;
5601 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5603 /* leveldir_current may be invalid (level group, parent link) */
5604 if (!validLevelSeries(leveldir_current))
5607 /* 1st step: determine artwork set to be activated in descending order:
5608 --------------------------------------------------------------------
5609 1. setup artwork (when configured to override everything else)
5610 2. artwork set configured in "levelinfo.conf" of current level set
5611 (artwork in level directory will have priority when loading later)
5612 3. artwork in level directory (stored in artwork sub-directory)
5613 4. setup artwork (currently configured in setup menu) */
5615 if (setup_override_artwork)
5616 artwork_current_identifier = setup_artwork_set;
5617 else if (leveldir_artwork_set != NULL)
5618 artwork_current_identifier = leveldir_artwork_set;
5619 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5620 artwork_current_identifier = leveldir_identifier;
5622 artwork_current_identifier = setup_artwork_set;
5625 /* 2nd step: check if it is really needed to reload artwork set
5626 ------------------------------------------------------------ */
5628 /* ---------- reload if level set and also artwork set has changed ------- */
5629 if (leveldir_current_identifier[type] != leveldir_identifier &&
5630 (last_has_level_artwork_set[type] || has_level_artwork_set))
5631 artwork_new_identifier = artwork_current_identifier;
5633 leveldir_current_identifier[type] = leveldir_identifier;
5634 last_has_level_artwork_set[type] = has_level_artwork_set;
5636 /* ---------- reload if "override artwork" setting has changed ----------- */
5637 if (last_override_level_artwork[type] != setup_override_artwork)
5638 artwork_new_identifier = artwork_current_identifier;
5640 last_override_level_artwork[type] = setup_override_artwork;
5642 /* ---------- reload if current artwork identifier has changed ----------- */
5643 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5644 artwork_current_identifier))
5645 artwork_new_identifier = artwork_current_identifier;
5647 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5649 /* ---------- do not reload directly after starting ---------------------- */
5650 if (!initialized[type])
5651 artwork_new_identifier = NULL;
5653 initialized[type] = TRUE;
5655 return artwork_new_identifier;
5658 void ReloadCustomArtwork(int force_reload)
5660 int last_game_status = game_status; /* save current game status */
5661 char *gfx_new_identifier;
5662 char *snd_new_identifier;
5663 char *mus_new_identifier;
5664 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5665 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5666 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5667 boolean reload_needed;
5669 InitOverrideArtwork();
5671 force_reload_gfx |= AdjustGraphicsForEMC();
5673 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5674 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5675 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5677 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5678 snd_new_identifier != NULL || force_reload_snd ||
5679 mus_new_identifier != NULL || force_reload_mus);
5684 print_timestamp_init("ReloadCustomArtwork");
5686 game_status = GAME_MODE_LOADING;
5688 FadeOut(REDRAW_ALL);
5690 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5691 print_timestamp_time("ClearRectangle");
5695 if (gfx_new_identifier != NULL || force_reload_gfx)
5698 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5699 artwork.gfx_current_identifier,
5701 artwork.gfx_current->identifier,
5702 leveldir_current->graphics_set);
5706 print_timestamp_time("InitImages");
5709 if (snd_new_identifier != NULL || force_reload_snd)
5711 InitSound(snd_new_identifier);
5712 print_timestamp_time("InitSound");
5715 if (mus_new_identifier != NULL || force_reload_mus)
5717 InitMusic(mus_new_identifier);
5718 print_timestamp_time("InitMusic");
5721 game_status = last_game_status; /* restore current game status */
5723 init_last = init; /* switch to new busy animation */
5725 FadeOut(REDRAW_ALL);
5727 RedrawGlobalBorder();
5729 /* force redraw of (open or closed) door graphics */
5730 SetDoorState(DOOR_OPEN_ALL);
5731 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5733 FadeSetEnterScreen();
5734 FadeSkipNextFadeOut();
5736 print_timestamp_done("ReloadCustomArtwork");
5738 LimitScreenUpdates(FALSE);
5741 void KeyboardAutoRepeatOffUnlessAutoplay()
5743 if (global.autoplay_leveldir == NULL)
5744 KeyboardAutoRepeatOff();
5747 void DisplayExitMessage(char *format, va_list ap)
5749 // check if draw buffer and fonts for exit message are already available
5750 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5753 int font_1 = FC_RED;
5754 int font_2 = FC_YELLOW;
5755 int font_3 = FC_BLUE;
5756 int font_width = getFontWidth(font_2);
5757 int font_height = getFontHeight(font_2);
5760 int sxsize = WIN_XSIZE - 2 * sx;
5761 int sysize = WIN_YSIZE - 2 * sy;
5762 int line_length = sxsize / font_width;
5763 int max_lines = sysize / font_height;
5764 int num_lines_printed;
5768 gfx.sxsize = sxsize;
5769 gfx.sysize = sysize;
5773 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5775 DrawTextSCentered(sy, font_1, "Fatal error:");
5776 sy += 3 * font_height;;
5779 DrawTextBufferVA(sx, sy, format, ap, font_2,
5780 line_length, line_length, max_lines,
5781 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5782 sy += (num_lines_printed + 3) * font_height;
5784 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5785 sy += 3 * font_height;
5788 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5789 line_length, line_length, max_lines,
5790 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5792 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5794 redraw_mask = REDRAW_ALL;
5796 /* force drawing exit message even if screen updates are currently limited */
5797 LimitScreenUpdates(FALSE);
5801 /* deactivate toons on error message screen */
5802 setup.toons = FALSE;
5804 WaitForEventToContinue();
5808 /* ========================================================================= */
5810 /* ========================================================================= */
5814 print_timestamp_init("OpenAll");
5816 game_status = GAME_MODE_LOADING;
5820 InitGlobal(); /* initialize some global variables */
5822 print_timestamp_time("[init global stuff]");
5826 print_timestamp_time("[init setup/config stuff (1)]");
5828 if (options.execute_command)
5829 Execute_Command(options.execute_command);
5831 if (options.serveronly)
5833 #if defined(PLATFORM_UNIX)
5834 NetworkServer(options.server_port, options.serveronly);
5836 Error(ERR_WARN, "networking only supported in Unix version");
5839 exit(0); /* never reached, server loops forever */
5843 print_timestamp_time("[init setup/config stuff (2)]");
5845 print_timestamp_time("[init setup/config stuff (3)]");
5846 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5847 print_timestamp_time("[init setup/config stuff (4)]");
5848 InitArtworkConfig(); /* needed before forking sound child process */
5849 print_timestamp_time("[init setup/config stuff (5)]");
5851 print_timestamp_time("[init setup/config stuff (6)]");
5853 InitRND(NEW_RANDOMIZE);
5854 InitSimpleRandom(NEW_RANDOMIZE);
5858 print_timestamp_time("[init setup/config stuff]");
5861 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5863 InitEventFilter(FilterEvents);
5865 print_timestamp_time("[init video stuff]");
5867 InitElementPropertiesStatic();
5868 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5869 InitElementPropertiesGfxElement();
5871 print_timestamp_time("[init element properties stuff]");
5875 print_timestamp_time("InitGfx");
5878 print_timestamp_time("InitLevelInfo");
5880 InitLevelArtworkInfo();
5881 print_timestamp_time("InitLevelArtworkInfo");
5883 InitOverrideArtwork(); /* needs to know current level directory */
5884 print_timestamp_time("InitOverrideArtwork");
5886 InitImages(); /* needs to know current level directory */
5887 print_timestamp_time("InitImages");
5889 InitSound(NULL); /* needs to know current level directory */
5890 print_timestamp_time("InitSound");
5892 InitMusic(NULL); /* needs to know current level directory */
5893 print_timestamp_time("InitMusic");
5895 InitGfxBackground();
5900 if (global.autoplay_leveldir)
5905 else if (global.convert_leveldir)
5910 else if (global.create_images_dir)
5912 CreateLevelSketchImages();
5916 game_status = GAME_MODE_MAIN;
5918 FadeSetEnterScreen();
5919 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5920 FadeSkipNextFadeOut();
5922 print_timestamp_time("[post-artwork]");
5924 print_timestamp_done("OpenAll");
5928 InitNetworkServer();
5931 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5933 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5934 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5935 #if defined(PLATFORM_ANDROID)
5936 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5937 SDL_AndroidGetInternalStoragePath());
5938 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5939 SDL_AndroidGetExternalStoragePath());
5940 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5941 (SDL_AndroidGetExternalStorageState() ==
5942 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5943 SDL_AndroidGetExternalStorageState() ==
5944 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5949 void CloseAllAndExit(int exit_value)
5954 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5961 #if defined(TARGET_SDL)
5962 #if defined(TARGET_SDL2)
5964 // set a flag to tell the network server thread to quit and wait for it
5965 // using SDL_WaitThread()
5967 if (network_server) /* terminate network server */
5968 SDL_KillThread(server_thread);
5972 CloseVideoDisplay();
5973 ClosePlatformDependentStuff();
5975 if (exit_value != 0)
5977 /* fall back to default level set (current set may have caused an error) */
5978 SaveLevelSetup_LastSeries_Deactivate();
5980 /* tell user where to find error log file which may contain more details */
5981 // (error notification now directly displayed on screen inside R'n'D
5982 // NotifyUserAboutErrorFile(); /* currently only works for Windows */