1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" /* include auto-generated data structure definitions */
28 #include "conf_esg.c" /* include auto-generated data structure definitions */
29 #include "conf_e2s.c" /* include auto-generated data structure definitions */
30 #include "conf_fnt.c" /* include auto-generated data structure definitions */
31 #include "conf_g2s.c" /* include auto-generated data structure definitions */
32 #include "conf_g2m.c" /* include auto-generated data structure definitions */
33 #include "conf_act.c" /* include auto-generated data structure definitions */
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
89 struct GraphicInfo *graphic_info_last = graphic_info;
91 static unsigned int action_delay = 0;
92 unsigned int action_delay_value = GameFrameDelay;
93 int sync_frame = FrameCounter;
96 if (game_status != GAME_MODE_LOADING)
99 if (anim_initial.bitmap == NULL || window == NULL)
102 if (!DelayReached(&action_delay, action_delay_value))
105 if (init_last.busy.x == -1)
106 init_last.busy.x = WIN_XSIZE / 2;
107 if (init_last.busy.y == -1)
108 init_last.busy.y = WIN_YSIZE / 2;
110 x = ALIGNED_TEXT_XPOS(&init_last.busy);
111 y = ALIGNED_TEXT_YPOS(&init_last.busy);
113 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
115 if (sync_frame % anim_initial.anim_delay == 0)
119 int width = graphic_info[graphic].width;
120 int height = graphic_info[graphic].height;
121 int frame = getGraphicAnimationFrame(graphic, sync_frame);
123 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
124 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
127 graphic_info = graphic_info_last;
134 FreeLevelEditorGadgets();
143 static boolean gadgets_initialized = FALSE;
145 if (gadgets_initialized)
148 CreateLevelEditorGadgets();
152 CreateScreenGadgets();
154 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
156 gadgets_initialized = TRUE;
159 inline static void InitElementSmallImagesScaledUp(int graphic)
161 struct GraphicInfo *g = &graphic_info[graphic];
163 // create small and game tile sized bitmaps (and scale up, if needed)
164 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
167 void InitElementSmallImages()
169 print_timestamp_init("InitElementSmallImages");
171 static int special_graphics[] =
173 IMG_EDITOR_ELEMENT_BORDER,
174 IMG_EDITOR_ELEMENT_BORDER_INPUT,
175 IMG_EDITOR_CASCADE_LIST,
176 IMG_EDITOR_CASCADE_LIST_ACTIVE,
179 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
180 int num_property_mappings = getImageListPropertyMappingSize();
183 print_timestamp_time("getImageListPropertyMapping/Size");
185 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
186 /* initialize normal images from static configuration */
187 for (i = 0; element_to_graphic[i].element > -1; i++)
188 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
189 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
191 /* initialize special images from static configuration */
192 for (i = 0; element_to_special_graphic[i].element > -1; i++)
193 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
194 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
196 /* initialize images from dynamic configuration (may be elements or other) */
197 for (i = 0; i < num_property_mappings; i++)
198 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
199 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
201 /* initialize special images from above list (non-element images) */
202 for (i = 0; special_graphics[i] > -1; i++)
203 InitElementSmallImagesScaledUp(special_graphics[i]);
204 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
206 print_timestamp_done("InitElementSmallImages");
209 void InitScaledImages()
213 /* scale normal images from static configuration, if not already scaled */
214 for (i = 0; i < NUM_IMAGE_FILES; i++)
215 ScaleImage(i, graphic_info[i].scale_up_factor);
218 void InitBitmapPointers()
220 int num_images = getImageListSize();
223 // standard size bitmap may have changed -- update default bitmap pointer
224 for (i = 0; i < num_images; i++)
225 if (graphic_info[i].bitmaps)
226 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
229 void InitImageTextures()
233 FreeAllImageTextures();
235 for (i = 0; i < MAX_NUM_TOONS; i++)
236 CreateImageTextures(IMG_TOON_1 + i);
238 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
240 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
242 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
244 int graphic = global_anim_info[i].graphic[j][k];
246 if (graphic == IMG_UNDEFINED)
249 CreateImageTextures(graphic);
256 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
257 void SetBitmaps_EM(Bitmap **em_bitmap)
259 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
260 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
265 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
266 void SetBitmaps_SP(Bitmap **sp_bitmap)
268 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
272 static int getFontBitmapID(int font_nr)
276 /* (special case: do not use special font for GAME_MODE_LOADING) */
277 if (game_status >= GAME_MODE_TITLE_INITIAL &&
278 game_status <= GAME_MODE_PSEUDO_PREVIEW)
279 special = game_status;
280 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
281 special = GFX_SPECIAL_ARG_MAIN;
284 return font_info[font_nr].special_bitmap_id[special];
289 static int getFontFromToken(char *token)
291 char *value = getHashEntry(font_token_hash, token);
296 /* if font not found, use reliable default value */
297 return FONT_INITIAL_1;
300 void InitFontGraphicInfo()
302 static struct FontBitmapInfo *font_bitmap_info = NULL;
303 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
304 int num_property_mappings = getImageListPropertyMappingSize();
305 int num_font_bitmaps = NUM_FONTS;
308 if (graphic_info == NULL) /* still at startup phase */
310 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
311 getFontBitmapID, getFontFromToken);
316 /* ---------- initialize font graphic definitions ---------- */
318 /* always start with reliable default values (normal font graphics) */
319 for (i = 0; i < NUM_FONTS; i++)
320 font_info[i].graphic = IMG_FONT_INITIAL_1;
322 /* initialize normal font/graphic mapping from static configuration */
323 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
325 int font_nr = font_to_graphic[i].font_nr;
326 int special = font_to_graphic[i].special;
327 int graphic = font_to_graphic[i].graphic;
332 font_info[font_nr].graphic = graphic;
335 /* always start with reliable default values (special font graphics) */
336 for (i = 0; i < NUM_FONTS; i++)
338 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
340 font_info[i].special_graphic[j] = font_info[i].graphic;
341 font_info[i].special_bitmap_id[j] = i;
345 /* initialize special font/graphic mapping from static configuration */
346 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
348 int font_nr = font_to_graphic[i].font_nr;
349 int special = font_to_graphic[i].special;
350 int graphic = font_to_graphic[i].graphic;
351 int base_graphic = font2baseimg(font_nr);
353 if (IS_SPECIAL_GFX_ARG(special))
355 boolean base_redefined =
356 getImageListEntryFromImageID(base_graphic)->redefined;
357 boolean special_redefined =
358 getImageListEntryFromImageID(graphic)->redefined;
359 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
361 /* if the base font ("font.title_1", for example) has been redefined,
362 but not the special font ("font.title_1.LEVELS", for example), do not
363 use an existing (in this case considered obsolete) special font
364 anymore, but use the automatically determined default font */
365 /* special case: cloned special fonts must be explicitly redefined,
366 but are not automatically redefined by redefining base font */
367 if (base_redefined && !special_redefined && !special_cloned)
370 font_info[font_nr].special_graphic[special] = graphic;
371 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
376 /* initialize special font/graphic mapping from dynamic configuration */
377 for (i = 0; i < num_property_mappings; i++)
379 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
380 int special = property_mapping[i].ext3_index;
381 int graphic = property_mapping[i].artwork_index;
386 if (IS_SPECIAL_GFX_ARG(special))
388 font_info[font_nr].special_graphic[special] = graphic;
389 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
394 /* correct special font/graphic mapping for cloned fonts for downwards
395 compatibility of PREVIEW fonts -- this is only needed for implicit
396 redefinition of special font by redefined base font, and only if other
397 fonts are cloned from this special font (like in the "Zelda" level set) */
398 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
400 int font_nr = font_to_graphic[i].font_nr;
401 int special = font_to_graphic[i].special;
402 int graphic = font_to_graphic[i].graphic;
404 if (IS_SPECIAL_GFX_ARG(special))
406 boolean special_redefined =
407 getImageListEntryFromImageID(graphic)->redefined;
408 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
410 if (special_cloned && !special_redefined)
414 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
416 int font_nr2 = font_to_graphic[j].font_nr;
417 int special2 = font_to_graphic[j].special;
418 int graphic2 = font_to_graphic[j].graphic;
420 if (IS_SPECIAL_GFX_ARG(special2) &&
421 graphic2 == graphic_info[graphic].clone_from)
423 font_info[font_nr].special_graphic[special] =
424 font_info[font_nr2].special_graphic[special2];
425 font_info[font_nr].special_bitmap_id[special] =
426 font_info[font_nr2].special_bitmap_id[special2];
433 /* reset non-redefined ".active" font graphics if normal font is redefined */
434 /* (this different treatment is needed because normal and active fonts are
435 independently defined ("active" is not a property of font definitions!) */
436 for (i = 0; i < NUM_FONTS; i++)
438 int font_nr_base = i;
439 int font_nr_active = FONT_ACTIVE(font_nr_base);
441 /* check only those fonts with exist as normal and ".active" variant */
442 if (font_nr_base != font_nr_active)
444 int base_graphic = font_info[font_nr_base].graphic;
445 int active_graphic = font_info[font_nr_active].graphic;
446 boolean base_redefined =
447 getImageListEntryFromImageID(base_graphic)->redefined;
448 boolean active_redefined =
449 getImageListEntryFromImageID(active_graphic)->redefined;
451 /* if the base font ("font.menu_1", for example) has been redefined,
452 but not the active font ("font.menu_1.active", for example), do not
453 use an existing (in this case considered obsolete) active font
454 anymore, but use the automatically determined default font */
455 if (base_redefined && !active_redefined)
456 font_info[font_nr_active].graphic = base_graphic;
458 /* now also check each "special" font (which may be the same as above) */
459 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
461 int base_graphic = font_info[font_nr_base].special_graphic[j];
462 int active_graphic = font_info[font_nr_active].special_graphic[j];
463 boolean base_redefined =
464 getImageListEntryFromImageID(base_graphic)->redefined;
465 boolean active_redefined =
466 getImageListEntryFromImageID(active_graphic)->redefined;
468 /* same as above, but check special graphic definitions, for example:
469 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
470 if (base_redefined && !active_redefined)
472 font_info[font_nr_active].special_graphic[j] =
473 font_info[font_nr_base].special_graphic[j];
474 font_info[font_nr_active].special_bitmap_id[j] =
475 font_info[font_nr_base].special_bitmap_id[j];
481 /* ---------- initialize font bitmap array ---------- */
483 if (font_bitmap_info != NULL)
484 FreeFontInfo(font_bitmap_info);
487 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
489 /* ---------- initialize font bitmap definitions ---------- */
491 for (i = 0; i < NUM_FONTS; i++)
493 if (i < NUM_INITIAL_FONTS)
495 font_bitmap_info[i] = font_initial[i];
499 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
501 int font_bitmap_id = font_info[i].special_bitmap_id[j];
502 int graphic = font_info[i].special_graphic[j];
504 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
505 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
507 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
508 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
511 /* copy font relevant information from graphics information */
512 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
513 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
514 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
515 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
516 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
518 font_bitmap_info[font_bitmap_id].draw_xoffset =
519 graphic_info[graphic].draw_xoffset;
520 font_bitmap_info[font_bitmap_id].draw_yoffset =
521 graphic_info[graphic].draw_yoffset;
523 font_bitmap_info[font_bitmap_id].num_chars =
524 graphic_info[graphic].anim_frames;
525 font_bitmap_info[font_bitmap_id].num_chars_per_line =
526 graphic_info[graphic].anim_frames_per_line;
530 InitFontInfo(font_bitmap_info, num_font_bitmaps,
531 getFontBitmapID, getFontFromToken);
534 void InitGlobalAnimGraphicInfo()
536 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
537 int num_property_mappings = getImageListPropertyMappingSize();
540 if (graphic_info == NULL) /* still at startup phase */
543 /* always start with reliable default values (no global animations) */
544 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
545 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
546 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
547 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
549 /* initialize global animation definitions from static configuration */
550 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
552 int j = GLOBAL_ANIM_ID_PART_BASE;
553 int k = GFX_SPECIAL_ARG_DEFAULT;
555 global_anim_info[i].graphic[j][k] = IMG_GLOBAL_ANIM_1_GFX + i;
558 /* initialize global animation definitions from dynamic configuration */
559 for (i = 0; i < num_property_mappings; i++)
561 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
562 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
563 int special = property_mapping[i].ext3_index;
564 int graphic = property_mapping[i].artwork_index;
566 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
569 /* set animation part to base part, if not specified */
570 if (!IS_GLOBAL_ANIM_PART(part_nr))
571 part_nr = GLOBAL_ANIM_ID_PART_BASE;
573 /* set animation screen to default, if not specified */
574 if (!IS_SPECIAL_GFX_ARG(special))
575 special = GFX_SPECIAL_ARG_DEFAULT;
577 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
581 printf("::: InitGlobalAnimGraphicInfo\n");
583 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
584 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
585 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
586 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
587 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
588 printf("::: - anim %d, part %d, mode %d => %d\n",
589 i, j, k, global_anim_info[i].graphic[j][k]);
593 void InitElementGraphicInfo()
595 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
596 int num_property_mappings = getImageListPropertyMappingSize();
599 if (graphic_info == NULL) /* still at startup phase */
602 /* set values to -1 to identify later as "uninitialized" values */
603 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
605 for (act = 0; act < NUM_ACTIONS; act++)
607 element_info[i].graphic[act] = -1;
608 element_info[i].crumbled[act] = -1;
610 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
612 element_info[i].direction_graphic[act][dir] = -1;
613 element_info[i].direction_crumbled[act][dir] = -1;
620 /* initialize normal element/graphic mapping from static configuration */
621 for (i = 0; element_to_graphic[i].element > -1; i++)
623 int element = element_to_graphic[i].element;
624 int action = element_to_graphic[i].action;
625 int direction = element_to_graphic[i].direction;
626 boolean crumbled = element_to_graphic[i].crumbled;
627 int graphic = element_to_graphic[i].graphic;
628 int base_graphic = el2baseimg(element);
630 if (graphic_info[graphic].bitmap == NULL)
633 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
636 boolean base_redefined =
637 getImageListEntryFromImageID(base_graphic)->redefined;
638 boolean act_dir_redefined =
639 getImageListEntryFromImageID(graphic)->redefined;
641 /* if the base graphic ("emerald", for example) has been redefined,
642 but not the action graphic ("emerald.falling", for example), do not
643 use an existing (in this case considered obsolete) action graphic
644 anymore, but use the automatically determined default graphic */
645 if (base_redefined && !act_dir_redefined)
650 action = ACTION_DEFAULT;
655 element_info[element].direction_crumbled[action][direction] = graphic;
657 element_info[element].crumbled[action] = graphic;
662 element_info[element].direction_graphic[action][direction] = graphic;
664 element_info[element].graphic[action] = graphic;
668 /* initialize normal element/graphic mapping from dynamic configuration */
669 for (i = 0; i < num_property_mappings; i++)
671 int element = property_mapping[i].base_index;
672 int action = property_mapping[i].ext1_index;
673 int direction = property_mapping[i].ext2_index;
674 int special = property_mapping[i].ext3_index;
675 int graphic = property_mapping[i].artwork_index;
676 boolean crumbled = FALSE;
678 if (special == GFX_SPECIAL_ARG_CRUMBLED)
684 if (graphic_info[graphic].bitmap == NULL)
687 if (element >= MAX_NUM_ELEMENTS || special != -1)
691 action = ACTION_DEFAULT;
696 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
697 element_info[element].direction_crumbled[action][dir] = -1;
700 element_info[element].direction_crumbled[action][direction] = graphic;
702 element_info[element].crumbled[action] = graphic;
707 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
708 element_info[element].direction_graphic[action][dir] = -1;
711 element_info[element].direction_graphic[action][direction] = graphic;
713 element_info[element].graphic[action] = graphic;
717 /* now copy all graphics that are defined to be cloned from other graphics */
718 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
720 int graphic = element_info[i].graphic[ACTION_DEFAULT];
721 int crumbled_like, diggable_like;
726 crumbled_like = graphic_info[graphic].crumbled_like;
727 diggable_like = graphic_info[graphic].diggable_like;
729 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
731 for (act = 0; act < NUM_ACTIONS; act++)
732 element_info[i].crumbled[act] =
733 element_info[crumbled_like].crumbled[act];
734 for (act = 0; act < NUM_ACTIONS; act++)
735 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
736 element_info[i].direction_crumbled[act][dir] =
737 element_info[crumbled_like].direction_crumbled[act][dir];
740 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
742 element_info[i].graphic[ACTION_DIGGING] =
743 element_info[diggable_like].graphic[ACTION_DIGGING];
744 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
745 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
746 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
750 /* set hardcoded definitions for some runtime elements without graphic */
751 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
753 /* set hardcoded definitions for some internal elements without graphic */
754 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
756 if (IS_EDITOR_CASCADE_INACTIVE(i))
757 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
758 else if (IS_EDITOR_CASCADE_ACTIVE(i))
759 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
762 /* now set all undefined/invalid graphics to -1 to set to default after it */
763 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
765 for (act = 0; act < NUM_ACTIONS; act++)
769 graphic = element_info[i].graphic[act];
770 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
771 element_info[i].graphic[act] = -1;
773 graphic = element_info[i].crumbled[act];
774 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
775 element_info[i].crumbled[act] = -1;
777 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
779 graphic = element_info[i].direction_graphic[act][dir];
780 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
781 element_info[i].direction_graphic[act][dir] = -1;
783 graphic = element_info[i].direction_crumbled[act][dir];
784 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
785 element_info[i].direction_crumbled[act][dir] = -1;
792 /* adjust graphics with 2nd tile for movement according to direction
793 (do this before correcting '-1' values to minimize calculations) */
794 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
796 for (act = 0; act < NUM_ACTIONS; act++)
798 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
800 int graphic = element_info[i].direction_graphic[act][dir];
801 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
803 if (act == ACTION_FALLING) /* special case */
804 graphic = element_info[i].graphic[act];
807 graphic_info[graphic].double_movement &&
808 graphic_info[graphic].swap_double_tiles != 0)
810 struct GraphicInfo *g = &graphic_info[graphic];
811 int src_x_front = g->src_x;
812 int src_y_front = g->src_y;
813 int src_x_back = g->src_x + g->offset2_x;
814 int src_y_back = g->src_y + g->offset2_y;
815 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
817 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
818 src_y_front < src_y_back);
819 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
820 boolean swap_movement_tiles_autodetected =
821 (!frames_are_ordered_diagonally &&
822 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
823 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
824 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
825 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
828 /* swap frontside and backside graphic tile coordinates, if needed */
829 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
831 /* get current (wrong) backside tile coordinates */
832 getFixedGraphicSourceExt(graphic, 0, &dummy,
833 &src_x_back, &src_y_back, TRUE);
835 /* set frontside tile coordinates to backside tile coordinates */
836 g->src_x = src_x_back;
837 g->src_y = src_y_back;
839 /* invert tile offset to point to new backside tile coordinates */
843 /* do not swap front and backside tiles again after correction */
844 g->swap_double_tiles = 0;
853 /* now set all '-1' values to element specific default values */
854 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
856 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
857 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
858 int default_direction_graphic[NUM_DIRECTIONS_FULL];
859 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
861 if (default_graphic == -1)
862 default_graphic = IMG_UNKNOWN;
864 if (default_crumbled == -1)
865 default_crumbled = default_graphic;
867 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
869 default_direction_graphic[dir] =
870 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
871 default_direction_crumbled[dir] =
872 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
874 if (default_direction_graphic[dir] == -1)
875 default_direction_graphic[dir] = default_graphic;
877 if (default_direction_crumbled[dir] == -1)
878 default_direction_crumbled[dir] = default_direction_graphic[dir];
881 for (act = 0; act < NUM_ACTIONS; act++)
883 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
884 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
885 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
886 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
887 act == ACTION_TURNING_FROM_RIGHT ||
888 act == ACTION_TURNING_FROM_UP ||
889 act == ACTION_TURNING_FROM_DOWN);
891 /* generic default action graphic (defined by "[default]" directive) */
892 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
893 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
894 int default_remove_graphic = IMG_EMPTY;
896 if (act_remove && default_action_graphic != -1)
897 default_remove_graphic = default_action_graphic;
899 /* look for special default action graphic (classic game specific) */
900 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
901 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
902 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
903 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
904 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
905 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
907 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
908 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
909 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
910 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
911 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
912 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
914 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
915 /* !!! make this better !!! */
916 if (i == EL_EMPTY_SPACE)
918 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
919 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
922 if (default_action_graphic == -1)
923 default_action_graphic = default_graphic;
925 if (default_action_crumbled == -1)
926 default_action_crumbled = default_action_graphic;
928 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
930 /* use action graphic as the default direction graphic, if undefined */
931 int default_action_direction_graphic = element_info[i].graphic[act];
932 int default_action_direction_crumbled = element_info[i].crumbled[act];
934 /* no graphic for current action -- use default direction graphic */
935 if (default_action_direction_graphic == -1)
936 default_action_direction_graphic =
937 (act_remove ? default_remove_graphic :
939 element_info[i].direction_graphic[ACTION_TURNING][dir] :
940 default_action_graphic != default_graphic ?
941 default_action_graphic :
942 default_direction_graphic[dir]);
944 if (element_info[i].direction_graphic[act][dir] == -1)
945 element_info[i].direction_graphic[act][dir] =
946 default_action_direction_graphic;
948 if (default_action_direction_crumbled == -1)
949 default_action_direction_crumbled =
950 element_info[i].direction_graphic[act][dir];
952 if (element_info[i].direction_crumbled[act][dir] == -1)
953 element_info[i].direction_crumbled[act][dir] =
954 default_action_direction_crumbled;
957 /* no graphic for this specific action -- use default action graphic */
958 if (element_info[i].graphic[act] == -1)
959 element_info[i].graphic[act] =
960 (act_remove ? default_remove_graphic :
961 act_turning ? element_info[i].graphic[ACTION_TURNING] :
962 default_action_graphic);
964 if (element_info[i].crumbled[act] == -1)
965 element_info[i].crumbled[act] = element_info[i].graphic[act];
972 void InitElementSpecialGraphicInfo()
974 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
975 int num_property_mappings = getImageListPropertyMappingSize();
978 /* always start with reliable default values */
979 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
980 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
981 element_info[i].special_graphic[j] =
982 element_info[i].graphic[ACTION_DEFAULT];
984 /* initialize special element/graphic mapping from static configuration */
985 for (i = 0; element_to_special_graphic[i].element > -1; i++)
987 int element = element_to_special_graphic[i].element;
988 int special = element_to_special_graphic[i].special;
989 int graphic = element_to_special_graphic[i].graphic;
990 int base_graphic = el2baseimg(element);
991 boolean base_redefined =
992 getImageListEntryFromImageID(base_graphic)->redefined;
993 boolean special_redefined =
994 getImageListEntryFromImageID(graphic)->redefined;
996 /* if the base graphic ("emerald", for example) has been redefined,
997 but not the special graphic ("emerald.EDITOR", for example), do not
998 use an existing (in this case considered obsolete) special graphic
999 anymore, but use the automatically created (down-scaled) graphic */
1000 if (base_redefined && !special_redefined)
1003 element_info[element].special_graphic[special] = graphic;
1006 /* initialize special element/graphic mapping from dynamic configuration */
1007 for (i = 0; i < num_property_mappings; i++)
1009 int element = property_mapping[i].base_index;
1010 int action = property_mapping[i].ext1_index;
1011 int direction = property_mapping[i].ext2_index;
1012 int special = property_mapping[i].ext3_index;
1013 int graphic = property_mapping[i].artwork_index;
1015 /* for action ".active", replace element with active element, if exists */
1016 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1018 element = ELEMENT_ACTIVE(element);
1022 if (element >= MAX_NUM_ELEMENTS)
1025 /* do not change special graphic if action or direction was specified */
1026 if (action != -1 || direction != -1)
1029 if (IS_SPECIAL_GFX_ARG(special))
1030 element_info[element].special_graphic[special] = graphic;
1033 /* now set all undefined/invalid graphics to default */
1034 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1035 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1036 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1037 element_info[i].special_graphic[j] =
1038 element_info[i].graphic[ACTION_DEFAULT];
1041 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1043 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1044 return get_parameter_value(value_raw, suffix, type);
1046 if (strEqual(value_raw, ARG_UNDEFINED))
1047 return ARG_UNDEFINED_VALUE;
1049 if (type == TYPE_ELEMENT)
1051 char *value = getHashEntry(element_token_hash, value_raw);
1055 Error(ERR_INFO_LINE, "-");
1056 Error(ERR_INFO, "warning: error found in config file:");
1057 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1058 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1059 Error(ERR_INFO, "custom graphic rejected for this element/action");
1060 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1061 Error(ERR_INFO_LINE, "-");
1064 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1066 else if (type == TYPE_GRAPHIC)
1068 char *value = getHashEntry(graphic_token_hash, value_raw);
1069 int fallback_graphic = IMG_CHAR_EXCLAM;
1073 Error(ERR_INFO_LINE, "-");
1074 Error(ERR_INFO, "warning: error found in config file:");
1075 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1076 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1077 Error(ERR_INFO, "custom graphic rejected for this element/action");
1078 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1079 Error(ERR_INFO_LINE, "-");
1082 return (value != NULL ? atoi(value) : fallback_graphic);
1088 static int get_scaled_graphic_width(int graphic)
1090 int original_width = getOriginalImageWidthFromImageID(graphic);
1091 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1093 return original_width * scale_up_factor;
1096 static int get_scaled_graphic_height(int graphic)
1098 int original_height = getOriginalImageHeightFromImageID(graphic);
1099 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1101 return original_height * scale_up_factor;
1104 static void set_graphic_parameters_ext(int graphic, int *parameter,
1105 Bitmap **src_bitmaps)
1107 struct GraphicInfo *g = &graphic_info[graphic];
1108 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1109 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1110 int anim_frames_per_line = 1;
1112 /* always start with reliable default values */
1113 g->src_image_width = 0;
1114 g->src_image_height = 0;
1117 g->width = TILEX; /* default for element graphics */
1118 g->height = TILEY; /* default for element graphics */
1119 g->offset_x = 0; /* one or both of these values ... */
1120 g->offset_y = 0; /* ... will be corrected later */
1121 g->offset2_x = 0; /* one or both of these values ... */
1122 g->offset2_y = 0; /* ... will be corrected later */
1123 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1124 g->crumbled_like = -1; /* do not use clone element */
1125 g->diggable_like = -1; /* do not use clone element */
1126 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1127 g->scale_up_factor = 1; /* default: no scaling up */
1128 g->tile_size = TILESIZE; /* default: standard tile size */
1129 g->clone_from = -1; /* do not use clone graphic */
1130 g->init_delay_fixed = 0;
1131 g->init_delay_random = 0;
1132 g->anim_delay_fixed = 0;
1133 g->anim_delay_random = 0;
1134 g->post_delay_fixed = 0;
1135 g->post_delay_random = 0;
1136 g->fade_mode = FADE_MODE_DEFAULT;
1140 g->align = ALIGN_CENTER; /* default for title screens */
1141 g->valign = VALIGN_MIDDLE; /* default for title screens */
1142 g->sort_priority = 0; /* default for title screens */
1144 g->style = STYLE_DEFAULT;
1146 g->bitmaps = src_bitmaps;
1147 g->bitmap = src_bitmap;
1149 /* optional zoom factor for scaling up the image to a larger size */
1150 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1151 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1152 if (g->scale_up_factor < 1)
1153 g->scale_up_factor = 1; /* no scaling */
1155 /* optional tile size for using non-standard image size */
1156 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1158 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1161 // CHECK: should tile sizes less than standard tile size be allowed?
1162 if (g->tile_size < TILESIZE)
1163 g->tile_size = TILESIZE; /* standard tile size */
1166 // when setting tile size, also set width and height accordingly
1167 g->width = g->tile_size;
1168 g->height = g->tile_size;
1171 if (g->use_image_size)
1173 /* set new default bitmap size (with scaling, but without small images) */
1174 g->width = get_scaled_graphic_width(graphic);
1175 g->height = get_scaled_graphic_height(graphic);
1178 /* optional width and height of each animation frame */
1179 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1180 g->width = parameter[GFX_ARG_WIDTH];
1181 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1182 g->height = parameter[GFX_ARG_HEIGHT];
1184 /* optional x and y tile position of animation frame sequence */
1185 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1186 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1187 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1188 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1190 /* optional x and y pixel position of animation frame sequence */
1191 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1192 g->src_x = parameter[GFX_ARG_X];
1193 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1194 g->src_y = parameter[GFX_ARG_Y];
1200 Error(ERR_INFO_LINE, "-");
1201 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1202 g->width, getTokenFromImageID(graphic), TILEX);
1203 Error(ERR_INFO_LINE, "-");
1205 g->width = TILEX; /* will be checked to be inside bitmap later */
1210 Error(ERR_INFO_LINE, "-");
1211 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1212 g->height, getTokenFromImageID(graphic), TILEY);
1213 Error(ERR_INFO_LINE, "-");
1215 g->height = TILEY; /* will be checked to be inside bitmap later */
1221 /* get final bitmap size (with scaling, but without small images) */
1222 int src_image_width = get_scaled_graphic_width(graphic);
1223 int src_image_height = get_scaled_graphic_height(graphic);
1225 if (src_image_width == 0 || src_image_height == 0)
1227 /* only happens when loaded outside artwork system (like "global.busy") */
1228 src_image_width = src_bitmap->width;
1229 src_image_height = src_bitmap->height;
1232 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1234 anim_frames_per_row = src_image_width / g->tile_size;
1235 anim_frames_per_col = src_image_height / g->tile_size;
1239 anim_frames_per_row = src_image_width / g->width;
1240 anim_frames_per_col = src_image_height / g->height;
1243 g->src_image_width = src_image_width;
1244 g->src_image_height = src_image_height;
1247 /* correct x or y offset dependent of vertical or horizontal frame order */
1248 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1250 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1251 parameter[GFX_ARG_OFFSET] : g->height);
1252 anim_frames_per_line = anim_frames_per_col;
1254 else /* frames are ordered horizontally */
1256 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1257 parameter[GFX_ARG_OFFSET] : g->width);
1258 anim_frames_per_line = anim_frames_per_row;
1261 /* optionally, the x and y offset of frames can be specified directly */
1262 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1263 g->offset_x = parameter[GFX_ARG_XOFFSET];
1264 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1265 g->offset_y = parameter[GFX_ARG_YOFFSET];
1267 /* optionally, moving animations may have separate start and end graphics */
1268 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1270 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1271 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1273 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1274 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1275 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1276 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1277 else /* frames are ordered horizontally */
1278 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1279 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1281 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1282 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1283 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1284 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1285 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1287 /* optionally, the second movement tile can be specified as start tile */
1288 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1289 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1291 /* automatically determine correct number of frames, if not defined */
1292 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1293 g->anim_frames = parameter[GFX_ARG_FRAMES];
1294 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1295 g->anim_frames = anim_frames_per_row;
1296 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1297 g->anim_frames = anim_frames_per_col;
1301 if (g->anim_frames == 0) /* frames must be at least 1 */
1304 g->anim_frames_per_line =
1305 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1306 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1308 g->anim_delay = parameter[GFX_ARG_DELAY];
1309 if (g->anim_delay == 0) /* delay must be at least 1 */
1312 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1314 /* automatically determine correct start frame, if not defined */
1315 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1316 g->anim_start_frame = 0;
1317 else if (g->anim_mode & ANIM_REVERSE)
1318 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1320 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1322 /* animation synchronized with global frame counter, not move position */
1323 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1325 /* optional element for cloning crumble graphics */
1326 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1327 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1329 /* optional element for cloning digging graphics */
1330 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1331 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1333 /* optional border size for "crumbling" diggable graphics */
1334 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1335 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1337 /* used for global animations and player "boring" and "sleeping" actions */
1338 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1339 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1340 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1341 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1342 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1343 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1344 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1345 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1346 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1347 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1348 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1349 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1351 /* used for toon animations and global animations */
1352 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1353 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1354 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1355 g->step_frames = parameter[GFX_ARG_STEP_FRAMES];
1356 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1357 g->direction = parameter[GFX_ARG_DIRECTION];
1358 g->position = parameter[GFX_ARG_POSITION];
1359 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1360 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1362 /* this is only used for drawing font characters */
1363 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1364 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1366 /* this is only used for drawing envelope graphics */
1367 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1369 /* optional graphic for cloning all graphics settings */
1370 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1371 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1373 /* optional settings for drawing title screens and title messages */
1374 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1375 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1376 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1377 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1378 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1379 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1380 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1381 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1382 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1383 g->align = parameter[GFX_ARG_ALIGN];
1384 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1385 g->valign = parameter[GFX_ARG_VALIGN];
1386 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1387 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1389 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1390 g->class = parameter[GFX_ARG_CLASS];
1391 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1392 g->style = parameter[GFX_ARG_STYLE];
1394 /* this is only used for drawing menu buttons and text */
1395 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1396 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1397 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1398 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1401 static void set_graphic_parameters(int graphic)
1403 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1404 char **parameter_raw = image->parameter;
1405 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1406 int parameter[NUM_GFX_ARGS];
1409 /* if fallback to default artwork is done, also use the default parameters */
1410 if (image->fallback_to_default)
1411 parameter_raw = image->default_parameter;
1413 /* get integer values from string parameters */
1414 for (i = 0; i < NUM_GFX_ARGS; i++)
1415 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1416 image_config_suffix[i].token,
1417 image_config_suffix[i].type);
1419 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1421 UPDATE_BUSY_STATE();
1424 static void set_cloned_graphic_parameters(int graphic)
1426 int fallback_graphic = IMG_CHAR_EXCLAM;
1427 int max_num_images = getImageListSize();
1428 int clone_graphic = graphic_info[graphic].clone_from;
1429 int num_references_followed = 1;
1431 while (graphic_info[clone_graphic].clone_from != -1 &&
1432 num_references_followed < max_num_images)
1434 clone_graphic = graphic_info[clone_graphic].clone_from;
1436 num_references_followed++;
1439 if (num_references_followed >= max_num_images)
1441 Error(ERR_INFO_LINE, "-");
1442 Error(ERR_INFO, "warning: error found in config file:");
1443 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1444 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1445 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1446 Error(ERR_INFO, "custom graphic rejected for this element/action");
1448 if (graphic == fallback_graphic)
1449 Error(ERR_EXIT, "no fallback graphic available");
1451 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1452 Error(ERR_INFO_LINE, "-");
1454 graphic_info[graphic] = graphic_info[fallback_graphic];
1458 graphic_info[graphic] = graphic_info[clone_graphic];
1459 graphic_info[graphic].clone_from = clone_graphic;
1463 static void InitGraphicInfo()
1465 int fallback_graphic = IMG_CHAR_EXCLAM;
1466 int num_images = getImageListSize();
1469 /* use image size as default values for width and height for these images */
1470 static int full_size_graphics[] =
1473 IMG_GLOBAL_BORDER_MAIN,
1474 IMG_GLOBAL_BORDER_SCORES,
1475 IMG_GLOBAL_BORDER_EDITOR,
1476 IMG_GLOBAL_BORDER_PLAYING,
1479 IMG_BACKGROUND_ENVELOPE_1,
1480 IMG_BACKGROUND_ENVELOPE_2,
1481 IMG_BACKGROUND_ENVELOPE_3,
1482 IMG_BACKGROUND_ENVELOPE_4,
1483 IMG_BACKGROUND_REQUEST,
1486 IMG_BACKGROUND_TITLE_INITIAL,
1487 IMG_BACKGROUND_TITLE,
1488 IMG_BACKGROUND_MAIN,
1489 IMG_BACKGROUND_LEVELS,
1490 IMG_BACKGROUND_LEVELNR,
1491 IMG_BACKGROUND_SCORES,
1492 IMG_BACKGROUND_EDITOR,
1493 IMG_BACKGROUND_INFO,
1494 IMG_BACKGROUND_INFO_ELEMENTS,
1495 IMG_BACKGROUND_INFO_MUSIC,
1496 IMG_BACKGROUND_INFO_CREDITS,
1497 IMG_BACKGROUND_INFO_PROGRAM,
1498 IMG_BACKGROUND_INFO_VERSION,
1499 IMG_BACKGROUND_INFO_LEVELSET,
1500 IMG_BACKGROUND_SETUP,
1501 IMG_BACKGROUND_PLAYING,
1502 IMG_BACKGROUND_DOOR,
1503 IMG_BACKGROUND_TAPE,
1504 IMG_BACKGROUND_PANEL,
1505 IMG_BACKGROUND_PALETTE,
1506 IMG_BACKGROUND_TOOLBOX,
1508 IMG_TITLESCREEN_INITIAL_1,
1509 IMG_TITLESCREEN_INITIAL_2,
1510 IMG_TITLESCREEN_INITIAL_3,
1511 IMG_TITLESCREEN_INITIAL_4,
1512 IMG_TITLESCREEN_INITIAL_5,
1519 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1520 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1521 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1522 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1523 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1524 IMG_BACKGROUND_TITLEMESSAGE_1,
1525 IMG_BACKGROUND_TITLEMESSAGE_2,
1526 IMG_BACKGROUND_TITLEMESSAGE_3,
1527 IMG_BACKGROUND_TITLEMESSAGE_4,
1528 IMG_BACKGROUND_TITLEMESSAGE_5,
1533 checked_free(graphic_info);
1535 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1537 /* initialize "use_image_size" flag with default value */
1538 for (i = 0; i < num_images; i++)
1539 graphic_info[i].use_image_size = FALSE;
1541 /* initialize "use_image_size" flag from static configuration above */
1542 for (i = 0; full_size_graphics[i] != -1; i++)
1543 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1545 /* first set all graphic paramaters ... */
1546 for (i = 0; i < num_images; i++)
1547 set_graphic_parameters(i);
1549 /* ... then copy these parameters for cloned graphics */
1550 for (i = 0; i < num_images; i++)
1551 if (graphic_info[i].clone_from != -1)
1552 set_cloned_graphic_parameters(i);
1554 for (i = 0; i < num_images; i++)
1559 int first_frame, last_frame;
1560 int src_bitmap_width, src_bitmap_height;
1562 /* now check if no animation frames are outside of the loaded image */
1564 if (graphic_info[i].bitmap == NULL)
1565 continue; /* skip check for optional images that are undefined */
1567 /* get image size (this can differ from the standard element tile size!) */
1568 width = graphic_info[i].width;
1569 height = graphic_info[i].height;
1571 /* get final bitmap size (with scaling, but without small images) */
1572 src_bitmap_width = graphic_info[i].src_image_width;
1573 src_bitmap_height = graphic_info[i].src_image_height;
1575 /* check if first animation frame is inside specified bitmap */
1578 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1580 /* this avoids calculating wrong start position for out-of-bounds frame */
1581 src_x = graphic_info[i].src_x;
1582 src_y = graphic_info[i].src_y;
1584 if (src_x < 0 || src_y < 0 ||
1585 src_x + width > src_bitmap_width ||
1586 src_y + height > src_bitmap_height)
1588 Error(ERR_INFO_LINE, "-");
1589 Error(ERR_INFO, "warning: error found in config file:");
1590 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1591 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1592 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1594 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1595 src_x, src_y, src_bitmap_width, src_bitmap_height);
1596 Error(ERR_INFO, "custom graphic rejected for this element/action");
1598 if (i == fallback_graphic)
1599 Error(ERR_EXIT, "no fallback graphic available");
1601 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1602 Error(ERR_INFO_LINE, "-");
1604 graphic_info[i] = graphic_info[fallback_graphic];
1607 /* check if last animation frame is inside specified bitmap */
1609 last_frame = graphic_info[i].anim_frames - 1;
1610 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1612 if (src_x < 0 || src_y < 0 ||
1613 src_x + width > src_bitmap_width ||
1614 src_y + height > src_bitmap_height)
1616 Error(ERR_INFO_LINE, "-");
1617 Error(ERR_INFO, "warning: error found in config file:");
1618 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1619 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1620 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1622 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1623 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1624 Error(ERR_INFO, "::: %d, %d", width, height);
1625 Error(ERR_INFO, "custom graphic rejected for this element/action");
1627 if (i == fallback_graphic)
1628 Error(ERR_EXIT, "no fallback graphic available");
1630 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1631 Error(ERR_INFO_LINE, "-");
1633 graphic_info[i] = graphic_info[fallback_graphic];
1638 static void InitGraphicCompatibilityInfo()
1640 struct FileInfo *fi_global_door =
1641 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1642 int num_images = getImageListSize();
1645 /* the following compatibility handling is needed for the following case:
1646 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1647 graphics mainly used for door and panel graphics, like editor, tape and
1648 in-game buttons with hard-coded bitmap positions and button sizes; as
1649 these graphics now have individual definitions, redefining "global.door"
1650 to change all these graphics at once like before does not work anymore
1651 (because all those individual definitions still have their default values);
1652 to solve this, remap all those individual definitions that are not
1653 redefined to the new bitmap of "global.door" if it was redefined */
1655 /* special compatibility handling if image "global.door" was redefined */
1656 if (fi_global_door->redefined)
1658 for (i = 0; i < num_images; i++)
1660 struct FileInfo *fi = getImageListEntryFromImageID(i);
1662 /* process only those images that still use the default settings */
1665 /* process all images which default to same image as "global.door" */
1666 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1668 // printf("::: special treatment needed for token '%s'\n", fi->token);
1670 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1676 InitGraphicCompatibilityInfo_Doors();
1679 static void InitElementSoundInfo()
1681 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1682 int num_property_mappings = getSoundListPropertyMappingSize();
1685 /* set values to -1 to identify later as "uninitialized" values */
1686 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1687 for (act = 0; act < NUM_ACTIONS; act++)
1688 element_info[i].sound[act] = -1;
1690 /* initialize element/sound mapping from static configuration */
1691 for (i = 0; element_to_sound[i].element > -1; i++)
1693 int element = element_to_sound[i].element;
1694 int action = element_to_sound[i].action;
1695 int sound = element_to_sound[i].sound;
1696 boolean is_class = element_to_sound[i].is_class;
1699 action = ACTION_DEFAULT;
1702 element_info[element].sound[action] = sound;
1704 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1705 if (strEqual(element_info[j].class_name,
1706 element_info[element].class_name))
1707 element_info[j].sound[action] = sound;
1710 /* initialize element class/sound mapping from dynamic configuration */
1711 for (i = 0; i < num_property_mappings; i++)
1713 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1714 int action = property_mapping[i].ext1_index;
1715 int sound = property_mapping[i].artwork_index;
1717 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1721 action = ACTION_DEFAULT;
1723 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1724 if (strEqual(element_info[j].class_name,
1725 element_info[element_class].class_name))
1726 element_info[j].sound[action] = sound;
1729 /* initialize element/sound mapping from dynamic configuration */
1730 for (i = 0; i < num_property_mappings; i++)
1732 int element = property_mapping[i].base_index;
1733 int action = property_mapping[i].ext1_index;
1734 int sound = property_mapping[i].artwork_index;
1736 if (element >= MAX_NUM_ELEMENTS)
1740 action = ACTION_DEFAULT;
1742 element_info[element].sound[action] = sound;
1745 /* now set all '-1' values to element specific default values */
1746 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1748 for (act = 0; act < NUM_ACTIONS; act++)
1750 /* generic default action sound (defined by "[default]" directive) */
1751 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1753 /* look for special default action sound (classic game specific) */
1754 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1755 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1756 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1757 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1758 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1759 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1761 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1762 /* !!! make this better !!! */
1763 if (i == EL_EMPTY_SPACE)
1764 default_action_sound = element_info[EL_DEFAULT].sound[act];
1766 /* no sound for this specific action -- use default action sound */
1767 if (element_info[i].sound[act] == -1)
1768 element_info[i].sound[act] = default_action_sound;
1772 /* copy sound settings to some elements that are only stored in level file
1773 in native R'n'D levels, but are used by game engine in native EM levels */
1774 for (i = 0; copy_properties[i][0] != -1; i++)
1775 for (j = 1; j <= 4; j++)
1776 for (act = 0; act < NUM_ACTIONS; act++)
1777 element_info[copy_properties[i][j]].sound[act] =
1778 element_info[copy_properties[i][0]].sound[act];
1781 static void InitGameModeSoundInfo()
1785 /* set values to -1 to identify later as "uninitialized" values */
1786 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1789 /* initialize gamemode/sound mapping from static configuration */
1790 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1792 int gamemode = gamemode_to_sound[i].gamemode;
1793 int sound = gamemode_to_sound[i].sound;
1796 gamemode = GAME_MODE_DEFAULT;
1798 menu.sound[gamemode] = sound;
1801 /* now set all '-1' values to levelset specific default values */
1802 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1803 if (menu.sound[i] == -1)
1804 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1807 static void set_sound_parameters(int sound, char **parameter_raw)
1809 int parameter[NUM_SND_ARGS];
1812 /* get integer values from string parameters */
1813 for (i = 0; i < NUM_SND_ARGS; i++)
1815 get_parameter_value(parameter_raw[i],
1816 sound_config_suffix[i].token,
1817 sound_config_suffix[i].type);
1819 /* explicit loop mode setting in configuration overrides default value */
1820 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1821 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1823 /* sound volume to change the original volume when loading the sound file */
1824 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1826 /* sound priority to give certain sounds a higher or lower priority */
1827 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1830 static void InitSoundInfo()
1832 int *sound_effect_properties;
1833 int num_sounds = getSoundListSize();
1836 checked_free(sound_info);
1838 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1839 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1841 /* initialize sound effect for all elements to "no sound" */
1842 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1843 for (j = 0; j < NUM_ACTIONS; j++)
1844 element_info[i].sound[j] = SND_UNDEFINED;
1846 for (i = 0; i < num_sounds; i++)
1848 struct FileInfo *sound = getSoundListEntry(i);
1849 int len_effect_text = strlen(sound->token);
1851 sound_effect_properties[i] = ACTION_OTHER;
1852 sound_info[i].loop = FALSE; /* default: play sound only once */
1854 /* determine all loop sounds and identify certain sound classes */
1856 for (j = 0; element_action_info[j].suffix; j++)
1858 int len_action_text = strlen(element_action_info[j].suffix);
1860 if (len_action_text < len_effect_text &&
1861 strEqual(&sound->token[len_effect_text - len_action_text],
1862 element_action_info[j].suffix))
1864 sound_effect_properties[i] = element_action_info[j].value;
1865 sound_info[i].loop = element_action_info[j].is_loop_sound;
1871 /* associate elements and some selected sound actions */
1873 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1875 if (element_info[j].class_name)
1877 int len_class_text = strlen(element_info[j].class_name);
1879 if (len_class_text + 1 < len_effect_text &&
1880 strncmp(sound->token,
1881 element_info[j].class_name, len_class_text) == 0 &&
1882 sound->token[len_class_text] == '.')
1884 int sound_action_value = sound_effect_properties[i];
1886 element_info[j].sound[sound_action_value] = i;
1891 set_sound_parameters(i, sound->parameter);
1894 free(sound_effect_properties);
1897 static void InitGameModeMusicInfo()
1899 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1900 int num_property_mappings = getMusicListPropertyMappingSize();
1901 int default_levelset_music = -1;
1904 /* set values to -1 to identify later as "uninitialized" values */
1905 for (i = 0; i < MAX_LEVELS; i++)
1906 levelset.music[i] = -1;
1907 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1910 /* initialize gamemode/music mapping from static configuration */
1911 for (i = 0; gamemode_to_music[i].music > -1; i++)
1913 int gamemode = gamemode_to_music[i].gamemode;
1914 int music = gamemode_to_music[i].music;
1917 gamemode = GAME_MODE_DEFAULT;
1919 menu.music[gamemode] = music;
1922 /* initialize gamemode/music mapping from dynamic configuration */
1923 for (i = 0; i < num_property_mappings; i++)
1925 int prefix = property_mapping[i].base_index;
1926 int gamemode = property_mapping[i].ext1_index;
1927 int level = property_mapping[i].ext2_index;
1928 int music = property_mapping[i].artwork_index;
1930 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1934 gamemode = GAME_MODE_DEFAULT;
1936 /* level specific music only allowed for in-game music */
1937 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1938 gamemode = GAME_MODE_PLAYING;
1943 default_levelset_music = music;
1946 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1947 levelset.music[level] = music;
1948 if (gamemode != GAME_MODE_PLAYING)
1949 menu.music[gamemode] = music;
1952 /* now set all '-1' values to menu specific default values */
1953 /* (undefined values of "levelset.music[]" might stay at "-1" to
1954 allow dynamic selection of music files from music directory!) */
1955 for (i = 0; i < MAX_LEVELS; i++)
1956 if (levelset.music[i] == -1)
1957 levelset.music[i] = default_levelset_music;
1958 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1959 if (menu.music[i] == -1)
1960 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1963 static void set_music_parameters(int music, char **parameter_raw)
1965 int parameter[NUM_MUS_ARGS];
1968 /* get integer values from string parameters */
1969 for (i = 0; i < NUM_MUS_ARGS; i++)
1971 get_parameter_value(parameter_raw[i],
1972 music_config_suffix[i].token,
1973 music_config_suffix[i].type);
1975 /* explicit loop mode setting in configuration overrides default value */
1976 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1977 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1980 static void InitMusicInfo()
1982 int num_music = getMusicListSize();
1985 checked_free(music_info);
1987 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1989 for (i = 0; i < num_music; i++)
1991 struct FileInfo *music = getMusicListEntry(i);
1992 int len_music_text = strlen(music->token);
1994 music_info[i].loop = TRUE; /* default: play music in loop mode */
1996 /* determine all loop music */
1998 for (j = 0; music_prefix_info[j].prefix; j++)
2000 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2002 if (len_prefix_text < len_music_text &&
2003 strncmp(music->token,
2004 music_prefix_info[j].prefix, len_prefix_text) == 0)
2006 music_info[i].loop = music_prefix_info[j].is_loop_music;
2012 set_music_parameters(i, music->parameter);
2016 static void ReinitializeGraphics()
2018 print_timestamp_init("ReinitializeGraphics");
2020 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2022 InitGraphicInfo(); /* graphic properties mapping */
2023 print_timestamp_time("InitGraphicInfo");
2024 InitElementGraphicInfo(); /* element game graphic mapping */
2025 print_timestamp_time("InitElementGraphicInfo");
2026 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2027 print_timestamp_time("InitElementSpecialGraphicInfo");
2029 InitElementSmallImages(); /* scale elements to all needed sizes */
2030 print_timestamp_time("InitElementSmallImages");
2031 InitScaledImages(); /* scale all other images, if needed */
2032 print_timestamp_time("InitScaledImages");
2033 InitBitmapPointers(); /* set standard size bitmap pointers */
2034 print_timestamp_time("InitBitmapPointers");
2035 InitFontGraphicInfo(); /* initialize text drawing functions */
2036 print_timestamp_time("InitFontGraphicInfo");
2037 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2038 print_timestamp_time("InitGlobalAnimGraphicInfo");
2040 InitImageTextures(); /* create textures for certain images */
2041 print_timestamp_time("InitImageTextures");
2043 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2044 print_timestamp_time("InitGraphicInfo_EM");
2046 InitGraphicCompatibilityInfo();
2047 print_timestamp_time("InitGraphicCompatibilityInfo");
2049 SetMainBackgroundImage(IMG_BACKGROUND);
2050 print_timestamp_time("SetMainBackgroundImage");
2051 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2052 print_timestamp_time("SetDoorBackgroundImage");
2055 print_timestamp_time("InitGadgets");
2057 print_timestamp_time("InitToons");
2059 print_timestamp_time("InitDoors");
2061 print_timestamp_done("ReinitializeGraphics");
2064 static void ReinitializeSounds()
2066 InitSoundInfo(); /* sound properties mapping */
2067 InitElementSoundInfo(); /* element game sound mapping */
2068 InitGameModeSoundInfo(); /* game mode sound mapping */
2070 InitPlayLevelSound(); /* internal game sound settings */
2073 static void ReinitializeMusic()
2075 InitMusicInfo(); /* music properties mapping */
2076 InitGameModeMusicInfo(); /* game mode music mapping */
2079 static int get_special_property_bit(int element, int property_bit_nr)
2081 struct PropertyBitInfo
2087 static struct PropertyBitInfo pb_can_move_into_acid[] =
2089 /* the player may be able fall into acid when gravity is activated */
2094 { EL_SP_MURPHY, 0 },
2095 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2097 /* all elements that can move may be able to also move into acid */
2100 { EL_BUG_RIGHT, 1 },
2103 { EL_SPACESHIP, 2 },
2104 { EL_SPACESHIP_LEFT, 2 },
2105 { EL_SPACESHIP_RIGHT, 2 },
2106 { EL_SPACESHIP_UP, 2 },
2107 { EL_SPACESHIP_DOWN, 2 },
2108 { EL_BD_BUTTERFLY, 3 },
2109 { EL_BD_BUTTERFLY_LEFT, 3 },
2110 { EL_BD_BUTTERFLY_RIGHT, 3 },
2111 { EL_BD_BUTTERFLY_UP, 3 },
2112 { EL_BD_BUTTERFLY_DOWN, 3 },
2113 { EL_BD_FIREFLY, 4 },
2114 { EL_BD_FIREFLY_LEFT, 4 },
2115 { EL_BD_FIREFLY_RIGHT, 4 },
2116 { EL_BD_FIREFLY_UP, 4 },
2117 { EL_BD_FIREFLY_DOWN, 4 },
2119 { EL_YAMYAM_LEFT, 5 },
2120 { EL_YAMYAM_RIGHT, 5 },
2121 { EL_YAMYAM_UP, 5 },
2122 { EL_YAMYAM_DOWN, 5 },
2123 { EL_DARK_YAMYAM, 6 },
2126 { EL_PACMAN_LEFT, 8 },
2127 { EL_PACMAN_RIGHT, 8 },
2128 { EL_PACMAN_UP, 8 },
2129 { EL_PACMAN_DOWN, 8 },
2131 { EL_MOLE_LEFT, 9 },
2132 { EL_MOLE_RIGHT, 9 },
2134 { EL_MOLE_DOWN, 9 },
2138 { EL_SATELLITE, 13 },
2139 { EL_SP_SNIKSNAK, 14 },
2140 { EL_SP_ELECTRON, 15 },
2143 { EL_EMC_ANDROID, 18 },
2148 static struct PropertyBitInfo pb_dont_collide_with[] =
2150 { EL_SP_SNIKSNAK, 0 },
2151 { EL_SP_ELECTRON, 1 },
2159 struct PropertyBitInfo *pb_info;
2162 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2163 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2168 struct PropertyBitInfo *pb_info = NULL;
2171 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2172 if (pb_definition[i].bit_nr == property_bit_nr)
2173 pb_info = pb_definition[i].pb_info;
2175 if (pb_info == NULL)
2178 for (i = 0; pb_info[i].element != -1; i++)
2179 if (pb_info[i].element == element)
2180 return pb_info[i].bit_nr;
2185 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2186 boolean property_value)
2188 int bit_nr = get_special_property_bit(element, property_bit_nr);
2193 *bitfield |= (1 << bit_nr);
2195 *bitfield &= ~(1 << bit_nr);
2199 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2201 int bit_nr = get_special_property_bit(element, property_bit_nr);
2204 return ((*bitfield & (1 << bit_nr)) != 0);
2209 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2211 static int group_nr;
2212 static struct ElementGroupInfo *group;
2213 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2216 if (actual_group == NULL) /* not yet initialized */
2219 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2221 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2222 group_element - EL_GROUP_START + 1);
2224 /* replace element which caused too deep recursion by question mark */
2225 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2230 if (recursion_depth == 0) /* initialization */
2232 group = actual_group;
2233 group_nr = GROUP_NR(group_element);
2235 group->num_elements_resolved = 0;
2236 group->choice_pos = 0;
2238 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2239 element_info[i].in_group[group_nr] = FALSE;
2242 for (i = 0; i < actual_group->num_elements; i++)
2244 int element = actual_group->element[i];
2246 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2249 if (IS_GROUP_ELEMENT(element))
2250 ResolveGroupElementExt(element, recursion_depth + 1);
2253 group->element_resolved[group->num_elements_resolved++] = element;
2254 element_info[element].in_group[group_nr] = TRUE;
2259 void ResolveGroupElement(int group_element)
2261 ResolveGroupElementExt(group_element, 0);
2264 void InitElementPropertiesStatic()
2266 static boolean clipboard_elements_initialized = FALSE;
2268 static int ep_diggable[] =
2273 EL_SP_BUGGY_BASE_ACTIVATING,
2276 EL_INVISIBLE_SAND_ACTIVE,
2279 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2280 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2285 EL_SP_BUGGY_BASE_ACTIVE,
2292 static int ep_collectible_only[] =
2314 EL_DYNABOMB_INCREASE_NUMBER,
2315 EL_DYNABOMB_INCREASE_SIZE,
2316 EL_DYNABOMB_INCREASE_POWER,
2334 /* !!! handle separately !!! */
2335 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2341 static int ep_dont_run_into[] =
2343 /* same elements as in 'ep_dont_touch' */
2349 /* same elements as in 'ep_dont_collide_with' */
2361 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2366 EL_SP_BUGGY_BASE_ACTIVE,
2373 static int ep_dont_collide_with[] =
2375 /* same elements as in 'ep_dont_touch' */
2392 static int ep_dont_touch[] =
2402 static int ep_indestructible[] =
2406 EL_ACID_POOL_TOPLEFT,
2407 EL_ACID_POOL_TOPRIGHT,
2408 EL_ACID_POOL_BOTTOMLEFT,
2409 EL_ACID_POOL_BOTTOM,
2410 EL_ACID_POOL_BOTTOMRIGHT,
2411 EL_SP_HARDWARE_GRAY,
2412 EL_SP_HARDWARE_GREEN,
2413 EL_SP_HARDWARE_BLUE,
2415 EL_SP_HARDWARE_YELLOW,
2416 EL_SP_HARDWARE_BASE_1,
2417 EL_SP_HARDWARE_BASE_2,
2418 EL_SP_HARDWARE_BASE_3,
2419 EL_SP_HARDWARE_BASE_4,
2420 EL_SP_HARDWARE_BASE_5,
2421 EL_SP_HARDWARE_BASE_6,
2422 EL_INVISIBLE_STEELWALL,
2423 EL_INVISIBLE_STEELWALL_ACTIVE,
2424 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2425 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2426 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2427 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2428 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2429 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2430 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2431 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2432 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2433 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2434 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2435 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2437 EL_LIGHT_SWITCH_ACTIVE,
2438 EL_SIGN_EXCLAMATION,
2439 EL_SIGN_RADIOACTIVITY,
2446 EL_SIGN_ENTRY_FORBIDDEN,
2447 EL_SIGN_EMERGENCY_EXIT,
2455 EL_STEEL_EXIT_CLOSED,
2457 EL_STEEL_EXIT_OPENING,
2458 EL_STEEL_EXIT_CLOSING,
2459 EL_EM_STEEL_EXIT_CLOSED,
2460 EL_EM_STEEL_EXIT_OPEN,
2461 EL_EM_STEEL_EXIT_OPENING,
2462 EL_EM_STEEL_EXIT_CLOSING,
2463 EL_DC_STEELWALL_1_LEFT,
2464 EL_DC_STEELWALL_1_RIGHT,
2465 EL_DC_STEELWALL_1_TOP,
2466 EL_DC_STEELWALL_1_BOTTOM,
2467 EL_DC_STEELWALL_1_HORIZONTAL,
2468 EL_DC_STEELWALL_1_VERTICAL,
2469 EL_DC_STEELWALL_1_TOPLEFT,
2470 EL_DC_STEELWALL_1_TOPRIGHT,
2471 EL_DC_STEELWALL_1_BOTTOMLEFT,
2472 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2473 EL_DC_STEELWALL_1_TOPLEFT_2,
2474 EL_DC_STEELWALL_1_TOPRIGHT_2,
2475 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2476 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2477 EL_DC_STEELWALL_2_LEFT,
2478 EL_DC_STEELWALL_2_RIGHT,
2479 EL_DC_STEELWALL_2_TOP,
2480 EL_DC_STEELWALL_2_BOTTOM,
2481 EL_DC_STEELWALL_2_HORIZONTAL,
2482 EL_DC_STEELWALL_2_VERTICAL,
2483 EL_DC_STEELWALL_2_MIDDLE,
2484 EL_DC_STEELWALL_2_SINGLE,
2485 EL_STEELWALL_SLIPPERY,
2499 EL_GATE_1_GRAY_ACTIVE,
2500 EL_GATE_2_GRAY_ACTIVE,
2501 EL_GATE_3_GRAY_ACTIVE,
2502 EL_GATE_4_GRAY_ACTIVE,
2511 EL_EM_GATE_1_GRAY_ACTIVE,
2512 EL_EM_GATE_2_GRAY_ACTIVE,
2513 EL_EM_GATE_3_GRAY_ACTIVE,
2514 EL_EM_GATE_4_GRAY_ACTIVE,
2523 EL_EMC_GATE_5_GRAY_ACTIVE,
2524 EL_EMC_GATE_6_GRAY_ACTIVE,
2525 EL_EMC_GATE_7_GRAY_ACTIVE,
2526 EL_EMC_GATE_8_GRAY_ACTIVE,
2528 EL_DC_GATE_WHITE_GRAY,
2529 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2530 EL_DC_GATE_FAKE_GRAY,
2532 EL_SWITCHGATE_OPENING,
2533 EL_SWITCHGATE_CLOSED,
2534 EL_SWITCHGATE_CLOSING,
2535 EL_DC_SWITCHGATE_SWITCH_UP,
2536 EL_DC_SWITCHGATE_SWITCH_DOWN,
2538 EL_TIMEGATE_OPENING,
2540 EL_TIMEGATE_CLOSING,
2541 EL_DC_TIMEGATE_SWITCH,
2542 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2546 EL_TUBE_VERTICAL_LEFT,
2547 EL_TUBE_VERTICAL_RIGHT,
2548 EL_TUBE_HORIZONTAL_UP,
2549 EL_TUBE_HORIZONTAL_DOWN,
2554 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2555 EL_EXPANDABLE_STEELWALL_VERTICAL,
2556 EL_EXPANDABLE_STEELWALL_ANY,
2561 static int ep_slippery[] =
2575 EL_ROBOT_WHEEL_ACTIVE,
2581 EL_ACID_POOL_TOPLEFT,
2582 EL_ACID_POOL_TOPRIGHT,
2592 EL_STEELWALL_SLIPPERY,
2595 EL_EMC_WALL_SLIPPERY_1,
2596 EL_EMC_WALL_SLIPPERY_2,
2597 EL_EMC_WALL_SLIPPERY_3,
2598 EL_EMC_WALL_SLIPPERY_4,
2600 EL_EMC_MAGIC_BALL_ACTIVE,
2605 static int ep_can_change[] =
2610 static int ep_can_move[] =
2612 /* same elements as in 'pb_can_move_into_acid' */
2635 static int ep_can_fall[] =
2649 EL_QUICKSAND_FAST_FULL,
2651 EL_BD_MAGIC_WALL_FULL,
2652 EL_DC_MAGIC_WALL_FULL,
2666 static int ep_can_smash_player[] =
2692 static int ep_can_smash_enemies[] =
2701 static int ep_can_smash_everything[] =
2710 static int ep_explodes_by_fire[] =
2712 /* same elements as in 'ep_explodes_impact' */
2717 /* same elements as in 'ep_explodes_smashed' */
2727 EL_EM_DYNAMITE_ACTIVE,
2728 EL_DYNABOMB_PLAYER_1_ACTIVE,
2729 EL_DYNABOMB_PLAYER_2_ACTIVE,
2730 EL_DYNABOMB_PLAYER_3_ACTIVE,
2731 EL_DYNABOMB_PLAYER_4_ACTIVE,
2732 EL_DYNABOMB_INCREASE_NUMBER,
2733 EL_DYNABOMB_INCREASE_SIZE,
2734 EL_DYNABOMB_INCREASE_POWER,
2735 EL_SP_DISK_RED_ACTIVE,
2749 static int ep_explodes_smashed[] =
2751 /* same elements as in 'ep_explodes_impact' */
2765 static int ep_explodes_impact[] =
2774 static int ep_walkable_over[] =
2778 EL_SOKOBAN_FIELD_EMPTY,
2785 EL_EM_STEEL_EXIT_OPEN,
2786 EL_EM_STEEL_EXIT_OPENING,
2795 EL_GATE_1_GRAY_ACTIVE,
2796 EL_GATE_2_GRAY_ACTIVE,
2797 EL_GATE_3_GRAY_ACTIVE,
2798 EL_GATE_4_GRAY_ACTIVE,
2806 static int ep_walkable_inside[] =
2811 EL_TUBE_VERTICAL_LEFT,
2812 EL_TUBE_VERTICAL_RIGHT,
2813 EL_TUBE_HORIZONTAL_UP,
2814 EL_TUBE_HORIZONTAL_DOWN,
2823 static int ep_walkable_under[] =
2828 static int ep_passable_over[] =
2838 EL_EM_GATE_1_GRAY_ACTIVE,
2839 EL_EM_GATE_2_GRAY_ACTIVE,
2840 EL_EM_GATE_3_GRAY_ACTIVE,
2841 EL_EM_GATE_4_GRAY_ACTIVE,
2850 EL_EMC_GATE_5_GRAY_ACTIVE,
2851 EL_EMC_GATE_6_GRAY_ACTIVE,
2852 EL_EMC_GATE_7_GRAY_ACTIVE,
2853 EL_EMC_GATE_8_GRAY_ACTIVE,
2855 EL_DC_GATE_WHITE_GRAY,
2856 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2863 static int ep_passable_inside[] =
2869 EL_SP_PORT_HORIZONTAL,
2870 EL_SP_PORT_VERTICAL,
2872 EL_SP_GRAVITY_PORT_LEFT,
2873 EL_SP_GRAVITY_PORT_RIGHT,
2874 EL_SP_GRAVITY_PORT_UP,
2875 EL_SP_GRAVITY_PORT_DOWN,
2876 EL_SP_GRAVITY_ON_PORT_LEFT,
2877 EL_SP_GRAVITY_ON_PORT_RIGHT,
2878 EL_SP_GRAVITY_ON_PORT_UP,
2879 EL_SP_GRAVITY_ON_PORT_DOWN,
2880 EL_SP_GRAVITY_OFF_PORT_LEFT,
2881 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2882 EL_SP_GRAVITY_OFF_PORT_UP,
2883 EL_SP_GRAVITY_OFF_PORT_DOWN,
2888 static int ep_passable_under[] =
2893 static int ep_droppable[] =
2898 static int ep_explodes_1x1_old[] =
2903 static int ep_pushable[] =
2915 EL_SOKOBAN_FIELD_FULL,
2924 static int ep_explodes_cross_old[] =
2929 static int ep_protected[] =
2931 /* same elements as in 'ep_walkable_inside' */
2935 EL_TUBE_VERTICAL_LEFT,
2936 EL_TUBE_VERTICAL_RIGHT,
2937 EL_TUBE_HORIZONTAL_UP,
2938 EL_TUBE_HORIZONTAL_DOWN,
2944 /* same elements as in 'ep_passable_over' */
2953 EL_EM_GATE_1_GRAY_ACTIVE,
2954 EL_EM_GATE_2_GRAY_ACTIVE,
2955 EL_EM_GATE_3_GRAY_ACTIVE,
2956 EL_EM_GATE_4_GRAY_ACTIVE,
2965 EL_EMC_GATE_5_GRAY_ACTIVE,
2966 EL_EMC_GATE_6_GRAY_ACTIVE,
2967 EL_EMC_GATE_7_GRAY_ACTIVE,
2968 EL_EMC_GATE_8_GRAY_ACTIVE,
2970 EL_DC_GATE_WHITE_GRAY,
2971 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2975 /* same elements as in 'ep_passable_inside' */
2980 EL_SP_PORT_HORIZONTAL,
2981 EL_SP_PORT_VERTICAL,
2983 EL_SP_GRAVITY_PORT_LEFT,
2984 EL_SP_GRAVITY_PORT_RIGHT,
2985 EL_SP_GRAVITY_PORT_UP,
2986 EL_SP_GRAVITY_PORT_DOWN,
2987 EL_SP_GRAVITY_ON_PORT_LEFT,
2988 EL_SP_GRAVITY_ON_PORT_RIGHT,
2989 EL_SP_GRAVITY_ON_PORT_UP,
2990 EL_SP_GRAVITY_ON_PORT_DOWN,
2991 EL_SP_GRAVITY_OFF_PORT_LEFT,
2992 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2993 EL_SP_GRAVITY_OFF_PORT_UP,
2994 EL_SP_GRAVITY_OFF_PORT_DOWN,
2999 static int ep_throwable[] =
3004 static int ep_can_explode[] =
3006 /* same elements as in 'ep_explodes_impact' */
3011 /* same elements as in 'ep_explodes_smashed' */
3017 /* elements that can explode by explosion or by dragonfire */
3021 EL_EM_DYNAMITE_ACTIVE,
3022 EL_DYNABOMB_PLAYER_1_ACTIVE,
3023 EL_DYNABOMB_PLAYER_2_ACTIVE,
3024 EL_DYNABOMB_PLAYER_3_ACTIVE,
3025 EL_DYNABOMB_PLAYER_4_ACTIVE,
3026 EL_DYNABOMB_INCREASE_NUMBER,
3027 EL_DYNABOMB_INCREASE_SIZE,
3028 EL_DYNABOMB_INCREASE_POWER,
3029 EL_SP_DISK_RED_ACTIVE,
3037 /* elements that can explode only by explosion */
3043 static int ep_gravity_reachable[] =
3049 EL_INVISIBLE_SAND_ACTIVE,
3054 EL_SP_PORT_HORIZONTAL,
3055 EL_SP_PORT_VERTICAL,
3057 EL_SP_GRAVITY_PORT_LEFT,
3058 EL_SP_GRAVITY_PORT_RIGHT,
3059 EL_SP_GRAVITY_PORT_UP,
3060 EL_SP_GRAVITY_PORT_DOWN,
3061 EL_SP_GRAVITY_ON_PORT_LEFT,
3062 EL_SP_GRAVITY_ON_PORT_RIGHT,
3063 EL_SP_GRAVITY_ON_PORT_UP,
3064 EL_SP_GRAVITY_ON_PORT_DOWN,
3065 EL_SP_GRAVITY_OFF_PORT_LEFT,
3066 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3067 EL_SP_GRAVITY_OFF_PORT_UP,
3068 EL_SP_GRAVITY_OFF_PORT_DOWN,
3074 static int ep_player[] =
3081 EL_SOKOBAN_FIELD_PLAYER,
3087 static int ep_can_pass_magic_wall[] =
3101 static int ep_can_pass_dc_magic_wall[] =
3117 static int ep_switchable[] =
3121 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3122 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3123 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3124 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3125 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3126 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3127 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3128 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3129 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3130 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3131 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3132 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3133 EL_SWITCHGATE_SWITCH_UP,
3134 EL_SWITCHGATE_SWITCH_DOWN,
3135 EL_DC_SWITCHGATE_SWITCH_UP,
3136 EL_DC_SWITCHGATE_SWITCH_DOWN,
3138 EL_LIGHT_SWITCH_ACTIVE,
3140 EL_DC_TIMEGATE_SWITCH,
3141 EL_BALLOON_SWITCH_LEFT,
3142 EL_BALLOON_SWITCH_RIGHT,
3143 EL_BALLOON_SWITCH_UP,
3144 EL_BALLOON_SWITCH_DOWN,
3145 EL_BALLOON_SWITCH_ANY,
3146 EL_BALLOON_SWITCH_NONE,
3149 EL_EMC_MAGIC_BALL_SWITCH,
3150 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3155 static int ep_bd_element[] =
3189 static int ep_sp_element[] =
3191 /* should always be valid */
3194 /* standard classic Supaplex elements */
3201 EL_SP_HARDWARE_GRAY,
3209 EL_SP_GRAVITY_PORT_RIGHT,
3210 EL_SP_GRAVITY_PORT_DOWN,
3211 EL_SP_GRAVITY_PORT_LEFT,
3212 EL_SP_GRAVITY_PORT_UP,
3217 EL_SP_PORT_VERTICAL,
3218 EL_SP_PORT_HORIZONTAL,
3224 EL_SP_HARDWARE_BASE_1,
3225 EL_SP_HARDWARE_GREEN,
3226 EL_SP_HARDWARE_BLUE,
3228 EL_SP_HARDWARE_YELLOW,
3229 EL_SP_HARDWARE_BASE_2,
3230 EL_SP_HARDWARE_BASE_3,
3231 EL_SP_HARDWARE_BASE_4,
3232 EL_SP_HARDWARE_BASE_5,
3233 EL_SP_HARDWARE_BASE_6,
3237 /* additional elements that appeared in newer Supaplex levels */
3240 /* additional gravity port elements (not switching, but setting gravity) */
3241 EL_SP_GRAVITY_ON_PORT_LEFT,
3242 EL_SP_GRAVITY_ON_PORT_RIGHT,
3243 EL_SP_GRAVITY_ON_PORT_UP,
3244 EL_SP_GRAVITY_ON_PORT_DOWN,
3245 EL_SP_GRAVITY_OFF_PORT_LEFT,
3246 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3247 EL_SP_GRAVITY_OFF_PORT_UP,
3248 EL_SP_GRAVITY_OFF_PORT_DOWN,
3250 /* more than one Murphy in a level results in an inactive clone */
3253 /* runtime Supaplex elements */
3254 EL_SP_DISK_RED_ACTIVE,
3255 EL_SP_TERMINAL_ACTIVE,
3256 EL_SP_BUGGY_BASE_ACTIVATING,
3257 EL_SP_BUGGY_BASE_ACTIVE,
3264 static int ep_sb_element[] =
3269 EL_SOKOBAN_FIELD_EMPTY,
3270 EL_SOKOBAN_FIELD_FULL,
3271 EL_SOKOBAN_FIELD_PLAYER,
3276 EL_INVISIBLE_STEELWALL,
3281 static int ep_gem[] =
3293 static int ep_food_dark_yamyam[] =
3321 static int ep_food_penguin[] =
3335 static int ep_food_pig[] =
3347 static int ep_historic_wall[] =
3358 EL_GATE_1_GRAY_ACTIVE,
3359 EL_GATE_2_GRAY_ACTIVE,
3360 EL_GATE_3_GRAY_ACTIVE,
3361 EL_GATE_4_GRAY_ACTIVE,
3370 EL_EM_GATE_1_GRAY_ACTIVE,
3371 EL_EM_GATE_2_GRAY_ACTIVE,
3372 EL_EM_GATE_3_GRAY_ACTIVE,
3373 EL_EM_GATE_4_GRAY_ACTIVE,
3380 EL_EXPANDABLE_WALL_HORIZONTAL,
3381 EL_EXPANDABLE_WALL_VERTICAL,
3382 EL_EXPANDABLE_WALL_ANY,
3383 EL_EXPANDABLE_WALL_GROWING,
3384 EL_BD_EXPANDABLE_WALL,
3391 EL_SP_HARDWARE_GRAY,
3392 EL_SP_HARDWARE_GREEN,
3393 EL_SP_HARDWARE_BLUE,
3395 EL_SP_HARDWARE_YELLOW,
3396 EL_SP_HARDWARE_BASE_1,
3397 EL_SP_HARDWARE_BASE_2,
3398 EL_SP_HARDWARE_BASE_3,
3399 EL_SP_HARDWARE_BASE_4,
3400 EL_SP_HARDWARE_BASE_5,
3401 EL_SP_HARDWARE_BASE_6,
3403 EL_SP_TERMINAL_ACTIVE,
3406 EL_INVISIBLE_STEELWALL,
3407 EL_INVISIBLE_STEELWALL_ACTIVE,
3409 EL_INVISIBLE_WALL_ACTIVE,
3410 EL_STEELWALL_SLIPPERY,
3427 static int ep_historic_solid[] =
3431 EL_EXPANDABLE_WALL_HORIZONTAL,
3432 EL_EXPANDABLE_WALL_VERTICAL,
3433 EL_EXPANDABLE_WALL_ANY,
3434 EL_BD_EXPANDABLE_WALL,
3447 EL_QUICKSAND_FILLING,
3448 EL_QUICKSAND_EMPTYING,
3450 EL_MAGIC_WALL_ACTIVE,
3451 EL_MAGIC_WALL_EMPTYING,
3452 EL_MAGIC_WALL_FILLING,
3456 EL_BD_MAGIC_WALL_ACTIVE,
3457 EL_BD_MAGIC_WALL_EMPTYING,
3458 EL_BD_MAGIC_WALL_FULL,
3459 EL_BD_MAGIC_WALL_FILLING,
3460 EL_BD_MAGIC_WALL_DEAD,
3469 EL_SP_TERMINAL_ACTIVE,
3473 EL_INVISIBLE_WALL_ACTIVE,
3474 EL_SWITCHGATE_SWITCH_UP,
3475 EL_SWITCHGATE_SWITCH_DOWN,
3476 EL_DC_SWITCHGATE_SWITCH_UP,
3477 EL_DC_SWITCHGATE_SWITCH_DOWN,
3479 EL_TIMEGATE_SWITCH_ACTIVE,
3480 EL_DC_TIMEGATE_SWITCH,
3481 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3493 /* the following elements are a direct copy of "indestructible" elements,
3494 except "EL_ACID", which is "indestructible", but not "solid"! */
3499 EL_ACID_POOL_TOPLEFT,
3500 EL_ACID_POOL_TOPRIGHT,
3501 EL_ACID_POOL_BOTTOMLEFT,
3502 EL_ACID_POOL_BOTTOM,
3503 EL_ACID_POOL_BOTTOMRIGHT,
3504 EL_SP_HARDWARE_GRAY,
3505 EL_SP_HARDWARE_GREEN,
3506 EL_SP_HARDWARE_BLUE,
3508 EL_SP_HARDWARE_YELLOW,
3509 EL_SP_HARDWARE_BASE_1,
3510 EL_SP_HARDWARE_BASE_2,
3511 EL_SP_HARDWARE_BASE_3,
3512 EL_SP_HARDWARE_BASE_4,
3513 EL_SP_HARDWARE_BASE_5,
3514 EL_SP_HARDWARE_BASE_6,
3515 EL_INVISIBLE_STEELWALL,
3516 EL_INVISIBLE_STEELWALL_ACTIVE,
3517 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3518 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3519 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3520 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3521 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3522 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3523 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3524 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3525 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3526 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3527 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3528 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3530 EL_LIGHT_SWITCH_ACTIVE,
3531 EL_SIGN_EXCLAMATION,
3532 EL_SIGN_RADIOACTIVITY,
3539 EL_SIGN_ENTRY_FORBIDDEN,
3540 EL_SIGN_EMERGENCY_EXIT,
3548 EL_STEEL_EXIT_CLOSED,
3550 EL_DC_STEELWALL_1_LEFT,
3551 EL_DC_STEELWALL_1_RIGHT,
3552 EL_DC_STEELWALL_1_TOP,
3553 EL_DC_STEELWALL_1_BOTTOM,
3554 EL_DC_STEELWALL_1_HORIZONTAL,
3555 EL_DC_STEELWALL_1_VERTICAL,
3556 EL_DC_STEELWALL_1_TOPLEFT,
3557 EL_DC_STEELWALL_1_TOPRIGHT,
3558 EL_DC_STEELWALL_1_BOTTOMLEFT,
3559 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3560 EL_DC_STEELWALL_1_TOPLEFT_2,
3561 EL_DC_STEELWALL_1_TOPRIGHT_2,
3562 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3563 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3564 EL_DC_STEELWALL_2_LEFT,
3565 EL_DC_STEELWALL_2_RIGHT,
3566 EL_DC_STEELWALL_2_TOP,
3567 EL_DC_STEELWALL_2_BOTTOM,
3568 EL_DC_STEELWALL_2_HORIZONTAL,
3569 EL_DC_STEELWALL_2_VERTICAL,
3570 EL_DC_STEELWALL_2_MIDDLE,
3571 EL_DC_STEELWALL_2_SINGLE,
3572 EL_STEELWALL_SLIPPERY,
3586 EL_GATE_1_GRAY_ACTIVE,
3587 EL_GATE_2_GRAY_ACTIVE,
3588 EL_GATE_3_GRAY_ACTIVE,
3589 EL_GATE_4_GRAY_ACTIVE,
3598 EL_EM_GATE_1_GRAY_ACTIVE,
3599 EL_EM_GATE_2_GRAY_ACTIVE,
3600 EL_EM_GATE_3_GRAY_ACTIVE,
3601 EL_EM_GATE_4_GRAY_ACTIVE,
3603 EL_SWITCHGATE_OPENING,
3604 EL_SWITCHGATE_CLOSED,
3605 EL_SWITCHGATE_CLOSING,
3607 EL_TIMEGATE_OPENING,
3609 EL_TIMEGATE_CLOSING,
3613 EL_TUBE_VERTICAL_LEFT,
3614 EL_TUBE_VERTICAL_RIGHT,
3615 EL_TUBE_HORIZONTAL_UP,
3616 EL_TUBE_HORIZONTAL_DOWN,
3625 static int ep_classic_enemy[] =
3642 static int ep_belt[] =
3644 EL_CONVEYOR_BELT_1_LEFT,
3645 EL_CONVEYOR_BELT_1_MIDDLE,
3646 EL_CONVEYOR_BELT_1_RIGHT,
3647 EL_CONVEYOR_BELT_2_LEFT,
3648 EL_CONVEYOR_BELT_2_MIDDLE,
3649 EL_CONVEYOR_BELT_2_RIGHT,
3650 EL_CONVEYOR_BELT_3_LEFT,
3651 EL_CONVEYOR_BELT_3_MIDDLE,
3652 EL_CONVEYOR_BELT_3_RIGHT,
3653 EL_CONVEYOR_BELT_4_LEFT,
3654 EL_CONVEYOR_BELT_4_MIDDLE,
3655 EL_CONVEYOR_BELT_4_RIGHT,
3660 static int ep_belt_active[] =
3662 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3663 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3664 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3665 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3666 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3667 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3668 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3669 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3670 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3671 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3672 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3673 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3678 static int ep_belt_switch[] =
3680 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3681 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3682 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3683 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3684 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3685 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3686 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3687 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3688 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3689 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3690 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3691 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3696 static int ep_tube[] =
3703 EL_TUBE_HORIZONTAL_UP,
3704 EL_TUBE_HORIZONTAL_DOWN,
3706 EL_TUBE_VERTICAL_LEFT,
3707 EL_TUBE_VERTICAL_RIGHT,
3713 static int ep_acid_pool[] =
3715 EL_ACID_POOL_TOPLEFT,
3716 EL_ACID_POOL_TOPRIGHT,
3717 EL_ACID_POOL_BOTTOMLEFT,
3718 EL_ACID_POOL_BOTTOM,
3719 EL_ACID_POOL_BOTTOMRIGHT,
3724 static int ep_keygate[] =
3734 EL_GATE_1_GRAY_ACTIVE,
3735 EL_GATE_2_GRAY_ACTIVE,
3736 EL_GATE_3_GRAY_ACTIVE,
3737 EL_GATE_4_GRAY_ACTIVE,
3746 EL_EM_GATE_1_GRAY_ACTIVE,
3747 EL_EM_GATE_2_GRAY_ACTIVE,
3748 EL_EM_GATE_3_GRAY_ACTIVE,
3749 EL_EM_GATE_4_GRAY_ACTIVE,
3758 EL_EMC_GATE_5_GRAY_ACTIVE,
3759 EL_EMC_GATE_6_GRAY_ACTIVE,
3760 EL_EMC_GATE_7_GRAY_ACTIVE,
3761 EL_EMC_GATE_8_GRAY_ACTIVE,
3763 EL_DC_GATE_WHITE_GRAY,
3764 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3769 static int ep_amoeboid[] =
3781 static int ep_amoebalive[] =
3792 static int ep_has_editor_content[] =
3798 EL_SOKOBAN_FIELD_PLAYER,
3815 static int ep_can_turn_each_move[] =
3817 /* !!! do something with this one !!! */
3821 static int ep_can_grow[] =
3835 static int ep_active_bomb[] =
3838 EL_EM_DYNAMITE_ACTIVE,
3839 EL_DYNABOMB_PLAYER_1_ACTIVE,
3840 EL_DYNABOMB_PLAYER_2_ACTIVE,
3841 EL_DYNABOMB_PLAYER_3_ACTIVE,
3842 EL_DYNABOMB_PLAYER_4_ACTIVE,
3843 EL_SP_DISK_RED_ACTIVE,
3848 static int ep_inactive[] =
3858 EL_QUICKSAND_FAST_EMPTY,
3881 EL_GATE_1_GRAY_ACTIVE,
3882 EL_GATE_2_GRAY_ACTIVE,
3883 EL_GATE_3_GRAY_ACTIVE,
3884 EL_GATE_4_GRAY_ACTIVE,
3893 EL_EM_GATE_1_GRAY_ACTIVE,
3894 EL_EM_GATE_2_GRAY_ACTIVE,
3895 EL_EM_GATE_3_GRAY_ACTIVE,
3896 EL_EM_GATE_4_GRAY_ACTIVE,
3905 EL_EMC_GATE_5_GRAY_ACTIVE,
3906 EL_EMC_GATE_6_GRAY_ACTIVE,
3907 EL_EMC_GATE_7_GRAY_ACTIVE,
3908 EL_EMC_GATE_8_GRAY_ACTIVE,
3910 EL_DC_GATE_WHITE_GRAY,
3911 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3912 EL_DC_GATE_FAKE_GRAY,
3915 EL_INVISIBLE_STEELWALL,
3923 EL_WALL_EMERALD_YELLOW,
3924 EL_DYNABOMB_INCREASE_NUMBER,
3925 EL_DYNABOMB_INCREASE_SIZE,
3926 EL_DYNABOMB_INCREASE_POWER,
3930 EL_SOKOBAN_FIELD_EMPTY,
3931 EL_SOKOBAN_FIELD_FULL,
3932 EL_WALL_EMERALD_RED,
3933 EL_WALL_EMERALD_PURPLE,
3934 EL_ACID_POOL_TOPLEFT,
3935 EL_ACID_POOL_TOPRIGHT,
3936 EL_ACID_POOL_BOTTOMLEFT,
3937 EL_ACID_POOL_BOTTOM,
3938 EL_ACID_POOL_BOTTOMRIGHT,
3942 EL_BD_MAGIC_WALL_DEAD,
3944 EL_DC_MAGIC_WALL_DEAD,
3945 EL_AMOEBA_TO_DIAMOND,
3953 EL_SP_GRAVITY_PORT_RIGHT,
3954 EL_SP_GRAVITY_PORT_DOWN,
3955 EL_SP_GRAVITY_PORT_LEFT,
3956 EL_SP_GRAVITY_PORT_UP,
3957 EL_SP_PORT_HORIZONTAL,
3958 EL_SP_PORT_VERTICAL,
3969 EL_SP_HARDWARE_GRAY,
3970 EL_SP_HARDWARE_GREEN,
3971 EL_SP_HARDWARE_BLUE,
3973 EL_SP_HARDWARE_YELLOW,
3974 EL_SP_HARDWARE_BASE_1,
3975 EL_SP_HARDWARE_BASE_2,
3976 EL_SP_HARDWARE_BASE_3,
3977 EL_SP_HARDWARE_BASE_4,
3978 EL_SP_HARDWARE_BASE_5,
3979 EL_SP_HARDWARE_BASE_6,
3980 EL_SP_GRAVITY_ON_PORT_LEFT,
3981 EL_SP_GRAVITY_ON_PORT_RIGHT,
3982 EL_SP_GRAVITY_ON_PORT_UP,
3983 EL_SP_GRAVITY_ON_PORT_DOWN,
3984 EL_SP_GRAVITY_OFF_PORT_LEFT,
3985 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3986 EL_SP_GRAVITY_OFF_PORT_UP,
3987 EL_SP_GRAVITY_OFF_PORT_DOWN,
3988 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3989 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3990 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3991 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3992 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3993 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3994 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3995 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3996 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3997 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3998 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3999 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4000 EL_SIGN_EXCLAMATION,
4001 EL_SIGN_RADIOACTIVITY,
4008 EL_SIGN_ENTRY_FORBIDDEN,
4009 EL_SIGN_EMERGENCY_EXIT,
4017 EL_DC_STEELWALL_1_LEFT,
4018 EL_DC_STEELWALL_1_RIGHT,
4019 EL_DC_STEELWALL_1_TOP,
4020 EL_DC_STEELWALL_1_BOTTOM,
4021 EL_DC_STEELWALL_1_HORIZONTAL,
4022 EL_DC_STEELWALL_1_VERTICAL,
4023 EL_DC_STEELWALL_1_TOPLEFT,
4024 EL_DC_STEELWALL_1_TOPRIGHT,
4025 EL_DC_STEELWALL_1_BOTTOMLEFT,
4026 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4027 EL_DC_STEELWALL_1_TOPLEFT_2,
4028 EL_DC_STEELWALL_1_TOPRIGHT_2,
4029 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4030 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4031 EL_DC_STEELWALL_2_LEFT,
4032 EL_DC_STEELWALL_2_RIGHT,
4033 EL_DC_STEELWALL_2_TOP,
4034 EL_DC_STEELWALL_2_BOTTOM,
4035 EL_DC_STEELWALL_2_HORIZONTAL,
4036 EL_DC_STEELWALL_2_VERTICAL,
4037 EL_DC_STEELWALL_2_MIDDLE,
4038 EL_DC_STEELWALL_2_SINGLE,
4039 EL_STEELWALL_SLIPPERY,
4044 EL_EMC_WALL_SLIPPERY_1,
4045 EL_EMC_WALL_SLIPPERY_2,
4046 EL_EMC_WALL_SLIPPERY_3,
4047 EL_EMC_WALL_SLIPPERY_4,
4068 static int ep_em_slippery_wall[] =
4073 static int ep_gfx_crumbled[] =
4084 static int ep_editor_cascade_active[] =
4086 EL_INTERNAL_CASCADE_BD_ACTIVE,
4087 EL_INTERNAL_CASCADE_EM_ACTIVE,
4088 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4089 EL_INTERNAL_CASCADE_RND_ACTIVE,
4090 EL_INTERNAL_CASCADE_SB_ACTIVE,
4091 EL_INTERNAL_CASCADE_SP_ACTIVE,
4092 EL_INTERNAL_CASCADE_DC_ACTIVE,
4093 EL_INTERNAL_CASCADE_DX_ACTIVE,
4094 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4095 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4096 EL_INTERNAL_CASCADE_CE_ACTIVE,
4097 EL_INTERNAL_CASCADE_GE_ACTIVE,
4098 EL_INTERNAL_CASCADE_REF_ACTIVE,
4099 EL_INTERNAL_CASCADE_USER_ACTIVE,
4100 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4105 static int ep_editor_cascade_inactive[] =
4107 EL_INTERNAL_CASCADE_BD,
4108 EL_INTERNAL_CASCADE_EM,
4109 EL_INTERNAL_CASCADE_EMC,
4110 EL_INTERNAL_CASCADE_RND,
4111 EL_INTERNAL_CASCADE_SB,
4112 EL_INTERNAL_CASCADE_SP,
4113 EL_INTERNAL_CASCADE_DC,
4114 EL_INTERNAL_CASCADE_DX,
4115 EL_INTERNAL_CASCADE_CHARS,
4116 EL_INTERNAL_CASCADE_STEEL_CHARS,
4117 EL_INTERNAL_CASCADE_CE,
4118 EL_INTERNAL_CASCADE_GE,
4119 EL_INTERNAL_CASCADE_REF,
4120 EL_INTERNAL_CASCADE_USER,
4121 EL_INTERNAL_CASCADE_DYNAMIC,
4126 static int ep_obsolete[] =
4130 EL_EM_KEY_1_FILE_OBSOLETE,
4131 EL_EM_KEY_2_FILE_OBSOLETE,
4132 EL_EM_KEY_3_FILE_OBSOLETE,
4133 EL_EM_KEY_4_FILE_OBSOLETE,
4134 EL_ENVELOPE_OBSOLETE,
4143 } element_properties[] =
4145 { ep_diggable, EP_DIGGABLE },
4146 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4147 { ep_dont_run_into, EP_DONT_RUN_INTO },
4148 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4149 { ep_dont_touch, EP_DONT_TOUCH },
4150 { ep_indestructible, EP_INDESTRUCTIBLE },
4151 { ep_slippery, EP_SLIPPERY },
4152 { ep_can_change, EP_CAN_CHANGE },
4153 { ep_can_move, EP_CAN_MOVE },
4154 { ep_can_fall, EP_CAN_FALL },
4155 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4156 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4157 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4158 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4159 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4160 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4161 { ep_walkable_over, EP_WALKABLE_OVER },
4162 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4163 { ep_walkable_under, EP_WALKABLE_UNDER },
4164 { ep_passable_over, EP_PASSABLE_OVER },
4165 { ep_passable_inside, EP_PASSABLE_INSIDE },
4166 { ep_passable_under, EP_PASSABLE_UNDER },
4167 { ep_droppable, EP_DROPPABLE },
4168 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4169 { ep_pushable, EP_PUSHABLE },
4170 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4171 { ep_protected, EP_PROTECTED },
4172 { ep_throwable, EP_THROWABLE },
4173 { ep_can_explode, EP_CAN_EXPLODE },
4174 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4176 { ep_player, EP_PLAYER },
4177 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4178 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4179 { ep_switchable, EP_SWITCHABLE },
4180 { ep_bd_element, EP_BD_ELEMENT },
4181 { ep_sp_element, EP_SP_ELEMENT },
4182 { ep_sb_element, EP_SB_ELEMENT },
4184 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4185 { ep_food_penguin, EP_FOOD_PENGUIN },
4186 { ep_food_pig, EP_FOOD_PIG },
4187 { ep_historic_wall, EP_HISTORIC_WALL },
4188 { ep_historic_solid, EP_HISTORIC_SOLID },
4189 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4190 { ep_belt, EP_BELT },
4191 { ep_belt_active, EP_BELT_ACTIVE },
4192 { ep_belt_switch, EP_BELT_SWITCH },
4193 { ep_tube, EP_TUBE },
4194 { ep_acid_pool, EP_ACID_POOL },
4195 { ep_keygate, EP_KEYGATE },
4196 { ep_amoeboid, EP_AMOEBOID },
4197 { ep_amoebalive, EP_AMOEBALIVE },
4198 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4199 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4200 { ep_can_grow, EP_CAN_GROW },
4201 { ep_active_bomb, EP_ACTIVE_BOMB },
4202 { ep_inactive, EP_INACTIVE },
4204 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4206 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4208 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4209 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4211 { ep_obsolete, EP_OBSOLETE },
4218 /* always start with reliable default values (element has no properties) */
4219 /* (but never initialize clipboard elements after the very first time) */
4220 /* (to be able to use clipboard elements between several levels) */
4221 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4222 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4223 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4224 SET_PROPERTY(i, j, FALSE);
4226 /* set all base element properties from above array definitions */
4227 for (i = 0; element_properties[i].elements != NULL; i++)
4228 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4229 SET_PROPERTY((element_properties[i].elements)[j],
4230 element_properties[i].property, TRUE);
4232 /* copy properties to some elements that are only stored in level file */
4233 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4234 for (j = 0; copy_properties[j][0] != -1; j++)
4235 if (HAS_PROPERTY(copy_properties[j][0], i))
4236 for (k = 1; k <= 4; k++)
4237 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4239 /* set static element properties that are not listed in array definitions */
4240 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4241 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4243 clipboard_elements_initialized = TRUE;
4246 void InitElementPropertiesEngine(int engine_version)
4248 static int no_wall_properties[] =
4251 EP_COLLECTIBLE_ONLY,
4253 EP_DONT_COLLIDE_WITH,
4256 EP_CAN_SMASH_PLAYER,
4257 EP_CAN_SMASH_ENEMIES,
4258 EP_CAN_SMASH_EVERYTHING,
4263 EP_FOOD_DARK_YAMYAM,
4279 /* important: after initialization in InitElementPropertiesStatic(), the
4280 elements are not again initialized to a default value; therefore all
4281 changes have to make sure that they leave the element with a defined
4282 property (which means that conditional property changes must be set to
4283 a reliable default value before) */
4285 /* resolve group elements */
4286 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4287 ResolveGroupElement(EL_GROUP_START + i);
4289 /* set all special, combined or engine dependent element properties */
4290 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4292 /* do not change (already initialized) clipboard elements here */
4293 if (IS_CLIPBOARD_ELEMENT(i))
4296 /* ---------- INACTIVE ------------------------------------------------- */
4297 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4298 i <= EL_CHAR_END) ||
4299 (i >= EL_STEEL_CHAR_START &&
4300 i <= EL_STEEL_CHAR_END)));
4302 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4303 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4304 IS_WALKABLE_INSIDE(i) ||
4305 IS_WALKABLE_UNDER(i)));
4307 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4308 IS_PASSABLE_INSIDE(i) ||
4309 IS_PASSABLE_UNDER(i)));
4311 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4312 IS_PASSABLE_OVER(i)));
4314 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4315 IS_PASSABLE_INSIDE(i)));
4317 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4318 IS_PASSABLE_UNDER(i)));
4320 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4323 /* ---------- COLLECTIBLE ---------------------------------------------- */
4324 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4328 /* ---------- SNAPPABLE ------------------------------------------------ */
4329 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4330 IS_COLLECTIBLE(i) ||
4334 /* ---------- WALL ----------------------------------------------------- */
4335 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4337 for (j = 0; no_wall_properties[j] != -1; j++)
4338 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4339 i >= EL_FIRST_RUNTIME_UNREAL)
4340 SET_PROPERTY(i, EP_WALL, FALSE);
4342 if (IS_HISTORIC_WALL(i))
4343 SET_PROPERTY(i, EP_WALL, TRUE);
4345 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4346 if (engine_version < VERSION_IDENT(2,2,0,0))
4347 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4349 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4351 !IS_COLLECTIBLE(i)));
4353 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4354 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4355 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4357 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4358 IS_INDESTRUCTIBLE(i)));
4360 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4362 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4363 else if (engine_version < VERSION_IDENT(2,2,0,0))
4364 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4366 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4370 if (IS_CUSTOM_ELEMENT(i))
4372 /* these are additional properties which are initially false when set */
4374 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4376 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4377 if (DONT_COLLIDE_WITH(i))
4378 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4380 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4381 if (CAN_SMASH_EVERYTHING(i))
4382 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4383 if (CAN_SMASH_ENEMIES(i))
4384 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4387 /* ---------- CAN_SMASH ------------------------------------------------ */
4388 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4389 CAN_SMASH_ENEMIES(i) ||
4390 CAN_SMASH_EVERYTHING(i)));
4392 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4393 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4394 EXPLODES_BY_FIRE(i)));
4396 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4397 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4398 EXPLODES_SMASHED(i)));
4400 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4401 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4402 EXPLODES_IMPACT(i)));
4404 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4405 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4407 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4408 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4409 i == EL_BLACK_ORB));
4411 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4412 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4414 IS_CUSTOM_ELEMENT(i)));
4416 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4417 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4418 i == EL_SP_ELECTRON));
4420 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4421 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4422 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4423 getMoveIntoAcidProperty(&level, i));
4425 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4426 if (MAYBE_DONT_COLLIDE_WITH(i))
4427 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4428 getDontCollideWithProperty(&level, i));
4430 /* ---------- SP_PORT -------------------------------------------------- */
4431 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4432 IS_PASSABLE_INSIDE(i)));
4434 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4435 for (j = 0; j < level.num_android_clone_elements; j++)
4436 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4438 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4440 /* ---------- CAN_CHANGE ----------------------------------------------- */
4441 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4442 for (j = 0; j < element_info[i].num_change_pages; j++)
4443 if (element_info[i].change_page[j].can_change)
4444 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4446 /* ---------- HAS_ACTION ----------------------------------------------- */
4447 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4448 for (j = 0; j < element_info[i].num_change_pages; j++)
4449 if (element_info[i].change_page[j].has_action)
4450 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4452 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4453 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4456 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4457 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4458 element_info[i].crumbled[ACTION_DEFAULT] !=
4459 element_info[i].graphic[ACTION_DEFAULT]);
4461 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4462 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4463 IS_EDITOR_CASCADE_INACTIVE(i)));
4466 /* dynamically adjust element properties according to game engine version */
4468 static int ep_em_slippery_wall[] =
4473 EL_EXPANDABLE_WALL_HORIZONTAL,
4474 EL_EXPANDABLE_WALL_VERTICAL,
4475 EL_EXPANDABLE_WALL_ANY,
4476 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4477 EL_EXPANDABLE_STEELWALL_VERTICAL,
4478 EL_EXPANDABLE_STEELWALL_ANY,
4479 EL_EXPANDABLE_STEELWALL_GROWING,
4483 static int ep_em_explodes_by_fire[] =
4486 EL_EM_DYNAMITE_ACTIVE,
4491 /* special EM style gems behaviour */
4492 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4493 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4494 level.em_slippery_gems);
4496 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4497 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4498 (level.em_slippery_gems &&
4499 engine_version > VERSION_IDENT(2,0,1,0)));
4501 /* special EM style explosion behaviour regarding chain reactions */
4502 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4503 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4504 level.em_explodes_by_fire);
4507 /* this is needed because some graphics depend on element properties */
4508 if (game_status == GAME_MODE_PLAYING)
4509 InitElementGraphicInfo();
4512 void InitElementPropertiesAfterLoading(int engine_version)
4516 /* set some other uninitialized values of custom elements in older levels */
4517 if (engine_version < VERSION_IDENT(3,1,0,0))
4519 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4521 int element = EL_CUSTOM_START + i;
4523 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4525 element_info[element].explosion_delay = 17;
4526 element_info[element].ignition_delay = 8;
4531 void InitElementPropertiesGfxElement()
4535 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4537 struct ElementInfo *ei = &element_info[i];
4539 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4543 static void InitGlobal()
4548 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4550 /* check if element_name_info entry defined for each element in "main.h" */
4551 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4552 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4554 element_info[i].token_name = element_name_info[i].token_name;
4555 element_info[i].class_name = element_name_info[i].class_name;
4556 element_info[i].editor_description= element_name_info[i].editor_description;
4559 /* create hash from image config list */
4560 image_config_hash = newSetupFileHash();
4561 for (i = 0; image_config[i].token != NULL; i++)
4562 setHashEntry(image_config_hash,
4563 image_config[i].token,
4564 image_config[i].value);
4566 /* create hash from element token list */
4567 element_token_hash = newSetupFileHash();
4568 for (i = 0; element_name_info[i].token_name != NULL; i++)
4569 setHashEntry(element_token_hash,
4570 element_name_info[i].token_name,
4573 /* create hash from graphic token list */
4574 graphic_token_hash = newSetupFileHash();
4575 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4576 if (strSuffix(image_config[i].value, ".png") ||
4577 strSuffix(image_config[i].value, ".pcx") ||
4578 strSuffix(image_config[i].value, ".wav") ||
4579 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4580 setHashEntry(graphic_token_hash,
4581 image_config[i].token,
4582 int2str(graphic++, 0));
4584 /* create hash from font token list */
4585 font_token_hash = newSetupFileHash();
4586 for (i = 0; font_info[i].token_name != NULL; i++)
4587 setHashEntry(font_token_hash,
4588 font_info[i].token_name,
4591 /* set default filenames for all cloned graphics in static configuration */
4592 for (i = 0; image_config[i].token != NULL; i++)
4594 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4596 char *token = image_config[i].token;
4597 char *token_clone_from = getStringCat2(token, ".clone_from");
4598 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4600 if (token_cloned != NULL)
4602 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4604 if (value_cloned != NULL)
4606 /* set default filename in static configuration */
4607 image_config[i].value = value_cloned;
4609 /* set default filename in image config hash */
4610 setHashEntry(image_config_hash, token, value_cloned);
4614 free(token_clone_from);
4618 /* always start with reliable default values (all elements) */
4619 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4620 ActiveElement[i] = i;
4622 /* now add all entries that have an active state (active elements) */
4623 for (i = 0; element_with_active_state[i].element != -1; i++)
4625 int element = element_with_active_state[i].element;
4626 int element_active = element_with_active_state[i].element_active;
4628 ActiveElement[element] = element_active;
4631 /* always start with reliable default values (all buttons) */
4632 for (i = 0; i < NUM_IMAGE_FILES; i++)
4633 ActiveButton[i] = i;
4635 /* now add all entries that have an active state (active buttons) */
4636 for (i = 0; button_with_active_state[i].button != -1; i++)
4638 int button = button_with_active_state[i].button;
4639 int button_active = button_with_active_state[i].button_active;
4641 ActiveButton[button] = button_active;
4644 /* always start with reliable default values (all fonts) */
4645 for (i = 0; i < NUM_FONTS; i++)
4648 /* now add all entries that have an active state (active fonts) */
4649 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4651 int font = font_with_active_state[i].font_nr;
4652 int font_active = font_with_active_state[i].font_nr_active;
4654 ActiveFont[font] = font_active;
4657 global.autoplay_leveldir = NULL;
4658 global.convert_leveldir = NULL;
4659 global.create_images_dir = NULL;
4661 global.frames_per_second = 0;
4663 global.border_status = GAME_MODE_MAIN;
4665 global.use_envelope_request = FALSE;
4668 void Execute_Command(char *command)
4672 if (strEqual(command, "print graphicsinfo.conf"))
4674 Print("# You can configure additional/alternative image files here.\n");
4675 Print("# (The entries below are default and therefore commented out.)\n");
4677 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4679 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4682 for (i = 0; image_config[i].token != NULL; i++)
4683 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4684 image_config[i].value));
4688 else if (strEqual(command, "print soundsinfo.conf"))
4690 Print("# You can configure additional/alternative sound files here.\n");
4691 Print("# (The entries below are default and therefore commented out.)\n");
4693 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4695 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4698 for (i = 0; sound_config[i].token != NULL; i++)
4699 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4700 sound_config[i].value));
4704 else if (strEqual(command, "print musicinfo.conf"))
4706 Print("# You can configure additional/alternative music files here.\n");
4707 Print("# (The entries below are default and therefore commented out.)\n");
4709 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4711 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4714 for (i = 0; music_config[i].token != NULL; i++)
4715 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4716 music_config[i].value));
4720 else if (strEqual(command, "print editorsetup.conf"))
4722 Print("# You can configure your personal editor element list here.\n");
4723 Print("# (The entries below are default and therefore commented out.)\n");
4726 /* this is needed to be able to check element list for cascade elements */
4727 InitElementPropertiesStatic();
4728 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4730 PrintEditorElementList();
4734 else if (strEqual(command, "print helpanim.conf"))
4736 Print("# You can configure different element help animations here.\n");
4737 Print("# (The entries below are default and therefore commented out.)\n");
4740 for (i = 0; helpanim_config[i].token != NULL; i++)
4742 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4743 helpanim_config[i].value));
4745 if (strEqual(helpanim_config[i].token, "end"))
4751 else if (strEqual(command, "print helptext.conf"))
4753 Print("# You can configure different element help text here.\n");
4754 Print("# (The entries below are default and therefore commented out.)\n");
4757 for (i = 0; helptext_config[i].token != NULL; i++)
4758 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4759 helptext_config[i].value));
4763 else if (strPrefix(command, "dump level "))
4765 char *filename = &command[11];
4767 if (!fileExists(filename))
4768 Error(ERR_EXIT, "cannot open file '%s'", filename);
4770 LoadLevelFromFilename(&level, filename);
4775 else if (strPrefix(command, "dump tape "))
4777 char *filename = &command[10];
4779 if (!fileExists(filename))
4780 Error(ERR_EXIT, "cannot open file '%s'", filename);
4782 LoadTapeFromFilename(filename);
4787 else if (strPrefix(command, "autotest ") ||
4788 strPrefix(command, "autoplay ") ||
4789 strPrefix(command, "autoffwd "))
4791 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4793 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4794 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4795 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4797 while (*str_ptr != '\0') /* continue parsing string */
4799 /* cut leading whitespace from string, replace it by string terminator */
4800 while (*str_ptr == ' ' || *str_ptr == '\t')
4803 if (*str_ptr == '\0') /* end of string reached */
4806 if (global.autoplay_leveldir == NULL) /* read level set string */
4808 global.autoplay_leveldir = str_ptr;
4809 global.autoplay_all = TRUE; /* default: play all tapes */
4811 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4812 global.autoplay_level[i] = FALSE;
4814 else /* read level number string */
4816 int level_nr = atoi(str_ptr); /* get level_nr value */
4818 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4819 global.autoplay_level[level_nr] = TRUE;
4821 global.autoplay_all = FALSE;
4824 /* advance string pointer to the next whitespace (or end of string) */
4825 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4829 else if (strPrefix(command, "convert "))
4831 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4832 char *str_ptr = strchr(str_copy, ' ');
4834 global.convert_leveldir = str_copy;
4835 global.convert_level_nr = -1;
4837 if (str_ptr != NULL) /* level number follows */
4839 *str_ptr++ = '\0'; /* terminate leveldir string */
4840 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4843 else if (strPrefix(command, "create images "))
4845 global.create_images_dir = getStringCopy(&command[14]);
4847 if (access(global.create_images_dir, W_OK) != 0)
4848 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4849 global.create_images_dir);
4851 else if (strPrefix(command, "create CE image "))
4853 CreateCustomElementImages(&command[16]);
4859 #if defined(TARGET_SDL2)
4860 else if (strEqual(command, "SDL_ListModes"))
4862 SDL_Init(SDL_INIT_VIDEO);
4864 int num_displays = SDL_GetNumVideoDisplays();
4866 // check if there are any displays available
4867 if (num_displays < 0)
4869 Print("No displays available: %s\n", SDL_GetError());
4874 for (i = 0; i < num_displays; i++)
4876 int num_modes = SDL_GetNumDisplayModes(i);
4879 Print("Available display modes for display %d:\n", i);
4881 // check if there are any display modes available for this display
4884 Print("No display modes available for display %d: %s\n",
4890 for (j = 0; j < num_modes; j++)
4892 SDL_DisplayMode mode;
4894 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4896 Print("Cannot get display mode %d for display %d: %s\n",
4897 j, i, SDL_GetError());
4902 Print("- %d x %d\n", mode.w, mode.h);
4908 #elif defined(TARGET_SDL)
4909 else if (strEqual(command, "SDL_ListModes"))
4914 SDL_Init(SDL_INIT_VIDEO);
4916 /* get available fullscreen/hardware modes */
4917 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4919 /* check if there are any modes available */
4922 Print("No modes available!\n");
4927 /* check if our resolution is restricted */
4928 if (modes == (SDL_Rect **)-1)
4930 Print("All resolutions available.\n");
4934 Print("Available display modes:\n");
4936 for (i = 0; modes[i]; i++)
4937 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4947 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4951 static void InitSetup()
4953 LoadSetup(); /* global setup info */
4955 /* set some options from setup file */
4957 if (setup.options.verbose)
4958 options.verbose = TRUE;
4961 static void InitGameInfo()
4963 game.restart_level = FALSE;
4966 static void InitPlayerInfo()
4970 /* choose default local player */
4971 local_player = &stored_player[0];
4973 for (i = 0; i < MAX_PLAYERS; i++)
4974 stored_player[i].connected = FALSE;
4976 local_player->connected = TRUE;
4979 static void InitArtworkInfo()
4984 static char *get_string_in_brackets(char *string)
4986 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4988 sprintf(string_in_brackets, "[%s]", string);
4990 return string_in_brackets;
4993 static char *get_level_id_suffix(int id_nr)
4995 char *id_suffix = checked_malloc(1 + 3 + 1);
4997 if (id_nr < 0 || id_nr > 999)
5000 sprintf(id_suffix, ".%03d", id_nr);
5005 static void InitArtworkConfig()
5007 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5009 NUM_GLOBAL_ANIM_TOKENS + 1];
5010 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5011 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5012 static char *action_id_suffix[NUM_ACTIONS + 1];
5013 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5014 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5015 static char *level_id_suffix[MAX_LEVELS + 1];
5016 static char *dummy[1] = { NULL };
5017 static char *ignore_generic_tokens[] =
5023 static char **ignore_image_tokens;
5024 static char **ignore_sound_tokens;
5025 static char **ignore_music_tokens;
5026 int num_ignore_generic_tokens;
5027 int num_ignore_image_tokens;
5028 int num_ignore_sound_tokens;
5029 int num_ignore_music_tokens;
5032 /* dynamically determine list of generic tokens to be ignored */
5033 num_ignore_generic_tokens = 0;
5034 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5035 num_ignore_generic_tokens++;
5037 /* dynamically determine list of image tokens to be ignored */
5038 num_ignore_image_tokens = num_ignore_generic_tokens;
5039 for (i = 0; image_config_vars[i].token != NULL; i++)
5040 num_ignore_image_tokens++;
5041 ignore_image_tokens =
5042 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5043 for (i = 0; i < num_ignore_generic_tokens; i++)
5044 ignore_image_tokens[i] = ignore_generic_tokens[i];
5045 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5046 ignore_image_tokens[num_ignore_generic_tokens + i] =
5047 image_config_vars[i].token;
5048 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5050 /* dynamically determine list of sound tokens to be ignored */
5051 num_ignore_sound_tokens = num_ignore_generic_tokens;
5052 ignore_sound_tokens =
5053 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5054 for (i = 0; i < num_ignore_generic_tokens; i++)
5055 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5056 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5058 /* dynamically determine list of music tokens to be ignored */
5059 num_ignore_music_tokens = num_ignore_generic_tokens;
5060 ignore_music_tokens =
5061 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5062 for (i = 0; i < num_ignore_generic_tokens; i++)
5063 ignore_music_tokens[i] = ignore_generic_tokens[i];
5064 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5066 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5067 image_id_prefix[i] = element_info[i].token_name;
5068 for (i = 0; i < NUM_FONTS; i++)
5069 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5070 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5071 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5072 global_anim_info[i].token_name;
5073 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5075 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5076 sound_id_prefix[i] = element_info[i].token_name;
5077 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5078 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5079 get_string_in_brackets(element_info[i].class_name);
5080 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5082 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5083 music_id_prefix[i] = music_prefix_info[i].prefix;
5084 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5086 for (i = 0; i < NUM_ACTIONS; i++)
5087 action_id_suffix[i] = element_action_info[i].suffix;
5088 action_id_suffix[NUM_ACTIONS] = NULL;
5090 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5091 direction_id_suffix[i] = element_direction_info[i].suffix;
5092 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5094 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5095 special_id_suffix[i] = special_suffix_info[i].suffix;
5096 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5098 for (i = 0; i < MAX_LEVELS; i++)
5099 level_id_suffix[i] = get_level_id_suffix(i);
5100 level_id_suffix[MAX_LEVELS] = NULL;
5102 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5103 image_id_prefix, action_id_suffix, direction_id_suffix,
5104 special_id_suffix, ignore_image_tokens);
5105 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5106 sound_id_prefix, action_id_suffix, dummy,
5107 special_id_suffix, ignore_sound_tokens);
5108 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5109 music_id_prefix, special_id_suffix, level_id_suffix,
5110 dummy, ignore_music_tokens);
5113 static void InitMixer()
5120 void InitGfxBuffers()
5122 static int win_xsize_last = -1;
5123 static int win_ysize_last = -1;
5125 /* create additional image buffers for double-buffering and cross-fading */
5127 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5129 /* may contain content for cross-fading -- only re-create if changed */
5130 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5131 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5133 win_xsize_last = WIN_XSIZE;
5134 win_ysize_last = WIN_YSIZE;
5137 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5138 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5139 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5140 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5141 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5143 /* initialize screen properties */
5144 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5145 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5147 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5148 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5149 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5150 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5151 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5152 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5154 /* required if door size definitions have changed */
5155 InitGraphicCompatibilityInfo_Doors();
5157 InitGfxBuffers_EM();
5158 InitGfxBuffers_SP();
5163 struct GraphicInfo *graphic_info_last = graphic_info;
5164 char *filename_font_initial = NULL;
5165 char *filename_anim_initial = NULL;
5166 Bitmap *bitmap_font_initial = NULL;
5170 /* determine settings for initial font (for displaying startup messages) */
5171 for (i = 0; image_config[i].token != NULL; i++)
5173 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5175 char font_token[128];
5178 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5179 len_font_token = strlen(font_token);
5181 if (strEqual(image_config[i].token, font_token))
5182 filename_font_initial = image_config[i].value;
5183 else if (strlen(image_config[i].token) > len_font_token &&
5184 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5186 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5187 font_initial[j].src_x = atoi(image_config[i].value);
5188 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5189 font_initial[j].src_y = atoi(image_config[i].value);
5190 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5191 font_initial[j].width = atoi(image_config[i].value);
5192 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5193 font_initial[j].height = atoi(image_config[i].value);
5198 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5200 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5201 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5204 if (filename_font_initial == NULL) /* should not happen */
5205 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5208 InitGfxCustomArtworkInfo();
5209 InitGfxOtherSettings();
5211 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5213 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5214 font_initial[j].bitmap = bitmap_font_initial;
5216 InitFontGraphicInfo();
5218 font_height = getFontHeight(FC_RED);
5220 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5221 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5222 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5225 DrawInitText("Loading graphics", 120, FC_GREEN);
5227 /* initialize settings for busy animation with default values */
5228 int parameter[NUM_GFX_ARGS];
5229 for (i = 0; i < NUM_GFX_ARGS; i++)
5230 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5231 image_config_suffix[i].token,
5232 image_config_suffix[i].type);
5234 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5235 int len_anim_token = strlen(anim_token);
5237 /* read settings for busy animation from default custom artwork config */
5238 char *gfx_config_filename = getPath3(options.graphics_directory,
5240 GRAPHICSINFO_FILENAME);
5242 if (fileExists(gfx_config_filename))
5244 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5246 if (setup_file_hash)
5248 char *filename = getHashEntry(setup_file_hash, anim_token);
5252 filename_anim_initial = getStringCopy(filename);
5254 for (j = 0; image_config_suffix[j].token != NULL; j++)
5256 int type = image_config_suffix[j].type;
5257 char *suffix = image_config_suffix[j].token;
5258 char *token = getStringCat2(anim_token, suffix);
5259 char *value = getHashEntry(setup_file_hash, token);
5261 checked_free(token);
5264 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5268 freeSetupFileHash(setup_file_hash);
5272 if (filename_anim_initial == NULL)
5274 /* read settings for busy animation from static default artwork config */
5275 for (i = 0; image_config[i].token != NULL; i++)
5277 if (strEqual(image_config[i].token, anim_token))
5278 filename_anim_initial = getStringCopy(image_config[i].value);
5279 else if (strlen(image_config[i].token) > len_anim_token &&
5280 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5282 for (j = 0; image_config_suffix[j].token != NULL; j++)
5284 if (strEqual(&image_config[i].token[len_anim_token],
5285 image_config_suffix[j].token))
5287 get_graphic_parameter_value(image_config[i].value,
5288 image_config_suffix[j].token,
5289 image_config_suffix[j].type);
5295 if (filename_anim_initial == NULL) /* should not happen */
5296 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5298 anim_initial.bitmaps =
5299 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5301 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5302 LoadCustomImage(filename_anim_initial);
5304 checked_free(filename_anim_initial);
5306 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5308 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5310 graphic_info = graphic_info_last;
5312 init.busy.width = anim_initial.width;
5313 init.busy.height = anim_initial.height;
5315 InitMenuDesignSettings_Static();
5317 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5318 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5320 /* use copy of busy animation to prevent change while reloading artwork */
5324 void InitGfxBackground()
5326 fieldbuffer = bitmap_db_field;
5327 SetDrawtoField(DRAW_BACKBUFFER);
5329 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5331 redraw_mask = REDRAW_ALL;
5334 static void InitLevelInfo()
5336 LoadLevelInfo(); /* global level info */
5337 LoadLevelSetup_LastSeries(); /* last played series info */
5338 LoadLevelSetup_SeriesInfo(); /* last played level info */
5340 if (global.autoplay_leveldir &&
5341 global.autoplay_mode != AUTOPLAY_TEST)
5343 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5344 global.autoplay_leveldir);
5345 if (leveldir_current == NULL)
5346 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5350 static void InitLevelArtworkInfo()
5352 LoadLevelArtworkInfo();
5355 static void InitImages()
5357 print_timestamp_init("InitImages");
5360 printf("::: leveldir_current->identifier == '%s'\n",
5361 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5362 printf("::: leveldir_current->graphics_path == '%s'\n",
5363 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5364 printf("::: leveldir_current->graphics_set == '%s'\n",
5365 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5366 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5367 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5370 setLevelArtworkDir(artwork.gfx_first);
5373 printf("::: leveldir_current->identifier == '%s'\n",
5374 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5375 printf("::: leveldir_current->graphics_path == '%s'\n",
5376 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5377 printf("::: leveldir_current->graphics_set == '%s'\n",
5378 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5379 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5380 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5384 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5385 leveldir_current->identifier,
5386 artwork.gfx_current_identifier,
5387 artwork.gfx_current->identifier,
5388 leveldir_current->graphics_set,
5389 leveldir_current->graphics_path);
5392 UPDATE_BUSY_STATE();
5394 ReloadCustomImages();
5395 print_timestamp_time("ReloadCustomImages");
5397 UPDATE_BUSY_STATE();
5399 LoadCustomElementDescriptions();
5400 print_timestamp_time("LoadCustomElementDescriptions");
5402 UPDATE_BUSY_STATE();
5404 LoadMenuDesignSettings();
5405 print_timestamp_time("LoadMenuDesignSettings");
5407 UPDATE_BUSY_STATE();
5409 ReinitializeGraphics();
5410 print_timestamp_time("ReinitializeGraphics");
5412 UPDATE_BUSY_STATE();
5414 print_timestamp_done("InitImages");
5417 static void InitSound(char *identifier)
5419 print_timestamp_init("InitSound");
5421 if (identifier == NULL)
5422 identifier = artwork.snd_current->identifier;
5424 /* set artwork path to send it to the sound server process */
5425 setLevelArtworkDir(artwork.snd_first);
5427 InitReloadCustomSounds(identifier);
5428 print_timestamp_time("InitReloadCustomSounds");
5430 ReinitializeSounds();
5431 print_timestamp_time("ReinitializeSounds");
5433 print_timestamp_done("InitSound");
5436 static void InitMusic(char *identifier)
5438 print_timestamp_init("InitMusic");
5440 if (identifier == NULL)
5441 identifier = artwork.mus_current->identifier;
5443 /* set artwork path to send it to the sound server process */
5444 setLevelArtworkDir(artwork.mus_first);
5446 InitReloadCustomMusic(identifier);
5447 print_timestamp_time("InitReloadCustomMusic");
5449 ReinitializeMusic();
5450 print_timestamp_time("ReinitializeMusic");
5452 print_timestamp_done("InitMusic");
5455 void InitNetworkServer()
5457 #if defined(NETWORK_AVALIABLE)
5461 if (!options.network)
5464 #if defined(NETWORK_AVALIABLE)
5465 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5467 if (!ConnectToServer(options.server_host, options.server_port))
5468 Error(ERR_EXIT, "cannot connect to network game server");
5470 SendToServer_PlayerName(setup.player_name);
5471 SendToServer_ProtocolVersion();
5474 SendToServer_NrWanted(nr_wanted);
5478 static boolean CheckArtworkConfigForCustomElements(char *filename)
5480 SetupFileHash *setup_file_hash;
5481 boolean redefined_ce_found = FALSE;
5483 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5485 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5487 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5489 char *token = HASH_ITERATION_TOKEN(itr);
5491 if (strPrefix(token, "custom_"))
5493 redefined_ce_found = TRUE;
5498 END_HASH_ITERATION(setup_file_hash, itr)
5500 freeSetupFileHash(setup_file_hash);
5503 return redefined_ce_found;
5506 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5508 char *filename_base, *filename_local;
5509 boolean redefined_ce_found = FALSE;
5511 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5514 printf("::: leveldir_current->identifier == '%s'\n",
5515 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5516 printf("::: leveldir_current->graphics_path == '%s'\n",
5517 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5518 printf("::: leveldir_current->graphics_set == '%s'\n",
5519 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5520 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5521 leveldir_current == NULL ? "[NULL]" :
5522 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5525 /* first look for special artwork configured in level series config */
5526 filename_base = getCustomArtworkLevelConfigFilename(type);
5529 printf("::: filename_base == '%s'\n", filename_base);
5532 if (fileExists(filename_base))
5533 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5535 filename_local = getCustomArtworkConfigFilename(type);
5538 printf("::: filename_local == '%s'\n", filename_local);
5541 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5542 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5545 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5548 return redefined_ce_found;
5551 static void InitOverrideArtwork()
5553 boolean redefined_ce_found = FALSE;
5555 /* to check if this level set redefines any CEs, do not use overriding */
5556 gfx.override_level_graphics = FALSE;
5557 gfx.override_level_sounds = FALSE;
5558 gfx.override_level_music = FALSE;
5560 /* now check if this level set has definitions for custom elements */
5561 if (setup.override_level_graphics == AUTO ||
5562 setup.override_level_sounds == AUTO ||
5563 setup.override_level_music == AUTO)
5564 redefined_ce_found =
5565 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5566 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5567 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5570 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5573 if (redefined_ce_found)
5575 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5576 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5577 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5578 gfx.override_level_music = (setup.override_level_music == TRUE);
5582 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5583 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5584 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5585 gfx.override_level_music = (setup.override_level_music != FALSE);
5589 printf("::: => %d, %d, %d\n",
5590 gfx.override_level_graphics,
5591 gfx.override_level_sounds,
5592 gfx.override_level_music);
5596 static char *getNewArtworkIdentifier(int type)
5598 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5599 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5600 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5601 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5602 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5603 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5604 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5605 char *leveldir_identifier = leveldir_current->identifier;
5606 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5607 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5608 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5609 char *artwork_current_identifier;
5610 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5612 /* leveldir_current may be invalid (level group, parent link) */
5613 if (!validLevelSeries(leveldir_current))
5616 /* 1st step: determine artwork set to be activated in descending order:
5617 --------------------------------------------------------------------
5618 1. setup artwork (when configured to override everything else)
5619 2. artwork set configured in "levelinfo.conf" of current level set
5620 (artwork in level directory will have priority when loading later)
5621 3. artwork in level directory (stored in artwork sub-directory)
5622 4. setup artwork (currently configured in setup menu) */
5624 if (setup_override_artwork)
5625 artwork_current_identifier = setup_artwork_set;
5626 else if (leveldir_artwork_set != NULL)
5627 artwork_current_identifier = leveldir_artwork_set;
5628 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5629 artwork_current_identifier = leveldir_identifier;
5631 artwork_current_identifier = setup_artwork_set;
5634 /* 2nd step: check if it is really needed to reload artwork set
5635 ------------------------------------------------------------ */
5637 /* ---------- reload if level set and also artwork set has changed ------- */
5638 if (leveldir_current_identifier[type] != leveldir_identifier &&
5639 (last_has_level_artwork_set[type] || has_level_artwork_set))
5640 artwork_new_identifier = artwork_current_identifier;
5642 leveldir_current_identifier[type] = leveldir_identifier;
5643 last_has_level_artwork_set[type] = has_level_artwork_set;
5645 /* ---------- reload if "override artwork" setting has changed ----------- */
5646 if (last_override_level_artwork[type] != setup_override_artwork)
5647 artwork_new_identifier = artwork_current_identifier;
5649 last_override_level_artwork[type] = setup_override_artwork;
5651 /* ---------- reload if current artwork identifier has changed ----------- */
5652 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5653 artwork_current_identifier))
5654 artwork_new_identifier = artwork_current_identifier;
5656 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5658 /* ---------- do not reload directly after starting ---------------------- */
5659 if (!initialized[type])
5660 artwork_new_identifier = NULL;
5662 initialized[type] = TRUE;
5664 return artwork_new_identifier;
5667 void ReloadCustomArtwork(int force_reload)
5669 int last_game_status = game_status; /* save current game status */
5670 char *gfx_new_identifier;
5671 char *snd_new_identifier;
5672 char *mus_new_identifier;
5673 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5674 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5675 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5676 boolean reload_needed;
5678 InitOverrideArtwork();
5680 force_reload_gfx |= AdjustGraphicsForEMC();
5682 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5683 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5684 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5686 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5687 snd_new_identifier != NULL || force_reload_snd ||
5688 mus_new_identifier != NULL || force_reload_mus);
5693 print_timestamp_init("ReloadCustomArtwork");
5695 game_status = GAME_MODE_LOADING;
5697 FadeOut(REDRAW_ALL);
5699 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5700 print_timestamp_time("ClearRectangle");
5704 if (gfx_new_identifier != NULL || force_reload_gfx)
5707 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5708 artwork.gfx_current_identifier,
5710 artwork.gfx_current->identifier,
5711 leveldir_current->graphics_set);
5715 print_timestamp_time("InitImages");
5718 if (snd_new_identifier != NULL || force_reload_snd)
5720 InitSound(snd_new_identifier);
5721 print_timestamp_time("InitSound");
5724 if (mus_new_identifier != NULL || force_reload_mus)
5726 InitMusic(mus_new_identifier);
5727 print_timestamp_time("InitMusic");
5730 game_status = last_game_status; /* restore current game status */
5732 init_last = init; /* switch to new busy animation */
5734 FadeOut(REDRAW_ALL);
5736 RedrawGlobalBorder();
5738 /* force redraw of (open or closed) door graphics */
5739 SetDoorState(DOOR_OPEN_ALL);
5740 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5742 FadeSetEnterScreen();
5743 FadeSkipNextFadeOut();
5745 print_timestamp_done("ReloadCustomArtwork");
5747 LimitScreenUpdates(FALSE);
5750 void KeyboardAutoRepeatOffUnlessAutoplay()
5752 if (global.autoplay_leveldir == NULL)
5753 KeyboardAutoRepeatOff();
5756 void DisplayExitMessage(char *format, va_list ap)
5758 // check if draw buffer and fonts for exit message are already available
5759 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5762 int font_1 = FC_RED;
5763 int font_2 = FC_YELLOW;
5764 int font_3 = FC_BLUE;
5765 int font_width = getFontWidth(font_2);
5766 int font_height = getFontHeight(font_2);
5769 int sxsize = WIN_XSIZE - 2 * sx;
5770 int sysize = WIN_YSIZE - 2 * sy;
5771 int line_length = sxsize / font_width;
5772 int max_lines = sysize / font_height;
5773 int num_lines_printed;
5777 gfx.sxsize = sxsize;
5778 gfx.sysize = sysize;
5782 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5784 DrawTextSCentered(sy, font_1, "Fatal error:");
5785 sy += 3 * font_height;;
5788 DrawTextBufferVA(sx, sy, format, ap, font_2,
5789 line_length, line_length, max_lines,
5790 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5791 sy += (num_lines_printed + 3) * font_height;
5793 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5794 sy += 3 * font_height;
5797 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5798 line_length, line_length, max_lines,
5799 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5801 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5803 redraw_mask = REDRAW_ALL;
5805 /* force drawing exit message even if screen updates are currently limited */
5806 LimitScreenUpdates(FALSE);
5810 /* deactivate toons on error message screen */
5811 setup.toons = FALSE;
5813 WaitForEventToContinue();
5817 /* ========================================================================= */
5819 /* ========================================================================= */
5823 print_timestamp_init("OpenAll");
5825 game_status = GAME_MODE_LOADING;
5829 InitGlobal(); /* initialize some global variables */
5831 print_timestamp_time("[init global stuff]");
5835 print_timestamp_time("[init setup/config stuff (1)]");
5837 if (options.execute_command)
5838 Execute_Command(options.execute_command);
5840 if (options.serveronly)
5842 #if defined(PLATFORM_UNIX)
5843 NetworkServer(options.server_port, options.serveronly);
5845 Error(ERR_WARN, "networking only supported in Unix version");
5848 exit(0); /* never reached, server loops forever */
5852 print_timestamp_time("[init setup/config stuff (2)]");
5854 print_timestamp_time("[init setup/config stuff (3)]");
5855 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5856 print_timestamp_time("[init setup/config stuff (4)]");
5857 InitArtworkConfig(); /* needed before forking sound child process */
5858 print_timestamp_time("[init setup/config stuff (5)]");
5860 print_timestamp_time("[init setup/config stuff (6)]");
5862 InitRND(NEW_RANDOMIZE);
5863 InitSimpleRandom(NEW_RANDOMIZE);
5867 print_timestamp_time("[init setup/config stuff]");
5870 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5872 InitEventFilter(FilterEvents);
5874 print_timestamp_time("[init video stuff]");
5876 InitElementPropertiesStatic();
5877 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5878 InitElementPropertiesGfxElement();
5880 print_timestamp_time("[init element properties stuff]");
5884 print_timestamp_time("InitGfx");
5887 print_timestamp_time("InitLevelInfo");
5889 InitLevelArtworkInfo();
5890 print_timestamp_time("InitLevelArtworkInfo");
5892 InitOverrideArtwork(); /* needs to know current level directory */
5893 print_timestamp_time("InitOverrideArtwork");
5895 InitImages(); /* needs to know current level directory */
5896 print_timestamp_time("InitImages");
5898 InitSound(NULL); /* needs to know current level directory */
5899 print_timestamp_time("InitSound");
5901 InitMusic(NULL); /* needs to know current level directory */
5902 print_timestamp_time("InitMusic");
5904 InitGfxBackground();
5909 if (global.autoplay_leveldir)
5914 else if (global.convert_leveldir)
5919 else if (global.create_images_dir)
5921 CreateLevelSketchImages();
5925 game_status = GAME_MODE_MAIN;
5927 FadeSetEnterScreen();
5928 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5929 FadeSkipNextFadeOut();
5931 print_timestamp_time("[post-artwork]");
5933 print_timestamp_done("OpenAll");
5937 InitNetworkServer();
5940 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5942 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5943 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5944 #if defined(PLATFORM_ANDROID)
5945 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5946 SDL_AndroidGetInternalStoragePath());
5947 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5948 SDL_AndroidGetExternalStoragePath());
5949 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5950 (SDL_AndroidGetExternalStorageState() ==
5951 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5952 SDL_AndroidGetExternalStorageState() ==
5953 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5958 void CloseAllAndExit(int exit_value)
5963 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5970 #if defined(TARGET_SDL)
5971 #if defined(TARGET_SDL2)
5973 // set a flag to tell the network server thread to quit and wait for it
5974 // using SDL_WaitThread()
5976 if (network_server) /* terminate network server */
5977 SDL_KillThread(server_thread);
5981 CloseVideoDisplay();
5982 ClosePlatformDependentStuff();
5984 if (exit_value != 0)
5986 /* fall back to default level set (current set may have caused an error) */
5987 SaveLevelSetup_LastSeries_Deactivate();
5989 /* tell user where to find error log file which may contain more details */
5990 // (error notification now directly displayed on screen inside R'n'D
5991 // NotifyUserAboutErrorFile(); /* currently only works for Windows */