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->anim_delay_fixed = 0;
1131 g->anim_delay_random = 0;
1132 g->post_delay_fixed = 0;
1133 g->post_delay_random = 0;
1134 g->fade_mode = FADE_MODE_DEFAULT;
1138 g->align = ALIGN_CENTER; /* default for title screens */
1139 g->valign = VALIGN_MIDDLE; /* default for title screens */
1140 g->sort_priority = 0; /* default for title screens */
1142 g->style = STYLE_DEFAULT;
1144 g->bitmaps = src_bitmaps;
1145 g->bitmap = src_bitmap;
1147 /* optional zoom factor for scaling up the image to a larger size */
1148 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1149 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1150 if (g->scale_up_factor < 1)
1151 g->scale_up_factor = 1; /* no scaling */
1153 /* optional tile size for using non-standard image size */
1154 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1156 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1159 // CHECK: should tile sizes less than standard tile size be allowed?
1160 if (g->tile_size < TILESIZE)
1161 g->tile_size = TILESIZE; /* standard tile size */
1164 // when setting tile size, also set width and height accordingly
1165 g->width = g->tile_size;
1166 g->height = g->tile_size;
1169 if (g->use_image_size)
1171 /* set new default bitmap size (with scaling, but without small images) */
1172 g->width = get_scaled_graphic_width(graphic);
1173 g->height = get_scaled_graphic_height(graphic);
1176 /* optional width and height of each animation frame */
1177 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1178 g->width = parameter[GFX_ARG_WIDTH];
1179 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1180 g->height = parameter[GFX_ARG_HEIGHT];
1182 /* optional x and y tile position of animation frame sequence */
1183 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1184 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1185 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1186 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1188 /* optional x and y pixel position of animation frame sequence */
1189 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1190 g->src_x = parameter[GFX_ARG_X];
1191 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1192 g->src_y = parameter[GFX_ARG_Y];
1198 Error(ERR_INFO_LINE, "-");
1199 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1200 g->width, getTokenFromImageID(graphic), TILEX);
1201 Error(ERR_INFO_LINE, "-");
1203 g->width = TILEX; /* will be checked to be inside bitmap later */
1208 Error(ERR_INFO_LINE, "-");
1209 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1210 g->height, getTokenFromImageID(graphic), TILEY);
1211 Error(ERR_INFO_LINE, "-");
1213 g->height = TILEY; /* will be checked to be inside bitmap later */
1219 /* get final bitmap size (with scaling, but without small images) */
1220 int src_image_width = get_scaled_graphic_width(graphic);
1221 int src_image_height = get_scaled_graphic_height(graphic);
1223 if (src_image_width == 0 || src_image_height == 0)
1225 /* only happens when loaded outside artwork system (like "global.busy") */
1226 src_image_width = src_bitmap->width;
1227 src_image_height = src_bitmap->height;
1230 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1232 anim_frames_per_row = src_image_width / g->tile_size;
1233 anim_frames_per_col = src_image_height / g->tile_size;
1237 anim_frames_per_row = src_image_width / g->width;
1238 anim_frames_per_col = src_image_height / g->height;
1241 g->src_image_width = src_image_width;
1242 g->src_image_height = src_image_height;
1245 /* correct x or y offset dependent of vertical or horizontal frame order */
1246 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1248 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1249 parameter[GFX_ARG_OFFSET] : g->height);
1250 anim_frames_per_line = anim_frames_per_col;
1252 else /* frames are ordered horizontally */
1254 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1255 parameter[GFX_ARG_OFFSET] : g->width);
1256 anim_frames_per_line = anim_frames_per_row;
1259 /* optionally, the x and y offset of frames can be specified directly */
1260 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1261 g->offset_x = parameter[GFX_ARG_XOFFSET];
1262 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1263 g->offset_y = parameter[GFX_ARG_YOFFSET];
1265 /* optionally, moving animations may have separate start and end graphics */
1266 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1268 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1269 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1271 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1272 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1273 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1274 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1275 else /* frames are ordered horizontally */
1276 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1277 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1279 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1280 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1281 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1282 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1283 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1285 /* optionally, the second movement tile can be specified as start tile */
1286 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1287 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1289 /* automatically determine correct number of frames, if not defined */
1290 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1291 g->anim_frames = parameter[GFX_ARG_FRAMES];
1292 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1293 g->anim_frames = anim_frames_per_row;
1294 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1295 g->anim_frames = anim_frames_per_col;
1299 if (g->anim_frames == 0) /* frames must be at least 1 */
1302 g->anim_frames_per_line =
1303 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1304 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1306 g->anim_delay = parameter[GFX_ARG_DELAY];
1307 if (g->anim_delay == 0) /* delay must be at least 1 */
1310 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1312 /* automatically determine correct start frame, if not defined */
1313 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1314 g->anim_start_frame = 0;
1315 else if (g->anim_mode & ANIM_REVERSE)
1316 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1318 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1320 /* animation synchronized with global frame counter, not move position */
1321 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1323 /* optional element for cloning crumble graphics */
1324 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1325 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1327 /* optional element for cloning digging graphics */
1328 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1329 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1331 /* optional border size for "crumbling" diggable graphics */
1332 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1333 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1335 /* this is only used for player "boring" and "sleeping" actions */
1336 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1337 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1338 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1339 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1340 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1341 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1342 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1343 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1345 /* this is only used for toon animations */
1346 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1347 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1348 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1349 g->step_frames = parameter[GFX_ARG_STEP_FRAMES];
1350 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1351 g->direction = parameter[GFX_ARG_DIRECTION];
1352 g->position = parameter[GFX_ARG_POSITION];
1353 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1354 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1356 /* this is only used for drawing font characters */
1357 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1358 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1360 /* this is only used for drawing envelope graphics */
1361 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1363 /* optional graphic for cloning all graphics settings */
1364 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1365 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1367 /* optional settings for drawing title screens and title messages */
1368 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1369 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1370 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1371 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1372 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1373 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1374 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1375 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1376 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1377 g->align = parameter[GFX_ARG_ALIGN];
1378 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1379 g->valign = parameter[GFX_ARG_VALIGN];
1380 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1381 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1383 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1384 g->class = parameter[GFX_ARG_CLASS];
1385 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1386 g->style = parameter[GFX_ARG_STYLE];
1388 /* this is only used for drawing menu buttons and text */
1389 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1390 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1391 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1392 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1395 static void set_graphic_parameters(int graphic)
1397 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1398 char **parameter_raw = image->parameter;
1399 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1400 int parameter[NUM_GFX_ARGS];
1403 /* if fallback to default artwork is done, also use the default parameters */
1404 if (image->fallback_to_default)
1405 parameter_raw = image->default_parameter;
1407 /* get integer values from string parameters */
1408 for (i = 0; i < NUM_GFX_ARGS; i++)
1409 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1410 image_config_suffix[i].token,
1411 image_config_suffix[i].type);
1413 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1415 UPDATE_BUSY_STATE();
1418 static void set_cloned_graphic_parameters(int graphic)
1420 int fallback_graphic = IMG_CHAR_EXCLAM;
1421 int max_num_images = getImageListSize();
1422 int clone_graphic = graphic_info[graphic].clone_from;
1423 int num_references_followed = 1;
1425 while (graphic_info[clone_graphic].clone_from != -1 &&
1426 num_references_followed < max_num_images)
1428 clone_graphic = graphic_info[clone_graphic].clone_from;
1430 num_references_followed++;
1433 if (num_references_followed >= max_num_images)
1435 Error(ERR_INFO_LINE, "-");
1436 Error(ERR_INFO, "warning: error found in config file:");
1437 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1438 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1439 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1440 Error(ERR_INFO, "custom graphic rejected for this element/action");
1442 if (graphic == fallback_graphic)
1443 Error(ERR_EXIT, "no fallback graphic available");
1445 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1446 Error(ERR_INFO_LINE, "-");
1448 graphic_info[graphic] = graphic_info[fallback_graphic];
1452 graphic_info[graphic] = graphic_info[clone_graphic];
1453 graphic_info[graphic].clone_from = clone_graphic;
1457 static void InitGraphicInfo()
1459 int fallback_graphic = IMG_CHAR_EXCLAM;
1460 int num_images = getImageListSize();
1463 /* use image size as default values for width and height for these images */
1464 static int full_size_graphics[] =
1467 IMG_GLOBAL_BORDER_MAIN,
1468 IMG_GLOBAL_BORDER_SCORES,
1469 IMG_GLOBAL_BORDER_EDITOR,
1470 IMG_GLOBAL_BORDER_PLAYING,
1473 IMG_BACKGROUND_ENVELOPE_1,
1474 IMG_BACKGROUND_ENVELOPE_2,
1475 IMG_BACKGROUND_ENVELOPE_3,
1476 IMG_BACKGROUND_ENVELOPE_4,
1477 IMG_BACKGROUND_REQUEST,
1480 IMG_BACKGROUND_TITLE_INITIAL,
1481 IMG_BACKGROUND_TITLE,
1482 IMG_BACKGROUND_MAIN,
1483 IMG_BACKGROUND_LEVELS,
1484 IMG_BACKGROUND_LEVELNR,
1485 IMG_BACKGROUND_SCORES,
1486 IMG_BACKGROUND_EDITOR,
1487 IMG_BACKGROUND_INFO,
1488 IMG_BACKGROUND_INFO_ELEMENTS,
1489 IMG_BACKGROUND_INFO_MUSIC,
1490 IMG_BACKGROUND_INFO_CREDITS,
1491 IMG_BACKGROUND_INFO_PROGRAM,
1492 IMG_BACKGROUND_INFO_VERSION,
1493 IMG_BACKGROUND_INFO_LEVELSET,
1494 IMG_BACKGROUND_SETUP,
1495 IMG_BACKGROUND_PLAYING,
1496 IMG_BACKGROUND_DOOR,
1497 IMG_BACKGROUND_TAPE,
1498 IMG_BACKGROUND_PANEL,
1499 IMG_BACKGROUND_PALETTE,
1500 IMG_BACKGROUND_TOOLBOX,
1502 IMG_TITLESCREEN_INITIAL_1,
1503 IMG_TITLESCREEN_INITIAL_2,
1504 IMG_TITLESCREEN_INITIAL_3,
1505 IMG_TITLESCREEN_INITIAL_4,
1506 IMG_TITLESCREEN_INITIAL_5,
1513 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1514 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1515 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1516 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1517 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1518 IMG_BACKGROUND_TITLEMESSAGE_1,
1519 IMG_BACKGROUND_TITLEMESSAGE_2,
1520 IMG_BACKGROUND_TITLEMESSAGE_3,
1521 IMG_BACKGROUND_TITLEMESSAGE_4,
1522 IMG_BACKGROUND_TITLEMESSAGE_5,
1527 checked_free(graphic_info);
1529 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1531 /* initialize "use_image_size" flag with default value */
1532 for (i = 0; i < num_images; i++)
1533 graphic_info[i].use_image_size = FALSE;
1535 /* initialize "use_image_size" flag from static configuration above */
1536 for (i = 0; full_size_graphics[i] != -1; i++)
1537 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1539 /* first set all graphic paramaters ... */
1540 for (i = 0; i < num_images; i++)
1541 set_graphic_parameters(i);
1543 /* ... then copy these parameters for cloned graphics */
1544 for (i = 0; i < num_images; i++)
1545 if (graphic_info[i].clone_from != -1)
1546 set_cloned_graphic_parameters(i);
1548 for (i = 0; i < num_images; i++)
1553 int first_frame, last_frame;
1554 int src_bitmap_width, src_bitmap_height;
1556 /* now check if no animation frames are outside of the loaded image */
1558 if (graphic_info[i].bitmap == NULL)
1559 continue; /* skip check for optional images that are undefined */
1561 /* get image size (this can differ from the standard element tile size!) */
1562 width = graphic_info[i].width;
1563 height = graphic_info[i].height;
1565 /* get final bitmap size (with scaling, but without small images) */
1566 src_bitmap_width = graphic_info[i].src_image_width;
1567 src_bitmap_height = graphic_info[i].src_image_height;
1569 /* check if first animation frame is inside specified bitmap */
1572 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1574 /* this avoids calculating wrong start position for out-of-bounds frame */
1575 src_x = graphic_info[i].src_x;
1576 src_y = graphic_info[i].src_y;
1578 if (src_x < 0 || src_y < 0 ||
1579 src_x + width > src_bitmap_width ||
1580 src_y + height > src_bitmap_height)
1582 Error(ERR_INFO_LINE, "-");
1583 Error(ERR_INFO, "warning: error found in config file:");
1584 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1585 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1586 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1588 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1589 src_x, src_y, src_bitmap_width, src_bitmap_height);
1590 Error(ERR_INFO, "custom graphic rejected for this element/action");
1592 if (i == fallback_graphic)
1593 Error(ERR_EXIT, "no fallback graphic available");
1595 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1596 Error(ERR_INFO_LINE, "-");
1598 graphic_info[i] = graphic_info[fallback_graphic];
1601 /* check if last animation frame is inside specified bitmap */
1603 last_frame = graphic_info[i].anim_frames - 1;
1604 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1606 if (src_x < 0 || src_y < 0 ||
1607 src_x + width > src_bitmap_width ||
1608 src_y + height > src_bitmap_height)
1610 Error(ERR_INFO_LINE, "-");
1611 Error(ERR_INFO, "warning: error found in config file:");
1612 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1613 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1614 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1616 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1617 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1618 Error(ERR_INFO, "::: %d, %d", width, height);
1619 Error(ERR_INFO, "custom graphic rejected for this element/action");
1621 if (i == fallback_graphic)
1622 Error(ERR_EXIT, "no fallback graphic available");
1624 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1625 Error(ERR_INFO_LINE, "-");
1627 graphic_info[i] = graphic_info[fallback_graphic];
1632 static void InitGraphicCompatibilityInfo()
1634 struct FileInfo *fi_global_door =
1635 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1636 int num_images = getImageListSize();
1639 /* the following compatibility handling is needed for the following case:
1640 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1641 graphics mainly used for door and panel graphics, like editor, tape and
1642 in-game buttons with hard-coded bitmap positions and button sizes; as
1643 these graphics now have individual definitions, redefining "global.door"
1644 to change all these graphics at once like before does not work anymore
1645 (because all those individual definitions still have their default values);
1646 to solve this, remap all those individual definitions that are not
1647 redefined to the new bitmap of "global.door" if it was redefined */
1649 /* special compatibility handling if image "global.door" was redefined */
1650 if (fi_global_door->redefined)
1652 for (i = 0; i < num_images; i++)
1654 struct FileInfo *fi = getImageListEntryFromImageID(i);
1656 /* process only those images that still use the default settings */
1659 /* process all images which default to same image as "global.door" */
1660 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1662 // printf("::: special treatment needed for token '%s'\n", fi->token);
1664 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1670 InitGraphicCompatibilityInfo_Doors();
1673 static void InitElementSoundInfo()
1675 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1676 int num_property_mappings = getSoundListPropertyMappingSize();
1679 /* set values to -1 to identify later as "uninitialized" values */
1680 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1681 for (act = 0; act < NUM_ACTIONS; act++)
1682 element_info[i].sound[act] = -1;
1684 /* initialize element/sound mapping from static configuration */
1685 for (i = 0; element_to_sound[i].element > -1; i++)
1687 int element = element_to_sound[i].element;
1688 int action = element_to_sound[i].action;
1689 int sound = element_to_sound[i].sound;
1690 boolean is_class = element_to_sound[i].is_class;
1693 action = ACTION_DEFAULT;
1696 element_info[element].sound[action] = sound;
1698 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1699 if (strEqual(element_info[j].class_name,
1700 element_info[element].class_name))
1701 element_info[j].sound[action] = sound;
1704 /* initialize element class/sound mapping from dynamic configuration */
1705 for (i = 0; i < num_property_mappings; i++)
1707 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1708 int action = property_mapping[i].ext1_index;
1709 int sound = property_mapping[i].artwork_index;
1711 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1715 action = ACTION_DEFAULT;
1717 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1718 if (strEqual(element_info[j].class_name,
1719 element_info[element_class].class_name))
1720 element_info[j].sound[action] = sound;
1723 /* initialize element/sound mapping from dynamic configuration */
1724 for (i = 0; i < num_property_mappings; i++)
1726 int element = property_mapping[i].base_index;
1727 int action = property_mapping[i].ext1_index;
1728 int sound = property_mapping[i].artwork_index;
1730 if (element >= MAX_NUM_ELEMENTS)
1734 action = ACTION_DEFAULT;
1736 element_info[element].sound[action] = sound;
1739 /* now set all '-1' values to element specific default values */
1740 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1742 for (act = 0; act < NUM_ACTIONS; act++)
1744 /* generic default action sound (defined by "[default]" directive) */
1745 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1747 /* look for special default action sound (classic game specific) */
1748 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1749 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1750 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1751 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1752 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1753 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1755 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1756 /* !!! make this better !!! */
1757 if (i == EL_EMPTY_SPACE)
1758 default_action_sound = element_info[EL_DEFAULT].sound[act];
1760 /* no sound for this specific action -- use default action sound */
1761 if (element_info[i].sound[act] == -1)
1762 element_info[i].sound[act] = default_action_sound;
1766 /* copy sound settings to some elements that are only stored in level file
1767 in native R'n'D levels, but are used by game engine in native EM levels */
1768 for (i = 0; copy_properties[i][0] != -1; i++)
1769 for (j = 1; j <= 4; j++)
1770 for (act = 0; act < NUM_ACTIONS; act++)
1771 element_info[copy_properties[i][j]].sound[act] =
1772 element_info[copy_properties[i][0]].sound[act];
1775 static void InitGameModeSoundInfo()
1779 /* set values to -1 to identify later as "uninitialized" values */
1780 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1783 /* initialize gamemode/sound mapping from static configuration */
1784 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1786 int gamemode = gamemode_to_sound[i].gamemode;
1787 int sound = gamemode_to_sound[i].sound;
1790 gamemode = GAME_MODE_DEFAULT;
1792 menu.sound[gamemode] = sound;
1795 /* now set all '-1' values to levelset specific default values */
1796 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1797 if (menu.sound[i] == -1)
1798 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1801 static void set_sound_parameters(int sound, char **parameter_raw)
1803 int parameter[NUM_SND_ARGS];
1806 /* get integer values from string parameters */
1807 for (i = 0; i < NUM_SND_ARGS; i++)
1809 get_parameter_value(parameter_raw[i],
1810 sound_config_suffix[i].token,
1811 sound_config_suffix[i].type);
1813 /* explicit loop mode setting in configuration overrides default value */
1814 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1815 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1817 /* sound volume to change the original volume when loading the sound file */
1818 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1820 /* sound priority to give certain sounds a higher or lower priority */
1821 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1824 static void InitSoundInfo()
1826 int *sound_effect_properties;
1827 int num_sounds = getSoundListSize();
1830 checked_free(sound_info);
1832 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1833 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1835 /* initialize sound effect for all elements to "no sound" */
1836 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1837 for (j = 0; j < NUM_ACTIONS; j++)
1838 element_info[i].sound[j] = SND_UNDEFINED;
1840 for (i = 0; i < num_sounds; i++)
1842 struct FileInfo *sound = getSoundListEntry(i);
1843 int len_effect_text = strlen(sound->token);
1845 sound_effect_properties[i] = ACTION_OTHER;
1846 sound_info[i].loop = FALSE; /* default: play sound only once */
1848 /* determine all loop sounds and identify certain sound classes */
1850 for (j = 0; element_action_info[j].suffix; j++)
1852 int len_action_text = strlen(element_action_info[j].suffix);
1854 if (len_action_text < len_effect_text &&
1855 strEqual(&sound->token[len_effect_text - len_action_text],
1856 element_action_info[j].suffix))
1858 sound_effect_properties[i] = element_action_info[j].value;
1859 sound_info[i].loop = element_action_info[j].is_loop_sound;
1865 /* associate elements and some selected sound actions */
1867 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1869 if (element_info[j].class_name)
1871 int len_class_text = strlen(element_info[j].class_name);
1873 if (len_class_text + 1 < len_effect_text &&
1874 strncmp(sound->token,
1875 element_info[j].class_name, len_class_text) == 0 &&
1876 sound->token[len_class_text] == '.')
1878 int sound_action_value = sound_effect_properties[i];
1880 element_info[j].sound[sound_action_value] = i;
1885 set_sound_parameters(i, sound->parameter);
1888 free(sound_effect_properties);
1891 static void InitGameModeMusicInfo()
1893 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1894 int num_property_mappings = getMusicListPropertyMappingSize();
1895 int default_levelset_music = -1;
1898 /* set values to -1 to identify later as "uninitialized" values */
1899 for (i = 0; i < MAX_LEVELS; i++)
1900 levelset.music[i] = -1;
1901 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1904 /* initialize gamemode/music mapping from static configuration */
1905 for (i = 0; gamemode_to_music[i].music > -1; i++)
1907 int gamemode = gamemode_to_music[i].gamemode;
1908 int music = gamemode_to_music[i].music;
1911 gamemode = GAME_MODE_DEFAULT;
1913 menu.music[gamemode] = music;
1916 /* initialize gamemode/music mapping from dynamic configuration */
1917 for (i = 0; i < num_property_mappings; i++)
1919 int prefix = property_mapping[i].base_index;
1920 int gamemode = property_mapping[i].ext1_index;
1921 int level = property_mapping[i].ext2_index;
1922 int music = property_mapping[i].artwork_index;
1924 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1928 gamemode = GAME_MODE_DEFAULT;
1930 /* level specific music only allowed for in-game music */
1931 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1932 gamemode = GAME_MODE_PLAYING;
1937 default_levelset_music = music;
1940 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1941 levelset.music[level] = music;
1942 if (gamemode != GAME_MODE_PLAYING)
1943 menu.music[gamemode] = music;
1946 /* now set all '-1' values to menu specific default values */
1947 /* (undefined values of "levelset.music[]" might stay at "-1" to
1948 allow dynamic selection of music files from music directory!) */
1949 for (i = 0; i < MAX_LEVELS; i++)
1950 if (levelset.music[i] == -1)
1951 levelset.music[i] = default_levelset_music;
1952 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1953 if (menu.music[i] == -1)
1954 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1957 static void set_music_parameters(int music, char **parameter_raw)
1959 int parameter[NUM_MUS_ARGS];
1962 /* get integer values from string parameters */
1963 for (i = 0; i < NUM_MUS_ARGS; i++)
1965 get_parameter_value(parameter_raw[i],
1966 music_config_suffix[i].token,
1967 music_config_suffix[i].type);
1969 /* explicit loop mode setting in configuration overrides default value */
1970 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1971 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1974 static void InitMusicInfo()
1976 int num_music = getMusicListSize();
1979 checked_free(music_info);
1981 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1983 for (i = 0; i < num_music; i++)
1985 struct FileInfo *music = getMusicListEntry(i);
1986 int len_music_text = strlen(music->token);
1988 music_info[i].loop = TRUE; /* default: play music in loop mode */
1990 /* determine all loop music */
1992 for (j = 0; music_prefix_info[j].prefix; j++)
1994 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1996 if (len_prefix_text < len_music_text &&
1997 strncmp(music->token,
1998 music_prefix_info[j].prefix, len_prefix_text) == 0)
2000 music_info[i].loop = music_prefix_info[j].is_loop_music;
2006 set_music_parameters(i, music->parameter);
2010 static void ReinitializeGraphics()
2012 print_timestamp_init("ReinitializeGraphics");
2014 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2016 InitGraphicInfo(); /* graphic properties mapping */
2017 print_timestamp_time("InitGraphicInfo");
2018 InitElementGraphicInfo(); /* element game graphic mapping */
2019 print_timestamp_time("InitElementGraphicInfo");
2020 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2021 print_timestamp_time("InitElementSpecialGraphicInfo");
2023 InitElementSmallImages(); /* scale elements to all needed sizes */
2024 print_timestamp_time("InitElementSmallImages");
2025 InitScaledImages(); /* scale all other images, if needed */
2026 print_timestamp_time("InitScaledImages");
2027 InitBitmapPointers(); /* set standard size bitmap pointers */
2028 print_timestamp_time("InitBitmapPointers");
2029 InitFontGraphicInfo(); /* initialize text drawing functions */
2030 print_timestamp_time("InitFontGraphicInfo");
2031 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2032 print_timestamp_time("InitGlobalAnimGraphicInfo");
2034 InitImageTextures(); /* create textures for certain images */
2035 print_timestamp_time("InitImageTextures");
2037 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2038 print_timestamp_time("InitGraphicInfo_EM");
2040 InitGraphicCompatibilityInfo();
2041 print_timestamp_time("InitGraphicCompatibilityInfo");
2043 SetMainBackgroundImage(IMG_BACKGROUND);
2044 print_timestamp_time("SetMainBackgroundImage");
2045 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2046 print_timestamp_time("SetDoorBackgroundImage");
2049 print_timestamp_time("InitGadgets");
2051 print_timestamp_time("InitToons");
2053 print_timestamp_time("InitDoors");
2055 print_timestamp_done("ReinitializeGraphics");
2058 static void ReinitializeSounds()
2060 InitSoundInfo(); /* sound properties mapping */
2061 InitElementSoundInfo(); /* element game sound mapping */
2062 InitGameModeSoundInfo(); /* game mode sound mapping */
2064 InitPlayLevelSound(); /* internal game sound settings */
2067 static void ReinitializeMusic()
2069 InitMusicInfo(); /* music properties mapping */
2070 InitGameModeMusicInfo(); /* game mode music mapping */
2073 static int get_special_property_bit(int element, int property_bit_nr)
2075 struct PropertyBitInfo
2081 static struct PropertyBitInfo pb_can_move_into_acid[] =
2083 /* the player may be able fall into acid when gravity is activated */
2088 { EL_SP_MURPHY, 0 },
2089 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2091 /* all elements that can move may be able to also move into acid */
2094 { EL_BUG_RIGHT, 1 },
2097 { EL_SPACESHIP, 2 },
2098 { EL_SPACESHIP_LEFT, 2 },
2099 { EL_SPACESHIP_RIGHT, 2 },
2100 { EL_SPACESHIP_UP, 2 },
2101 { EL_SPACESHIP_DOWN, 2 },
2102 { EL_BD_BUTTERFLY, 3 },
2103 { EL_BD_BUTTERFLY_LEFT, 3 },
2104 { EL_BD_BUTTERFLY_RIGHT, 3 },
2105 { EL_BD_BUTTERFLY_UP, 3 },
2106 { EL_BD_BUTTERFLY_DOWN, 3 },
2107 { EL_BD_FIREFLY, 4 },
2108 { EL_BD_FIREFLY_LEFT, 4 },
2109 { EL_BD_FIREFLY_RIGHT, 4 },
2110 { EL_BD_FIREFLY_UP, 4 },
2111 { EL_BD_FIREFLY_DOWN, 4 },
2113 { EL_YAMYAM_LEFT, 5 },
2114 { EL_YAMYAM_RIGHT, 5 },
2115 { EL_YAMYAM_UP, 5 },
2116 { EL_YAMYAM_DOWN, 5 },
2117 { EL_DARK_YAMYAM, 6 },
2120 { EL_PACMAN_LEFT, 8 },
2121 { EL_PACMAN_RIGHT, 8 },
2122 { EL_PACMAN_UP, 8 },
2123 { EL_PACMAN_DOWN, 8 },
2125 { EL_MOLE_LEFT, 9 },
2126 { EL_MOLE_RIGHT, 9 },
2128 { EL_MOLE_DOWN, 9 },
2132 { EL_SATELLITE, 13 },
2133 { EL_SP_SNIKSNAK, 14 },
2134 { EL_SP_ELECTRON, 15 },
2137 { EL_EMC_ANDROID, 18 },
2142 static struct PropertyBitInfo pb_dont_collide_with[] =
2144 { EL_SP_SNIKSNAK, 0 },
2145 { EL_SP_ELECTRON, 1 },
2153 struct PropertyBitInfo *pb_info;
2156 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2157 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2162 struct PropertyBitInfo *pb_info = NULL;
2165 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2166 if (pb_definition[i].bit_nr == property_bit_nr)
2167 pb_info = pb_definition[i].pb_info;
2169 if (pb_info == NULL)
2172 for (i = 0; pb_info[i].element != -1; i++)
2173 if (pb_info[i].element == element)
2174 return pb_info[i].bit_nr;
2179 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2180 boolean property_value)
2182 int bit_nr = get_special_property_bit(element, property_bit_nr);
2187 *bitfield |= (1 << bit_nr);
2189 *bitfield &= ~(1 << bit_nr);
2193 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2195 int bit_nr = get_special_property_bit(element, property_bit_nr);
2198 return ((*bitfield & (1 << bit_nr)) != 0);
2203 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2205 static int group_nr;
2206 static struct ElementGroupInfo *group;
2207 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2210 if (actual_group == NULL) /* not yet initialized */
2213 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2215 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2216 group_element - EL_GROUP_START + 1);
2218 /* replace element which caused too deep recursion by question mark */
2219 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2224 if (recursion_depth == 0) /* initialization */
2226 group = actual_group;
2227 group_nr = GROUP_NR(group_element);
2229 group->num_elements_resolved = 0;
2230 group->choice_pos = 0;
2232 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2233 element_info[i].in_group[group_nr] = FALSE;
2236 for (i = 0; i < actual_group->num_elements; i++)
2238 int element = actual_group->element[i];
2240 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2243 if (IS_GROUP_ELEMENT(element))
2244 ResolveGroupElementExt(element, recursion_depth + 1);
2247 group->element_resolved[group->num_elements_resolved++] = element;
2248 element_info[element].in_group[group_nr] = TRUE;
2253 void ResolveGroupElement(int group_element)
2255 ResolveGroupElementExt(group_element, 0);
2258 void InitElementPropertiesStatic()
2260 static boolean clipboard_elements_initialized = FALSE;
2262 static int ep_diggable[] =
2267 EL_SP_BUGGY_BASE_ACTIVATING,
2270 EL_INVISIBLE_SAND_ACTIVE,
2273 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2274 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2279 EL_SP_BUGGY_BASE_ACTIVE,
2286 static int ep_collectible_only[] =
2308 EL_DYNABOMB_INCREASE_NUMBER,
2309 EL_DYNABOMB_INCREASE_SIZE,
2310 EL_DYNABOMB_INCREASE_POWER,
2328 /* !!! handle separately !!! */
2329 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2335 static int ep_dont_run_into[] =
2337 /* same elements as in 'ep_dont_touch' */
2343 /* same elements as in 'ep_dont_collide_with' */
2355 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2360 EL_SP_BUGGY_BASE_ACTIVE,
2367 static int ep_dont_collide_with[] =
2369 /* same elements as in 'ep_dont_touch' */
2386 static int ep_dont_touch[] =
2396 static int ep_indestructible[] =
2400 EL_ACID_POOL_TOPLEFT,
2401 EL_ACID_POOL_TOPRIGHT,
2402 EL_ACID_POOL_BOTTOMLEFT,
2403 EL_ACID_POOL_BOTTOM,
2404 EL_ACID_POOL_BOTTOMRIGHT,
2405 EL_SP_HARDWARE_GRAY,
2406 EL_SP_HARDWARE_GREEN,
2407 EL_SP_HARDWARE_BLUE,
2409 EL_SP_HARDWARE_YELLOW,
2410 EL_SP_HARDWARE_BASE_1,
2411 EL_SP_HARDWARE_BASE_2,
2412 EL_SP_HARDWARE_BASE_3,
2413 EL_SP_HARDWARE_BASE_4,
2414 EL_SP_HARDWARE_BASE_5,
2415 EL_SP_HARDWARE_BASE_6,
2416 EL_INVISIBLE_STEELWALL,
2417 EL_INVISIBLE_STEELWALL_ACTIVE,
2418 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2419 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2420 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2421 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2422 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2423 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2424 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2425 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2426 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2427 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2428 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2429 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2431 EL_LIGHT_SWITCH_ACTIVE,
2432 EL_SIGN_EXCLAMATION,
2433 EL_SIGN_RADIOACTIVITY,
2440 EL_SIGN_ENTRY_FORBIDDEN,
2441 EL_SIGN_EMERGENCY_EXIT,
2449 EL_STEEL_EXIT_CLOSED,
2451 EL_STEEL_EXIT_OPENING,
2452 EL_STEEL_EXIT_CLOSING,
2453 EL_EM_STEEL_EXIT_CLOSED,
2454 EL_EM_STEEL_EXIT_OPEN,
2455 EL_EM_STEEL_EXIT_OPENING,
2456 EL_EM_STEEL_EXIT_CLOSING,
2457 EL_DC_STEELWALL_1_LEFT,
2458 EL_DC_STEELWALL_1_RIGHT,
2459 EL_DC_STEELWALL_1_TOP,
2460 EL_DC_STEELWALL_1_BOTTOM,
2461 EL_DC_STEELWALL_1_HORIZONTAL,
2462 EL_DC_STEELWALL_1_VERTICAL,
2463 EL_DC_STEELWALL_1_TOPLEFT,
2464 EL_DC_STEELWALL_1_TOPRIGHT,
2465 EL_DC_STEELWALL_1_BOTTOMLEFT,
2466 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2467 EL_DC_STEELWALL_1_TOPLEFT_2,
2468 EL_DC_STEELWALL_1_TOPRIGHT_2,
2469 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2470 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2471 EL_DC_STEELWALL_2_LEFT,
2472 EL_DC_STEELWALL_2_RIGHT,
2473 EL_DC_STEELWALL_2_TOP,
2474 EL_DC_STEELWALL_2_BOTTOM,
2475 EL_DC_STEELWALL_2_HORIZONTAL,
2476 EL_DC_STEELWALL_2_VERTICAL,
2477 EL_DC_STEELWALL_2_MIDDLE,
2478 EL_DC_STEELWALL_2_SINGLE,
2479 EL_STEELWALL_SLIPPERY,
2493 EL_GATE_1_GRAY_ACTIVE,
2494 EL_GATE_2_GRAY_ACTIVE,
2495 EL_GATE_3_GRAY_ACTIVE,
2496 EL_GATE_4_GRAY_ACTIVE,
2505 EL_EM_GATE_1_GRAY_ACTIVE,
2506 EL_EM_GATE_2_GRAY_ACTIVE,
2507 EL_EM_GATE_3_GRAY_ACTIVE,
2508 EL_EM_GATE_4_GRAY_ACTIVE,
2517 EL_EMC_GATE_5_GRAY_ACTIVE,
2518 EL_EMC_GATE_6_GRAY_ACTIVE,
2519 EL_EMC_GATE_7_GRAY_ACTIVE,
2520 EL_EMC_GATE_8_GRAY_ACTIVE,
2522 EL_DC_GATE_WHITE_GRAY,
2523 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2524 EL_DC_GATE_FAKE_GRAY,
2526 EL_SWITCHGATE_OPENING,
2527 EL_SWITCHGATE_CLOSED,
2528 EL_SWITCHGATE_CLOSING,
2529 EL_DC_SWITCHGATE_SWITCH_UP,
2530 EL_DC_SWITCHGATE_SWITCH_DOWN,
2532 EL_TIMEGATE_OPENING,
2534 EL_TIMEGATE_CLOSING,
2535 EL_DC_TIMEGATE_SWITCH,
2536 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2540 EL_TUBE_VERTICAL_LEFT,
2541 EL_TUBE_VERTICAL_RIGHT,
2542 EL_TUBE_HORIZONTAL_UP,
2543 EL_TUBE_HORIZONTAL_DOWN,
2548 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2549 EL_EXPANDABLE_STEELWALL_VERTICAL,
2550 EL_EXPANDABLE_STEELWALL_ANY,
2555 static int ep_slippery[] =
2569 EL_ROBOT_WHEEL_ACTIVE,
2575 EL_ACID_POOL_TOPLEFT,
2576 EL_ACID_POOL_TOPRIGHT,
2586 EL_STEELWALL_SLIPPERY,
2589 EL_EMC_WALL_SLIPPERY_1,
2590 EL_EMC_WALL_SLIPPERY_2,
2591 EL_EMC_WALL_SLIPPERY_3,
2592 EL_EMC_WALL_SLIPPERY_4,
2594 EL_EMC_MAGIC_BALL_ACTIVE,
2599 static int ep_can_change[] =
2604 static int ep_can_move[] =
2606 /* same elements as in 'pb_can_move_into_acid' */
2629 static int ep_can_fall[] =
2643 EL_QUICKSAND_FAST_FULL,
2645 EL_BD_MAGIC_WALL_FULL,
2646 EL_DC_MAGIC_WALL_FULL,
2660 static int ep_can_smash_player[] =
2686 static int ep_can_smash_enemies[] =
2695 static int ep_can_smash_everything[] =
2704 static int ep_explodes_by_fire[] =
2706 /* same elements as in 'ep_explodes_impact' */
2711 /* same elements as in 'ep_explodes_smashed' */
2721 EL_EM_DYNAMITE_ACTIVE,
2722 EL_DYNABOMB_PLAYER_1_ACTIVE,
2723 EL_DYNABOMB_PLAYER_2_ACTIVE,
2724 EL_DYNABOMB_PLAYER_3_ACTIVE,
2725 EL_DYNABOMB_PLAYER_4_ACTIVE,
2726 EL_DYNABOMB_INCREASE_NUMBER,
2727 EL_DYNABOMB_INCREASE_SIZE,
2728 EL_DYNABOMB_INCREASE_POWER,
2729 EL_SP_DISK_RED_ACTIVE,
2743 static int ep_explodes_smashed[] =
2745 /* same elements as in 'ep_explodes_impact' */
2759 static int ep_explodes_impact[] =
2768 static int ep_walkable_over[] =
2772 EL_SOKOBAN_FIELD_EMPTY,
2779 EL_EM_STEEL_EXIT_OPEN,
2780 EL_EM_STEEL_EXIT_OPENING,
2789 EL_GATE_1_GRAY_ACTIVE,
2790 EL_GATE_2_GRAY_ACTIVE,
2791 EL_GATE_3_GRAY_ACTIVE,
2792 EL_GATE_4_GRAY_ACTIVE,
2800 static int ep_walkable_inside[] =
2805 EL_TUBE_VERTICAL_LEFT,
2806 EL_TUBE_VERTICAL_RIGHT,
2807 EL_TUBE_HORIZONTAL_UP,
2808 EL_TUBE_HORIZONTAL_DOWN,
2817 static int ep_walkable_under[] =
2822 static int ep_passable_over[] =
2832 EL_EM_GATE_1_GRAY_ACTIVE,
2833 EL_EM_GATE_2_GRAY_ACTIVE,
2834 EL_EM_GATE_3_GRAY_ACTIVE,
2835 EL_EM_GATE_4_GRAY_ACTIVE,
2844 EL_EMC_GATE_5_GRAY_ACTIVE,
2845 EL_EMC_GATE_6_GRAY_ACTIVE,
2846 EL_EMC_GATE_7_GRAY_ACTIVE,
2847 EL_EMC_GATE_8_GRAY_ACTIVE,
2849 EL_DC_GATE_WHITE_GRAY,
2850 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2857 static int ep_passable_inside[] =
2863 EL_SP_PORT_HORIZONTAL,
2864 EL_SP_PORT_VERTICAL,
2866 EL_SP_GRAVITY_PORT_LEFT,
2867 EL_SP_GRAVITY_PORT_RIGHT,
2868 EL_SP_GRAVITY_PORT_UP,
2869 EL_SP_GRAVITY_PORT_DOWN,
2870 EL_SP_GRAVITY_ON_PORT_LEFT,
2871 EL_SP_GRAVITY_ON_PORT_RIGHT,
2872 EL_SP_GRAVITY_ON_PORT_UP,
2873 EL_SP_GRAVITY_ON_PORT_DOWN,
2874 EL_SP_GRAVITY_OFF_PORT_LEFT,
2875 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2876 EL_SP_GRAVITY_OFF_PORT_UP,
2877 EL_SP_GRAVITY_OFF_PORT_DOWN,
2882 static int ep_passable_under[] =
2887 static int ep_droppable[] =
2892 static int ep_explodes_1x1_old[] =
2897 static int ep_pushable[] =
2909 EL_SOKOBAN_FIELD_FULL,
2918 static int ep_explodes_cross_old[] =
2923 static int ep_protected[] =
2925 /* same elements as in 'ep_walkable_inside' */
2929 EL_TUBE_VERTICAL_LEFT,
2930 EL_TUBE_VERTICAL_RIGHT,
2931 EL_TUBE_HORIZONTAL_UP,
2932 EL_TUBE_HORIZONTAL_DOWN,
2938 /* same elements as in 'ep_passable_over' */
2947 EL_EM_GATE_1_GRAY_ACTIVE,
2948 EL_EM_GATE_2_GRAY_ACTIVE,
2949 EL_EM_GATE_3_GRAY_ACTIVE,
2950 EL_EM_GATE_4_GRAY_ACTIVE,
2959 EL_EMC_GATE_5_GRAY_ACTIVE,
2960 EL_EMC_GATE_6_GRAY_ACTIVE,
2961 EL_EMC_GATE_7_GRAY_ACTIVE,
2962 EL_EMC_GATE_8_GRAY_ACTIVE,
2964 EL_DC_GATE_WHITE_GRAY,
2965 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2969 /* same elements as in 'ep_passable_inside' */
2974 EL_SP_PORT_HORIZONTAL,
2975 EL_SP_PORT_VERTICAL,
2977 EL_SP_GRAVITY_PORT_LEFT,
2978 EL_SP_GRAVITY_PORT_RIGHT,
2979 EL_SP_GRAVITY_PORT_UP,
2980 EL_SP_GRAVITY_PORT_DOWN,
2981 EL_SP_GRAVITY_ON_PORT_LEFT,
2982 EL_SP_GRAVITY_ON_PORT_RIGHT,
2983 EL_SP_GRAVITY_ON_PORT_UP,
2984 EL_SP_GRAVITY_ON_PORT_DOWN,
2985 EL_SP_GRAVITY_OFF_PORT_LEFT,
2986 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2987 EL_SP_GRAVITY_OFF_PORT_UP,
2988 EL_SP_GRAVITY_OFF_PORT_DOWN,
2993 static int ep_throwable[] =
2998 static int ep_can_explode[] =
3000 /* same elements as in 'ep_explodes_impact' */
3005 /* same elements as in 'ep_explodes_smashed' */
3011 /* elements that can explode by explosion or by dragonfire */
3015 EL_EM_DYNAMITE_ACTIVE,
3016 EL_DYNABOMB_PLAYER_1_ACTIVE,
3017 EL_DYNABOMB_PLAYER_2_ACTIVE,
3018 EL_DYNABOMB_PLAYER_3_ACTIVE,
3019 EL_DYNABOMB_PLAYER_4_ACTIVE,
3020 EL_DYNABOMB_INCREASE_NUMBER,
3021 EL_DYNABOMB_INCREASE_SIZE,
3022 EL_DYNABOMB_INCREASE_POWER,
3023 EL_SP_DISK_RED_ACTIVE,
3031 /* elements that can explode only by explosion */
3037 static int ep_gravity_reachable[] =
3043 EL_INVISIBLE_SAND_ACTIVE,
3048 EL_SP_PORT_HORIZONTAL,
3049 EL_SP_PORT_VERTICAL,
3051 EL_SP_GRAVITY_PORT_LEFT,
3052 EL_SP_GRAVITY_PORT_RIGHT,
3053 EL_SP_GRAVITY_PORT_UP,
3054 EL_SP_GRAVITY_PORT_DOWN,
3055 EL_SP_GRAVITY_ON_PORT_LEFT,
3056 EL_SP_GRAVITY_ON_PORT_RIGHT,
3057 EL_SP_GRAVITY_ON_PORT_UP,
3058 EL_SP_GRAVITY_ON_PORT_DOWN,
3059 EL_SP_GRAVITY_OFF_PORT_LEFT,
3060 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3061 EL_SP_GRAVITY_OFF_PORT_UP,
3062 EL_SP_GRAVITY_OFF_PORT_DOWN,
3068 static int ep_player[] =
3075 EL_SOKOBAN_FIELD_PLAYER,
3081 static int ep_can_pass_magic_wall[] =
3095 static int ep_can_pass_dc_magic_wall[] =
3111 static int ep_switchable[] =
3115 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3116 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3117 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3118 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3119 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3120 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3121 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3122 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3123 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3124 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3125 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3126 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3127 EL_SWITCHGATE_SWITCH_UP,
3128 EL_SWITCHGATE_SWITCH_DOWN,
3129 EL_DC_SWITCHGATE_SWITCH_UP,
3130 EL_DC_SWITCHGATE_SWITCH_DOWN,
3132 EL_LIGHT_SWITCH_ACTIVE,
3134 EL_DC_TIMEGATE_SWITCH,
3135 EL_BALLOON_SWITCH_LEFT,
3136 EL_BALLOON_SWITCH_RIGHT,
3137 EL_BALLOON_SWITCH_UP,
3138 EL_BALLOON_SWITCH_DOWN,
3139 EL_BALLOON_SWITCH_ANY,
3140 EL_BALLOON_SWITCH_NONE,
3143 EL_EMC_MAGIC_BALL_SWITCH,
3144 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3149 static int ep_bd_element[] =
3183 static int ep_sp_element[] =
3185 /* should always be valid */
3188 /* standard classic Supaplex elements */
3195 EL_SP_HARDWARE_GRAY,
3203 EL_SP_GRAVITY_PORT_RIGHT,
3204 EL_SP_GRAVITY_PORT_DOWN,
3205 EL_SP_GRAVITY_PORT_LEFT,
3206 EL_SP_GRAVITY_PORT_UP,
3211 EL_SP_PORT_VERTICAL,
3212 EL_SP_PORT_HORIZONTAL,
3218 EL_SP_HARDWARE_BASE_1,
3219 EL_SP_HARDWARE_GREEN,
3220 EL_SP_HARDWARE_BLUE,
3222 EL_SP_HARDWARE_YELLOW,
3223 EL_SP_HARDWARE_BASE_2,
3224 EL_SP_HARDWARE_BASE_3,
3225 EL_SP_HARDWARE_BASE_4,
3226 EL_SP_HARDWARE_BASE_5,
3227 EL_SP_HARDWARE_BASE_6,
3231 /* additional elements that appeared in newer Supaplex levels */
3234 /* additional gravity port elements (not switching, but setting gravity) */
3235 EL_SP_GRAVITY_ON_PORT_LEFT,
3236 EL_SP_GRAVITY_ON_PORT_RIGHT,
3237 EL_SP_GRAVITY_ON_PORT_UP,
3238 EL_SP_GRAVITY_ON_PORT_DOWN,
3239 EL_SP_GRAVITY_OFF_PORT_LEFT,
3240 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3241 EL_SP_GRAVITY_OFF_PORT_UP,
3242 EL_SP_GRAVITY_OFF_PORT_DOWN,
3244 /* more than one Murphy in a level results in an inactive clone */
3247 /* runtime Supaplex elements */
3248 EL_SP_DISK_RED_ACTIVE,
3249 EL_SP_TERMINAL_ACTIVE,
3250 EL_SP_BUGGY_BASE_ACTIVATING,
3251 EL_SP_BUGGY_BASE_ACTIVE,
3258 static int ep_sb_element[] =
3263 EL_SOKOBAN_FIELD_EMPTY,
3264 EL_SOKOBAN_FIELD_FULL,
3265 EL_SOKOBAN_FIELD_PLAYER,
3270 EL_INVISIBLE_STEELWALL,
3275 static int ep_gem[] =
3287 static int ep_food_dark_yamyam[] =
3315 static int ep_food_penguin[] =
3329 static int ep_food_pig[] =
3341 static int ep_historic_wall[] =
3352 EL_GATE_1_GRAY_ACTIVE,
3353 EL_GATE_2_GRAY_ACTIVE,
3354 EL_GATE_3_GRAY_ACTIVE,
3355 EL_GATE_4_GRAY_ACTIVE,
3364 EL_EM_GATE_1_GRAY_ACTIVE,
3365 EL_EM_GATE_2_GRAY_ACTIVE,
3366 EL_EM_GATE_3_GRAY_ACTIVE,
3367 EL_EM_GATE_4_GRAY_ACTIVE,
3374 EL_EXPANDABLE_WALL_HORIZONTAL,
3375 EL_EXPANDABLE_WALL_VERTICAL,
3376 EL_EXPANDABLE_WALL_ANY,
3377 EL_EXPANDABLE_WALL_GROWING,
3378 EL_BD_EXPANDABLE_WALL,
3385 EL_SP_HARDWARE_GRAY,
3386 EL_SP_HARDWARE_GREEN,
3387 EL_SP_HARDWARE_BLUE,
3389 EL_SP_HARDWARE_YELLOW,
3390 EL_SP_HARDWARE_BASE_1,
3391 EL_SP_HARDWARE_BASE_2,
3392 EL_SP_HARDWARE_BASE_3,
3393 EL_SP_HARDWARE_BASE_4,
3394 EL_SP_HARDWARE_BASE_5,
3395 EL_SP_HARDWARE_BASE_6,
3397 EL_SP_TERMINAL_ACTIVE,
3400 EL_INVISIBLE_STEELWALL,
3401 EL_INVISIBLE_STEELWALL_ACTIVE,
3403 EL_INVISIBLE_WALL_ACTIVE,
3404 EL_STEELWALL_SLIPPERY,
3421 static int ep_historic_solid[] =
3425 EL_EXPANDABLE_WALL_HORIZONTAL,
3426 EL_EXPANDABLE_WALL_VERTICAL,
3427 EL_EXPANDABLE_WALL_ANY,
3428 EL_BD_EXPANDABLE_WALL,
3441 EL_QUICKSAND_FILLING,
3442 EL_QUICKSAND_EMPTYING,
3444 EL_MAGIC_WALL_ACTIVE,
3445 EL_MAGIC_WALL_EMPTYING,
3446 EL_MAGIC_WALL_FILLING,
3450 EL_BD_MAGIC_WALL_ACTIVE,
3451 EL_BD_MAGIC_WALL_EMPTYING,
3452 EL_BD_MAGIC_WALL_FULL,
3453 EL_BD_MAGIC_WALL_FILLING,
3454 EL_BD_MAGIC_WALL_DEAD,
3463 EL_SP_TERMINAL_ACTIVE,
3467 EL_INVISIBLE_WALL_ACTIVE,
3468 EL_SWITCHGATE_SWITCH_UP,
3469 EL_SWITCHGATE_SWITCH_DOWN,
3470 EL_DC_SWITCHGATE_SWITCH_UP,
3471 EL_DC_SWITCHGATE_SWITCH_DOWN,
3473 EL_TIMEGATE_SWITCH_ACTIVE,
3474 EL_DC_TIMEGATE_SWITCH,
3475 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3487 /* the following elements are a direct copy of "indestructible" elements,
3488 except "EL_ACID", which is "indestructible", but not "solid"! */
3493 EL_ACID_POOL_TOPLEFT,
3494 EL_ACID_POOL_TOPRIGHT,
3495 EL_ACID_POOL_BOTTOMLEFT,
3496 EL_ACID_POOL_BOTTOM,
3497 EL_ACID_POOL_BOTTOMRIGHT,
3498 EL_SP_HARDWARE_GRAY,
3499 EL_SP_HARDWARE_GREEN,
3500 EL_SP_HARDWARE_BLUE,
3502 EL_SP_HARDWARE_YELLOW,
3503 EL_SP_HARDWARE_BASE_1,
3504 EL_SP_HARDWARE_BASE_2,
3505 EL_SP_HARDWARE_BASE_3,
3506 EL_SP_HARDWARE_BASE_4,
3507 EL_SP_HARDWARE_BASE_5,
3508 EL_SP_HARDWARE_BASE_6,
3509 EL_INVISIBLE_STEELWALL,
3510 EL_INVISIBLE_STEELWALL_ACTIVE,
3511 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3512 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3513 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3514 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3515 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3516 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3517 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3518 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3519 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3520 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3521 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3522 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3524 EL_LIGHT_SWITCH_ACTIVE,
3525 EL_SIGN_EXCLAMATION,
3526 EL_SIGN_RADIOACTIVITY,
3533 EL_SIGN_ENTRY_FORBIDDEN,
3534 EL_SIGN_EMERGENCY_EXIT,
3542 EL_STEEL_EXIT_CLOSED,
3544 EL_DC_STEELWALL_1_LEFT,
3545 EL_DC_STEELWALL_1_RIGHT,
3546 EL_DC_STEELWALL_1_TOP,
3547 EL_DC_STEELWALL_1_BOTTOM,
3548 EL_DC_STEELWALL_1_HORIZONTAL,
3549 EL_DC_STEELWALL_1_VERTICAL,
3550 EL_DC_STEELWALL_1_TOPLEFT,
3551 EL_DC_STEELWALL_1_TOPRIGHT,
3552 EL_DC_STEELWALL_1_BOTTOMLEFT,
3553 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3554 EL_DC_STEELWALL_1_TOPLEFT_2,
3555 EL_DC_STEELWALL_1_TOPRIGHT_2,
3556 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3557 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3558 EL_DC_STEELWALL_2_LEFT,
3559 EL_DC_STEELWALL_2_RIGHT,
3560 EL_DC_STEELWALL_2_TOP,
3561 EL_DC_STEELWALL_2_BOTTOM,
3562 EL_DC_STEELWALL_2_HORIZONTAL,
3563 EL_DC_STEELWALL_2_VERTICAL,
3564 EL_DC_STEELWALL_2_MIDDLE,
3565 EL_DC_STEELWALL_2_SINGLE,
3566 EL_STEELWALL_SLIPPERY,
3580 EL_GATE_1_GRAY_ACTIVE,
3581 EL_GATE_2_GRAY_ACTIVE,
3582 EL_GATE_3_GRAY_ACTIVE,
3583 EL_GATE_4_GRAY_ACTIVE,
3592 EL_EM_GATE_1_GRAY_ACTIVE,
3593 EL_EM_GATE_2_GRAY_ACTIVE,
3594 EL_EM_GATE_3_GRAY_ACTIVE,
3595 EL_EM_GATE_4_GRAY_ACTIVE,
3597 EL_SWITCHGATE_OPENING,
3598 EL_SWITCHGATE_CLOSED,
3599 EL_SWITCHGATE_CLOSING,
3601 EL_TIMEGATE_OPENING,
3603 EL_TIMEGATE_CLOSING,
3607 EL_TUBE_VERTICAL_LEFT,
3608 EL_TUBE_VERTICAL_RIGHT,
3609 EL_TUBE_HORIZONTAL_UP,
3610 EL_TUBE_HORIZONTAL_DOWN,
3619 static int ep_classic_enemy[] =
3636 static int ep_belt[] =
3638 EL_CONVEYOR_BELT_1_LEFT,
3639 EL_CONVEYOR_BELT_1_MIDDLE,
3640 EL_CONVEYOR_BELT_1_RIGHT,
3641 EL_CONVEYOR_BELT_2_LEFT,
3642 EL_CONVEYOR_BELT_2_MIDDLE,
3643 EL_CONVEYOR_BELT_2_RIGHT,
3644 EL_CONVEYOR_BELT_3_LEFT,
3645 EL_CONVEYOR_BELT_3_MIDDLE,
3646 EL_CONVEYOR_BELT_3_RIGHT,
3647 EL_CONVEYOR_BELT_4_LEFT,
3648 EL_CONVEYOR_BELT_4_MIDDLE,
3649 EL_CONVEYOR_BELT_4_RIGHT,
3654 static int ep_belt_active[] =
3656 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3657 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3658 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3659 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3660 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3661 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3662 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3663 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3664 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3665 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3666 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3667 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3672 static int ep_belt_switch[] =
3674 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3675 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3676 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3677 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3678 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3679 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3680 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3681 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3682 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3683 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3684 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3685 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3690 static int ep_tube[] =
3697 EL_TUBE_HORIZONTAL_UP,
3698 EL_TUBE_HORIZONTAL_DOWN,
3700 EL_TUBE_VERTICAL_LEFT,
3701 EL_TUBE_VERTICAL_RIGHT,
3707 static int ep_acid_pool[] =
3709 EL_ACID_POOL_TOPLEFT,
3710 EL_ACID_POOL_TOPRIGHT,
3711 EL_ACID_POOL_BOTTOMLEFT,
3712 EL_ACID_POOL_BOTTOM,
3713 EL_ACID_POOL_BOTTOMRIGHT,
3718 static int ep_keygate[] =
3728 EL_GATE_1_GRAY_ACTIVE,
3729 EL_GATE_2_GRAY_ACTIVE,
3730 EL_GATE_3_GRAY_ACTIVE,
3731 EL_GATE_4_GRAY_ACTIVE,
3740 EL_EM_GATE_1_GRAY_ACTIVE,
3741 EL_EM_GATE_2_GRAY_ACTIVE,
3742 EL_EM_GATE_3_GRAY_ACTIVE,
3743 EL_EM_GATE_4_GRAY_ACTIVE,
3752 EL_EMC_GATE_5_GRAY_ACTIVE,
3753 EL_EMC_GATE_6_GRAY_ACTIVE,
3754 EL_EMC_GATE_7_GRAY_ACTIVE,
3755 EL_EMC_GATE_8_GRAY_ACTIVE,
3757 EL_DC_GATE_WHITE_GRAY,
3758 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3763 static int ep_amoeboid[] =
3775 static int ep_amoebalive[] =
3786 static int ep_has_editor_content[] =
3792 EL_SOKOBAN_FIELD_PLAYER,
3809 static int ep_can_turn_each_move[] =
3811 /* !!! do something with this one !!! */
3815 static int ep_can_grow[] =
3829 static int ep_active_bomb[] =
3832 EL_EM_DYNAMITE_ACTIVE,
3833 EL_DYNABOMB_PLAYER_1_ACTIVE,
3834 EL_DYNABOMB_PLAYER_2_ACTIVE,
3835 EL_DYNABOMB_PLAYER_3_ACTIVE,
3836 EL_DYNABOMB_PLAYER_4_ACTIVE,
3837 EL_SP_DISK_RED_ACTIVE,
3842 static int ep_inactive[] =
3852 EL_QUICKSAND_FAST_EMPTY,
3875 EL_GATE_1_GRAY_ACTIVE,
3876 EL_GATE_2_GRAY_ACTIVE,
3877 EL_GATE_3_GRAY_ACTIVE,
3878 EL_GATE_4_GRAY_ACTIVE,
3887 EL_EM_GATE_1_GRAY_ACTIVE,
3888 EL_EM_GATE_2_GRAY_ACTIVE,
3889 EL_EM_GATE_3_GRAY_ACTIVE,
3890 EL_EM_GATE_4_GRAY_ACTIVE,
3899 EL_EMC_GATE_5_GRAY_ACTIVE,
3900 EL_EMC_GATE_6_GRAY_ACTIVE,
3901 EL_EMC_GATE_7_GRAY_ACTIVE,
3902 EL_EMC_GATE_8_GRAY_ACTIVE,
3904 EL_DC_GATE_WHITE_GRAY,
3905 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3906 EL_DC_GATE_FAKE_GRAY,
3909 EL_INVISIBLE_STEELWALL,
3917 EL_WALL_EMERALD_YELLOW,
3918 EL_DYNABOMB_INCREASE_NUMBER,
3919 EL_DYNABOMB_INCREASE_SIZE,
3920 EL_DYNABOMB_INCREASE_POWER,
3924 EL_SOKOBAN_FIELD_EMPTY,
3925 EL_SOKOBAN_FIELD_FULL,
3926 EL_WALL_EMERALD_RED,
3927 EL_WALL_EMERALD_PURPLE,
3928 EL_ACID_POOL_TOPLEFT,
3929 EL_ACID_POOL_TOPRIGHT,
3930 EL_ACID_POOL_BOTTOMLEFT,
3931 EL_ACID_POOL_BOTTOM,
3932 EL_ACID_POOL_BOTTOMRIGHT,
3936 EL_BD_MAGIC_WALL_DEAD,
3938 EL_DC_MAGIC_WALL_DEAD,
3939 EL_AMOEBA_TO_DIAMOND,
3947 EL_SP_GRAVITY_PORT_RIGHT,
3948 EL_SP_GRAVITY_PORT_DOWN,
3949 EL_SP_GRAVITY_PORT_LEFT,
3950 EL_SP_GRAVITY_PORT_UP,
3951 EL_SP_PORT_HORIZONTAL,
3952 EL_SP_PORT_VERTICAL,
3963 EL_SP_HARDWARE_GRAY,
3964 EL_SP_HARDWARE_GREEN,
3965 EL_SP_HARDWARE_BLUE,
3967 EL_SP_HARDWARE_YELLOW,
3968 EL_SP_HARDWARE_BASE_1,
3969 EL_SP_HARDWARE_BASE_2,
3970 EL_SP_HARDWARE_BASE_3,
3971 EL_SP_HARDWARE_BASE_4,
3972 EL_SP_HARDWARE_BASE_5,
3973 EL_SP_HARDWARE_BASE_6,
3974 EL_SP_GRAVITY_ON_PORT_LEFT,
3975 EL_SP_GRAVITY_ON_PORT_RIGHT,
3976 EL_SP_GRAVITY_ON_PORT_UP,
3977 EL_SP_GRAVITY_ON_PORT_DOWN,
3978 EL_SP_GRAVITY_OFF_PORT_LEFT,
3979 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3980 EL_SP_GRAVITY_OFF_PORT_UP,
3981 EL_SP_GRAVITY_OFF_PORT_DOWN,
3982 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3983 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3984 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3985 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3986 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3987 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3988 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3989 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3990 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3991 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3992 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3993 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3994 EL_SIGN_EXCLAMATION,
3995 EL_SIGN_RADIOACTIVITY,
4002 EL_SIGN_ENTRY_FORBIDDEN,
4003 EL_SIGN_EMERGENCY_EXIT,
4011 EL_DC_STEELWALL_1_LEFT,
4012 EL_DC_STEELWALL_1_RIGHT,
4013 EL_DC_STEELWALL_1_TOP,
4014 EL_DC_STEELWALL_1_BOTTOM,
4015 EL_DC_STEELWALL_1_HORIZONTAL,
4016 EL_DC_STEELWALL_1_VERTICAL,
4017 EL_DC_STEELWALL_1_TOPLEFT,
4018 EL_DC_STEELWALL_1_TOPRIGHT,
4019 EL_DC_STEELWALL_1_BOTTOMLEFT,
4020 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4021 EL_DC_STEELWALL_1_TOPLEFT_2,
4022 EL_DC_STEELWALL_1_TOPRIGHT_2,
4023 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4024 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4025 EL_DC_STEELWALL_2_LEFT,
4026 EL_DC_STEELWALL_2_RIGHT,
4027 EL_DC_STEELWALL_2_TOP,
4028 EL_DC_STEELWALL_2_BOTTOM,
4029 EL_DC_STEELWALL_2_HORIZONTAL,
4030 EL_DC_STEELWALL_2_VERTICAL,
4031 EL_DC_STEELWALL_2_MIDDLE,
4032 EL_DC_STEELWALL_2_SINGLE,
4033 EL_STEELWALL_SLIPPERY,
4038 EL_EMC_WALL_SLIPPERY_1,
4039 EL_EMC_WALL_SLIPPERY_2,
4040 EL_EMC_WALL_SLIPPERY_3,
4041 EL_EMC_WALL_SLIPPERY_4,
4062 static int ep_em_slippery_wall[] =
4067 static int ep_gfx_crumbled[] =
4078 static int ep_editor_cascade_active[] =
4080 EL_INTERNAL_CASCADE_BD_ACTIVE,
4081 EL_INTERNAL_CASCADE_EM_ACTIVE,
4082 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4083 EL_INTERNAL_CASCADE_RND_ACTIVE,
4084 EL_INTERNAL_CASCADE_SB_ACTIVE,
4085 EL_INTERNAL_CASCADE_SP_ACTIVE,
4086 EL_INTERNAL_CASCADE_DC_ACTIVE,
4087 EL_INTERNAL_CASCADE_DX_ACTIVE,
4088 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4089 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4090 EL_INTERNAL_CASCADE_CE_ACTIVE,
4091 EL_INTERNAL_CASCADE_GE_ACTIVE,
4092 EL_INTERNAL_CASCADE_REF_ACTIVE,
4093 EL_INTERNAL_CASCADE_USER_ACTIVE,
4094 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4099 static int ep_editor_cascade_inactive[] =
4101 EL_INTERNAL_CASCADE_BD,
4102 EL_INTERNAL_CASCADE_EM,
4103 EL_INTERNAL_CASCADE_EMC,
4104 EL_INTERNAL_CASCADE_RND,
4105 EL_INTERNAL_CASCADE_SB,
4106 EL_INTERNAL_CASCADE_SP,
4107 EL_INTERNAL_CASCADE_DC,
4108 EL_INTERNAL_CASCADE_DX,
4109 EL_INTERNAL_CASCADE_CHARS,
4110 EL_INTERNAL_CASCADE_STEEL_CHARS,
4111 EL_INTERNAL_CASCADE_CE,
4112 EL_INTERNAL_CASCADE_GE,
4113 EL_INTERNAL_CASCADE_REF,
4114 EL_INTERNAL_CASCADE_USER,
4115 EL_INTERNAL_CASCADE_DYNAMIC,
4120 static int ep_obsolete[] =
4124 EL_EM_KEY_1_FILE_OBSOLETE,
4125 EL_EM_KEY_2_FILE_OBSOLETE,
4126 EL_EM_KEY_3_FILE_OBSOLETE,
4127 EL_EM_KEY_4_FILE_OBSOLETE,
4128 EL_ENVELOPE_OBSOLETE,
4137 } element_properties[] =
4139 { ep_diggable, EP_DIGGABLE },
4140 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4141 { ep_dont_run_into, EP_DONT_RUN_INTO },
4142 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4143 { ep_dont_touch, EP_DONT_TOUCH },
4144 { ep_indestructible, EP_INDESTRUCTIBLE },
4145 { ep_slippery, EP_SLIPPERY },
4146 { ep_can_change, EP_CAN_CHANGE },
4147 { ep_can_move, EP_CAN_MOVE },
4148 { ep_can_fall, EP_CAN_FALL },
4149 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4150 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4151 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4152 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4153 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4154 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4155 { ep_walkable_over, EP_WALKABLE_OVER },
4156 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4157 { ep_walkable_under, EP_WALKABLE_UNDER },
4158 { ep_passable_over, EP_PASSABLE_OVER },
4159 { ep_passable_inside, EP_PASSABLE_INSIDE },
4160 { ep_passable_under, EP_PASSABLE_UNDER },
4161 { ep_droppable, EP_DROPPABLE },
4162 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4163 { ep_pushable, EP_PUSHABLE },
4164 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4165 { ep_protected, EP_PROTECTED },
4166 { ep_throwable, EP_THROWABLE },
4167 { ep_can_explode, EP_CAN_EXPLODE },
4168 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4170 { ep_player, EP_PLAYER },
4171 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4172 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4173 { ep_switchable, EP_SWITCHABLE },
4174 { ep_bd_element, EP_BD_ELEMENT },
4175 { ep_sp_element, EP_SP_ELEMENT },
4176 { ep_sb_element, EP_SB_ELEMENT },
4178 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4179 { ep_food_penguin, EP_FOOD_PENGUIN },
4180 { ep_food_pig, EP_FOOD_PIG },
4181 { ep_historic_wall, EP_HISTORIC_WALL },
4182 { ep_historic_solid, EP_HISTORIC_SOLID },
4183 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4184 { ep_belt, EP_BELT },
4185 { ep_belt_active, EP_BELT_ACTIVE },
4186 { ep_belt_switch, EP_BELT_SWITCH },
4187 { ep_tube, EP_TUBE },
4188 { ep_acid_pool, EP_ACID_POOL },
4189 { ep_keygate, EP_KEYGATE },
4190 { ep_amoeboid, EP_AMOEBOID },
4191 { ep_amoebalive, EP_AMOEBALIVE },
4192 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4193 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4194 { ep_can_grow, EP_CAN_GROW },
4195 { ep_active_bomb, EP_ACTIVE_BOMB },
4196 { ep_inactive, EP_INACTIVE },
4198 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4200 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4202 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4203 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4205 { ep_obsolete, EP_OBSOLETE },
4212 /* always start with reliable default values (element has no properties) */
4213 /* (but never initialize clipboard elements after the very first time) */
4214 /* (to be able to use clipboard elements between several levels) */
4215 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4216 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4217 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4218 SET_PROPERTY(i, j, FALSE);
4220 /* set all base element properties from above array definitions */
4221 for (i = 0; element_properties[i].elements != NULL; i++)
4222 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4223 SET_PROPERTY((element_properties[i].elements)[j],
4224 element_properties[i].property, TRUE);
4226 /* copy properties to some elements that are only stored in level file */
4227 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4228 for (j = 0; copy_properties[j][0] != -1; j++)
4229 if (HAS_PROPERTY(copy_properties[j][0], i))
4230 for (k = 1; k <= 4; k++)
4231 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4233 /* set static element properties that are not listed in array definitions */
4234 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4235 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4237 clipboard_elements_initialized = TRUE;
4240 void InitElementPropertiesEngine(int engine_version)
4242 static int no_wall_properties[] =
4245 EP_COLLECTIBLE_ONLY,
4247 EP_DONT_COLLIDE_WITH,
4250 EP_CAN_SMASH_PLAYER,
4251 EP_CAN_SMASH_ENEMIES,
4252 EP_CAN_SMASH_EVERYTHING,
4257 EP_FOOD_DARK_YAMYAM,
4273 /* important: after initialization in InitElementPropertiesStatic(), the
4274 elements are not again initialized to a default value; therefore all
4275 changes have to make sure that they leave the element with a defined
4276 property (which means that conditional property changes must be set to
4277 a reliable default value before) */
4279 /* resolve group elements */
4280 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4281 ResolveGroupElement(EL_GROUP_START + i);
4283 /* set all special, combined or engine dependent element properties */
4284 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4286 /* do not change (already initialized) clipboard elements here */
4287 if (IS_CLIPBOARD_ELEMENT(i))
4290 /* ---------- INACTIVE ------------------------------------------------- */
4291 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4292 i <= EL_CHAR_END) ||
4293 (i >= EL_STEEL_CHAR_START &&
4294 i <= EL_STEEL_CHAR_END)));
4296 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4297 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4298 IS_WALKABLE_INSIDE(i) ||
4299 IS_WALKABLE_UNDER(i)));
4301 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4302 IS_PASSABLE_INSIDE(i) ||
4303 IS_PASSABLE_UNDER(i)));
4305 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4306 IS_PASSABLE_OVER(i)));
4308 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4309 IS_PASSABLE_INSIDE(i)));
4311 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4312 IS_PASSABLE_UNDER(i)));
4314 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4317 /* ---------- COLLECTIBLE ---------------------------------------------- */
4318 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4322 /* ---------- SNAPPABLE ------------------------------------------------ */
4323 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4324 IS_COLLECTIBLE(i) ||
4328 /* ---------- WALL ----------------------------------------------------- */
4329 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4331 for (j = 0; no_wall_properties[j] != -1; j++)
4332 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4333 i >= EL_FIRST_RUNTIME_UNREAL)
4334 SET_PROPERTY(i, EP_WALL, FALSE);
4336 if (IS_HISTORIC_WALL(i))
4337 SET_PROPERTY(i, EP_WALL, TRUE);
4339 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4340 if (engine_version < VERSION_IDENT(2,2,0,0))
4341 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4343 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4345 !IS_COLLECTIBLE(i)));
4347 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4348 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4349 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4351 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4352 IS_INDESTRUCTIBLE(i)));
4354 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4356 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4357 else if (engine_version < VERSION_IDENT(2,2,0,0))
4358 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4360 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4364 if (IS_CUSTOM_ELEMENT(i))
4366 /* these are additional properties which are initially false when set */
4368 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4370 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4371 if (DONT_COLLIDE_WITH(i))
4372 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4374 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4375 if (CAN_SMASH_EVERYTHING(i))
4376 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4377 if (CAN_SMASH_ENEMIES(i))
4378 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4381 /* ---------- CAN_SMASH ------------------------------------------------ */
4382 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4383 CAN_SMASH_ENEMIES(i) ||
4384 CAN_SMASH_EVERYTHING(i)));
4386 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4387 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4388 EXPLODES_BY_FIRE(i)));
4390 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4391 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4392 EXPLODES_SMASHED(i)));
4394 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4395 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4396 EXPLODES_IMPACT(i)));
4398 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4399 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4401 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4402 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4403 i == EL_BLACK_ORB));
4405 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4406 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4408 IS_CUSTOM_ELEMENT(i)));
4410 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4411 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4412 i == EL_SP_ELECTRON));
4414 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4415 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4416 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4417 getMoveIntoAcidProperty(&level, i));
4419 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4420 if (MAYBE_DONT_COLLIDE_WITH(i))
4421 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4422 getDontCollideWithProperty(&level, i));
4424 /* ---------- SP_PORT -------------------------------------------------- */
4425 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4426 IS_PASSABLE_INSIDE(i)));
4428 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4429 for (j = 0; j < level.num_android_clone_elements; j++)
4430 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4432 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4434 /* ---------- CAN_CHANGE ----------------------------------------------- */
4435 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4436 for (j = 0; j < element_info[i].num_change_pages; j++)
4437 if (element_info[i].change_page[j].can_change)
4438 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4440 /* ---------- HAS_ACTION ----------------------------------------------- */
4441 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4442 for (j = 0; j < element_info[i].num_change_pages; j++)
4443 if (element_info[i].change_page[j].has_action)
4444 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4446 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4447 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4450 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4451 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4452 element_info[i].crumbled[ACTION_DEFAULT] !=
4453 element_info[i].graphic[ACTION_DEFAULT]);
4455 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4456 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4457 IS_EDITOR_CASCADE_INACTIVE(i)));
4460 /* dynamically adjust element properties according to game engine version */
4462 static int ep_em_slippery_wall[] =
4467 EL_EXPANDABLE_WALL_HORIZONTAL,
4468 EL_EXPANDABLE_WALL_VERTICAL,
4469 EL_EXPANDABLE_WALL_ANY,
4470 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4471 EL_EXPANDABLE_STEELWALL_VERTICAL,
4472 EL_EXPANDABLE_STEELWALL_ANY,
4473 EL_EXPANDABLE_STEELWALL_GROWING,
4477 static int ep_em_explodes_by_fire[] =
4480 EL_EM_DYNAMITE_ACTIVE,
4485 /* special EM style gems behaviour */
4486 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4487 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4488 level.em_slippery_gems);
4490 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4491 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4492 (level.em_slippery_gems &&
4493 engine_version > VERSION_IDENT(2,0,1,0)));
4495 /* special EM style explosion behaviour regarding chain reactions */
4496 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4497 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4498 level.em_explodes_by_fire);
4501 /* this is needed because some graphics depend on element properties */
4502 if (game_status == GAME_MODE_PLAYING)
4503 InitElementGraphicInfo();
4506 void InitElementPropertiesAfterLoading(int engine_version)
4510 /* set some other uninitialized values of custom elements in older levels */
4511 if (engine_version < VERSION_IDENT(3,1,0,0))
4513 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4515 int element = EL_CUSTOM_START + i;
4517 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4519 element_info[element].explosion_delay = 17;
4520 element_info[element].ignition_delay = 8;
4525 void InitElementPropertiesGfxElement()
4529 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4531 struct ElementInfo *ei = &element_info[i];
4533 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4537 static void InitGlobal()
4542 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4544 /* check if element_name_info entry defined for each element in "main.h" */
4545 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4546 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4548 element_info[i].token_name = element_name_info[i].token_name;
4549 element_info[i].class_name = element_name_info[i].class_name;
4550 element_info[i].editor_description= element_name_info[i].editor_description;
4553 /* create hash from image config list */
4554 image_config_hash = newSetupFileHash();
4555 for (i = 0; image_config[i].token != NULL; i++)
4556 setHashEntry(image_config_hash,
4557 image_config[i].token,
4558 image_config[i].value);
4560 /* create hash from element token list */
4561 element_token_hash = newSetupFileHash();
4562 for (i = 0; element_name_info[i].token_name != NULL; i++)
4563 setHashEntry(element_token_hash,
4564 element_name_info[i].token_name,
4567 /* create hash from graphic token list */
4568 graphic_token_hash = newSetupFileHash();
4569 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4570 if (strSuffix(image_config[i].value, ".png") ||
4571 strSuffix(image_config[i].value, ".pcx") ||
4572 strSuffix(image_config[i].value, ".wav") ||
4573 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4574 setHashEntry(graphic_token_hash,
4575 image_config[i].token,
4576 int2str(graphic++, 0));
4578 /* create hash from font token list */
4579 font_token_hash = newSetupFileHash();
4580 for (i = 0; font_info[i].token_name != NULL; i++)
4581 setHashEntry(font_token_hash,
4582 font_info[i].token_name,
4585 /* set default filenames for all cloned graphics in static configuration */
4586 for (i = 0; image_config[i].token != NULL; i++)
4588 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4590 char *token = image_config[i].token;
4591 char *token_clone_from = getStringCat2(token, ".clone_from");
4592 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4594 if (token_cloned != NULL)
4596 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4598 if (value_cloned != NULL)
4600 /* set default filename in static configuration */
4601 image_config[i].value = value_cloned;
4603 /* set default filename in image config hash */
4604 setHashEntry(image_config_hash, token, value_cloned);
4608 free(token_clone_from);
4612 /* always start with reliable default values (all elements) */
4613 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4614 ActiveElement[i] = i;
4616 /* now add all entries that have an active state (active elements) */
4617 for (i = 0; element_with_active_state[i].element != -1; i++)
4619 int element = element_with_active_state[i].element;
4620 int element_active = element_with_active_state[i].element_active;
4622 ActiveElement[element] = element_active;
4625 /* always start with reliable default values (all buttons) */
4626 for (i = 0; i < NUM_IMAGE_FILES; i++)
4627 ActiveButton[i] = i;
4629 /* now add all entries that have an active state (active buttons) */
4630 for (i = 0; button_with_active_state[i].button != -1; i++)
4632 int button = button_with_active_state[i].button;
4633 int button_active = button_with_active_state[i].button_active;
4635 ActiveButton[button] = button_active;
4638 /* always start with reliable default values (all fonts) */
4639 for (i = 0; i < NUM_FONTS; i++)
4642 /* now add all entries that have an active state (active fonts) */
4643 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4645 int font = font_with_active_state[i].font_nr;
4646 int font_active = font_with_active_state[i].font_nr_active;
4648 ActiveFont[font] = font_active;
4651 global.autoplay_leveldir = NULL;
4652 global.convert_leveldir = NULL;
4653 global.create_images_dir = NULL;
4655 global.frames_per_second = 0;
4657 global.border_status = GAME_MODE_MAIN;
4659 global.use_envelope_request = FALSE;
4662 void Execute_Command(char *command)
4666 if (strEqual(command, "print graphicsinfo.conf"))
4668 Print("# You can configure additional/alternative image files here.\n");
4669 Print("# (The entries below are default and therefore commented out.)\n");
4671 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4673 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4676 for (i = 0; image_config[i].token != NULL; i++)
4677 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4678 image_config[i].value));
4682 else if (strEqual(command, "print soundsinfo.conf"))
4684 Print("# You can configure additional/alternative sound files here.\n");
4685 Print("# (The entries below are default and therefore commented out.)\n");
4687 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4689 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4692 for (i = 0; sound_config[i].token != NULL; i++)
4693 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4694 sound_config[i].value));
4698 else if (strEqual(command, "print musicinfo.conf"))
4700 Print("# You can configure additional/alternative music files here.\n");
4701 Print("# (The entries below are default and therefore commented out.)\n");
4703 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4705 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4708 for (i = 0; music_config[i].token != NULL; i++)
4709 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4710 music_config[i].value));
4714 else if (strEqual(command, "print editorsetup.conf"))
4716 Print("# You can configure your personal editor element list here.\n");
4717 Print("# (The entries below are default and therefore commented out.)\n");
4720 /* this is needed to be able to check element list for cascade elements */
4721 InitElementPropertiesStatic();
4722 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4724 PrintEditorElementList();
4728 else if (strEqual(command, "print helpanim.conf"))
4730 Print("# You can configure different element help animations here.\n");
4731 Print("# (The entries below are default and therefore commented out.)\n");
4734 for (i = 0; helpanim_config[i].token != NULL; i++)
4736 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4737 helpanim_config[i].value));
4739 if (strEqual(helpanim_config[i].token, "end"))
4745 else if (strEqual(command, "print helptext.conf"))
4747 Print("# You can configure different element help text here.\n");
4748 Print("# (The entries below are default and therefore commented out.)\n");
4751 for (i = 0; helptext_config[i].token != NULL; i++)
4752 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4753 helptext_config[i].value));
4757 else if (strPrefix(command, "dump level "))
4759 char *filename = &command[11];
4761 if (!fileExists(filename))
4762 Error(ERR_EXIT, "cannot open file '%s'", filename);
4764 LoadLevelFromFilename(&level, filename);
4769 else if (strPrefix(command, "dump tape "))
4771 char *filename = &command[10];
4773 if (!fileExists(filename))
4774 Error(ERR_EXIT, "cannot open file '%s'", filename);
4776 LoadTapeFromFilename(filename);
4781 else if (strPrefix(command, "autotest ") ||
4782 strPrefix(command, "autoplay ") ||
4783 strPrefix(command, "autoffwd "))
4785 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4787 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4788 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4789 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4791 while (*str_ptr != '\0') /* continue parsing string */
4793 /* cut leading whitespace from string, replace it by string terminator */
4794 while (*str_ptr == ' ' || *str_ptr == '\t')
4797 if (*str_ptr == '\0') /* end of string reached */
4800 if (global.autoplay_leveldir == NULL) /* read level set string */
4802 global.autoplay_leveldir = str_ptr;
4803 global.autoplay_all = TRUE; /* default: play all tapes */
4805 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4806 global.autoplay_level[i] = FALSE;
4808 else /* read level number string */
4810 int level_nr = atoi(str_ptr); /* get level_nr value */
4812 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4813 global.autoplay_level[level_nr] = TRUE;
4815 global.autoplay_all = FALSE;
4818 /* advance string pointer to the next whitespace (or end of string) */
4819 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4823 else if (strPrefix(command, "convert "))
4825 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4826 char *str_ptr = strchr(str_copy, ' ');
4828 global.convert_leveldir = str_copy;
4829 global.convert_level_nr = -1;
4831 if (str_ptr != NULL) /* level number follows */
4833 *str_ptr++ = '\0'; /* terminate leveldir string */
4834 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4837 else if (strPrefix(command, "create images "))
4839 global.create_images_dir = getStringCopy(&command[14]);
4841 if (access(global.create_images_dir, W_OK) != 0)
4842 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4843 global.create_images_dir);
4845 else if (strPrefix(command, "create CE image "))
4847 CreateCustomElementImages(&command[16]);
4853 #if defined(TARGET_SDL2)
4854 else if (strEqual(command, "SDL_ListModes"))
4856 SDL_Init(SDL_INIT_VIDEO);
4858 int num_displays = SDL_GetNumVideoDisplays();
4860 // check if there are any displays available
4861 if (num_displays < 0)
4863 Print("No displays available: %s\n", SDL_GetError());
4868 for (i = 0; i < num_displays; i++)
4870 int num_modes = SDL_GetNumDisplayModes(i);
4873 Print("Available display modes for display %d:\n", i);
4875 // check if there are any display modes available for this display
4878 Print("No display modes available for display %d: %s\n",
4884 for (j = 0; j < num_modes; j++)
4886 SDL_DisplayMode mode;
4888 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4890 Print("Cannot get display mode %d for display %d: %s\n",
4891 j, i, SDL_GetError());
4896 Print("- %d x %d\n", mode.w, mode.h);
4902 #elif defined(TARGET_SDL)
4903 else if (strEqual(command, "SDL_ListModes"))
4908 SDL_Init(SDL_INIT_VIDEO);
4910 /* get available fullscreen/hardware modes */
4911 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4913 /* check if there are any modes available */
4916 Print("No modes available!\n");
4921 /* check if our resolution is restricted */
4922 if (modes == (SDL_Rect **)-1)
4924 Print("All resolutions available.\n");
4928 Print("Available display modes:\n");
4930 for (i = 0; modes[i]; i++)
4931 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4941 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4945 static void InitSetup()
4947 LoadSetup(); /* global setup info */
4949 /* set some options from setup file */
4951 if (setup.options.verbose)
4952 options.verbose = TRUE;
4955 static void InitGameInfo()
4957 game.restart_level = FALSE;
4960 static void InitPlayerInfo()
4964 /* choose default local player */
4965 local_player = &stored_player[0];
4967 for (i = 0; i < MAX_PLAYERS; i++)
4968 stored_player[i].connected = FALSE;
4970 local_player->connected = TRUE;
4973 static void InitArtworkInfo()
4978 static char *get_string_in_brackets(char *string)
4980 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4982 sprintf(string_in_brackets, "[%s]", string);
4984 return string_in_brackets;
4987 static char *get_level_id_suffix(int id_nr)
4989 char *id_suffix = checked_malloc(1 + 3 + 1);
4991 if (id_nr < 0 || id_nr > 999)
4994 sprintf(id_suffix, ".%03d", id_nr);
4999 static void InitArtworkConfig()
5001 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5003 NUM_GLOBAL_ANIM_TOKENS + 1];
5004 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5005 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5006 static char *action_id_suffix[NUM_ACTIONS + 1];
5007 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5008 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5009 static char *level_id_suffix[MAX_LEVELS + 1];
5010 static char *dummy[1] = { NULL };
5011 static char *ignore_generic_tokens[] =
5017 static char **ignore_image_tokens;
5018 static char **ignore_sound_tokens;
5019 static char **ignore_music_tokens;
5020 int num_ignore_generic_tokens;
5021 int num_ignore_image_tokens;
5022 int num_ignore_sound_tokens;
5023 int num_ignore_music_tokens;
5026 /* dynamically determine list of generic tokens to be ignored */
5027 num_ignore_generic_tokens = 0;
5028 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5029 num_ignore_generic_tokens++;
5031 /* dynamically determine list of image tokens to be ignored */
5032 num_ignore_image_tokens = num_ignore_generic_tokens;
5033 for (i = 0; image_config_vars[i].token != NULL; i++)
5034 num_ignore_image_tokens++;
5035 ignore_image_tokens =
5036 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5037 for (i = 0; i < num_ignore_generic_tokens; i++)
5038 ignore_image_tokens[i] = ignore_generic_tokens[i];
5039 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5040 ignore_image_tokens[num_ignore_generic_tokens + i] =
5041 image_config_vars[i].token;
5042 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5044 /* dynamically determine list of sound tokens to be ignored */
5045 num_ignore_sound_tokens = num_ignore_generic_tokens;
5046 ignore_sound_tokens =
5047 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5048 for (i = 0; i < num_ignore_generic_tokens; i++)
5049 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5050 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5052 /* dynamically determine list of music tokens to be ignored */
5053 num_ignore_music_tokens = num_ignore_generic_tokens;
5054 ignore_music_tokens =
5055 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5056 for (i = 0; i < num_ignore_generic_tokens; i++)
5057 ignore_music_tokens[i] = ignore_generic_tokens[i];
5058 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5060 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5061 image_id_prefix[i] = element_info[i].token_name;
5062 for (i = 0; i < NUM_FONTS; i++)
5063 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5064 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5065 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5066 global_anim_info[i].token_name;
5067 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5069 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5070 sound_id_prefix[i] = element_info[i].token_name;
5071 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5072 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5073 get_string_in_brackets(element_info[i].class_name);
5074 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5076 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5077 music_id_prefix[i] = music_prefix_info[i].prefix;
5078 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5080 for (i = 0; i < NUM_ACTIONS; i++)
5081 action_id_suffix[i] = element_action_info[i].suffix;
5082 action_id_suffix[NUM_ACTIONS] = NULL;
5084 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5085 direction_id_suffix[i] = element_direction_info[i].suffix;
5086 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5088 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5089 special_id_suffix[i] = special_suffix_info[i].suffix;
5090 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5092 for (i = 0; i < MAX_LEVELS; i++)
5093 level_id_suffix[i] = get_level_id_suffix(i);
5094 level_id_suffix[MAX_LEVELS] = NULL;
5096 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5097 image_id_prefix, action_id_suffix, direction_id_suffix,
5098 special_id_suffix, ignore_image_tokens);
5099 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5100 sound_id_prefix, action_id_suffix, dummy,
5101 special_id_suffix, ignore_sound_tokens);
5102 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5103 music_id_prefix, special_id_suffix, level_id_suffix,
5104 dummy, ignore_music_tokens);
5107 static void InitMixer()
5114 void InitGfxBuffers()
5116 static int win_xsize_last = -1;
5117 static int win_ysize_last = -1;
5119 /* create additional image buffers for double-buffering and cross-fading */
5121 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5123 /* may contain content for cross-fading -- only re-create if changed */
5124 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5125 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5127 win_xsize_last = WIN_XSIZE;
5128 win_ysize_last = WIN_YSIZE;
5131 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5132 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5133 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5134 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5135 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5137 /* initialize screen properties */
5138 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5139 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5141 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5142 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5143 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5144 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5145 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5146 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5148 /* required if door size definitions have changed */
5149 InitGraphicCompatibilityInfo_Doors();
5151 InitGfxBuffers_EM();
5152 InitGfxBuffers_SP();
5157 struct GraphicInfo *graphic_info_last = graphic_info;
5158 char *filename_font_initial = NULL;
5159 char *filename_anim_initial = NULL;
5160 Bitmap *bitmap_font_initial = NULL;
5164 /* determine settings for initial font (for displaying startup messages) */
5165 for (i = 0; image_config[i].token != NULL; i++)
5167 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5169 char font_token[128];
5172 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5173 len_font_token = strlen(font_token);
5175 if (strEqual(image_config[i].token, font_token))
5176 filename_font_initial = image_config[i].value;
5177 else if (strlen(image_config[i].token) > len_font_token &&
5178 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5180 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5181 font_initial[j].src_x = atoi(image_config[i].value);
5182 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5183 font_initial[j].src_y = atoi(image_config[i].value);
5184 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5185 font_initial[j].width = atoi(image_config[i].value);
5186 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5187 font_initial[j].height = atoi(image_config[i].value);
5192 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5194 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5195 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5198 if (filename_font_initial == NULL) /* should not happen */
5199 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5202 InitGfxCustomArtworkInfo();
5203 InitGfxOtherSettings();
5205 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5207 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5208 font_initial[j].bitmap = bitmap_font_initial;
5210 InitFontGraphicInfo();
5212 font_height = getFontHeight(FC_RED);
5214 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5215 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5216 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5219 DrawInitText("Loading graphics", 120, FC_GREEN);
5221 /* initialize settings for busy animation with default values */
5222 int parameter[NUM_GFX_ARGS];
5223 for (i = 0; i < NUM_GFX_ARGS; i++)
5224 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5225 image_config_suffix[i].token,
5226 image_config_suffix[i].type);
5228 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5229 int len_anim_token = strlen(anim_token);
5231 /* read settings for busy animation from default custom artwork config */
5232 char *gfx_config_filename = getPath3(options.graphics_directory,
5234 GRAPHICSINFO_FILENAME);
5236 if (fileExists(gfx_config_filename))
5238 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5240 if (setup_file_hash)
5242 char *filename = getHashEntry(setup_file_hash, anim_token);
5246 filename_anim_initial = getStringCopy(filename);
5248 for (j = 0; image_config_suffix[j].token != NULL; j++)
5250 int type = image_config_suffix[j].type;
5251 char *suffix = image_config_suffix[j].token;
5252 char *token = getStringCat2(anim_token, suffix);
5253 char *value = getHashEntry(setup_file_hash, token);
5255 checked_free(token);
5258 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5262 freeSetupFileHash(setup_file_hash);
5266 if (filename_anim_initial == NULL)
5268 /* read settings for busy animation from static default artwork config */
5269 for (i = 0; image_config[i].token != NULL; i++)
5271 if (strEqual(image_config[i].token, anim_token))
5272 filename_anim_initial = getStringCopy(image_config[i].value);
5273 else if (strlen(image_config[i].token) > len_anim_token &&
5274 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5276 for (j = 0; image_config_suffix[j].token != NULL; j++)
5278 if (strEqual(&image_config[i].token[len_anim_token],
5279 image_config_suffix[j].token))
5281 get_graphic_parameter_value(image_config[i].value,
5282 image_config_suffix[j].token,
5283 image_config_suffix[j].type);
5289 if (filename_anim_initial == NULL) /* should not happen */
5290 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5292 anim_initial.bitmaps =
5293 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5295 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5296 LoadCustomImage(filename_anim_initial);
5298 checked_free(filename_anim_initial);
5300 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5302 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5304 graphic_info = graphic_info_last;
5306 init.busy.width = anim_initial.width;
5307 init.busy.height = anim_initial.height;
5309 InitMenuDesignSettings_Static();
5311 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5312 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5314 /* use copy of busy animation to prevent change while reloading artwork */
5318 void InitGfxBackground()
5320 fieldbuffer = bitmap_db_field;
5321 SetDrawtoField(DRAW_BACKBUFFER);
5323 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5325 redraw_mask = REDRAW_ALL;
5328 static void InitLevelInfo()
5330 LoadLevelInfo(); /* global level info */
5331 LoadLevelSetup_LastSeries(); /* last played series info */
5332 LoadLevelSetup_SeriesInfo(); /* last played level info */
5334 if (global.autoplay_leveldir &&
5335 global.autoplay_mode != AUTOPLAY_TEST)
5337 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5338 global.autoplay_leveldir);
5339 if (leveldir_current == NULL)
5340 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5344 static void InitLevelArtworkInfo()
5346 LoadLevelArtworkInfo();
5349 static void InitImages()
5351 print_timestamp_init("InitImages");
5354 printf("::: leveldir_current->identifier == '%s'\n",
5355 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5356 printf("::: leveldir_current->graphics_path == '%s'\n",
5357 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5358 printf("::: leveldir_current->graphics_set == '%s'\n",
5359 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5360 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5361 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5364 setLevelArtworkDir(artwork.gfx_first);
5367 printf("::: leveldir_current->identifier == '%s'\n",
5368 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5369 printf("::: leveldir_current->graphics_path == '%s'\n",
5370 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5371 printf("::: leveldir_current->graphics_set == '%s'\n",
5372 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5373 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5374 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5378 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5379 leveldir_current->identifier,
5380 artwork.gfx_current_identifier,
5381 artwork.gfx_current->identifier,
5382 leveldir_current->graphics_set,
5383 leveldir_current->graphics_path);
5386 UPDATE_BUSY_STATE();
5388 ReloadCustomImages();
5389 print_timestamp_time("ReloadCustomImages");
5391 UPDATE_BUSY_STATE();
5393 LoadCustomElementDescriptions();
5394 print_timestamp_time("LoadCustomElementDescriptions");
5396 UPDATE_BUSY_STATE();
5398 LoadMenuDesignSettings();
5399 print_timestamp_time("LoadMenuDesignSettings");
5401 UPDATE_BUSY_STATE();
5403 ReinitializeGraphics();
5404 print_timestamp_time("ReinitializeGraphics");
5406 UPDATE_BUSY_STATE();
5408 print_timestamp_done("InitImages");
5411 static void InitSound(char *identifier)
5413 print_timestamp_init("InitSound");
5415 if (identifier == NULL)
5416 identifier = artwork.snd_current->identifier;
5418 /* set artwork path to send it to the sound server process */
5419 setLevelArtworkDir(artwork.snd_first);
5421 InitReloadCustomSounds(identifier);
5422 print_timestamp_time("InitReloadCustomSounds");
5424 ReinitializeSounds();
5425 print_timestamp_time("ReinitializeSounds");
5427 print_timestamp_done("InitSound");
5430 static void InitMusic(char *identifier)
5432 print_timestamp_init("InitMusic");
5434 if (identifier == NULL)
5435 identifier = artwork.mus_current->identifier;
5437 /* set artwork path to send it to the sound server process */
5438 setLevelArtworkDir(artwork.mus_first);
5440 InitReloadCustomMusic(identifier);
5441 print_timestamp_time("InitReloadCustomMusic");
5443 ReinitializeMusic();
5444 print_timestamp_time("ReinitializeMusic");
5446 print_timestamp_done("InitMusic");
5449 void InitNetworkServer()
5451 #if defined(NETWORK_AVALIABLE)
5455 if (!options.network)
5458 #if defined(NETWORK_AVALIABLE)
5459 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5461 if (!ConnectToServer(options.server_host, options.server_port))
5462 Error(ERR_EXIT, "cannot connect to network game server");
5464 SendToServer_PlayerName(setup.player_name);
5465 SendToServer_ProtocolVersion();
5468 SendToServer_NrWanted(nr_wanted);
5472 static boolean CheckArtworkConfigForCustomElements(char *filename)
5474 SetupFileHash *setup_file_hash;
5475 boolean redefined_ce_found = FALSE;
5477 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5479 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5481 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5483 char *token = HASH_ITERATION_TOKEN(itr);
5485 if (strPrefix(token, "custom_"))
5487 redefined_ce_found = TRUE;
5492 END_HASH_ITERATION(setup_file_hash, itr)
5494 freeSetupFileHash(setup_file_hash);
5497 return redefined_ce_found;
5500 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5502 char *filename_base, *filename_local;
5503 boolean redefined_ce_found = FALSE;
5505 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5508 printf("::: leveldir_current->identifier == '%s'\n",
5509 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5510 printf("::: leveldir_current->graphics_path == '%s'\n",
5511 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5512 printf("::: leveldir_current->graphics_set == '%s'\n",
5513 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5514 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5515 leveldir_current == NULL ? "[NULL]" :
5516 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5519 /* first look for special artwork configured in level series config */
5520 filename_base = getCustomArtworkLevelConfigFilename(type);
5523 printf("::: filename_base == '%s'\n", filename_base);
5526 if (fileExists(filename_base))
5527 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5529 filename_local = getCustomArtworkConfigFilename(type);
5532 printf("::: filename_local == '%s'\n", filename_local);
5535 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5536 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5539 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5542 return redefined_ce_found;
5545 static void InitOverrideArtwork()
5547 boolean redefined_ce_found = FALSE;
5549 /* to check if this level set redefines any CEs, do not use overriding */
5550 gfx.override_level_graphics = FALSE;
5551 gfx.override_level_sounds = FALSE;
5552 gfx.override_level_music = FALSE;
5554 /* now check if this level set has definitions for custom elements */
5555 if (setup.override_level_graphics == AUTO ||
5556 setup.override_level_sounds == AUTO ||
5557 setup.override_level_music == AUTO)
5558 redefined_ce_found =
5559 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5560 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5561 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5564 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5567 if (redefined_ce_found)
5569 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5570 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5571 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5572 gfx.override_level_music = (setup.override_level_music == TRUE);
5576 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5577 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5578 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5579 gfx.override_level_music = (setup.override_level_music != FALSE);
5583 printf("::: => %d, %d, %d\n",
5584 gfx.override_level_graphics,
5585 gfx.override_level_sounds,
5586 gfx.override_level_music);
5590 static char *getNewArtworkIdentifier(int type)
5592 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5593 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5594 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5595 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5596 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5597 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5598 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5599 char *leveldir_identifier = leveldir_current->identifier;
5600 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5601 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5602 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5603 char *artwork_current_identifier;
5604 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5606 /* leveldir_current may be invalid (level group, parent link) */
5607 if (!validLevelSeries(leveldir_current))
5610 /* 1st step: determine artwork set to be activated in descending order:
5611 --------------------------------------------------------------------
5612 1. setup artwork (when configured to override everything else)
5613 2. artwork set configured in "levelinfo.conf" of current level set
5614 (artwork in level directory will have priority when loading later)
5615 3. artwork in level directory (stored in artwork sub-directory)
5616 4. setup artwork (currently configured in setup menu) */
5618 if (setup_override_artwork)
5619 artwork_current_identifier = setup_artwork_set;
5620 else if (leveldir_artwork_set != NULL)
5621 artwork_current_identifier = leveldir_artwork_set;
5622 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5623 artwork_current_identifier = leveldir_identifier;
5625 artwork_current_identifier = setup_artwork_set;
5628 /* 2nd step: check if it is really needed to reload artwork set
5629 ------------------------------------------------------------ */
5631 /* ---------- reload if level set and also artwork set has changed ------- */
5632 if (leveldir_current_identifier[type] != leveldir_identifier &&
5633 (last_has_level_artwork_set[type] || has_level_artwork_set))
5634 artwork_new_identifier = artwork_current_identifier;
5636 leveldir_current_identifier[type] = leveldir_identifier;
5637 last_has_level_artwork_set[type] = has_level_artwork_set;
5639 /* ---------- reload if "override artwork" setting has changed ----------- */
5640 if (last_override_level_artwork[type] != setup_override_artwork)
5641 artwork_new_identifier = artwork_current_identifier;
5643 last_override_level_artwork[type] = setup_override_artwork;
5645 /* ---------- reload if current artwork identifier has changed ----------- */
5646 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5647 artwork_current_identifier))
5648 artwork_new_identifier = artwork_current_identifier;
5650 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5652 /* ---------- do not reload directly after starting ---------------------- */
5653 if (!initialized[type])
5654 artwork_new_identifier = NULL;
5656 initialized[type] = TRUE;
5658 return artwork_new_identifier;
5661 void ReloadCustomArtwork(int force_reload)
5663 int last_game_status = game_status; /* save current game status */
5664 char *gfx_new_identifier;
5665 char *snd_new_identifier;
5666 char *mus_new_identifier;
5667 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5668 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5669 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5670 boolean reload_needed;
5672 InitOverrideArtwork();
5674 force_reload_gfx |= AdjustGraphicsForEMC();
5676 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5677 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5678 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5680 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5681 snd_new_identifier != NULL || force_reload_snd ||
5682 mus_new_identifier != NULL || force_reload_mus);
5687 print_timestamp_init("ReloadCustomArtwork");
5689 game_status = GAME_MODE_LOADING;
5691 FadeOut(REDRAW_ALL);
5693 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5694 print_timestamp_time("ClearRectangle");
5698 if (gfx_new_identifier != NULL || force_reload_gfx)
5701 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5702 artwork.gfx_current_identifier,
5704 artwork.gfx_current->identifier,
5705 leveldir_current->graphics_set);
5709 print_timestamp_time("InitImages");
5712 if (snd_new_identifier != NULL || force_reload_snd)
5714 InitSound(snd_new_identifier);
5715 print_timestamp_time("InitSound");
5718 if (mus_new_identifier != NULL || force_reload_mus)
5720 InitMusic(mus_new_identifier);
5721 print_timestamp_time("InitMusic");
5724 game_status = last_game_status; /* restore current game status */
5726 init_last = init; /* switch to new busy animation */
5728 FadeOut(REDRAW_ALL);
5730 RedrawGlobalBorder();
5732 /* force redraw of (open or closed) door graphics */
5733 SetDoorState(DOOR_OPEN_ALL);
5734 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5736 FadeSetEnterScreen();
5737 FadeSkipNextFadeOut();
5739 print_timestamp_done("ReloadCustomArtwork");
5741 LimitScreenUpdates(FALSE);
5744 void KeyboardAutoRepeatOffUnlessAutoplay()
5746 if (global.autoplay_leveldir == NULL)
5747 KeyboardAutoRepeatOff();
5750 void DisplayExitMessage(char *format, va_list ap)
5752 // check if draw buffer and fonts for exit message are already available
5753 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5756 int font_1 = FC_RED;
5757 int font_2 = FC_YELLOW;
5758 int font_3 = FC_BLUE;
5759 int font_width = getFontWidth(font_2);
5760 int font_height = getFontHeight(font_2);
5763 int sxsize = WIN_XSIZE - 2 * sx;
5764 int sysize = WIN_YSIZE - 2 * sy;
5765 int line_length = sxsize / font_width;
5766 int max_lines = sysize / font_height;
5767 int num_lines_printed;
5771 gfx.sxsize = sxsize;
5772 gfx.sysize = sysize;
5776 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5778 DrawTextSCentered(sy, font_1, "Fatal error:");
5779 sy += 3 * font_height;;
5782 DrawTextBufferVA(sx, sy, format, ap, font_2,
5783 line_length, line_length, max_lines,
5784 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5785 sy += (num_lines_printed + 3) * font_height;
5787 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5788 sy += 3 * font_height;
5791 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5792 line_length, line_length, max_lines,
5793 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5795 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5797 redraw_mask = REDRAW_ALL;
5799 /* force drawing exit message even if screen updates are currently limited */
5800 LimitScreenUpdates(FALSE);
5804 /* deactivate toons on error message screen */
5805 setup.toons = FALSE;
5807 WaitForEventToContinue();
5811 /* ========================================================================= */
5813 /* ========================================================================= */
5817 print_timestamp_init("OpenAll");
5819 game_status = GAME_MODE_LOADING;
5823 InitGlobal(); /* initialize some global variables */
5825 print_timestamp_time("[init global stuff]");
5829 print_timestamp_time("[init setup/config stuff (1)]");
5831 if (options.execute_command)
5832 Execute_Command(options.execute_command);
5834 if (options.serveronly)
5836 #if defined(PLATFORM_UNIX)
5837 NetworkServer(options.server_port, options.serveronly);
5839 Error(ERR_WARN, "networking only supported in Unix version");
5842 exit(0); /* never reached, server loops forever */
5846 print_timestamp_time("[init setup/config stuff (2)]");
5848 print_timestamp_time("[init setup/config stuff (3)]");
5849 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5850 print_timestamp_time("[init setup/config stuff (4)]");
5851 InitArtworkConfig(); /* needed before forking sound child process */
5852 print_timestamp_time("[init setup/config stuff (5)]");
5854 print_timestamp_time("[init setup/config stuff (6)]");
5856 InitRND(NEW_RANDOMIZE);
5857 InitSimpleRandom(NEW_RANDOMIZE);
5861 print_timestamp_time("[init setup/config stuff]");
5864 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5866 InitEventFilter(FilterEvents);
5868 print_timestamp_time("[init video stuff]");
5870 InitElementPropertiesStatic();
5871 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5872 InitElementPropertiesGfxElement();
5874 print_timestamp_time("[init element properties stuff]");
5878 print_timestamp_time("InitGfx");
5881 print_timestamp_time("InitLevelInfo");
5883 InitLevelArtworkInfo();
5884 print_timestamp_time("InitLevelArtworkInfo");
5886 InitOverrideArtwork(); /* needs to know current level directory */
5887 print_timestamp_time("InitOverrideArtwork");
5889 InitImages(); /* needs to know current level directory */
5890 print_timestamp_time("InitImages");
5892 InitSound(NULL); /* needs to know current level directory */
5893 print_timestamp_time("InitSound");
5895 InitMusic(NULL); /* needs to know current level directory */
5896 print_timestamp_time("InitMusic");
5898 InitGfxBackground();
5903 if (global.autoplay_leveldir)
5908 else if (global.convert_leveldir)
5913 else if (global.create_images_dir)
5915 CreateLevelSketchImages();
5919 game_status = GAME_MODE_MAIN;
5921 FadeSetEnterScreen();
5922 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5923 FadeSkipNextFadeOut();
5925 print_timestamp_time("[post-artwork]");
5927 print_timestamp_done("OpenAll");
5931 InitNetworkServer();
5934 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5936 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5937 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5938 #if defined(PLATFORM_ANDROID)
5939 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5940 SDL_AndroidGetInternalStoragePath());
5941 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5942 SDL_AndroidGetExternalStoragePath());
5943 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5944 (SDL_AndroidGetExternalStorageState() ==
5945 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5946 SDL_AndroidGetExternalStorageState() ==
5947 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5952 void CloseAllAndExit(int exit_value)
5957 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5964 #if defined(TARGET_SDL)
5965 #if defined(TARGET_SDL2)
5967 // set a flag to tell the network server thread to quit and wait for it
5968 // using SDL_WaitThread()
5970 if (network_server) /* terminate network server */
5971 SDL_KillThread(server_thread);
5975 CloseVideoDisplay();
5976 ClosePlatformDependentStuff();
5978 if (exit_value != 0)
5980 /* fall back to default level set (current set may have caused an error) */
5981 SaveLevelSetup_LastSeries_Deactivate();
5983 /* tell user where to find error log file which may contain more details */
5984 // (error notification now directly displayed on screen inside R'n'D
5985 // NotifyUserAboutErrorFile(); /* currently only works for Windows */