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 < MAX_NUM_TOONS; i++)
236 CreateImageTextures(IMG_TOON_1 + i);
238 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
240 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
242 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
244 int graphic = global_anim_info[i].graphic[j][k];
246 if (graphic == IMG_UNDEFINED)
249 CreateImageTextures(graphic);
256 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
257 void SetBitmaps_EM(Bitmap **em_bitmap)
259 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
260 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
265 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
266 void SetBitmaps_SP(Bitmap **sp_bitmap)
268 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
272 static int getFontBitmapID(int font_nr)
276 /* (special case: do not use special font for GAME_MODE_LOADING) */
277 if (game_status >= GAME_MODE_TITLE_INITIAL &&
278 game_status <= GAME_MODE_PSEUDO_PREVIEW)
279 special = game_status;
280 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
281 special = GFX_SPECIAL_ARG_MAIN;
284 return font_info[font_nr].special_bitmap_id[special];
289 static int getFontFromToken(char *token)
291 char *value = getHashEntry(font_token_hash, token);
296 /* if font not found, use reliable default value */
297 return FONT_INITIAL_1;
300 void InitFontGraphicInfo()
302 static struct FontBitmapInfo *font_bitmap_info = NULL;
303 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
304 int num_property_mappings = getImageListPropertyMappingSize();
305 int num_font_bitmaps = NUM_FONTS;
308 if (graphic_info == NULL) /* still at startup phase */
310 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
311 getFontBitmapID, getFontFromToken);
316 /* ---------- initialize font graphic definitions ---------- */
318 /* always start with reliable default values (normal font graphics) */
319 for (i = 0; i < NUM_FONTS; i++)
320 font_info[i].graphic = IMG_FONT_INITIAL_1;
322 /* initialize normal font/graphic mapping from static configuration */
323 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
325 int font_nr = font_to_graphic[i].font_nr;
326 int special = font_to_graphic[i].special;
327 int graphic = font_to_graphic[i].graphic;
332 font_info[font_nr].graphic = graphic;
335 /* always start with reliable default values (special font graphics) */
336 for (i = 0; i < NUM_FONTS; i++)
338 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
340 font_info[i].special_graphic[j] = font_info[i].graphic;
341 font_info[i].special_bitmap_id[j] = i;
345 /* initialize special font/graphic mapping from static configuration */
346 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
348 int font_nr = font_to_graphic[i].font_nr;
349 int special = font_to_graphic[i].special;
350 int graphic = font_to_graphic[i].graphic;
351 int base_graphic = font2baseimg(font_nr);
353 if (IS_SPECIAL_GFX_ARG(special))
355 boolean base_redefined =
356 getImageListEntryFromImageID(base_graphic)->redefined;
357 boolean special_redefined =
358 getImageListEntryFromImageID(graphic)->redefined;
359 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
361 /* if the base font ("font.title_1", for example) has been redefined,
362 but not the special font ("font.title_1.LEVELS", for example), do not
363 use an existing (in this case considered obsolete) special font
364 anymore, but use the automatically determined default font */
365 /* special case: cloned special fonts must be explicitly redefined,
366 but are not automatically redefined by redefining base font */
367 if (base_redefined && !special_redefined && !special_cloned)
370 font_info[font_nr].special_graphic[special] = graphic;
371 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
376 /* initialize special font/graphic mapping from dynamic configuration */
377 for (i = 0; i < num_property_mappings; i++)
379 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
380 int special = property_mapping[i].ext3_index;
381 int graphic = property_mapping[i].artwork_index;
386 if (IS_SPECIAL_GFX_ARG(special))
388 font_info[font_nr].special_graphic[special] = graphic;
389 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
394 /* correct special font/graphic mapping for cloned fonts for downwards
395 compatibility of PREVIEW fonts -- this is only needed for implicit
396 redefinition of special font by redefined base font, and only if other
397 fonts are cloned from this special font (like in the "Zelda" level set) */
398 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
400 int font_nr = font_to_graphic[i].font_nr;
401 int special = font_to_graphic[i].special;
402 int graphic = font_to_graphic[i].graphic;
404 if (IS_SPECIAL_GFX_ARG(special))
406 boolean special_redefined =
407 getImageListEntryFromImageID(graphic)->redefined;
408 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
410 if (special_cloned && !special_redefined)
414 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
416 int font_nr2 = font_to_graphic[j].font_nr;
417 int special2 = font_to_graphic[j].special;
418 int graphic2 = font_to_graphic[j].graphic;
420 if (IS_SPECIAL_GFX_ARG(special2) &&
421 graphic2 == graphic_info[graphic].clone_from)
423 font_info[font_nr].special_graphic[special] =
424 font_info[font_nr2].special_graphic[special2];
425 font_info[font_nr].special_bitmap_id[special] =
426 font_info[font_nr2].special_bitmap_id[special2];
433 /* reset non-redefined ".active" font graphics if normal font is redefined */
434 /* (this different treatment is needed because normal and active fonts are
435 independently defined ("active" is not a property of font definitions!) */
436 for (i = 0; i < NUM_FONTS; i++)
438 int font_nr_base = i;
439 int font_nr_active = FONT_ACTIVE(font_nr_base);
441 /* check only those fonts with exist as normal and ".active" variant */
442 if (font_nr_base != font_nr_active)
444 int base_graphic = font_info[font_nr_base].graphic;
445 int active_graphic = font_info[font_nr_active].graphic;
446 boolean base_redefined =
447 getImageListEntryFromImageID(base_graphic)->redefined;
448 boolean active_redefined =
449 getImageListEntryFromImageID(active_graphic)->redefined;
451 /* if the base font ("font.menu_1", for example) has been redefined,
452 but not the active font ("font.menu_1.active", for example), do not
453 use an existing (in this case considered obsolete) active font
454 anymore, but use the automatically determined default font */
455 if (base_redefined && !active_redefined)
456 font_info[font_nr_active].graphic = base_graphic;
458 /* now also check each "special" font (which may be the same as above) */
459 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
461 int base_graphic = font_info[font_nr_base].special_graphic[j];
462 int active_graphic = font_info[font_nr_active].special_graphic[j];
463 boolean base_redefined =
464 getImageListEntryFromImageID(base_graphic)->redefined;
465 boolean active_redefined =
466 getImageListEntryFromImageID(active_graphic)->redefined;
468 /* same as above, but check special graphic definitions, for example:
469 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
470 if (base_redefined && !active_redefined)
472 font_info[font_nr_active].special_graphic[j] =
473 font_info[font_nr_base].special_graphic[j];
474 font_info[font_nr_active].special_bitmap_id[j] =
475 font_info[font_nr_base].special_bitmap_id[j];
481 /* ---------- initialize font bitmap array ---------- */
483 if (font_bitmap_info != NULL)
484 FreeFontInfo(font_bitmap_info);
487 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
489 /* ---------- initialize font bitmap definitions ---------- */
491 for (i = 0; i < NUM_FONTS; i++)
493 if (i < NUM_INITIAL_FONTS)
495 font_bitmap_info[i] = font_initial[i];
499 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
501 int font_bitmap_id = font_info[i].special_bitmap_id[j];
502 int graphic = font_info[i].special_graphic[j];
504 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
505 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
507 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
508 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
511 /* copy font relevant information from graphics information */
512 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
513 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
514 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
515 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
516 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
518 font_bitmap_info[font_bitmap_id].draw_xoffset =
519 graphic_info[graphic].draw_xoffset;
520 font_bitmap_info[font_bitmap_id].draw_yoffset =
521 graphic_info[graphic].draw_yoffset;
523 font_bitmap_info[font_bitmap_id].num_chars =
524 graphic_info[graphic].anim_frames;
525 font_bitmap_info[font_bitmap_id].num_chars_per_line =
526 graphic_info[graphic].anim_frames_per_line;
530 InitFontInfo(font_bitmap_info, num_font_bitmaps,
531 getFontBitmapID, getFontFromToken);
534 void InitGlobalAnimGraphicInfo()
536 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
537 int num_property_mappings = getImageListPropertyMappingSize();
540 if (graphic_info == NULL) /* still at startup phase */
543 /* always start with reliable default values (no global animations) */
544 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
545 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
546 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
547 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
549 /* initialize global animation definitions from static configuration */
550 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
552 int j = GLOBAL_ANIM_ID_PART_BASE;
553 int k = GFX_SPECIAL_ARG_DEFAULT;
555 global_anim_info[i].graphic[j][k] = IMG_GLOBAL_ANIM_1_GFX + i;
558 /* initialize global animation definitions from dynamic configuration */
559 for (i = 0; i < num_property_mappings; i++)
561 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
562 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
563 int special = property_mapping[i].ext3_index;
564 int graphic = property_mapping[i].artwork_index;
566 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
569 /* set animation part to base part, if not specified */
570 if (!IS_GLOBAL_ANIM_PART(part_nr))
571 part_nr = GLOBAL_ANIM_ID_PART_BASE;
573 /* set animation screen to default, if not specified */
574 if (!IS_SPECIAL_GFX_ARG(special))
575 special = GFX_SPECIAL_ARG_DEFAULT;
577 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
581 printf("::: InitGlobalAnimGraphicInfo\n");
583 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
584 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
585 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
586 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
587 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
588 printf("::: - anim %d, part %d, mode %d => %d\n",
589 i, j, k, global_anim_info[i].graphic[j][k]);
593 void InitElementGraphicInfo()
595 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
596 int num_property_mappings = getImageListPropertyMappingSize();
599 if (graphic_info == NULL) /* still at startup phase */
602 /* set values to -1 to identify later as "uninitialized" values */
603 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
605 for (act = 0; act < NUM_ACTIONS; act++)
607 element_info[i].graphic[act] = -1;
608 element_info[i].crumbled[act] = -1;
610 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
612 element_info[i].direction_graphic[act][dir] = -1;
613 element_info[i].direction_crumbled[act][dir] = -1;
620 /* initialize normal element/graphic mapping from static configuration */
621 for (i = 0; element_to_graphic[i].element > -1; i++)
623 int element = element_to_graphic[i].element;
624 int action = element_to_graphic[i].action;
625 int direction = element_to_graphic[i].direction;
626 boolean crumbled = element_to_graphic[i].crumbled;
627 int graphic = element_to_graphic[i].graphic;
628 int base_graphic = el2baseimg(element);
630 if (graphic_info[graphic].bitmap == NULL)
633 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
636 boolean base_redefined =
637 getImageListEntryFromImageID(base_graphic)->redefined;
638 boolean act_dir_redefined =
639 getImageListEntryFromImageID(graphic)->redefined;
641 /* if the base graphic ("emerald", for example) has been redefined,
642 but not the action graphic ("emerald.falling", for example), do not
643 use an existing (in this case considered obsolete) action graphic
644 anymore, but use the automatically determined default graphic */
645 if (base_redefined && !act_dir_redefined)
650 action = ACTION_DEFAULT;
655 element_info[element].direction_crumbled[action][direction] = graphic;
657 element_info[element].crumbled[action] = graphic;
662 element_info[element].direction_graphic[action][direction] = graphic;
664 element_info[element].graphic[action] = graphic;
668 /* initialize normal element/graphic mapping from dynamic configuration */
669 for (i = 0; i < num_property_mappings; i++)
671 int element = property_mapping[i].base_index;
672 int action = property_mapping[i].ext1_index;
673 int direction = property_mapping[i].ext2_index;
674 int special = property_mapping[i].ext3_index;
675 int graphic = property_mapping[i].artwork_index;
676 boolean crumbled = FALSE;
678 if (special == GFX_SPECIAL_ARG_CRUMBLED)
684 if (graphic_info[graphic].bitmap == NULL)
687 if (element >= MAX_NUM_ELEMENTS || special != -1)
691 action = ACTION_DEFAULT;
696 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
697 element_info[element].direction_crumbled[action][dir] = -1;
700 element_info[element].direction_crumbled[action][direction] = graphic;
702 element_info[element].crumbled[action] = graphic;
707 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
708 element_info[element].direction_graphic[action][dir] = -1;
711 element_info[element].direction_graphic[action][direction] = graphic;
713 element_info[element].graphic[action] = graphic;
717 /* now copy all graphics that are defined to be cloned from other graphics */
718 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
720 int graphic = element_info[i].graphic[ACTION_DEFAULT];
721 int crumbled_like, diggable_like;
726 crumbled_like = graphic_info[graphic].crumbled_like;
727 diggable_like = graphic_info[graphic].diggable_like;
729 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
731 for (act = 0; act < NUM_ACTIONS; act++)
732 element_info[i].crumbled[act] =
733 element_info[crumbled_like].crumbled[act];
734 for (act = 0; act < NUM_ACTIONS; act++)
735 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
736 element_info[i].direction_crumbled[act][dir] =
737 element_info[crumbled_like].direction_crumbled[act][dir];
740 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
742 element_info[i].graphic[ACTION_DIGGING] =
743 element_info[diggable_like].graphic[ACTION_DIGGING];
744 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
745 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
746 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
750 /* set hardcoded definitions for some runtime elements without graphic */
751 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
753 /* set hardcoded definitions for some internal elements without graphic */
754 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
756 if (IS_EDITOR_CASCADE_INACTIVE(i))
757 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
758 else if (IS_EDITOR_CASCADE_ACTIVE(i))
759 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
762 /* now set all undefined/invalid graphics to -1 to set to default after it */
763 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
765 for (act = 0; act < NUM_ACTIONS; act++)
769 graphic = element_info[i].graphic[act];
770 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
771 element_info[i].graphic[act] = -1;
773 graphic = element_info[i].crumbled[act];
774 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
775 element_info[i].crumbled[act] = -1;
777 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
779 graphic = element_info[i].direction_graphic[act][dir];
780 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
781 element_info[i].direction_graphic[act][dir] = -1;
783 graphic = element_info[i].direction_crumbled[act][dir];
784 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
785 element_info[i].direction_crumbled[act][dir] = -1;
792 /* adjust graphics with 2nd tile for movement according to direction
793 (do this before correcting '-1' values to minimize calculations) */
794 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
796 for (act = 0; act < NUM_ACTIONS; act++)
798 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
800 int graphic = element_info[i].direction_graphic[act][dir];
801 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
803 if (act == ACTION_FALLING) /* special case */
804 graphic = element_info[i].graphic[act];
807 graphic_info[graphic].double_movement &&
808 graphic_info[graphic].swap_double_tiles != 0)
810 struct GraphicInfo *g = &graphic_info[graphic];
811 int src_x_front = g->src_x;
812 int src_y_front = g->src_y;
813 int src_x_back = g->src_x + g->offset2_x;
814 int src_y_back = g->src_y + g->offset2_y;
815 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
817 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
818 src_y_front < src_y_back);
819 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
820 boolean swap_movement_tiles_autodetected =
821 (!frames_are_ordered_diagonally &&
822 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
823 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
824 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
825 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
828 /* swap frontside and backside graphic tile coordinates, if needed */
829 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
831 /* get current (wrong) backside tile coordinates */
832 getFixedGraphicSourceExt(graphic, 0, &dummy,
833 &src_x_back, &src_y_back, TRUE);
835 /* set frontside tile coordinates to backside tile coordinates */
836 g->src_x = src_x_back;
837 g->src_y = src_y_back;
839 /* invert tile offset to point to new backside tile coordinates */
843 /* do not swap front and backside tiles again after correction */
844 g->swap_double_tiles = 0;
853 /* now set all '-1' values to element specific default values */
854 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
856 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
857 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
858 int default_direction_graphic[NUM_DIRECTIONS_FULL];
859 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
861 if (default_graphic == -1)
862 default_graphic = IMG_UNKNOWN;
864 if (default_crumbled == -1)
865 default_crumbled = default_graphic;
867 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
869 default_direction_graphic[dir] =
870 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
871 default_direction_crumbled[dir] =
872 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
874 if (default_direction_graphic[dir] == -1)
875 default_direction_graphic[dir] = default_graphic;
877 if (default_direction_crumbled[dir] == -1)
878 default_direction_crumbled[dir] = default_direction_graphic[dir];
881 for (act = 0; act < NUM_ACTIONS; act++)
883 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
884 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
885 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
886 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
887 act == ACTION_TURNING_FROM_RIGHT ||
888 act == ACTION_TURNING_FROM_UP ||
889 act == ACTION_TURNING_FROM_DOWN);
891 /* generic default action graphic (defined by "[default]" directive) */
892 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
893 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
894 int default_remove_graphic = IMG_EMPTY;
896 if (act_remove && default_action_graphic != -1)
897 default_remove_graphic = default_action_graphic;
899 /* look for special default action graphic (classic game specific) */
900 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
901 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
902 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
903 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
904 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
905 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
907 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
908 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
909 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
910 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
911 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
912 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
914 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
915 /* !!! make this better !!! */
916 if (i == EL_EMPTY_SPACE)
918 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
919 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
922 if (default_action_graphic == -1)
923 default_action_graphic = default_graphic;
925 if (default_action_crumbled == -1)
926 default_action_crumbled = default_action_graphic;
928 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
930 /* use action graphic as the default direction graphic, if undefined */
931 int default_action_direction_graphic = element_info[i].graphic[act];
932 int default_action_direction_crumbled = element_info[i].crumbled[act];
934 /* no graphic for current action -- use default direction graphic */
935 if (default_action_direction_graphic == -1)
936 default_action_direction_graphic =
937 (act_remove ? default_remove_graphic :
939 element_info[i].direction_graphic[ACTION_TURNING][dir] :
940 default_action_graphic != default_graphic ?
941 default_action_graphic :
942 default_direction_graphic[dir]);
944 if (element_info[i].direction_graphic[act][dir] == -1)
945 element_info[i].direction_graphic[act][dir] =
946 default_action_direction_graphic;
948 if (default_action_direction_crumbled == -1)
949 default_action_direction_crumbled =
950 element_info[i].direction_graphic[act][dir];
952 if (element_info[i].direction_crumbled[act][dir] == -1)
953 element_info[i].direction_crumbled[act][dir] =
954 default_action_direction_crumbled;
957 /* no graphic for this specific action -- use default action graphic */
958 if (element_info[i].graphic[act] == -1)
959 element_info[i].graphic[act] =
960 (act_remove ? default_remove_graphic :
961 act_turning ? element_info[i].graphic[ACTION_TURNING] :
962 default_action_graphic);
964 if (element_info[i].crumbled[act] == -1)
965 element_info[i].crumbled[act] = element_info[i].graphic[act];
972 void InitElementSpecialGraphicInfo()
974 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
975 int num_property_mappings = getImageListPropertyMappingSize();
978 /* always start with reliable default values */
979 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
980 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
981 element_info[i].special_graphic[j] =
982 element_info[i].graphic[ACTION_DEFAULT];
984 /* initialize special element/graphic mapping from static configuration */
985 for (i = 0; element_to_special_graphic[i].element > -1; i++)
987 int element = element_to_special_graphic[i].element;
988 int special = element_to_special_graphic[i].special;
989 int graphic = element_to_special_graphic[i].graphic;
990 int base_graphic = el2baseimg(element);
991 boolean base_redefined =
992 getImageListEntryFromImageID(base_graphic)->redefined;
993 boolean special_redefined =
994 getImageListEntryFromImageID(graphic)->redefined;
996 /* if the base graphic ("emerald", for example) has been redefined,
997 but not the special graphic ("emerald.EDITOR", for example), do not
998 use an existing (in this case considered obsolete) special graphic
999 anymore, but use the automatically created (down-scaled) graphic */
1000 if (base_redefined && !special_redefined)
1003 element_info[element].special_graphic[special] = graphic;
1006 /* initialize special element/graphic mapping from dynamic configuration */
1007 for (i = 0; i < num_property_mappings; i++)
1009 int element = property_mapping[i].base_index;
1010 int action = property_mapping[i].ext1_index;
1011 int direction = property_mapping[i].ext2_index;
1012 int special = property_mapping[i].ext3_index;
1013 int graphic = property_mapping[i].artwork_index;
1015 /* for action ".active", replace element with active element, if exists */
1016 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1018 element = ELEMENT_ACTIVE(element);
1022 if (element >= MAX_NUM_ELEMENTS)
1025 /* do not change special graphic if action or direction was specified */
1026 if (action != -1 || direction != -1)
1029 if (IS_SPECIAL_GFX_ARG(special))
1030 element_info[element].special_graphic[special] = graphic;
1033 /* now set all undefined/invalid graphics to default */
1034 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1035 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1036 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1037 element_info[i].special_graphic[j] =
1038 element_info[i].graphic[ACTION_DEFAULT];
1041 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1043 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1044 return get_parameter_value(value_raw, suffix, type);
1046 if (strEqual(value_raw, ARG_UNDEFINED))
1047 return ARG_UNDEFINED_VALUE;
1049 if (type == TYPE_ELEMENT)
1051 char *value = getHashEntry(element_token_hash, value_raw);
1055 Error(ERR_INFO_LINE, "-");
1056 Error(ERR_INFO, "warning: error found in config file:");
1057 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1058 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1059 Error(ERR_INFO, "custom graphic rejected for this element/action");
1060 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1061 Error(ERR_INFO_LINE, "-");
1064 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1066 else if (type == TYPE_GRAPHIC)
1068 char *value = getHashEntry(graphic_token_hash, value_raw);
1069 int fallback_graphic = IMG_CHAR_EXCLAM;
1073 Error(ERR_INFO_LINE, "-");
1074 Error(ERR_INFO, "warning: error found in config file:");
1075 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1076 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1077 Error(ERR_INFO, "custom graphic rejected for this element/action");
1078 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1079 Error(ERR_INFO_LINE, "-");
1082 return (value != NULL ? atoi(value) : fallback_graphic);
1088 static int get_scaled_graphic_width(int graphic)
1090 int original_width = getOriginalImageWidthFromImageID(graphic);
1091 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1093 return original_width * scale_up_factor;
1096 static int get_scaled_graphic_height(int graphic)
1098 int original_height = getOriginalImageHeightFromImageID(graphic);
1099 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1101 return original_height * scale_up_factor;
1104 static void set_graphic_parameters_ext(int graphic, int *parameter,
1105 Bitmap **src_bitmaps)
1107 struct GraphicInfo *g = &graphic_info[graphic];
1108 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1109 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1110 int anim_frames_per_line = 1;
1112 /* always start with reliable default values */
1113 g->src_image_width = 0;
1114 g->src_image_height = 0;
1117 g->width = TILEX; /* default for element graphics */
1118 g->height = TILEY; /* default for element graphics */
1119 g->offset_x = 0; /* one or both of these values ... */
1120 g->offset_y = 0; /* ... will be corrected later */
1121 g->offset2_x = 0; /* one or both of these values ... */
1122 g->offset2_y = 0; /* ... will be corrected later */
1123 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1124 g->crumbled_like = -1; /* do not use clone element */
1125 g->diggable_like = -1; /* do not use clone element */
1126 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1127 g->scale_up_factor = 1; /* default: no scaling up */
1128 g->tile_size = TILESIZE; /* default: standard tile size */
1129 g->clone_from = -1; /* do not use clone graphic */
1130 g->init_delay_fixed = 0;
1131 g->init_delay_random = 0;
1132 g->anim_delay_fixed = 0;
1133 g->anim_delay_random = 0;
1134 g->post_delay_fixed = 0;
1135 g->post_delay_random = 0;
1136 g->fade_mode = FADE_MODE_DEFAULT;
1140 g->align = ALIGN_CENTER; /* default for title screens */
1141 g->valign = VALIGN_MIDDLE; /* default for title screens */
1142 g->sort_priority = 0; /* default for title screens */
1144 g->style = STYLE_DEFAULT;
1146 g->bitmaps = src_bitmaps;
1147 g->bitmap = src_bitmap;
1149 /* optional zoom factor for scaling up the image to a larger size */
1150 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1151 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1152 if (g->scale_up_factor < 1)
1153 g->scale_up_factor = 1; /* no scaling */
1155 /* optional tile size for using non-standard image size */
1156 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1158 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1161 // CHECK: should tile sizes less than standard tile size be allowed?
1162 if (g->tile_size < TILESIZE)
1163 g->tile_size = TILESIZE; /* standard tile size */
1166 // when setting tile size, also set width and height accordingly
1167 g->width = g->tile_size;
1168 g->height = g->tile_size;
1171 if (g->use_image_size)
1173 /* set new default bitmap size (with scaling, but without small images) */
1174 g->width = get_scaled_graphic_width(graphic);
1175 g->height = get_scaled_graphic_height(graphic);
1178 /* optional width and height of each animation frame */
1179 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1180 g->width = parameter[GFX_ARG_WIDTH];
1181 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1182 g->height = parameter[GFX_ARG_HEIGHT];
1184 /* optional x and y tile position of animation frame sequence */
1185 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1186 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1187 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1188 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1190 /* optional x and y pixel position of animation frame sequence */
1191 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1192 g->src_x = parameter[GFX_ARG_X];
1193 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1194 g->src_y = parameter[GFX_ARG_Y];
1200 Error(ERR_INFO_LINE, "-");
1201 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1202 g->width, getTokenFromImageID(graphic), TILEX);
1203 Error(ERR_INFO_LINE, "-");
1205 g->width = TILEX; /* will be checked to be inside bitmap later */
1210 Error(ERR_INFO_LINE, "-");
1211 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1212 g->height, getTokenFromImageID(graphic), TILEY);
1213 Error(ERR_INFO_LINE, "-");
1215 g->height = TILEY; /* will be checked to be inside bitmap later */
1221 /* get final bitmap size (with scaling, but without small images) */
1222 int src_image_width = get_scaled_graphic_width(graphic);
1223 int src_image_height = get_scaled_graphic_height(graphic);
1225 if (src_image_width == 0 || src_image_height == 0)
1227 /* only happens when loaded outside artwork system (like "global.busy") */
1228 src_image_width = src_bitmap->width;
1229 src_image_height = src_bitmap->height;
1232 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1234 anim_frames_per_row = src_image_width / g->tile_size;
1235 anim_frames_per_col = src_image_height / g->tile_size;
1239 anim_frames_per_row = src_image_width / g->width;
1240 anim_frames_per_col = src_image_height / g->height;
1243 g->src_image_width = src_image_width;
1244 g->src_image_height = src_image_height;
1247 /* correct x or y offset dependent of vertical or horizontal frame order */
1248 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1250 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1251 parameter[GFX_ARG_OFFSET] : g->height);
1252 anim_frames_per_line = anim_frames_per_col;
1254 else /* frames are ordered horizontally */
1256 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1257 parameter[GFX_ARG_OFFSET] : g->width);
1258 anim_frames_per_line = anim_frames_per_row;
1261 /* optionally, the x and y offset of frames can be specified directly */
1262 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1263 g->offset_x = parameter[GFX_ARG_XOFFSET];
1264 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1265 g->offset_y = parameter[GFX_ARG_YOFFSET];
1267 /* optionally, moving animations may have separate start and end graphics */
1268 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1270 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1271 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1273 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1274 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1275 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1276 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1277 else /* frames are ordered horizontally */
1278 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1279 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1281 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1282 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1283 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1284 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1285 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1287 /* optionally, the second movement tile can be specified as start tile */
1288 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1289 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1291 /* automatically determine correct number of frames, if not defined */
1292 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1293 g->anim_frames = parameter[GFX_ARG_FRAMES];
1294 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1295 g->anim_frames = anim_frames_per_row;
1296 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1297 g->anim_frames = anim_frames_per_col;
1301 if (g->anim_frames == 0) /* frames must be at least 1 */
1304 g->anim_frames_per_line =
1305 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1306 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1308 g->anim_delay = parameter[GFX_ARG_DELAY];
1309 if (g->anim_delay == 0) /* delay must be at least 1 */
1312 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1314 /* automatically determine correct start frame, if not defined */
1315 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1316 g->anim_start_frame = 0;
1317 else if (g->anim_mode & ANIM_REVERSE)
1318 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1320 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1322 /* animation synchronized with global frame counter, not move position */
1323 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1325 /* optional element for cloning crumble graphics */
1326 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1327 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1329 /* optional element for cloning digging graphics */
1330 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1331 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1333 /* optional border size for "crumbling" diggable graphics */
1334 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1335 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1337 /* used for global animations and player "boring" and "sleeping" actions */
1338 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1339 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1340 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1341 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1342 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1343 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1344 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1345 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1346 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1347 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1348 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1349 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1351 /* used for toon animations and global animations */
1352 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1353 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1354 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1355 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1356 g->direction = parameter[GFX_ARG_DIRECTION];
1357 g->position = parameter[GFX_ARG_POSITION];
1358 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1359 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1361 /* this is only used for drawing font characters */
1362 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1363 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1365 /* this is only used for drawing envelope graphics */
1366 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1368 /* used for toon animations and global animations */
1369 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1371 /* optional graphic for cloning all graphics settings */
1372 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1373 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1375 /* optional settings for drawing title screens and title messages */
1376 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1377 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1378 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1379 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1380 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1381 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1382 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1383 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1384 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1385 g->align = parameter[GFX_ARG_ALIGN];
1386 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1387 g->valign = parameter[GFX_ARG_VALIGN];
1388 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1389 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1391 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1392 g->class = parameter[GFX_ARG_CLASS];
1393 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1394 g->style = parameter[GFX_ARG_STYLE];
1396 /* this is only used for drawing menu buttons and text */
1397 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1398 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1399 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1400 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1403 static void set_graphic_parameters(int graphic)
1405 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1406 char **parameter_raw = image->parameter;
1407 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1408 int parameter[NUM_GFX_ARGS];
1411 /* if fallback to default artwork is done, also use the default parameters */
1412 if (image->fallback_to_default)
1413 parameter_raw = image->default_parameter;
1415 /* get integer values from string parameters */
1416 for (i = 0; i < NUM_GFX_ARGS; i++)
1417 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1418 image_config_suffix[i].token,
1419 image_config_suffix[i].type);
1421 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1423 UPDATE_BUSY_STATE();
1426 static void set_cloned_graphic_parameters(int graphic)
1428 int fallback_graphic = IMG_CHAR_EXCLAM;
1429 int max_num_images = getImageListSize();
1430 int clone_graphic = graphic_info[graphic].clone_from;
1431 int num_references_followed = 1;
1433 while (graphic_info[clone_graphic].clone_from != -1 &&
1434 num_references_followed < max_num_images)
1436 clone_graphic = graphic_info[clone_graphic].clone_from;
1438 num_references_followed++;
1441 if (num_references_followed >= max_num_images)
1443 Error(ERR_INFO_LINE, "-");
1444 Error(ERR_INFO, "warning: error found in config file:");
1445 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1446 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1447 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1448 Error(ERR_INFO, "custom graphic rejected for this element/action");
1450 if (graphic == fallback_graphic)
1451 Error(ERR_EXIT, "no fallback graphic available");
1453 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1454 Error(ERR_INFO_LINE, "-");
1456 graphic_info[graphic] = graphic_info[fallback_graphic];
1460 graphic_info[graphic] = graphic_info[clone_graphic];
1461 graphic_info[graphic].clone_from = clone_graphic;
1465 static void InitGraphicInfo()
1467 int fallback_graphic = IMG_CHAR_EXCLAM;
1468 int num_images = getImageListSize();
1471 /* use image size as default values for width and height for these images */
1472 static int full_size_graphics[] =
1475 IMG_GLOBAL_BORDER_MAIN,
1476 IMG_GLOBAL_BORDER_SCORES,
1477 IMG_GLOBAL_BORDER_EDITOR,
1478 IMG_GLOBAL_BORDER_PLAYING,
1481 IMG_BACKGROUND_ENVELOPE_1,
1482 IMG_BACKGROUND_ENVELOPE_2,
1483 IMG_BACKGROUND_ENVELOPE_3,
1484 IMG_BACKGROUND_ENVELOPE_4,
1485 IMG_BACKGROUND_REQUEST,
1488 IMG_BACKGROUND_TITLE_INITIAL,
1489 IMG_BACKGROUND_TITLE,
1490 IMG_BACKGROUND_MAIN,
1491 IMG_BACKGROUND_LEVELS,
1492 IMG_BACKGROUND_LEVELNR,
1493 IMG_BACKGROUND_SCORES,
1494 IMG_BACKGROUND_EDITOR,
1495 IMG_BACKGROUND_INFO,
1496 IMG_BACKGROUND_INFO_ELEMENTS,
1497 IMG_BACKGROUND_INFO_MUSIC,
1498 IMG_BACKGROUND_INFO_CREDITS,
1499 IMG_BACKGROUND_INFO_PROGRAM,
1500 IMG_BACKGROUND_INFO_VERSION,
1501 IMG_BACKGROUND_INFO_LEVELSET,
1502 IMG_BACKGROUND_SETUP,
1503 IMG_BACKGROUND_PLAYING,
1504 IMG_BACKGROUND_DOOR,
1505 IMG_BACKGROUND_TAPE,
1506 IMG_BACKGROUND_PANEL,
1507 IMG_BACKGROUND_PALETTE,
1508 IMG_BACKGROUND_TOOLBOX,
1510 IMG_TITLESCREEN_INITIAL_1,
1511 IMG_TITLESCREEN_INITIAL_2,
1512 IMG_TITLESCREEN_INITIAL_3,
1513 IMG_TITLESCREEN_INITIAL_4,
1514 IMG_TITLESCREEN_INITIAL_5,
1521 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1522 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1523 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1524 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1525 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1526 IMG_BACKGROUND_TITLEMESSAGE_1,
1527 IMG_BACKGROUND_TITLEMESSAGE_2,
1528 IMG_BACKGROUND_TITLEMESSAGE_3,
1529 IMG_BACKGROUND_TITLEMESSAGE_4,
1530 IMG_BACKGROUND_TITLEMESSAGE_5,
1535 checked_free(graphic_info);
1537 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1539 /* initialize "use_image_size" flag with default value */
1540 for (i = 0; i < num_images; i++)
1541 graphic_info[i].use_image_size = FALSE;
1543 /* initialize "use_image_size" flag from static configuration above */
1544 for (i = 0; full_size_graphics[i] != -1; i++)
1545 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1547 /* first set all graphic paramaters ... */
1548 for (i = 0; i < num_images; i++)
1549 set_graphic_parameters(i);
1551 /* ... then copy these parameters for cloned graphics */
1552 for (i = 0; i < num_images; i++)
1553 if (graphic_info[i].clone_from != -1)
1554 set_cloned_graphic_parameters(i);
1556 for (i = 0; i < num_images; i++)
1561 int first_frame, last_frame;
1562 int src_bitmap_width, src_bitmap_height;
1564 /* now check if no animation frames are outside of the loaded image */
1566 if (graphic_info[i].bitmap == NULL)
1567 continue; /* skip check for optional images that are undefined */
1569 /* get image size (this can differ from the standard element tile size!) */
1570 width = graphic_info[i].width;
1571 height = graphic_info[i].height;
1573 /* get final bitmap size (with scaling, but without small images) */
1574 src_bitmap_width = graphic_info[i].src_image_width;
1575 src_bitmap_height = graphic_info[i].src_image_height;
1577 /* check if first animation frame is inside specified bitmap */
1580 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1582 /* this avoids calculating wrong start position for out-of-bounds frame */
1583 src_x = graphic_info[i].src_x;
1584 src_y = graphic_info[i].src_y;
1586 if (src_x < 0 || src_y < 0 ||
1587 src_x + width > src_bitmap_width ||
1588 src_y + height > src_bitmap_height)
1590 Error(ERR_INFO_LINE, "-");
1591 Error(ERR_INFO, "warning: error found in config file:");
1592 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1593 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1594 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1596 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1597 src_x, src_y, src_bitmap_width, src_bitmap_height);
1598 Error(ERR_INFO, "custom graphic rejected for this element/action");
1600 if (i == fallback_graphic)
1601 Error(ERR_EXIT, "no fallback graphic available");
1603 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1604 Error(ERR_INFO_LINE, "-");
1606 graphic_info[i] = graphic_info[fallback_graphic];
1609 /* check if last animation frame is inside specified bitmap */
1611 last_frame = graphic_info[i].anim_frames - 1;
1612 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1614 if (src_x < 0 || src_y < 0 ||
1615 src_x + width > src_bitmap_width ||
1616 src_y + height > src_bitmap_height)
1618 Error(ERR_INFO_LINE, "-");
1619 Error(ERR_INFO, "warning: error found in config file:");
1620 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1621 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1622 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1624 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1625 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1626 Error(ERR_INFO, "::: %d, %d", width, height);
1627 Error(ERR_INFO, "custom graphic rejected for this element/action");
1629 if (i == fallback_graphic)
1630 Error(ERR_EXIT, "no fallback graphic available");
1632 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1633 Error(ERR_INFO_LINE, "-");
1635 graphic_info[i] = graphic_info[fallback_graphic];
1640 static void InitGraphicCompatibilityInfo()
1642 struct FileInfo *fi_global_door =
1643 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1644 int num_images = getImageListSize();
1647 /* the following compatibility handling is needed for the following case:
1648 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1649 graphics mainly used for door and panel graphics, like editor, tape and
1650 in-game buttons with hard-coded bitmap positions and button sizes; as
1651 these graphics now have individual definitions, redefining "global.door"
1652 to change all these graphics at once like before does not work anymore
1653 (because all those individual definitions still have their default values);
1654 to solve this, remap all those individual definitions that are not
1655 redefined to the new bitmap of "global.door" if it was redefined */
1657 /* special compatibility handling if image "global.door" was redefined */
1658 if (fi_global_door->redefined)
1660 for (i = 0; i < num_images; i++)
1662 struct FileInfo *fi = getImageListEntryFromImageID(i);
1664 /* process only those images that still use the default settings */
1667 /* process all images which default to same image as "global.door" */
1668 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1670 // printf("::: special treatment needed for token '%s'\n", fi->token);
1672 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1678 InitGraphicCompatibilityInfo_Doors();
1681 static void InitElementSoundInfo()
1683 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1684 int num_property_mappings = getSoundListPropertyMappingSize();
1687 /* set values to -1 to identify later as "uninitialized" values */
1688 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1689 for (act = 0; act < NUM_ACTIONS; act++)
1690 element_info[i].sound[act] = -1;
1692 /* initialize element/sound mapping from static configuration */
1693 for (i = 0; element_to_sound[i].element > -1; i++)
1695 int element = element_to_sound[i].element;
1696 int action = element_to_sound[i].action;
1697 int sound = element_to_sound[i].sound;
1698 boolean is_class = element_to_sound[i].is_class;
1701 action = ACTION_DEFAULT;
1704 element_info[element].sound[action] = sound;
1706 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1707 if (strEqual(element_info[j].class_name,
1708 element_info[element].class_name))
1709 element_info[j].sound[action] = sound;
1712 /* initialize element class/sound mapping from dynamic configuration */
1713 for (i = 0; i < num_property_mappings; i++)
1715 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1716 int action = property_mapping[i].ext1_index;
1717 int sound = property_mapping[i].artwork_index;
1719 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1723 action = ACTION_DEFAULT;
1725 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1726 if (strEqual(element_info[j].class_name,
1727 element_info[element_class].class_name))
1728 element_info[j].sound[action] = sound;
1731 /* initialize element/sound mapping from dynamic configuration */
1732 for (i = 0; i < num_property_mappings; i++)
1734 int element = property_mapping[i].base_index;
1735 int action = property_mapping[i].ext1_index;
1736 int sound = property_mapping[i].artwork_index;
1738 if (element >= MAX_NUM_ELEMENTS)
1742 action = ACTION_DEFAULT;
1744 element_info[element].sound[action] = sound;
1747 /* now set all '-1' values to element specific default values */
1748 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1750 for (act = 0; act < NUM_ACTIONS; act++)
1752 /* generic default action sound (defined by "[default]" directive) */
1753 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1755 /* look for special default action sound (classic game specific) */
1756 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1757 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1758 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1759 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1760 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1761 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1763 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1764 /* !!! make this better !!! */
1765 if (i == EL_EMPTY_SPACE)
1766 default_action_sound = element_info[EL_DEFAULT].sound[act];
1768 /* no sound for this specific action -- use default action sound */
1769 if (element_info[i].sound[act] == -1)
1770 element_info[i].sound[act] = default_action_sound;
1774 /* copy sound settings to some elements that are only stored in level file
1775 in native R'n'D levels, but are used by game engine in native EM levels */
1776 for (i = 0; copy_properties[i][0] != -1; i++)
1777 for (j = 1; j <= 4; j++)
1778 for (act = 0; act < NUM_ACTIONS; act++)
1779 element_info[copy_properties[i][j]].sound[act] =
1780 element_info[copy_properties[i][0]].sound[act];
1783 static void InitGameModeSoundInfo()
1787 /* set values to -1 to identify later as "uninitialized" values */
1788 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1791 /* initialize gamemode/sound mapping from static configuration */
1792 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1794 int gamemode = gamemode_to_sound[i].gamemode;
1795 int sound = gamemode_to_sound[i].sound;
1798 gamemode = GAME_MODE_DEFAULT;
1800 menu.sound[gamemode] = sound;
1803 /* now set all '-1' values to levelset specific default values */
1804 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1805 if (menu.sound[i] == -1)
1806 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1809 static void set_sound_parameters(int sound, char **parameter_raw)
1811 int parameter[NUM_SND_ARGS];
1814 /* get integer values from string parameters */
1815 for (i = 0; i < NUM_SND_ARGS; i++)
1817 get_parameter_value(parameter_raw[i],
1818 sound_config_suffix[i].token,
1819 sound_config_suffix[i].type);
1821 /* explicit loop mode setting in configuration overrides default value */
1822 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1823 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1825 /* sound volume to change the original volume when loading the sound file */
1826 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1828 /* sound priority to give certain sounds a higher or lower priority */
1829 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1832 static void InitSoundInfo()
1834 int *sound_effect_properties;
1835 int num_sounds = getSoundListSize();
1838 checked_free(sound_info);
1840 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1841 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1843 /* initialize sound effect for all elements to "no sound" */
1844 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1845 for (j = 0; j < NUM_ACTIONS; j++)
1846 element_info[i].sound[j] = SND_UNDEFINED;
1848 for (i = 0; i < num_sounds; i++)
1850 struct FileInfo *sound = getSoundListEntry(i);
1851 int len_effect_text = strlen(sound->token);
1853 sound_effect_properties[i] = ACTION_OTHER;
1854 sound_info[i].loop = FALSE; /* default: play sound only once */
1856 /* determine all loop sounds and identify certain sound classes */
1858 for (j = 0; element_action_info[j].suffix; j++)
1860 int len_action_text = strlen(element_action_info[j].suffix);
1862 if (len_action_text < len_effect_text &&
1863 strEqual(&sound->token[len_effect_text - len_action_text],
1864 element_action_info[j].suffix))
1866 sound_effect_properties[i] = element_action_info[j].value;
1867 sound_info[i].loop = element_action_info[j].is_loop_sound;
1873 /* associate elements and some selected sound actions */
1875 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1877 if (element_info[j].class_name)
1879 int len_class_text = strlen(element_info[j].class_name);
1881 if (len_class_text + 1 < len_effect_text &&
1882 strncmp(sound->token,
1883 element_info[j].class_name, len_class_text) == 0 &&
1884 sound->token[len_class_text] == '.')
1886 int sound_action_value = sound_effect_properties[i];
1888 element_info[j].sound[sound_action_value] = i;
1893 set_sound_parameters(i, sound->parameter);
1896 free(sound_effect_properties);
1899 static void InitGameModeMusicInfo()
1901 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1902 int num_property_mappings = getMusicListPropertyMappingSize();
1903 int default_levelset_music = -1;
1906 /* set values to -1 to identify later as "uninitialized" values */
1907 for (i = 0; i < MAX_LEVELS; i++)
1908 levelset.music[i] = -1;
1909 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1912 /* initialize gamemode/music mapping from static configuration */
1913 for (i = 0; gamemode_to_music[i].music > -1; i++)
1915 int gamemode = gamemode_to_music[i].gamemode;
1916 int music = gamemode_to_music[i].music;
1919 gamemode = GAME_MODE_DEFAULT;
1921 menu.music[gamemode] = music;
1924 /* initialize gamemode/music mapping from dynamic configuration */
1925 for (i = 0; i < num_property_mappings; i++)
1927 int prefix = property_mapping[i].base_index;
1928 int gamemode = property_mapping[i].ext1_index;
1929 int level = property_mapping[i].ext2_index;
1930 int music = property_mapping[i].artwork_index;
1932 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1936 gamemode = GAME_MODE_DEFAULT;
1938 /* level specific music only allowed for in-game music */
1939 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1940 gamemode = GAME_MODE_PLAYING;
1945 default_levelset_music = music;
1948 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1949 levelset.music[level] = music;
1950 if (gamemode != GAME_MODE_PLAYING)
1951 menu.music[gamemode] = music;
1954 /* now set all '-1' values to menu specific default values */
1955 /* (undefined values of "levelset.music[]" might stay at "-1" to
1956 allow dynamic selection of music files from music directory!) */
1957 for (i = 0; i < MAX_LEVELS; i++)
1958 if (levelset.music[i] == -1)
1959 levelset.music[i] = default_levelset_music;
1960 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1961 if (menu.music[i] == -1)
1962 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1965 static void set_music_parameters(int music, char **parameter_raw)
1967 int parameter[NUM_MUS_ARGS];
1970 /* get integer values from string parameters */
1971 for (i = 0; i < NUM_MUS_ARGS; i++)
1973 get_parameter_value(parameter_raw[i],
1974 music_config_suffix[i].token,
1975 music_config_suffix[i].type);
1977 /* explicit loop mode setting in configuration overrides default value */
1978 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1979 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1982 static void InitMusicInfo()
1984 int num_music = getMusicListSize();
1987 checked_free(music_info);
1989 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1991 for (i = 0; i < num_music; i++)
1993 struct FileInfo *music = getMusicListEntry(i);
1994 int len_music_text = strlen(music->token);
1996 music_info[i].loop = TRUE; /* default: play music in loop mode */
1998 /* determine all loop music */
2000 for (j = 0; music_prefix_info[j].prefix; j++)
2002 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2004 if (len_prefix_text < len_music_text &&
2005 strncmp(music->token,
2006 music_prefix_info[j].prefix, len_prefix_text) == 0)
2008 music_info[i].loop = music_prefix_info[j].is_loop_music;
2014 set_music_parameters(i, music->parameter);
2018 static void ReinitializeGraphics()
2020 print_timestamp_init("ReinitializeGraphics");
2022 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2024 InitGraphicInfo(); /* graphic properties mapping */
2025 print_timestamp_time("InitGraphicInfo");
2026 InitElementGraphicInfo(); /* element game graphic mapping */
2027 print_timestamp_time("InitElementGraphicInfo");
2028 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2029 print_timestamp_time("InitElementSpecialGraphicInfo");
2031 InitElementSmallImages(); /* scale elements to all needed sizes */
2032 print_timestamp_time("InitElementSmallImages");
2033 InitScaledImages(); /* scale all other images, if needed */
2034 print_timestamp_time("InitScaledImages");
2035 InitBitmapPointers(); /* set standard size bitmap pointers */
2036 print_timestamp_time("InitBitmapPointers");
2037 InitFontGraphicInfo(); /* initialize text drawing functions */
2038 print_timestamp_time("InitFontGraphicInfo");
2039 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2040 print_timestamp_time("InitGlobalAnimGraphicInfo");
2042 InitImageTextures(); /* create textures for certain images */
2043 print_timestamp_time("InitImageTextures");
2045 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2046 print_timestamp_time("InitGraphicInfo_EM");
2048 InitGraphicCompatibilityInfo();
2049 print_timestamp_time("InitGraphicCompatibilityInfo");
2051 SetMainBackgroundImage(IMG_BACKGROUND);
2052 print_timestamp_time("SetMainBackgroundImage");
2053 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2054 print_timestamp_time("SetDoorBackgroundImage");
2057 print_timestamp_time("InitGadgets");
2059 print_timestamp_time("InitToons");
2061 print_timestamp_time("InitDoors");
2063 print_timestamp_done("ReinitializeGraphics");
2066 static void ReinitializeSounds()
2068 InitSoundInfo(); /* sound properties mapping */
2069 InitElementSoundInfo(); /* element game sound mapping */
2070 InitGameModeSoundInfo(); /* game mode sound mapping */
2072 InitPlayLevelSound(); /* internal game sound settings */
2075 static void ReinitializeMusic()
2077 InitMusicInfo(); /* music properties mapping */
2078 InitGameModeMusicInfo(); /* game mode music mapping */
2081 static int get_special_property_bit(int element, int property_bit_nr)
2083 struct PropertyBitInfo
2089 static struct PropertyBitInfo pb_can_move_into_acid[] =
2091 /* the player may be able fall into acid when gravity is activated */
2096 { EL_SP_MURPHY, 0 },
2097 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2099 /* all elements that can move may be able to also move into acid */
2102 { EL_BUG_RIGHT, 1 },
2105 { EL_SPACESHIP, 2 },
2106 { EL_SPACESHIP_LEFT, 2 },
2107 { EL_SPACESHIP_RIGHT, 2 },
2108 { EL_SPACESHIP_UP, 2 },
2109 { EL_SPACESHIP_DOWN, 2 },
2110 { EL_BD_BUTTERFLY, 3 },
2111 { EL_BD_BUTTERFLY_LEFT, 3 },
2112 { EL_BD_BUTTERFLY_RIGHT, 3 },
2113 { EL_BD_BUTTERFLY_UP, 3 },
2114 { EL_BD_BUTTERFLY_DOWN, 3 },
2115 { EL_BD_FIREFLY, 4 },
2116 { EL_BD_FIREFLY_LEFT, 4 },
2117 { EL_BD_FIREFLY_RIGHT, 4 },
2118 { EL_BD_FIREFLY_UP, 4 },
2119 { EL_BD_FIREFLY_DOWN, 4 },
2121 { EL_YAMYAM_LEFT, 5 },
2122 { EL_YAMYAM_RIGHT, 5 },
2123 { EL_YAMYAM_UP, 5 },
2124 { EL_YAMYAM_DOWN, 5 },
2125 { EL_DARK_YAMYAM, 6 },
2128 { EL_PACMAN_LEFT, 8 },
2129 { EL_PACMAN_RIGHT, 8 },
2130 { EL_PACMAN_UP, 8 },
2131 { EL_PACMAN_DOWN, 8 },
2133 { EL_MOLE_LEFT, 9 },
2134 { EL_MOLE_RIGHT, 9 },
2136 { EL_MOLE_DOWN, 9 },
2140 { EL_SATELLITE, 13 },
2141 { EL_SP_SNIKSNAK, 14 },
2142 { EL_SP_ELECTRON, 15 },
2145 { EL_EMC_ANDROID, 18 },
2150 static struct PropertyBitInfo pb_dont_collide_with[] =
2152 { EL_SP_SNIKSNAK, 0 },
2153 { EL_SP_ELECTRON, 1 },
2161 struct PropertyBitInfo *pb_info;
2164 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2165 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2170 struct PropertyBitInfo *pb_info = NULL;
2173 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2174 if (pb_definition[i].bit_nr == property_bit_nr)
2175 pb_info = pb_definition[i].pb_info;
2177 if (pb_info == NULL)
2180 for (i = 0; pb_info[i].element != -1; i++)
2181 if (pb_info[i].element == element)
2182 return pb_info[i].bit_nr;
2187 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2188 boolean property_value)
2190 int bit_nr = get_special_property_bit(element, property_bit_nr);
2195 *bitfield |= (1 << bit_nr);
2197 *bitfield &= ~(1 << bit_nr);
2201 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2203 int bit_nr = get_special_property_bit(element, property_bit_nr);
2206 return ((*bitfield & (1 << bit_nr)) != 0);
2211 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2213 static int group_nr;
2214 static struct ElementGroupInfo *group;
2215 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2218 if (actual_group == NULL) /* not yet initialized */
2221 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2223 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2224 group_element - EL_GROUP_START + 1);
2226 /* replace element which caused too deep recursion by question mark */
2227 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2232 if (recursion_depth == 0) /* initialization */
2234 group = actual_group;
2235 group_nr = GROUP_NR(group_element);
2237 group->num_elements_resolved = 0;
2238 group->choice_pos = 0;
2240 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2241 element_info[i].in_group[group_nr] = FALSE;
2244 for (i = 0; i < actual_group->num_elements; i++)
2246 int element = actual_group->element[i];
2248 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2251 if (IS_GROUP_ELEMENT(element))
2252 ResolveGroupElementExt(element, recursion_depth + 1);
2255 group->element_resolved[group->num_elements_resolved++] = element;
2256 element_info[element].in_group[group_nr] = TRUE;
2261 void ResolveGroupElement(int group_element)
2263 ResolveGroupElementExt(group_element, 0);
2266 void InitElementPropertiesStatic()
2268 static boolean clipboard_elements_initialized = FALSE;
2270 static int ep_diggable[] =
2275 EL_SP_BUGGY_BASE_ACTIVATING,
2278 EL_INVISIBLE_SAND_ACTIVE,
2281 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2282 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2287 EL_SP_BUGGY_BASE_ACTIVE,
2294 static int ep_collectible_only[] =
2316 EL_DYNABOMB_INCREASE_NUMBER,
2317 EL_DYNABOMB_INCREASE_SIZE,
2318 EL_DYNABOMB_INCREASE_POWER,
2336 /* !!! handle separately !!! */
2337 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2343 static int ep_dont_run_into[] =
2345 /* same elements as in 'ep_dont_touch' */
2351 /* same elements as in 'ep_dont_collide_with' */
2363 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2368 EL_SP_BUGGY_BASE_ACTIVE,
2375 static int ep_dont_collide_with[] =
2377 /* same elements as in 'ep_dont_touch' */
2394 static int ep_dont_touch[] =
2404 static int ep_indestructible[] =
2408 EL_ACID_POOL_TOPLEFT,
2409 EL_ACID_POOL_TOPRIGHT,
2410 EL_ACID_POOL_BOTTOMLEFT,
2411 EL_ACID_POOL_BOTTOM,
2412 EL_ACID_POOL_BOTTOMRIGHT,
2413 EL_SP_HARDWARE_GRAY,
2414 EL_SP_HARDWARE_GREEN,
2415 EL_SP_HARDWARE_BLUE,
2417 EL_SP_HARDWARE_YELLOW,
2418 EL_SP_HARDWARE_BASE_1,
2419 EL_SP_HARDWARE_BASE_2,
2420 EL_SP_HARDWARE_BASE_3,
2421 EL_SP_HARDWARE_BASE_4,
2422 EL_SP_HARDWARE_BASE_5,
2423 EL_SP_HARDWARE_BASE_6,
2424 EL_INVISIBLE_STEELWALL,
2425 EL_INVISIBLE_STEELWALL_ACTIVE,
2426 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2427 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2428 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2429 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2430 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2431 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2432 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2433 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2434 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2435 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2436 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2437 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2439 EL_LIGHT_SWITCH_ACTIVE,
2440 EL_SIGN_EXCLAMATION,
2441 EL_SIGN_RADIOACTIVITY,
2448 EL_SIGN_ENTRY_FORBIDDEN,
2449 EL_SIGN_EMERGENCY_EXIT,
2457 EL_STEEL_EXIT_CLOSED,
2459 EL_STEEL_EXIT_OPENING,
2460 EL_STEEL_EXIT_CLOSING,
2461 EL_EM_STEEL_EXIT_CLOSED,
2462 EL_EM_STEEL_EXIT_OPEN,
2463 EL_EM_STEEL_EXIT_OPENING,
2464 EL_EM_STEEL_EXIT_CLOSING,
2465 EL_DC_STEELWALL_1_LEFT,
2466 EL_DC_STEELWALL_1_RIGHT,
2467 EL_DC_STEELWALL_1_TOP,
2468 EL_DC_STEELWALL_1_BOTTOM,
2469 EL_DC_STEELWALL_1_HORIZONTAL,
2470 EL_DC_STEELWALL_1_VERTICAL,
2471 EL_DC_STEELWALL_1_TOPLEFT,
2472 EL_DC_STEELWALL_1_TOPRIGHT,
2473 EL_DC_STEELWALL_1_BOTTOMLEFT,
2474 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2475 EL_DC_STEELWALL_1_TOPLEFT_2,
2476 EL_DC_STEELWALL_1_TOPRIGHT_2,
2477 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2478 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2479 EL_DC_STEELWALL_2_LEFT,
2480 EL_DC_STEELWALL_2_RIGHT,
2481 EL_DC_STEELWALL_2_TOP,
2482 EL_DC_STEELWALL_2_BOTTOM,
2483 EL_DC_STEELWALL_2_HORIZONTAL,
2484 EL_DC_STEELWALL_2_VERTICAL,
2485 EL_DC_STEELWALL_2_MIDDLE,
2486 EL_DC_STEELWALL_2_SINGLE,
2487 EL_STEELWALL_SLIPPERY,
2501 EL_GATE_1_GRAY_ACTIVE,
2502 EL_GATE_2_GRAY_ACTIVE,
2503 EL_GATE_3_GRAY_ACTIVE,
2504 EL_GATE_4_GRAY_ACTIVE,
2513 EL_EM_GATE_1_GRAY_ACTIVE,
2514 EL_EM_GATE_2_GRAY_ACTIVE,
2515 EL_EM_GATE_3_GRAY_ACTIVE,
2516 EL_EM_GATE_4_GRAY_ACTIVE,
2525 EL_EMC_GATE_5_GRAY_ACTIVE,
2526 EL_EMC_GATE_6_GRAY_ACTIVE,
2527 EL_EMC_GATE_7_GRAY_ACTIVE,
2528 EL_EMC_GATE_8_GRAY_ACTIVE,
2530 EL_DC_GATE_WHITE_GRAY,
2531 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2532 EL_DC_GATE_FAKE_GRAY,
2534 EL_SWITCHGATE_OPENING,
2535 EL_SWITCHGATE_CLOSED,
2536 EL_SWITCHGATE_CLOSING,
2537 EL_DC_SWITCHGATE_SWITCH_UP,
2538 EL_DC_SWITCHGATE_SWITCH_DOWN,
2540 EL_TIMEGATE_OPENING,
2542 EL_TIMEGATE_CLOSING,
2543 EL_DC_TIMEGATE_SWITCH,
2544 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2548 EL_TUBE_VERTICAL_LEFT,
2549 EL_TUBE_VERTICAL_RIGHT,
2550 EL_TUBE_HORIZONTAL_UP,
2551 EL_TUBE_HORIZONTAL_DOWN,
2556 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2557 EL_EXPANDABLE_STEELWALL_VERTICAL,
2558 EL_EXPANDABLE_STEELWALL_ANY,
2563 static int ep_slippery[] =
2577 EL_ROBOT_WHEEL_ACTIVE,
2583 EL_ACID_POOL_TOPLEFT,
2584 EL_ACID_POOL_TOPRIGHT,
2594 EL_STEELWALL_SLIPPERY,
2597 EL_EMC_WALL_SLIPPERY_1,
2598 EL_EMC_WALL_SLIPPERY_2,
2599 EL_EMC_WALL_SLIPPERY_3,
2600 EL_EMC_WALL_SLIPPERY_4,
2602 EL_EMC_MAGIC_BALL_ACTIVE,
2607 static int ep_can_change[] =
2612 static int ep_can_move[] =
2614 /* same elements as in 'pb_can_move_into_acid' */
2637 static int ep_can_fall[] =
2651 EL_QUICKSAND_FAST_FULL,
2653 EL_BD_MAGIC_WALL_FULL,
2654 EL_DC_MAGIC_WALL_FULL,
2668 static int ep_can_smash_player[] =
2694 static int ep_can_smash_enemies[] =
2703 static int ep_can_smash_everything[] =
2712 static int ep_explodes_by_fire[] =
2714 /* same elements as in 'ep_explodes_impact' */
2719 /* same elements as in 'ep_explodes_smashed' */
2729 EL_EM_DYNAMITE_ACTIVE,
2730 EL_DYNABOMB_PLAYER_1_ACTIVE,
2731 EL_DYNABOMB_PLAYER_2_ACTIVE,
2732 EL_DYNABOMB_PLAYER_3_ACTIVE,
2733 EL_DYNABOMB_PLAYER_4_ACTIVE,
2734 EL_DYNABOMB_INCREASE_NUMBER,
2735 EL_DYNABOMB_INCREASE_SIZE,
2736 EL_DYNABOMB_INCREASE_POWER,
2737 EL_SP_DISK_RED_ACTIVE,
2751 static int ep_explodes_smashed[] =
2753 /* same elements as in 'ep_explodes_impact' */
2767 static int ep_explodes_impact[] =
2776 static int ep_walkable_over[] =
2780 EL_SOKOBAN_FIELD_EMPTY,
2787 EL_EM_STEEL_EXIT_OPEN,
2788 EL_EM_STEEL_EXIT_OPENING,
2797 EL_GATE_1_GRAY_ACTIVE,
2798 EL_GATE_2_GRAY_ACTIVE,
2799 EL_GATE_3_GRAY_ACTIVE,
2800 EL_GATE_4_GRAY_ACTIVE,
2808 static int ep_walkable_inside[] =
2813 EL_TUBE_VERTICAL_LEFT,
2814 EL_TUBE_VERTICAL_RIGHT,
2815 EL_TUBE_HORIZONTAL_UP,
2816 EL_TUBE_HORIZONTAL_DOWN,
2825 static int ep_walkable_under[] =
2830 static int ep_passable_over[] =
2840 EL_EM_GATE_1_GRAY_ACTIVE,
2841 EL_EM_GATE_2_GRAY_ACTIVE,
2842 EL_EM_GATE_3_GRAY_ACTIVE,
2843 EL_EM_GATE_4_GRAY_ACTIVE,
2852 EL_EMC_GATE_5_GRAY_ACTIVE,
2853 EL_EMC_GATE_6_GRAY_ACTIVE,
2854 EL_EMC_GATE_7_GRAY_ACTIVE,
2855 EL_EMC_GATE_8_GRAY_ACTIVE,
2857 EL_DC_GATE_WHITE_GRAY,
2858 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2865 static int ep_passable_inside[] =
2871 EL_SP_PORT_HORIZONTAL,
2872 EL_SP_PORT_VERTICAL,
2874 EL_SP_GRAVITY_PORT_LEFT,
2875 EL_SP_GRAVITY_PORT_RIGHT,
2876 EL_SP_GRAVITY_PORT_UP,
2877 EL_SP_GRAVITY_PORT_DOWN,
2878 EL_SP_GRAVITY_ON_PORT_LEFT,
2879 EL_SP_GRAVITY_ON_PORT_RIGHT,
2880 EL_SP_GRAVITY_ON_PORT_UP,
2881 EL_SP_GRAVITY_ON_PORT_DOWN,
2882 EL_SP_GRAVITY_OFF_PORT_LEFT,
2883 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2884 EL_SP_GRAVITY_OFF_PORT_UP,
2885 EL_SP_GRAVITY_OFF_PORT_DOWN,
2890 static int ep_passable_under[] =
2895 static int ep_droppable[] =
2900 static int ep_explodes_1x1_old[] =
2905 static int ep_pushable[] =
2917 EL_SOKOBAN_FIELD_FULL,
2926 static int ep_explodes_cross_old[] =
2931 static int ep_protected[] =
2933 /* same elements as in 'ep_walkable_inside' */
2937 EL_TUBE_VERTICAL_LEFT,
2938 EL_TUBE_VERTICAL_RIGHT,
2939 EL_TUBE_HORIZONTAL_UP,
2940 EL_TUBE_HORIZONTAL_DOWN,
2946 /* same elements as in 'ep_passable_over' */
2955 EL_EM_GATE_1_GRAY_ACTIVE,
2956 EL_EM_GATE_2_GRAY_ACTIVE,
2957 EL_EM_GATE_3_GRAY_ACTIVE,
2958 EL_EM_GATE_4_GRAY_ACTIVE,
2967 EL_EMC_GATE_5_GRAY_ACTIVE,
2968 EL_EMC_GATE_6_GRAY_ACTIVE,
2969 EL_EMC_GATE_7_GRAY_ACTIVE,
2970 EL_EMC_GATE_8_GRAY_ACTIVE,
2972 EL_DC_GATE_WHITE_GRAY,
2973 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2977 /* same elements as in 'ep_passable_inside' */
2982 EL_SP_PORT_HORIZONTAL,
2983 EL_SP_PORT_VERTICAL,
2985 EL_SP_GRAVITY_PORT_LEFT,
2986 EL_SP_GRAVITY_PORT_RIGHT,
2987 EL_SP_GRAVITY_PORT_UP,
2988 EL_SP_GRAVITY_PORT_DOWN,
2989 EL_SP_GRAVITY_ON_PORT_LEFT,
2990 EL_SP_GRAVITY_ON_PORT_RIGHT,
2991 EL_SP_GRAVITY_ON_PORT_UP,
2992 EL_SP_GRAVITY_ON_PORT_DOWN,
2993 EL_SP_GRAVITY_OFF_PORT_LEFT,
2994 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2995 EL_SP_GRAVITY_OFF_PORT_UP,
2996 EL_SP_GRAVITY_OFF_PORT_DOWN,
3001 static int ep_throwable[] =
3006 static int ep_can_explode[] =
3008 /* same elements as in 'ep_explodes_impact' */
3013 /* same elements as in 'ep_explodes_smashed' */
3019 /* elements that can explode by explosion or by dragonfire */
3023 EL_EM_DYNAMITE_ACTIVE,
3024 EL_DYNABOMB_PLAYER_1_ACTIVE,
3025 EL_DYNABOMB_PLAYER_2_ACTIVE,
3026 EL_DYNABOMB_PLAYER_3_ACTIVE,
3027 EL_DYNABOMB_PLAYER_4_ACTIVE,
3028 EL_DYNABOMB_INCREASE_NUMBER,
3029 EL_DYNABOMB_INCREASE_SIZE,
3030 EL_DYNABOMB_INCREASE_POWER,
3031 EL_SP_DISK_RED_ACTIVE,
3039 /* elements that can explode only by explosion */
3045 static int ep_gravity_reachable[] =
3051 EL_INVISIBLE_SAND_ACTIVE,
3056 EL_SP_PORT_HORIZONTAL,
3057 EL_SP_PORT_VERTICAL,
3059 EL_SP_GRAVITY_PORT_LEFT,
3060 EL_SP_GRAVITY_PORT_RIGHT,
3061 EL_SP_GRAVITY_PORT_UP,
3062 EL_SP_GRAVITY_PORT_DOWN,
3063 EL_SP_GRAVITY_ON_PORT_LEFT,
3064 EL_SP_GRAVITY_ON_PORT_RIGHT,
3065 EL_SP_GRAVITY_ON_PORT_UP,
3066 EL_SP_GRAVITY_ON_PORT_DOWN,
3067 EL_SP_GRAVITY_OFF_PORT_LEFT,
3068 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3069 EL_SP_GRAVITY_OFF_PORT_UP,
3070 EL_SP_GRAVITY_OFF_PORT_DOWN,
3076 static int ep_player[] =
3083 EL_SOKOBAN_FIELD_PLAYER,
3089 static int ep_can_pass_magic_wall[] =
3103 static int ep_can_pass_dc_magic_wall[] =
3119 static int ep_switchable[] =
3123 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3124 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3125 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3126 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3127 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3128 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3129 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3130 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3131 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3132 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3133 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3134 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3135 EL_SWITCHGATE_SWITCH_UP,
3136 EL_SWITCHGATE_SWITCH_DOWN,
3137 EL_DC_SWITCHGATE_SWITCH_UP,
3138 EL_DC_SWITCHGATE_SWITCH_DOWN,
3140 EL_LIGHT_SWITCH_ACTIVE,
3142 EL_DC_TIMEGATE_SWITCH,
3143 EL_BALLOON_SWITCH_LEFT,
3144 EL_BALLOON_SWITCH_RIGHT,
3145 EL_BALLOON_SWITCH_UP,
3146 EL_BALLOON_SWITCH_DOWN,
3147 EL_BALLOON_SWITCH_ANY,
3148 EL_BALLOON_SWITCH_NONE,
3151 EL_EMC_MAGIC_BALL_SWITCH,
3152 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3157 static int ep_bd_element[] =
3191 static int ep_sp_element[] =
3193 /* should always be valid */
3196 /* standard classic Supaplex elements */
3203 EL_SP_HARDWARE_GRAY,
3211 EL_SP_GRAVITY_PORT_RIGHT,
3212 EL_SP_GRAVITY_PORT_DOWN,
3213 EL_SP_GRAVITY_PORT_LEFT,
3214 EL_SP_GRAVITY_PORT_UP,
3219 EL_SP_PORT_VERTICAL,
3220 EL_SP_PORT_HORIZONTAL,
3226 EL_SP_HARDWARE_BASE_1,
3227 EL_SP_HARDWARE_GREEN,
3228 EL_SP_HARDWARE_BLUE,
3230 EL_SP_HARDWARE_YELLOW,
3231 EL_SP_HARDWARE_BASE_2,
3232 EL_SP_HARDWARE_BASE_3,
3233 EL_SP_HARDWARE_BASE_4,
3234 EL_SP_HARDWARE_BASE_5,
3235 EL_SP_HARDWARE_BASE_6,
3239 /* additional elements that appeared in newer Supaplex levels */
3242 /* additional gravity port elements (not switching, but setting gravity) */
3243 EL_SP_GRAVITY_ON_PORT_LEFT,
3244 EL_SP_GRAVITY_ON_PORT_RIGHT,
3245 EL_SP_GRAVITY_ON_PORT_UP,
3246 EL_SP_GRAVITY_ON_PORT_DOWN,
3247 EL_SP_GRAVITY_OFF_PORT_LEFT,
3248 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3249 EL_SP_GRAVITY_OFF_PORT_UP,
3250 EL_SP_GRAVITY_OFF_PORT_DOWN,
3252 /* more than one Murphy in a level results in an inactive clone */
3255 /* runtime Supaplex elements */
3256 EL_SP_DISK_RED_ACTIVE,
3257 EL_SP_TERMINAL_ACTIVE,
3258 EL_SP_BUGGY_BASE_ACTIVATING,
3259 EL_SP_BUGGY_BASE_ACTIVE,
3266 static int ep_sb_element[] =
3271 EL_SOKOBAN_FIELD_EMPTY,
3272 EL_SOKOBAN_FIELD_FULL,
3273 EL_SOKOBAN_FIELD_PLAYER,
3278 EL_INVISIBLE_STEELWALL,
3283 static int ep_gem[] =
3295 static int ep_food_dark_yamyam[] =
3323 static int ep_food_penguin[] =
3337 static int ep_food_pig[] =
3349 static int ep_historic_wall[] =
3360 EL_GATE_1_GRAY_ACTIVE,
3361 EL_GATE_2_GRAY_ACTIVE,
3362 EL_GATE_3_GRAY_ACTIVE,
3363 EL_GATE_4_GRAY_ACTIVE,
3372 EL_EM_GATE_1_GRAY_ACTIVE,
3373 EL_EM_GATE_2_GRAY_ACTIVE,
3374 EL_EM_GATE_3_GRAY_ACTIVE,
3375 EL_EM_GATE_4_GRAY_ACTIVE,
3382 EL_EXPANDABLE_WALL_HORIZONTAL,
3383 EL_EXPANDABLE_WALL_VERTICAL,
3384 EL_EXPANDABLE_WALL_ANY,
3385 EL_EXPANDABLE_WALL_GROWING,
3386 EL_BD_EXPANDABLE_WALL,
3393 EL_SP_HARDWARE_GRAY,
3394 EL_SP_HARDWARE_GREEN,
3395 EL_SP_HARDWARE_BLUE,
3397 EL_SP_HARDWARE_YELLOW,
3398 EL_SP_HARDWARE_BASE_1,
3399 EL_SP_HARDWARE_BASE_2,
3400 EL_SP_HARDWARE_BASE_3,
3401 EL_SP_HARDWARE_BASE_4,
3402 EL_SP_HARDWARE_BASE_5,
3403 EL_SP_HARDWARE_BASE_6,
3405 EL_SP_TERMINAL_ACTIVE,
3408 EL_INVISIBLE_STEELWALL,
3409 EL_INVISIBLE_STEELWALL_ACTIVE,
3411 EL_INVISIBLE_WALL_ACTIVE,
3412 EL_STEELWALL_SLIPPERY,
3429 static int ep_historic_solid[] =
3433 EL_EXPANDABLE_WALL_HORIZONTAL,
3434 EL_EXPANDABLE_WALL_VERTICAL,
3435 EL_EXPANDABLE_WALL_ANY,
3436 EL_BD_EXPANDABLE_WALL,
3449 EL_QUICKSAND_FILLING,
3450 EL_QUICKSAND_EMPTYING,
3452 EL_MAGIC_WALL_ACTIVE,
3453 EL_MAGIC_WALL_EMPTYING,
3454 EL_MAGIC_WALL_FILLING,
3458 EL_BD_MAGIC_WALL_ACTIVE,
3459 EL_BD_MAGIC_WALL_EMPTYING,
3460 EL_BD_MAGIC_WALL_FULL,
3461 EL_BD_MAGIC_WALL_FILLING,
3462 EL_BD_MAGIC_WALL_DEAD,
3471 EL_SP_TERMINAL_ACTIVE,
3475 EL_INVISIBLE_WALL_ACTIVE,
3476 EL_SWITCHGATE_SWITCH_UP,
3477 EL_SWITCHGATE_SWITCH_DOWN,
3478 EL_DC_SWITCHGATE_SWITCH_UP,
3479 EL_DC_SWITCHGATE_SWITCH_DOWN,
3481 EL_TIMEGATE_SWITCH_ACTIVE,
3482 EL_DC_TIMEGATE_SWITCH,
3483 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3495 /* the following elements are a direct copy of "indestructible" elements,
3496 except "EL_ACID", which is "indestructible", but not "solid"! */
3501 EL_ACID_POOL_TOPLEFT,
3502 EL_ACID_POOL_TOPRIGHT,
3503 EL_ACID_POOL_BOTTOMLEFT,
3504 EL_ACID_POOL_BOTTOM,
3505 EL_ACID_POOL_BOTTOMRIGHT,
3506 EL_SP_HARDWARE_GRAY,
3507 EL_SP_HARDWARE_GREEN,
3508 EL_SP_HARDWARE_BLUE,
3510 EL_SP_HARDWARE_YELLOW,
3511 EL_SP_HARDWARE_BASE_1,
3512 EL_SP_HARDWARE_BASE_2,
3513 EL_SP_HARDWARE_BASE_3,
3514 EL_SP_HARDWARE_BASE_4,
3515 EL_SP_HARDWARE_BASE_5,
3516 EL_SP_HARDWARE_BASE_6,
3517 EL_INVISIBLE_STEELWALL,
3518 EL_INVISIBLE_STEELWALL_ACTIVE,
3519 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3520 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3521 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3522 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3523 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3524 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3525 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3526 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3527 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3528 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3529 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3530 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3532 EL_LIGHT_SWITCH_ACTIVE,
3533 EL_SIGN_EXCLAMATION,
3534 EL_SIGN_RADIOACTIVITY,
3541 EL_SIGN_ENTRY_FORBIDDEN,
3542 EL_SIGN_EMERGENCY_EXIT,
3550 EL_STEEL_EXIT_CLOSED,
3552 EL_DC_STEELWALL_1_LEFT,
3553 EL_DC_STEELWALL_1_RIGHT,
3554 EL_DC_STEELWALL_1_TOP,
3555 EL_DC_STEELWALL_1_BOTTOM,
3556 EL_DC_STEELWALL_1_HORIZONTAL,
3557 EL_DC_STEELWALL_1_VERTICAL,
3558 EL_DC_STEELWALL_1_TOPLEFT,
3559 EL_DC_STEELWALL_1_TOPRIGHT,
3560 EL_DC_STEELWALL_1_BOTTOMLEFT,
3561 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3562 EL_DC_STEELWALL_1_TOPLEFT_2,
3563 EL_DC_STEELWALL_1_TOPRIGHT_2,
3564 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3565 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3566 EL_DC_STEELWALL_2_LEFT,
3567 EL_DC_STEELWALL_2_RIGHT,
3568 EL_DC_STEELWALL_2_TOP,
3569 EL_DC_STEELWALL_2_BOTTOM,
3570 EL_DC_STEELWALL_2_HORIZONTAL,
3571 EL_DC_STEELWALL_2_VERTICAL,
3572 EL_DC_STEELWALL_2_MIDDLE,
3573 EL_DC_STEELWALL_2_SINGLE,
3574 EL_STEELWALL_SLIPPERY,
3588 EL_GATE_1_GRAY_ACTIVE,
3589 EL_GATE_2_GRAY_ACTIVE,
3590 EL_GATE_3_GRAY_ACTIVE,
3591 EL_GATE_4_GRAY_ACTIVE,
3600 EL_EM_GATE_1_GRAY_ACTIVE,
3601 EL_EM_GATE_2_GRAY_ACTIVE,
3602 EL_EM_GATE_3_GRAY_ACTIVE,
3603 EL_EM_GATE_4_GRAY_ACTIVE,
3605 EL_SWITCHGATE_OPENING,
3606 EL_SWITCHGATE_CLOSED,
3607 EL_SWITCHGATE_CLOSING,
3609 EL_TIMEGATE_OPENING,
3611 EL_TIMEGATE_CLOSING,
3615 EL_TUBE_VERTICAL_LEFT,
3616 EL_TUBE_VERTICAL_RIGHT,
3617 EL_TUBE_HORIZONTAL_UP,
3618 EL_TUBE_HORIZONTAL_DOWN,
3627 static int ep_classic_enemy[] =
3644 static int ep_belt[] =
3646 EL_CONVEYOR_BELT_1_LEFT,
3647 EL_CONVEYOR_BELT_1_MIDDLE,
3648 EL_CONVEYOR_BELT_1_RIGHT,
3649 EL_CONVEYOR_BELT_2_LEFT,
3650 EL_CONVEYOR_BELT_2_MIDDLE,
3651 EL_CONVEYOR_BELT_2_RIGHT,
3652 EL_CONVEYOR_BELT_3_LEFT,
3653 EL_CONVEYOR_BELT_3_MIDDLE,
3654 EL_CONVEYOR_BELT_3_RIGHT,
3655 EL_CONVEYOR_BELT_4_LEFT,
3656 EL_CONVEYOR_BELT_4_MIDDLE,
3657 EL_CONVEYOR_BELT_4_RIGHT,
3662 static int ep_belt_active[] =
3664 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3665 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3666 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3667 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3668 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3669 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3670 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3671 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3672 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3673 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3674 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3675 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3680 static int ep_belt_switch[] =
3682 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3683 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3684 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3685 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3686 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3687 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3688 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3689 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3690 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3691 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3692 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3693 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3698 static int ep_tube[] =
3705 EL_TUBE_HORIZONTAL_UP,
3706 EL_TUBE_HORIZONTAL_DOWN,
3708 EL_TUBE_VERTICAL_LEFT,
3709 EL_TUBE_VERTICAL_RIGHT,
3715 static int ep_acid_pool[] =
3717 EL_ACID_POOL_TOPLEFT,
3718 EL_ACID_POOL_TOPRIGHT,
3719 EL_ACID_POOL_BOTTOMLEFT,
3720 EL_ACID_POOL_BOTTOM,
3721 EL_ACID_POOL_BOTTOMRIGHT,
3726 static int ep_keygate[] =
3736 EL_GATE_1_GRAY_ACTIVE,
3737 EL_GATE_2_GRAY_ACTIVE,
3738 EL_GATE_3_GRAY_ACTIVE,
3739 EL_GATE_4_GRAY_ACTIVE,
3748 EL_EM_GATE_1_GRAY_ACTIVE,
3749 EL_EM_GATE_2_GRAY_ACTIVE,
3750 EL_EM_GATE_3_GRAY_ACTIVE,
3751 EL_EM_GATE_4_GRAY_ACTIVE,
3760 EL_EMC_GATE_5_GRAY_ACTIVE,
3761 EL_EMC_GATE_6_GRAY_ACTIVE,
3762 EL_EMC_GATE_7_GRAY_ACTIVE,
3763 EL_EMC_GATE_8_GRAY_ACTIVE,
3765 EL_DC_GATE_WHITE_GRAY,
3766 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3771 static int ep_amoeboid[] =
3783 static int ep_amoebalive[] =
3794 static int ep_has_editor_content[] =
3800 EL_SOKOBAN_FIELD_PLAYER,
3817 static int ep_can_turn_each_move[] =
3819 /* !!! do something with this one !!! */
3823 static int ep_can_grow[] =
3837 static int ep_active_bomb[] =
3840 EL_EM_DYNAMITE_ACTIVE,
3841 EL_DYNABOMB_PLAYER_1_ACTIVE,
3842 EL_DYNABOMB_PLAYER_2_ACTIVE,
3843 EL_DYNABOMB_PLAYER_3_ACTIVE,
3844 EL_DYNABOMB_PLAYER_4_ACTIVE,
3845 EL_SP_DISK_RED_ACTIVE,
3850 static int ep_inactive[] =
3860 EL_QUICKSAND_FAST_EMPTY,
3883 EL_GATE_1_GRAY_ACTIVE,
3884 EL_GATE_2_GRAY_ACTIVE,
3885 EL_GATE_3_GRAY_ACTIVE,
3886 EL_GATE_4_GRAY_ACTIVE,
3895 EL_EM_GATE_1_GRAY_ACTIVE,
3896 EL_EM_GATE_2_GRAY_ACTIVE,
3897 EL_EM_GATE_3_GRAY_ACTIVE,
3898 EL_EM_GATE_4_GRAY_ACTIVE,
3907 EL_EMC_GATE_5_GRAY_ACTIVE,
3908 EL_EMC_GATE_6_GRAY_ACTIVE,
3909 EL_EMC_GATE_7_GRAY_ACTIVE,
3910 EL_EMC_GATE_8_GRAY_ACTIVE,
3912 EL_DC_GATE_WHITE_GRAY,
3913 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3914 EL_DC_GATE_FAKE_GRAY,
3917 EL_INVISIBLE_STEELWALL,
3925 EL_WALL_EMERALD_YELLOW,
3926 EL_DYNABOMB_INCREASE_NUMBER,
3927 EL_DYNABOMB_INCREASE_SIZE,
3928 EL_DYNABOMB_INCREASE_POWER,
3932 EL_SOKOBAN_FIELD_EMPTY,
3933 EL_SOKOBAN_FIELD_FULL,
3934 EL_WALL_EMERALD_RED,
3935 EL_WALL_EMERALD_PURPLE,
3936 EL_ACID_POOL_TOPLEFT,
3937 EL_ACID_POOL_TOPRIGHT,
3938 EL_ACID_POOL_BOTTOMLEFT,
3939 EL_ACID_POOL_BOTTOM,
3940 EL_ACID_POOL_BOTTOMRIGHT,
3944 EL_BD_MAGIC_WALL_DEAD,
3946 EL_DC_MAGIC_WALL_DEAD,
3947 EL_AMOEBA_TO_DIAMOND,
3955 EL_SP_GRAVITY_PORT_RIGHT,
3956 EL_SP_GRAVITY_PORT_DOWN,
3957 EL_SP_GRAVITY_PORT_LEFT,
3958 EL_SP_GRAVITY_PORT_UP,
3959 EL_SP_PORT_HORIZONTAL,
3960 EL_SP_PORT_VERTICAL,
3971 EL_SP_HARDWARE_GRAY,
3972 EL_SP_HARDWARE_GREEN,
3973 EL_SP_HARDWARE_BLUE,
3975 EL_SP_HARDWARE_YELLOW,
3976 EL_SP_HARDWARE_BASE_1,
3977 EL_SP_HARDWARE_BASE_2,
3978 EL_SP_HARDWARE_BASE_3,
3979 EL_SP_HARDWARE_BASE_4,
3980 EL_SP_HARDWARE_BASE_5,
3981 EL_SP_HARDWARE_BASE_6,
3982 EL_SP_GRAVITY_ON_PORT_LEFT,
3983 EL_SP_GRAVITY_ON_PORT_RIGHT,
3984 EL_SP_GRAVITY_ON_PORT_UP,
3985 EL_SP_GRAVITY_ON_PORT_DOWN,
3986 EL_SP_GRAVITY_OFF_PORT_LEFT,
3987 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3988 EL_SP_GRAVITY_OFF_PORT_UP,
3989 EL_SP_GRAVITY_OFF_PORT_DOWN,
3990 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3991 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3992 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3993 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3994 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3995 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3996 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3997 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3998 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3999 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4000 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4001 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4002 EL_SIGN_EXCLAMATION,
4003 EL_SIGN_RADIOACTIVITY,
4010 EL_SIGN_ENTRY_FORBIDDEN,
4011 EL_SIGN_EMERGENCY_EXIT,
4019 EL_DC_STEELWALL_1_LEFT,
4020 EL_DC_STEELWALL_1_RIGHT,
4021 EL_DC_STEELWALL_1_TOP,
4022 EL_DC_STEELWALL_1_BOTTOM,
4023 EL_DC_STEELWALL_1_HORIZONTAL,
4024 EL_DC_STEELWALL_1_VERTICAL,
4025 EL_DC_STEELWALL_1_TOPLEFT,
4026 EL_DC_STEELWALL_1_TOPRIGHT,
4027 EL_DC_STEELWALL_1_BOTTOMLEFT,
4028 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4029 EL_DC_STEELWALL_1_TOPLEFT_2,
4030 EL_DC_STEELWALL_1_TOPRIGHT_2,
4031 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4032 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4033 EL_DC_STEELWALL_2_LEFT,
4034 EL_DC_STEELWALL_2_RIGHT,
4035 EL_DC_STEELWALL_2_TOP,
4036 EL_DC_STEELWALL_2_BOTTOM,
4037 EL_DC_STEELWALL_2_HORIZONTAL,
4038 EL_DC_STEELWALL_2_VERTICAL,
4039 EL_DC_STEELWALL_2_MIDDLE,
4040 EL_DC_STEELWALL_2_SINGLE,
4041 EL_STEELWALL_SLIPPERY,
4046 EL_EMC_WALL_SLIPPERY_1,
4047 EL_EMC_WALL_SLIPPERY_2,
4048 EL_EMC_WALL_SLIPPERY_3,
4049 EL_EMC_WALL_SLIPPERY_4,
4070 static int ep_em_slippery_wall[] =
4075 static int ep_gfx_crumbled[] =
4086 static int ep_editor_cascade_active[] =
4088 EL_INTERNAL_CASCADE_BD_ACTIVE,
4089 EL_INTERNAL_CASCADE_EM_ACTIVE,
4090 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4091 EL_INTERNAL_CASCADE_RND_ACTIVE,
4092 EL_INTERNAL_CASCADE_SB_ACTIVE,
4093 EL_INTERNAL_CASCADE_SP_ACTIVE,
4094 EL_INTERNAL_CASCADE_DC_ACTIVE,
4095 EL_INTERNAL_CASCADE_DX_ACTIVE,
4096 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4097 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4098 EL_INTERNAL_CASCADE_CE_ACTIVE,
4099 EL_INTERNAL_CASCADE_GE_ACTIVE,
4100 EL_INTERNAL_CASCADE_REF_ACTIVE,
4101 EL_INTERNAL_CASCADE_USER_ACTIVE,
4102 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4107 static int ep_editor_cascade_inactive[] =
4109 EL_INTERNAL_CASCADE_BD,
4110 EL_INTERNAL_CASCADE_EM,
4111 EL_INTERNAL_CASCADE_EMC,
4112 EL_INTERNAL_CASCADE_RND,
4113 EL_INTERNAL_CASCADE_SB,
4114 EL_INTERNAL_CASCADE_SP,
4115 EL_INTERNAL_CASCADE_DC,
4116 EL_INTERNAL_CASCADE_DX,
4117 EL_INTERNAL_CASCADE_CHARS,
4118 EL_INTERNAL_CASCADE_STEEL_CHARS,
4119 EL_INTERNAL_CASCADE_CE,
4120 EL_INTERNAL_CASCADE_GE,
4121 EL_INTERNAL_CASCADE_REF,
4122 EL_INTERNAL_CASCADE_USER,
4123 EL_INTERNAL_CASCADE_DYNAMIC,
4128 static int ep_obsolete[] =
4132 EL_EM_KEY_1_FILE_OBSOLETE,
4133 EL_EM_KEY_2_FILE_OBSOLETE,
4134 EL_EM_KEY_3_FILE_OBSOLETE,
4135 EL_EM_KEY_4_FILE_OBSOLETE,
4136 EL_ENVELOPE_OBSOLETE,
4145 } element_properties[] =
4147 { ep_diggable, EP_DIGGABLE },
4148 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4149 { ep_dont_run_into, EP_DONT_RUN_INTO },
4150 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4151 { ep_dont_touch, EP_DONT_TOUCH },
4152 { ep_indestructible, EP_INDESTRUCTIBLE },
4153 { ep_slippery, EP_SLIPPERY },
4154 { ep_can_change, EP_CAN_CHANGE },
4155 { ep_can_move, EP_CAN_MOVE },
4156 { ep_can_fall, EP_CAN_FALL },
4157 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4158 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4159 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4160 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4161 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4162 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4163 { ep_walkable_over, EP_WALKABLE_OVER },
4164 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4165 { ep_walkable_under, EP_WALKABLE_UNDER },
4166 { ep_passable_over, EP_PASSABLE_OVER },
4167 { ep_passable_inside, EP_PASSABLE_INSIDE },
4168 { ep_passable_under, EP_PASSABLE_UNDER },
4169 { ep_droppable, EP_DROPPABLE },
4170 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4171 { ep_pushable, EP_PUSHABLE },
4172 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4173 { ep_protected, EP_PROTECTED },
4174 { ep_throwable, EP_THROWABLE },
4175 { ep_can_explode, EP_CAN_EXPLODE },
4176 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4178 { ep_player, EP_PLAYER },
4179 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4180 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4181 { ep_switchable, EP_SWITCHABLE },
4182 { ep_bd_element, EP_BD_ELEMENT },
4183 { ep_sp_element, EP_SP_ELEMENT },
4184 { ep_sb_element, EP_SB_ELEMENT },
4186 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4187 { ep_food_penguin, EP_FOOD_PENGUIN },
4188 { ep_food_pig, EP_FOOD_PIG },
4189 { ep_historic_wall, EP_HISTORIC_WALL },
4190 { ep_historic_solid, EP_HISTORIC_SOLID },
4191 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4192 { ep_belt, EP_BELT },
4193 { ep_belt_active, EP_BELT_ACTIVE },
4194 { ep_belt_switch, EP_BELT_SWITCH },
4195 { ep_tube, EP_TUBE },
4196 { ep_acid_pool, EP_ACID_POOL },
4197 { ep_keygate, EP_KEYGATE },
4198 { ep_amoeboid, EP_AMOEBOID },
4199 { ep_amoebalive, EP_AMOEBALIVE },
4200 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4201 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4202 { ep_can_grow, EP_CAN_GROW },
4203 { ep_active_bomb, EP_ACTIVE_BOMB },
4204 { ep_inactive, EP_INACTIVE },
4206 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4208 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4210 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4211 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4213 { ep_obsolete, EP_OBSOLETE },
4220 /* always start with reliable default values (element has no properties) */
4221 /* (but never initialize clipboard elements after the very first time) */
4222 /* (to be able to use clipboard elements between several levels) */
4223 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4224 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4225 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4226 SET_PROPERTY(i, j, FALSE);
4228 /* set all base element properties from above array definitions */
4229 for (i = 0; element_properties[i].elements != NULL; i++)
4230 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4231 SET_PROPERTY((element_properties[i].elements)[j],
4232 element_properties[i].property, TRUE);
4234 /* copy properties to some elements that are only stored in level file */
4235 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4236 for (j = 0; copy_properties[j][0] != -1; j++)
4237 if (HAS_PROPERTY(copy_properties[j][0], i))
4238 for (k = 1; k <= 4; k++)
4239 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4241 /* set static element properties that are not listed in array definitions */
4242 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4243 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4245 clipboard_elements_initialized = TRUE;
4248 void InitElementPropertiesEngine(int engine_version)
4250 static int no_wall_properties[] =
4253 EP_COLLECTIBLE_ONLY,
4255 EP_DONT_COLLIDE_WITH,
4258 EP_CAN_SMASH_PLAYER,
4259 EP_CAN_SMASH_ENEMIES,
4260 EP_CAN_SMASH_EVERYTHING,
4265 EP_FOOD_DARK_YAMYAM,
4281 /* important: after initialization in InitElementPropertiesStatic(), the
4282 elements are not again initialized to a default value; therefore all
4283 changes have to make sure that they leave the element with a defined
4284 property (which means that conditional property changes must be set to
4285 a reliable default value before) */
4287 /* resolve group elements */
4288 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4289 ResolveGroupElement(EL_GROUP_START + i);
4291 /* set all special, combined or engine dependent element properties */
4292 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4294 /* do not change (already initialized) clipboard elements here */
4295 if (IS_CLIPBOARD_ELEMENT(i))
4298 /* ---------- INACTIVE ------------------------------------------------- */
4299 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4300 i <= EL_CHAR_END) ||
4301 (i >= EL_STEEL_CHAR_START &&
4302 i <= EL_STEEL_CHAR_END)));
4304 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4305 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4306 IS_WALKABLE_INSIDE(i) ||
4307 IS_WALKABLE_UNDER(i)));
4309 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4310 IS_PASSABLE_INSIDE(i) ||
4311 IS_PASSABLE_UNDER(i)));
4313 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4314 IS_PASSABLE_OVER(i)));
4316 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4317 IS_PASSABLE_INSIDE(i)));
4319 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4320 IS_PASSABLE_UNDER(i)));
4322 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4325 /* ---------- COLLECTIBLE ---------------------------------------------- */
4326 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4330 /* ---------- SNAPPABLE ------------------------------------------------ */
4331 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4332 IS_COLLECTIBLE(i) ||
4336 /* ---------- WALL ----------------------------------------------------- */
4337 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4339 for (j = 0; no_wall_properties[j] != -1; j++)
4340 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4341 i >= EL_FIRST_RUNTIME_UNREAL)
4342 SET_PROPERTY(i, EP_WALL, FALSE);
4344 if (IS_HISTORIC_WALL(i))
4345 SET_PROPERTY(i, EP_WALL, TRUE);
4347 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4348 if (engine_version < VERSION_IDENT(2,2,0,0))
4349 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4351 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4353 !IS_COLLECTIBLE(i)));
4355 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4356 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4357 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4359 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4360 IS_INDESTRUCTIBLE(i)));
4362 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4364 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4365 else if (engine_version < VERSION_IDENT(2,2,0,0))
4366 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4368 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4372 if (IS_CUSTOM_ELEMENT(i))
4374 /* these are additional properties which are initially false when set */
4376 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4378 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4379 if (DONT_COLLIDE_WITH(i))
4380 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4382 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4383 if (CAN_SMASH_EVERYTHING(i))
4384 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4385 if (CAN_SMASH_ENEMIES(i))
4386 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4389 /* ---------- CAN_SMASH ------------------------------------------------ */
4390 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4391 CAN_SMASH_ENEMIES(i) ||
4392 CAN_SMASH_EVERYTHING(i)));
4394 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4395 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4396 EXPLODES_BY_FIRE(i)));
4398 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4399 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4400 EXPLODES_SMASHED(i)));
4402 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4403 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4404 EXPLODES_IMPACT(i)));
4406 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4407 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4409 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4410 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4411 i == EL_BLACK_ORB));
4413 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4414 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4416 IS_CUSTOM_ELEMENT(i)));
4418 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4419 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4420 i == EL_SP_ELECTRON));
4422 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4423 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4424 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4425 getMoveIntoAcidProperty(&level, i));
4427 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4428 if (MAYBE_DONT_COLLIDE_WITH(i))
4429 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4430 getDontCollideWithProperty(&level, i));
4432 /* ---------- SP_PORT -------------------------------------------------- */
4433 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4434 IS_PASSABLE_INSIDE(i)));
4436 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4437 for (j = 0; j < level.num_android_clone_elements; j++)
4438 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4440 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4442 /* ---------- CAN_CHANGE ----------------------------------------------- */
4443 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4444 for (j = 0; j < element_info[i].num_change_pages; j++)
4445 if (element_info[i].change_page[j].can_change)
4446 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4448 /* ---------- HAS_ACTION ----------------------------------------------- */
4449 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4450 for (j = 0; j < element_info[i].num_change_pages; j++)
4451 if (element_info[i].change_page[j].has_action)
4452 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4454 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4455 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4458 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4459 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4460 element_info[i].crumbled[ACTION_DEFAULT] !=
4461 element_info[i].graphic[ACTION_DEFAULT]);
4463 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4464 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4465 IS_EDITOR_CASCADE_INACTIVE(i)));
4468 /* dynamically adjust element properties according to game engine version */
4470 static int ep_em_slippery_wall[] =
4475 EL_EXPANDABLE_WALL_HORIZONTAL,
4476 EL_EXPANDABLE_WALL_VERTICAL,
4477 EL_EXPANDABLE_WALL_ANY,
4478 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4479 EL_EXPANDABLE_STEELWALL_VERTICAL,
4480 EL_EXPANDABLE_STEELWALL_ANY,
4481 EL_EXPANDABLE_STEELWALL_GROWING,
4485 static int ep_em_explodes_by_fire[] =
4488 EL_EM_DYNAMITE_ACTIVE,
4493 /* special EM style gems behaviour */
4494 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4495 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4496 level.em_slippery_gems);
4498 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4499 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4500 (level.em_slippery_gems &&
4501 engine_version > VERSION_IDENT(2,0,1,0)));
4503 /* special EM style explosion behaviour regarding chain reactions */
4504 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4505 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4506 level.em_explodes_by_fire);
4509 /* this is needed because some graphics depend on element properties */
4510 if (game_status == GAME_MODE_PLAYING)
4511 InitElementGraphicInfo();
4514 void InitElementPropertiesAfterLoading(int engine_version)
4518 /* set some other uninitialized values of custom elements in older levels */
4519 if (engine_version < VERSION_IDENT(3,1,0,0))
4521 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4523 int element = EL_CUSTOM_START + i;
4525 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4527 element_info[element].explosion_delay = 17;
4528 element_info[element].ignition_delay = 8;
4533 void InitElementPropertiesGfxElement()
4537 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4539 struct ElementInfo *ei = &element_info[i];
4541 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4545 static void InitGlobal()
4550 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4552 /* check if element_name_info entry defined for each element in "main.h" */
4553 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4554 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4556 element_info[i].token_name = element_name_info[i].token_name;
4557 element_info[i].class_name = element_name_info[i].class_name;
4558 element_info[i].editor_description= element_name_info[i].editor_description;
4561 /* create hash from image config list */
4562 image_config_hash = newSetupFileHash();
4563 for (i = 0; image_config[i].token != NULL; i++)
4564 setHashEntry(image_config_hash,
4565 image_config[i].token,
4566 image_config[i].value);
4568 /* create hash from element token list */
4569 element_token_hash = newSetupFileHash();
4570 for (i = 0; element_name_info[i].token_name != NULL; i++)
4571 setHashEntry(element_token_hash,
4572 element_name_info[i].token_name,
4575 /* create hash from graphic token list */
4576 graphic_token_hash = newSetupFileHash();
4577 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4578 if (strSuffix(image_config[i].value, ".png") ||
4579 strSuffix(image_config[i].value, ".pcx") ||
4580 strSuffix(image_config[i].value, ".wav") ||
4581 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4582 setHashEntry(graphic_token_hash,
4583 image_config[i].token,
4584 int2str(graphic++, 0));
4586 /* create hash from font token list */
4587 font_token_hash = newSetupFileHash();
4588 for (i = 0; font_info[i].token_name != NULL; i++)
4589 setHashEntry(font_token_hash,
4590 font_info[i].token_name,
4593 /* set default filenames for all cloned graphics in static configuration */
4594 for (i = 0; image_config[i].token != NULL; i++)
4596 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4598 char *token = image_config[i].token;
4599 char *token_clone_from = getStringCat2(token, ".clone_from");
4600 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4602 if (token_cloned != NULL)
4604 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4606 if (value_cloned != NULL)
4608 /* set default filename in static configuration */
4609 image_config[i].value = value_cloned;
4611 /* set default filename in image config hash */
4612 setHashEntry(image_config_hash, token, value_cloned);
4616 free(token_clone_from);
4620 /* always start with reliable default values (all elements) */
4621 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4622 ActiveElement[i] = i;
4624 /* now add all entries that have an active state (active elements) */
4625 for (i = 0; element_with_active_state[i].element != -1; i++)
4627 int element = element_with_active_state[i].element;
4628 int element_active = element_with_active_state[i].element_active;
4630 ActiveElement[element] = element_active;
4633 /* always start with reliable default values (all buttons) */
4634 for (i = 0; i < NUM_IMAGE_FILES; i++)
4635 ActiveButton[i] = i;
4637 /* now add all entries that have an active state (active buttons) */
4638 for (i = 0; button_with_active_state[i].button != -1; i++)
4640 int button = button_with_active_state[i].button;
4641 int button_active = button_with_active_state[i].button_active;
4643 ActiveButton[button] = button_active;
4646 /* always start with reliable default values (all fonts) */
4647 for (i = 0; i < NUM_FONTS; i++)
4650 /* now add all entries that have an active state (active fonts) */
4651 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4653 int font = font_with_active_state[i].font_nr;
4654 int font_active = font_with_active_state[i].font_nr_active;
4656 ActiveFont[font] = font_active;
4659 global.autoplay_leveldir = NULL;
4660 global.convert_leveldir = NULL;
4661 global.create_images_dir = NULL;
4663 global.frames_per_second = 0;
4665 global.border_status = GAME_MODE_MAIN;
4667 global.use_envelope_request = FALSE;
4670 void Execute_Command(char *command)
4674 if (strEqual(command, "print graphicsinfo.conf"))
4676 Print("# You can configure additional/alternative image files here.\n");
4677 Print("# (The entries below are default and therefore commented out.)\n");
4679 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4681 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4684 for (i = 0; image_config[i].token != NULL; i++)
4685 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4686 image_config[i].value));
4690 else if (strEqual(command, "print soundsinfo.conf"))
4692 Print("# You can configure additional/alternative sound files here.\n");
4693 Print("# (The entries below are default and therefore commented out.)\n");
4695 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4697 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4700 for (i = 0; sound_config[i].token != NULL; i++)
4701 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4702 sound_config[i].value));
4706 else if (strEqual(command, "print musicinfo.conf"))
4708 Print("# You can configure additional/alternative music files here.\n");
4709 Print("# (The entries below are default and therefore commented out.)\n");
4711 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4713 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4716 for (i = 0; music_config[i].token != NULL; i++)
4717 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4718 music_config[i].value));
4722 else if (strEqual(command, "print editorsetup.conf"))
4724 Print("# You can configure your personal editor element list here.\n");
4725 Print("# (The entries below are default and therefore commented out.)\n");
4728 /* this is needed to be able to check element list for cascade elements */
4729 InitElementPropertiesStatic();
4730 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4732 PrintEditorElementList();
4736 else if (strEqual(command, "print helpanim.conf"))
4738 Print("# You can configure different element help animations here.\n");
4739 Print("# (The entries below are default and therefore commented out.)\n");
4742 for (i = 0; helpanim_config[i].token != NULL; i++)
4744 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4745 helpanim_config[i].value));
4747 if (strEqual(helpanim_config[i].token, "end"))
4753 else if (strEqual(command, "print helptext.conf"))
4755 Print("# You can configure different element help text here.\n");
4756 Print("# (The entries below are default and therefore commented out.)\n");
4759 for (i = 0; helptext_config[i].token != NULL; i++)
4760 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4761 helptext_config[i].value));
4765 else if (strPrefix(command, "dump level "))
4767 char *filename = &command[11];
4769 if (!fileExists(filename))
4770 Error(ERR_EXIT, "cannot open file '%s'", filename);
4772 LoadLevelFromFilename(&level, filename);
4777 else if (strPrefix(command, "dump tape "))
4779 char *filename = &command[10];
4781 if (!fileExists(filename))
4782 Error(ERR_EXIT, "cannot open file '%s'", filename);
4784 LoadTapeFromFilename(filename);
4789 else if (strPrefix(command, "autotest ") ||
4790 strPrefix(command, "autoplay ") ||
4791 strPrefix(command, "autoffwd "))
4793 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4795 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4796 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4797 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4799 while (*str_ptr != '\0') /* continue parsing string */
4801 /* cut leading whitespace from string, replace it by string terminator */
4802 while (*str_ptr == ' ' || *str_ptr == '\t')
4805 if (*str_ptr == '\0') /* end of string reached */
4808 if (global.autoplay_leveldir == NULL) /* read level set string */
4810 global.autoplay_leveldir = str_ptr;
4811 global.autoplay_all = TRUE; /* default: play all tapes */
4813 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4814 global.autoplay_level[i] = FALSE;
4816 else /* read level number string */
4818 int level_nr = atoi(str_ptr); /* get level_nr value */
4820 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4821 global.autoplay_level[level_nr] = TRUE;
4823 global.autoplay_all = FALSE;
4826 /* advance string pointer to the next whitespace (or end of string) */
4827 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4831 else if (strPrefix(command, "convert "))
4833 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4834 char *str_ptr = strchr(str_copy, ' ');
4836 global.convert_leveldir = str_copy;
4837 global.convert_level_nr = -1;
4839 if (str_ptr != NULL) /* level number follows */
4841 *str_ptr++ = '\0'; /* terminate leveldir string */
4842 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4845 else if (strPrefix(command, "create images "))
4847 global.create_images_dir = getStringCopy(&command[14]);
4849 if (access(global.create_images_dir, W_OK) != 0)
4850 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4851 global.create_images_dir);
4853 else if (strPrefix(command, "create CE image "))
4855 CreateCustomElementImages(&command[16]);
4861 #if defined(TARGET_SDL2)
4862 else if (strEqual(command, "SDL_ListModes"))
4864 SDL_Init(SDL_INIT_VIDEO);
4866 int num_displays = SDL_GetNumVideoDisplays();
4868 // check if there are any displays available
4869 if (num_displays < 0)
4871 Print("No displays available: %s\n", SDL_GetError());
4876 for (i = 0; i < num_displays; i++)
4878 int num_modes = SDL_GetNumDisplayModes(i);
4881 Print("Available display modes for display %d:\n", i);
4883 // check if there are any display modes available for this display
4886 Print("No display modes available for display %d: %s\n",
4892 for (j = 0; j < num_modes; j++)
4894 SDL_DisplayMode mode;
4896 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4898 Print("Cannot get display mode %d for display %d: %s\n",
4899 j, i, SDL_GetError());
4904 Print("- %d x %d\n", mode.w, mode.h);
4910 #elif defined(TARGET_SDL)
4911 else if (strEqual(command, "SDL_ListModes"))
4916 SDL_Init(SDL_INIT_VIDEO);
4918 /* get available fullscreen/hardware modes */
4919 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4921 /* check if there are any modes available */
4924 Print("No modes available!\n");
4929 /* check if our resolution is restricted */
4930 if (modes == (SDL_Rect **)-1)
4932 Print("All resolutions available.\n");
4936 Print("Available display modes:\n");
4938 for (i = 0; modes[i]; i++)
4939 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4949 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4953 static void InitSetup()
4955 LoadSetup(); /* global setup info */
4957 /* set some options from setup file */
4959 if (setup.options.verbose)
4960 options.verbose = TRUE;
4963 static void InitGameInfo()
4965 game.restart_level = FALSE;
4968 static void InitPlayerInfo()
4972 /* choose default local player */
4973 local_player = &stored_player[0];
4975 for (i = 0; i < MAX_PLAYERS; i++)
4976 stored_player[i].connected = FALSE;
4978 local_player->connected = TRUE;
4981 static void InitArtworkInfo()
4986 static char *get_string_in_brackets(char *string)
4988 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4990 sprintf(string_in_brackets, "[%s]", string);
4992 return string_in_brackets;
4995 static char *get_level_id_suffix(int id_nr)
4997 char *id_suffix = checked_malloc(1 + 3 + 1);
4999 if (id_nr < 0 || id_nr > 999)
5002 sprintf(id_suffix, ".%03d", id_nr);
5007 static void InitArtworkConfig()
5009 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5011 NUM_GLOBAL_ANIM_TOKENS + 1];
5012 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5013 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5014 static char *action_id_suffix[NUM_ACTIONS + 1];
5015 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5016 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5017 static char *level_id_suffix[MAX_LEVELS + 1];
5018 static char *dummy[1] = { NULL };
5019 static char *ignore_generic_tokens[] =
5025 static char **ignore_image_tokens;
5026 static char **ignore_sound_tokens;
5027 static char **ignore_music_tokens;
5028 int num_ignore_generic_tokens;
5029 int num_ignore_image_tokens;
5030 int num_ignore_sound_tokens;
5031 int num_ignore_music_tokens;
5034 /* dynamically determine list of generic tokens to be ignored */
5035 num_ignore_generic_tokens = 0;
5036 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5037 num_ignore_generic_tokens++;
5039 /* dynamically determine list of image tokens to be ignored */
5040 num_ignore_image_tokens = num_ignore_generic_tokens;
5041 for (i = 0; image_config_vars[i].token != NULL; i++)
5042 num_ignore_image_tokens++;
5043 ignore_image_tokens =
5044 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5045 for (i = 0; i < num_ignore_generic_tokens; i++)
5046 ignore_image_tokens[i] = ignore_generic_tokens[i];
5047 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5048 ignore_image_tokens[num_ignore_generic_tokens + i] =
5049 image_config_vars[i].token;
5050 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5052 /* dynamically determine list of sound tokens to be ignored */
5053 num_ignore_sound_tokens = num_ignore_generic_tokens;
5054 ignore_sound_tokens =
5055 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5056 for (i = 0; i < num_ignore_generic_tokens; i++)
5057 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5058 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5060 /* dynamically determine list of music tokens to be ignored */
5061 num_ignore_music_tokens = num_ignore_generic_tokens;
5062 ignore_music_tokens =
5063 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5064 for (i = 0; i < num_ignore_generic_tokens; i++)
5065 ignore_music_tokens[i] = ignore_generic_tokens[i];
5066 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5068 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5069 image_id_prefix[i] = element_info[i].token_name;
5070 for (i = 0; i < NUM_FONTS; i++)
5071 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5072 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5073 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5074 global_anim_info[i].token_name;
5075 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5077 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5078 sound_id_prefix[i] = element_info[i].token_name;
5079 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5080 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5081 get_string_in_brackets(element_info[i].class_name);
5082 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5084 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5085 music_id_prefix[i] = music_prefix_info[i].prefix;
5086 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5088 for (i = 0; i < NUM_ACTIONS; i++)
5089 action_id_suffix[i] = element_action_info[i].suffix;
5090 action_id_suffix[NUM_ACTIONS] = NULL;
5092 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5093 direction_id_suffix[i] = element_direction_info[i].suffix;
5094 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5096 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5097 special_id_suffix[i] = special_suffix_info[i].suffix;
5098 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5100 for (i = 0; i < MAX_LEVELS; i++)
5101 level_id_suffix[i] = get_level_id_suffix(i);
5102 level_id_suffix[MAX_LEVELS] = NULL;
5104 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5105 image_id_prefix, action_id_suffix, direction_id_suffix,
5106 special_id_suffix, ignore_image_tokens);
5107 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5108 sound_id_prefix, action_id_suffix, dummy,
5109 special_id_suffix, ignore_sound_tokens);
5110 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5111 music_id_prefix, special_id_suffix, level_id_suffix,
5112 dummy, ignore_music_tokens);
5115 static void InitMixer()
5122 void InitGfxBuffers()
5124 static int win_xsize_last = -1;
5125 static int win_ysize_last = -1;
5127 /* create additional image buffers for double-buffering and cross-fading */
5129 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5131 /* may contain content for cross-fading -- only re-create if changed */
5132 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5133 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5135 win_xsize_last = WIN_XSIZE;
5136 win_ysize_last = WIN_YSIZE;
5139 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5140 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5141 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5142 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5143 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5145 /* initialize screen properties */
5146 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5147 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5149 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5150 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5151 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5152 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5153 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5154 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5156 /* required if door size definitions have changed */
5157 InitGraphicCompatibilityInfo_Doors();
5159 InitGfxBuffers_EM();
5160 InitGfxBuffers_SP();
5165 struct GraphicInfo *graphic_info_last = graphic_info;
5166 char *filename_font_initial = NULL;
5167 char *filename_anim_initial = NULL;
5168 Bitmap *bitmap_font_initial = NULL;
5172 /* determine settings for initial font (for displaying startup messages) */
5173 for (i = 0; image_config[i].token != NULL; i++)
5175 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5177 char font_token[128];
5180 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5181 len_font_token = strlen(font_token);
5183 if (strEqual(image_config[i].token, font_token))
5184 filename_font_initial = image_config[i].value;
5185 else if (strlen(image_config[i].token) > len_font_token &&
5186 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5188 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5189 font_initial[j].src_x = atoi(image_config[i].value);
5190 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5191 font_initial[j].src_y = atoi(image_config[i].value);
5192 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5193 font_initial[j].width = atoi(image_config[i].value);
5194 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5195 font_initial[j].height = atoi(image_config[i].value);
5200 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5202 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5203 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5206 if (filename_font_initial == NULL) /* should not happen */
5207 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5210 InitGfxCustomArtworkInfo();
5211 InitGfxOtherSettings();
5213 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5215 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5216 font_initial[j].bitmap = bitmap_font_initial;
5218 InitFontGraphicInfo();
5220 font_height = getFontHeight(FC_RED);
5222 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5223 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5224 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5227 DrawInitText("Loading graphics", 120, FC_GREEN);
5229 /* initialize settings for busy animation with default values */
5230 int parameter[NUM_GFX_ARGS];
5231 for (i = 0; i < NUM_GFX_ARGS; i++)
5232 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5233 image_config_suffix[i].token,
5234 image_config_suffix[i].type);
5236 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5237 int len_anim_token = strlen(anim_token);
5239 /* read settings for busy animation from default custom artwork config */
5240 char *gfx_config_filename = getPath3(options.graphics_directory,
5242 GRAPHICSINFO_FILENAME);
5244 if (fileExists(gfx_config_filename))
5246 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5248 if (setup_file_hash)
5250 char *filename = getHashEntry(setup_file_hash, anim_token);
5254 filename_anim_initial = getStringCopy(filename);
5256 for (j = 0; image_config_suffix[j].token != NULL; j++)
5258 int type = image_config_suffix[j].type;
5259 char *suffix = image_config_suffix[j].token;
5260 char *token = getStringCat2(anim_token, suffix);
5261 char *value = getHashEntry(setup_file_hash, token);
5263 checked_free(token);
5266 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5270 freeSetupFileHash(setup_file_hash);
5274 if (filename_anim_initial == NULL)
5276 /* read settings for busy animation from static default artwork config */
5277 for (i = 0; image_config[i].token != NULL; i++)
5279 if (strEqual(image_config[i].token, anim_token))
5280 filename_anim_initial = getStringCopy(image_config[i].value);
5281 else if (strlen(image_config[i].token) > len_anim_token &&
5282 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5284 for (j = 0; image_config_suffix[j].token != NULL; j++)
5286 if (strEqual(&image_config[i].token[len_anim_token],
5287 image_config_suffix[j].token))
5289 get_graphic_parameter_value(image_config[i].value,
5290 image_config_suffix[j].token,
5291 image_config_suffix[j].type);
5297 if (filename_anim_initial == NULL) /* should not happen */
5298 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5300 anim_initial.bitmaps =
5301 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5303 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5304 LoadCustomImage(filename_anim_initial);
5306 checked_free(filename_anim_initial);
5308 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5310 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5312 graphic_info = graphic_info_last;
5314 init.busy.width = anim_initial.width;
5315 init.busy.height = anim_initial.height;
5317 InitMenuDesignSettings_Static();
5319 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5320 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5322 /* use copy of busy animation to prevent change while reloading artwork */
5326 void InitGfxBackground()
5328 fieldbuffer = bitmap_db_field;
5329 SetDrawtoField(DRAW_BACKBUFFER);
5331 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5333 redraw_mask = REDRAW_ALL;
5336 static void InitLevelInfo()
5338 LoadLevelInfo(); /* global level info */
5339 LoadLevelSetup_LastSeries(); /* last played series info */
5340 LoadLevelSetup_SeriesInfo(); /* last played level info */
5342 if (global.autoplay_leveldir &&
5343 global.autoplay_mode != AUTOPLAY_TEST)
5345 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5346 global.autoplay_leveldir);
5347 if (leveldir_current == NULL)
5348 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5352 static void InitLevelArtworkInfo()
5354 LoadLevelArtworkInfo();
5357 static void InitImages()
5359 print_timestamp_init("InitImages");
5362 printf("::: leveldir_current->identifier == '%s'\n",
5363 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5364 printf("::: leveldir_current->graphics_path == '%s'\n",
5365 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5366 printf("::: leveldir_current->graphics_set == '%s'\n",
5367 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5368 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5369 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5372 setLevelArtworkDir(artwork.gfx_first);
5375 printf("::: leveldir_current->identifier == '%s'\n",
5376 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5377 printf("::: leveldir_current->graphics_path == '%s'\n",
5378 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5379 printf("::: leveldir_current->graphics_set == '%s'\n",
5380 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5381 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5382 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5386 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5387 leveldir_current->identifier,
5388 artwork.gfx_current_identifier,
5389 artwork.gfx_current->identifier,
5390 leveldir_current->graphics_set,
5391 leveldir_current->graphics_path);
5394 UPDATE_BUSY_STATE();
5396 ReloadCustomImages();
5397 print_timestamp_time("ReloadCustomImages");
5399 UPDATE_BUSY_STATE();
5401 LoadCustomElementDescriptions();
5402 print_timestamp_time("LoadCustomElementDescriptions");
5404 UPDATE_BUSY_STATE();
5406 LoadMenuDesignSettings();
5407 print_timestamp_time("LoadMenuDesignSettings");
5409 UPDATE_BUSY_STATE();
5411 ReinitializeGraphics();
5412 print_timestamp_time("ReinitializeGraphics");
5414 UPDATE_BUSY_STATE();
5416 print_timestamp_done("InitImages");
5419 static void InitSound(char *identifier)
5421 print_timestamp_init("InitSound");
5423 if (identifier == NULL)
5424 identifier = artwork.snd_current->identifier;
5426 /* set artwork path to send it to the sound server process */
5427 setLevelArtworkDir(artwork.snd_first);
5429 InitReloadCustomSounds(identifier);
5430 print_timestamp_time("InitReloadCustomSounds");
5432 ReinitializeSounds();
5433 print_timestamp_time("ReinitializeSounds");
5435 print_timestamp_done("InitSound");
5438 static void InitMusic(char *identifier)
5440 print_timestamp_init("InitMusic");
5442 if (identifier == NULL)
5443 identifier = artwork.mus_current->identifier;
5445 /* set artwork path to send it to the sound server process */
5446 setLevelArtworkDir(artwork.mus_first);
5448 InitReloadCustomMusic(identifier);
5449 print_timestamp_time("InitReloadCustomMusic");
5451 ReinitializeMusic();
5452 print_timestamp_time("ReinitializeMusic");
5454 print_timestamp_done("InitMusic");
5457 void InitNetworkServer()
5459 #if defined(NETWORK_AVALIABLE)
5463 if (!options.network)
5466 #if defined(NETWORK_AVALIABLE)
5467 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5469 if (!ConnectToServer(options.server_host, options.server_port))
5470 Error(ERR_EXIT, "cannot connect to network game server");
5472 SendToServer_PlayerName(setup.player_name);
5473 SendToServer_ProtocolVersion();
5476 SendToServer_NrWanted(nr_wanted);
5480 static boolean CheckArtworkConfigForCustomElements(char *filename)
5482 SetupFileHash *setup_file_hash;
5483 boolean redefined_ce_found = FALSE;
5485 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5487 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5489 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5491 char *token = HASH_ITERATION_TOKEN(itr);
5493 if (strPrefix(token, "custom_"))
5495 redefined_ce_found = TRUE;
5500 END_HASH_ITERATION(setup_file_hash, itr)
5502 freeSetupFileHash(setup_file_hash);
5505 return redefined_ce_found;
5508 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5510 char *filename_base, *filename_local;
5511 boolean redefined_ce_found = FALSE;
5513 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5516 printf("::: leveldir_current->identifier == '%s'\n",
5517 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5518 printf("::: leveldir_current->graphics_path == '%s'\n",
5519 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5520 printf("::: leveldir_current->graphics_set == '%s'\n",
5521 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5522 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5523 leveldir_current == NULL ? "[NULL]" :
5524 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5527 /* first look for special artwork configured in level series config */
5528 filename_base = getCustomArtworkLevelConfigFilename(type);
5531 printf("::: filename_base == '%s'\n", filename_base);
5534 if (fileExists(filename_base))
5535 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5537 filename_local = getCustomArtworkConfigFilename(type);
5540 printf("::: filename_local == '%s'\n", filename_local);
5543 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5544 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5547 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5550 return redefined_ce_found;
5553 static void InitOverrideArtwork()
5555 boolean redefined_ce_found = FALSE;
5557 /* to check if this level set redefines any CEs, do not use overriding */
5558 gfx.override_level_graphics = FALSE;
5559 gfx.override_level_sounds = FALSE;
5560 gfx.override_level_music = FALSE;
5562 /* now check if this level set has definitions for custom elements */
5563 if (setup.override_level_graphics == AUTO ||
5564 setup.override_level_sounds == AUTO ||
5565 setup.override_level_music == AUTO)
5566 redefined_ce_found =
5567 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5568 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5569 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5572 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5575 if (redefined_ce_found)
5577 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5578 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5579 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5580 gfx.override_level_music = (setup.override_level_music == TRUE);
5584 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5585 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5586 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5587 gfx.override_level_music = (setup.override_level_music != FALSE);
5591 printf("::: => %d, %d, %d\n",
5592 gfx.override_level_graphics,
5593 gfx.override_level_sounds,
5594 gfx.override_level_music);
5598 static char *getNewArtworkIdentifier(int type)
5600 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5601 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5602 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5603 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5604 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5605 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5606 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5607 char *leveldir_identifier = leveldir_current->identifier;
5608 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5609 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5610 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5611 char *artwork_current_identifier;
5612 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5614 /* leveldir_current may be invalid (level group, parent link) */
5615 if (!validLevelSeries(leveldir_current))
5618 /* 1st step: determine artwork set to be activated in descending order:
5619 --------------------------------------------------------------------
5620 1. setup artwork (when configured to override everything else)
5621 2. artwork set configured in "levelinfo.conf" of current level set
5622 (artwork in level directory will have priority when loading later)
5623 3. artwork in level directory (stored in artwork sub-directory)
5624 4. setup artwork (currently configured in setup menu) */
5626 if (setup_override_artwork)
5627 artwork_current_identifier = setup_artwork_set;
5628 else if (leveldir_artwork_set != NULL)
5629 artwork_current_identifier = leveldir_artwork_set;
5630 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5631 artwork_current_identifier = leveldir_identifier;
5633 artwork_current_identifier = setup_artwork_set;
5636 /* 2nd step: check if it is really needed to reload artwork set
5637 ------------------------------------------------------------ */
5639 /* ---------- reload if level set and also artwork set has changed ------- */
5640 if (leveldir_current_identifier[type] != leveldir_identifier &&
5641 (last_has_level_artwork_set[type] || has_level_artwork_set))
5642 artwork_new_identifier = artwork_current_identifier;
5644 leveldir_current_identifier[type] = leveldir_identifier;
5645 last_has_level_artwork_set[type] = has_level_artwork_set;
5647 /* ---------- reload if "override artwork" setting has changed ----------- */
5648 if (last_override_level_artwork[type] != setup_override_artwork)
5649 artwork_new_identifier = artwork_current_identifier;
5651 last_override_level_artwork[type] = setup_override_artwork;
5653 /* ---------- reload if current artwork identifier has changed ----------- */
5654 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5655 artwork_current_identifier))
5656 artwork_new_identifier = artwork_current_identifier;
5658 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5660 /* ---------- do not reload directly after starting ---------------------- */
5661 if (!initialized[type])
5662 artwork_new_identifier = NULL;
5664 initialized[type] = TRUE;
5666 return artwork_new_identifier;
5669 void ReloadCustomArtwork(int force_reload)
5671 int last_game_status = game_status; /* save current game status */
5672 char *gfx_new_identifier;
5673 char *snd_new_identifier;
5674 char *mus_new_identifier;
5675 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5676 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5677 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5678 boolean reload_needed;
5680 InitOverrideArtwork();
5682 force_reload_gfx |= AdjustGraphicsForEMC();
5684 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5685 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5686 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5688 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5689 snd_new_identifier != NULL || force_reload_snd ||
5690 mus_new_identifier != NULL || force_reload_mus);
5695 print_timestamp_init("ReloadCustomArtwork");
5697 game_status = GAME_MODE_LOADING;
5699 FadeOut(REDRAW_ALL);
5701 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5702 print_timestamp_time("ClearRectangle");
5706 if (gfx_new_identifier != NULL || force_reload_gfx)
5709 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5710 artwork.gfx_current_identifier,
5712 artwork.gfx_current->identifier,
5713 leveldir_current->graphics_set);
5717 print_timestamp_time("InitImages");
5720 if (snd_new_identifier != NULL || force_reload_snd)
5722 InitSound(snd_new_identifier);
5723 print_timestamp_time("InitSound");
5726 if (mus_new_identifier != NULL || force_reload_mus)
5728 InitMusic(mus_new_identifier);
5729 print_timestamp_time("InitMusic");
5732 game_status = last_game_status; /* restore current game status */
5734 init_last = init; /* switch to new busy animation */
5736 FadeOut(REDRAW_ALL);
5738 RedrawGlobalBorder();
5740 /* force redraw of (open or closed) door graphics */
5741 SetDoorState(DOOR_OPEN_ALL);
5742 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5744 FadeSetEnterScreen();
5745 FadeSkipNextFadeOut();
5747 print_timestamp_done("ReloadCustomArtwork");
5749 LimitScreenUpdates(FALSE);
5752 void KeyboardAutoRepeatOffUnlessAutoplay()
5754 if (global.autoplay_leveldir == NULL)
5755 KeyboardAutoRepeatOff();
5758 void DisplayExitMessage(char *format, va_list ap)
5760 // check if draw buffer and fonts for exit message are already available
5761 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5764 int font_1 = FC_RED;
5765 int font_2 = FC_YELLOW;
5766 int font_3 = FC_BLUE;
5767 int font_width = getFontWidth(font_2);
5768 int font_height = getFontHeight(font_2);
5771 int sxsize = WIN_XSIZE - 2 * sx;
5772 int sysize = WIN_YSIZE - 2 * sy;
5773 int line_length = sxsize / font_width;
5774 int max_lines = sysize / font_height;
5775 int num_lines_printed;
5779 gfx.sxsize = sxsize;
5780 gfx.sysize = sysize;
5784 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5786 DrawTextSCentered(sy, font_1, "Fatal error:");
5787 sy += 3 * font_height;;
5790 DrawTextBufferVA(sx, sy, format, ap, font_2,
5791 line_length, line_length, max_lines,
5792 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5793 sy += (num_lines_printed + 3) * font_height;
5795 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5796 sy += 3 * font_height;
5799 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5800 line_length, line_length, max_lines,
5801 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5803 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5805 redraw_mask = REDRAW_ALL;
5807 /* force drawing exit message even if screen updates are currently limited */
5808 LimitScreenUpdates(FALSE);
5812 /* deactivate toons on error message screen */
5813 setup.toons = FALSE;
5815 WaitForEventToContinue();
5819 /* ========================================================================= */
5821 /* ========================================================================= */
5825 print_timestamp_init("OpenAll");
5827 game_status = GAME_MODE_LOADING;
5831 InitGlobal(); /* initialize some global variables */
5833 print_timestamp_time("[init global stuff]");
5837 print_timestamp_time("[init setup/config stuff (1)]");
5839 if (options.execute_command)
5840 Execute_Command(options.execute_command);
5842 if (options.serveronly)
5844 #if defined(PLATFORM_UNIX)
5845 NetworkServer(options.server_port, options.serveronly);
5847 Error(ERR_WARN, "networking only supported in Unix version");
5850 exit(0); /* never reached, server loops forever */
5854 print_timestamp_time("[init setup/config stuff (2)]");
5856 print_timestamp_time("[init setup/config stuff (3)]");
5857 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5858 print_timestamp_time("[init setup/config stuff (4)]");
5859 InitArtworkConfig(); /* needed before forking sound child process */
5860 print_timestamp_time("[init setup/config stuff (5)]");
5862 print_timestamp_time("[init setup/config stuff (6)]");
5864 InitRND(NEW_RANDOMIZE);
5865 InitSimpleRandom(NEW_RANDOMIZE);
5869 print_timestamp_time("[init setup/config stuff]");
5872 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5874 InitEventFilter(FilterEvents);
5876 print_timestamp_time("[init video stuff]");
5878 InitElementPropertiesStatic();
5879 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5880 InitElementPropertiesGfxElement();
5882 print_timestamp_time("[init element properties stuff]");
5886 print_timestamp_time("InitGfx");
5889 print_timestamp_time("InitLevelInfo");
5891 InitLevelArtworkInfo();
5892 print_timestamp_time("InitLevelArtworkInfo");
5894 InitOverrideArtwork(); /* needs to know current level directory */
5895 print_timestamp_time("InitOverrideArtwork");
5897 InitImages(); /* needs to know current level directory */
5898 print_timestamp_time("InitImages");
5900 InitSound(NULL); /* needs to know current level directory */
5901 print_timestamp_time("InitSound");
5903 InitMusic(NULL); /* needs to know current level directory */
5904 print_timestamp_time("InitMusic");
5906 InitGfxBackground();
5911 if (global.autoplay_leveldir)
5916 else if (global.convert_leveldir)
5921 else if (global.create_images_dir)
5923 CreateLevelSketchImages();
5927 game_status = GAME_MODE_MAIN;
5929 FadeSetEnterScreen();
5930 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5931 FadeSkipNextFadeOut();
5933 print_timestamp_time("[post-artwork]");
5935 print_timestamp_done("OpenAll");
5939 InitNetworkServer();
5942 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5944 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5945 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5946 #if defined(PLATFORM_ANDROID)
5947 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5948 SDL_AndroidGetInternalStoragePath());
5949 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5950 SDL_AndroidGetExternalStoragePath());
5951 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5952 (SDL_AndroidGetExternalStorageState() ==
5953 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5954 SDL_AndroidGetExternalStorageState() ==
5955 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5960 void CloseAllAndExit(int exit_value)
5965 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5972 #if defined(TARGET_SDL)
5973 #if defined(TARGET_SDL2)
5975 // set a flag to tell the network server thread to quit and wait for it
5976 // using SDL_WaitThread()
5978 if (network_server) /* terminate network server */
5979 SDL_KillThread(server_thread);
5983 CloseVideoDisplay();
5984 ClosePlatformDependentStuff();
5986 if (exit_value != 0)
5988 /* fall back to default level set (current set may have caused an error) */
5989 SaveLevelSetup_LastSeries_Deactivate();
5991 /* tell user where to find error log file which may contain more details */
5992 // (error notification now directly displayed on screen inside R'n'D
5993 // NotifyUserAboutErrorFile(); /* currently only works for Windows */