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 /* used for toon animations and global animations */
1370 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1372 /* optional graphic for cloning all graphics settings */
1373 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1374 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1376 /* optional settings for drawing title screens and title messages */
1377 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1378 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1379 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1380 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1381 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1382 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1383 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1384 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1385 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1386 g->align = parameter[GFX_ARG_ALIGN];
1387 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1388 g->valign = parameter[GFX_ARG_VALIGN];
1389 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1390 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1392 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1393 g->class = parameter[GFX_ARG_CLASS];
1394 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1395 g->style = parameter[GFX_ARG_STYLE];
1397 /* this is only used for drawing menu buttons and text */
1398 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1399 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1400 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1401 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1404 static void set_graphic_parameters(int graphic)
1406 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1407 char **parameter_raw = image->parameter;
1408 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1409 int parameter[NUM_GFX_ARGS];
1412 /* if fallback to default artwork is done, also use the default parameters */
1413 if (image->fallback_to_default)
1414 parameter_raw = image->default_parameter;
1416 /* get integer values from string parameters */
1417 for (i = 0; i < NUM_GFX_ARGS; i++)
1418 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1419 image_config_suffix[i].token,
1420 image_config_suffix[i].type);
1422 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1424 UPDATE_BUSY_STATE();
1427 static void set_cloned_graphic_parameters(int graphic)
1429 int fallback_graphic = IMG_CHAR_EXCLAM;
1430 int max_num_images = getImageListSize();
1431 int clone_graphic = graphic_info[graphic].clone_from;
1432 int num_references_followed = 1;
1434 while (graphic_info[clone_graphic].clone_from != -1 &&
1435 num_references_followed < max_num_images)
1437 clone_graphic = graphic_info[clone_graphic].clone_from;
1439 num_references_followed++;
1442 if (num_references_followed >= max_num_images)
1444 Error(ERR_INFO_LINE, "-");
1445 Error(ERR_INFO, "warning: error found in config file:");
1446 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1447 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1448 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1449 Error(ERR_INFO, "custom graphic rejected for this element/action");
1451 if (graphic == fallback_graphic)
1452 Error(ERR_EXIT, "no fallback graphic available");
1454 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1455 Error(ERR_INFO_LINE, "-");
1457 graphic_info[graphic] = graphic_info[fallback_graphic];
1461 graphic_info[graphic] = graphic_info[clone_graphic];
1462 graphic_info[graphic].clone_from = clone_graphic;
1466 static void InitGraphicInfo()
1468 int fallback_graphic = IMG_CHAR_EXCLAM;
1469 int num_images = getImageListSize();
1472 /* use image size as default values for width and height for these images */
1473 static int full_size_graphics[] =
1476 IMG_GLOBAL_BORDER_MAIN,
1477 IMG_GLOBAL_BORDER_SCORES,
1478 IMG_GLOBAL_BORDER_EDITOR,
1479 IMG_GLOBAL_BORDER_PLAYING,
1482 IMG_BACKGROUND_ENVELOPE_1,
1483 IMG_BACKGROUND_ENVELOPE_2,
1484 IMG_BACKGROUND_ENVELOPE_3,
1485 IMG_BACKGROUND_ENVELOPE_4,
1486 IMG_BACKGROUND_REQUEST,
1489 IMG_BACKGROUND_TITLE_INITIAL,
1490 IMG_BACKGROUND_TITLE,
1491 IMG_BACKGROUND_MAIN,
1492 IMG_BACKGROUND_LEVELS,
1493 IMG_BACKGROUND_LEVELNR,
1494 IMG_BACKGROUND_SCORES,
1495 IMG_BACKGROUND_EDITOR,
1496 IMG_BACKGROUND_INFO,
1497 IMG_BACKGROUND_INFO_ELEMENTS,
1498 IMG_BACKGROUND_INFO_MUSIC,
1499 IMG_BACKGROUND_INFO_CREDITS,
1500 IMG_BACKGROUND_INFO_PROGRAM,
1501 IMG_BACKGROUND_INFO_VERSION,
1502 IMG_BACKGROUND_INFO_LEVELSET,
1503 IMG_BACKGROUND_SETUP,
1504 IMG_BACKGROUND_PLAYING,
1505 IMG_BACKGROUND_DOOR,
1506 IMG_BACKGROUND_TAPE,
1507 IMG_BACKGROUND_PANEL,
1508 IMG_BACKGROUND_PALETTE,
1509 IMG_BACKGROUND_TOOLBOX,
1511 IMG_TITLESCREEN_INITIAL_1,
1512 IMG_TITLESCREEN_INITIAL_2,
1513 IMG_TITLESCREEN_INITIAL_3,
1514 IMG_TITLESCREEN_INITIAL_4,
1515 IMG_TITLESCREEN_INITIAL_5,
1522 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1523 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1524 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1525 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1526 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1527 IMG_BACKGROUND_TITLEMESSAGE_1,
1528 IMG_BACKGROUND_TITLEMESSAGE_2,
1529 IMG_BACKGROUND_TITLEMESSAGE_3,
1530 IMG_BACKGROUND_TITLEMESSAGE_4,
1531 IMG_BACKGROUND_TITLEMESSAGE_5,
1536 checked_free(graphic_info);
1538 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1540 /* initialize "use_image_size" flag with default value */
1541 for (i = 0; i < num_images; i++)
1542 graphic_info[i].use_image_size = FALSE;
1544 /* initialize "use_image_size" flag from static configuration above */
1545 for (i = 0; full_size_graphics[i] != -1; i++)
1546 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1548 /* first set all graphic paramaters ... */
1549 for (i = 0; i < num_images; i++)
1550 set_graphic_parameters(i);
1552 /* ... then copy these parameters for cloned graphics */
1553 for (i = 0; i < num_images; i++)
1554 if (graphic_info[i].clone_from != -1)
1555 set_cloned_graphic_parameters(i);
1557 for (i = 0; i < num_images; i++)
1562 int first_frame, last_frame;
1563 int src_bitmap_width, src_bitmap_height;
1565 /* now check if no animation frames are outside of the loaded image */
1567 if (graphic_info[i].bitmap == NULL)
1568 continue; /* skip check for optional images that are undefined */
1570 /* get image size (this can differ from the standard element tile size!) */
1571 width = graphic_info[i].width;
1572 height = graphic_info[i].height;
1574 /* get final bitmap size (with scaling, but without small images) */
1575 src_bitmap_width = graphic_info[i].src_image_width;
1576 src_bitmap_height = graphic_info[i].src_image_height;
1578 /* check if first animation frame is inside specified bitmap */
1581 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1583 /* this avoids calculating wrong start position for out-of-bounds frame */
1584 src_x = graphic_info[i].src_x;
1585 src_y = graphic_info[i].src_y;
1587 if (src_x < 0 || src_y < 0 ||
1588 src_x + width > src_bitmap_width ||
1589 src_y + height > src_bitmap_height)
1591 Error(ERR_INFO_LINE, "-");
1592 Error(ERR_INFO, "warning: error found in config file:");
1593 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1594 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1595 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1597 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1598 src_x, src_y, src_bitmap_width, src_bitmap_height);
1599 Error(ERR_INFO, "custom graphic rejected for this element/action");
1601 if (i == fallback_graphic)
1602 Error(ERR_EXIT, "no fallback graphic available");
1604 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1605 Error(ERR_INFO_LINE, "-");
1607 graphic_info[i] = graphic_info[fallback_graphic];
1610 /* check if last animation frame is inside specified bitmap */
1612 last_frame = graphic_info[i].anim_frames - 1;
1613 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1615 if (src_x < 0 || src_y < 0 ||
1616 src_x + width > src_bitmap_width ||
1617 src_y + height > src_bitmap_height)
1619 Error(ERR_INFO_LINE, "-");
1620 Error(ERR_INFO, "warning: error found in config file:");
1621 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1622 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1623 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1625 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1626 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1627 Error(ERR_INFO, "::: %d, %d", width, height);
1628 Error(ERR_INFO, "custom graphic rejected for this element/action");
1630 if (i == fallback_graphic)
1631 Error(ERR_EXIT, "no fallback graphic available");
1633 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1634 Error(ERR_INFO_LINE, "-");
1636 graphic_info[i] = graphic_info[fallback_graphic];
1641 static void InitGraphicCompatibilityInfo()
1643 struct FileInfo *fi_global_door =
1644 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1645 int num_images = getImageListSize();
1648 /* the following compatibility handling is needed for the following case:
1649 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1650 graphics mainly used for door and panel graphics, like editor, tape and
1651 in-game buttons with hard-coded bitmap positions and button sizes; as
1652 these graphics now have individual definitions, redefining "global.door"
1653 to change all these graphics at once like before does not work anymore
1654 (because all those individual definitions still have their default values);
1655 to solve this, remap all those individual definitions that are not
1656 redefined to the new bitmap of "global.door" if it was redefined */
1658 /* special compatibility handling if image "global.door" was redefined */
1659 if (fi_global_door->redefined)
1661 for (i = 0; i < num_images; i++)
1663 struct FileInfo *fi = getImageListEntryFromImageID(i);
1665 /* process only those images that still use the default settings */
1668 /* process all images which default to same image as "global.door" */
1669 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1671 // printf("::: special treatment needed for token '%s'\n", fi->token);
1673 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1679 InitGraphicCompatibilityInfo_Doors();
1682 static void InitElementSoundInfo()
1684 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1685 int num_property_mappings = getSoundListPropertyMappingSize();
1688 /* set values to -1 to identify later as "uninitialized" values */
1689 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1690 for (act = 0; act < NUM_ACTIONS; act++)
1691 element_info[i].sound[act] = -1;
1693 /* initialize element/sound mapping from static configuration */
1694 for (i = 0; element_to_sound[i].element > -1; i++)
1696 int element = element_to_sound[i].element;
1697 int action = element_to_sound[i].action;
1698 int sound = element_to_sound[i].sound;
1699 boolean is_class = element_to_sound[i].is_class;
1702 action = ACTION_DEFAULT;
1705 element_info[element].sound[action] = sound;
1707 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1708 if (strEqual(element_info[j].class_name,
1709 element_info[element].class_name))
1710 element_info[j].sound[action] = sound;
1713 /* initialize element class/sound mapping from dynamic configuration */
1714 for (i = 0; i < num_property_mappings; i++)
1716 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1717 int action = property_mapping[i].ext1_index;
1718 int sound = property_mapping[i].artwork_index;
1720 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1724 action = ACTION_DEFAULT;
1726 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1727 if (strEqual(element_info[j].class_name,
1728 element_info[element_class].class_name))
1729 element_info[j].sound[action] = sound;
1732 /* initialize element/sound mapping from dynamic configuration */
1733 for (i = 0; i < num_property_mappings; i++)
1735 int element = property_mapping[i].base_index;
1736 int action = property_mapping[i].ext1_index;
1737 int sound = property_mapping[i].artwork_index;
1739 if (element >= MAX_NUM_ELEMENTS)
1743 action = ACTION_DEFAULT;
1745 element_info[element].sound[action] = sound;
1748 /* now set all '-1' values to element specific default values */
1749 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1751 for (act = 0; act < NUM_ACTIONS; act++)
1753 /* generic default action sound (defined by "[default]" directive) */
1754 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1756 /* look for special default action sound (classic game specific) */
1757 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1758 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1759 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1760 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1761 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1762 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1764 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1765 /* !!! make this better !!! */
1766 if (i == EL_EMPTY_SPACE)
1767 default_action_sound = element_info[EL_DEFAULT].sound[act];
1769 /* no sound for this specific action -- use default action sound */
1770 if (element_info[i].sound[act] == -1)
1771 element_info[i].sound[act] = default_action_sound;
1775 /* copy sound settings to some elements that are only stored in level file
1776 in native R'n'D levels, but are used by game engine in native EM levels */
1777 for (i = 0; copy_properties[i][0] != -1; i++)
1778 for (j = 1; j <= 4; j++)
1779 for (act = 0; act < NUM_ACTIONS; act++)
1780 element_info[copy_properties[i][j]].sound[act] =
1781 element_info[copy_properties[i][0]].sound[act];
1784 static void InitGameModeSoundInfo()
1788 /* set values to -1 to identify later as "uninitialized" values */
1789 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1792 /* initialize gamemode/sound mapping from static configuration */
1793 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1795 int gamemode = gamemode_to_sound[i].gamemode;
1796 int sound = gamemode_to_sound[i].sound;
1799 gamemode = GAME_MODE_DEFAULT;
1801 menu.sound[gamemode] = sound;
1804 /* now set all '-1' values to levelset specific default values */
1805 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1806 if (menu.sound[i] == -1)
1807 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1810 static void set_sound_parameters(int sound, char **parameter_raw)
1812 int parameter[NUM_SND_ARGS];
1815 /* get integer values from string parameters */
1816 for (i = 0; i < NUM_SND_ARGS; i++)
1818 get_parameter_value(parameter_raw[i],
1819 sound_config_suffix[i].token,
1820 sound_config_suffix[i].type);
1822 /* explicit loop mode setting in configuration overrides default value */
1823 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1824 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1826 /* sound volume to change the original volume when loading the sound file */
1827 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1829 /* sound priority to give certain sounds a higher or lower priority */
1830 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1833 static void InitSoundInfo()
1835 int *sound_effect_properties;
1836 int num_sounds = getSoundListSize();
1839 checked_free(sound_info);
1841 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1842 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1844 /* initialize sound effect for all elements to "no sound" */
1845 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1846 for (j = 0; j < NUM_ACTIONS; j++)
1847 element_info[i].sound[j] = SND_UNDEFINED;
1849 for (i = 0; i < num_sounds; i++)
1851 struct FileInfo *sound = getSoundListEntry(i);
1852 int len_effect_text = strlen(sound->token);
1854 sound_effect_properties[i] = ACTION_OTHER;
1855 sound_info[i].loop = FALSE; /* default: play sound only once */
1857 /* determine all loop sounds and identify certain sound classes */
1859 for (j = 0; element_action_info[j].suffix; j++)
1861 int len_action_text = strlen(element_action_info[j].suffix);
1863 if (len_action_text < len_effect_text &&
1864 strEqual(&sound->token[len_effect_text - len_action_text],
1865 element_action_info[j].suffix))
1867 sound_effect_properties[i] = element_action_info[j].value;
1868 sound_info[i].loop = element_action_info[j].is_loop_sound;
1874 /* associate elements and some selected sound actions */
1876 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1878 if (element_info[j].class_name)
1880 int len_class_text = strlen(element_info[j].class_name);
1882 if (len_class_text + 1 < len_effect_text &&
1883 strncmp(sound->token,
1884 element_info[j].class_name, len_class_text) == 0 &&
1885 sound->token[len_class_text] == '.')
1887 int sound_action_value = sound_effect_properties[i];
1889 element_info[j].sound[sound_action_value] = i;
1894 set_sound_parameters(i, sound->parameter);
1897 free(sound_effect_properties);
1900 static void InitGameModeMusicInfo()
1902 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1903 int num_property_mappings = getMusicListPropertyMappingSize();
1904 int default_levelset_music = -1;
1907 /* set values to -1 to identify later as "uninitialized" values */
1908 for (i = 0; i < MAX_LEVELS; i++)
1909 levelset.music[i] = -1;
1910 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1913 /* initialize gamemode/music mapping from static configuration */
1914 for (i = 0; gamemode_to_music[i].music > -1; i++)
1916 int gamemode = gamemode_to_music[i].gamemode;
1917 int music = gamemode_to_music[i].music;
1920 gamemode = GAME_MODE_DEFAULT;
1922 menu.music[gamemode] = music;
1925 /* initialize gamemode/music mapping from dynamic configuration */
1926 for (i = 0; i < num_property_mappings; i++)
1928 int prefix = property_mapping[i].base_index;
1929 int gamemode = property_mapping[i].ext1_index;
1930 int level = property_mapping[i].ext2_index;
1931 int music = property_mapping[i].artwork_index;
1933 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1937 gamemode = GAME_MODE_DEFAULT;
1939 /* level specific music only allowed for in-game music */
1940 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1941 gamemode = GAME_MODE_PLAYING;
1946 default_levelset_music = music;
1949 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1950 levelset.music[level] = music;
1951 if (gamemode != GAME_MODE_PLAYING)
1952 menu.music[gamemode] = music;
1955 /* now set all '-1' values to menu specific default values */
1956 /* (undefined values of "levelset.music[]" might stay at "-1" to
1957 allow dynamic selection of music files from music directory!) */
1958 for (i = 0; i < MAX_LEVELS; i++)
1959 if (levelset.music[i] == -1)
1960 levelset.music[i] = default_levelset_music;
1961 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1962 if (menu.music[i] == -1)
1963 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1966 static void set_music_parameters(int music, char **parameter_raw)
1968 int parameter[NUM_MUS_ARGS];
1971 /* get integer values from string parameters */
1972 for (i = 0; i < NUM_MUS_ARGS; i++)
1974 get_parameter_value(parameter_raw[i],
1975 music_config_suffix[i].token,
1976 music_config_suffix[i].type);
1978 /* explicit loop mode setting in configuration overrides default value */
1979 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1980 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1983 static void InitMusicInfo()
1985 int num_music = getMusicListSize();
1988 checked_free(music_info);
1990 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1992 for (i = 0; i < num_music; i++)
1994 struct FileInfo *music = getMusicListEntry(i);
1995 int len_music_text = strlen(music->token);
1997 music_info[i].loop = TRUE; /* default: play music in loop mode */
1999 /* determine all loop music */
2001 for (j = 0; music_prefix_info[j].prefix; j++)
2003 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2005 if (len_prefix_text < len_music_text &&
2006 strncmp(music->token,
2007 music_prefix_info[j].prefix, len_prefix_text) == 0)
2009 music_info[i].loop = music_prefix_info[j].is_loop_music;
2015 set_music_parameters(i, music->parameter);
2019 static void ReinitializeGraphics()
2021 print_timestamp_init("ReinitializeGraphics");
2023 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2025 InitGraphicInfo(); /* graphic properties mapping */
2026 print_timestamp_time("InitGraphicInfo");
2027 InitElementGraphicInfo(); /* element game graphic mapping */
2028 print_timestamp_time("InitElementGraphicInfo");
2029 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2030 print_timestamp_time("InitElementSpecialGraphicInfo");
2032 InitElementSmallImages(); /* scale elements to all needed sizes */
2033 print_timestamp_time("InitElementSmallImages");
2034 InitScaledImages(); /* scale all other images, if needed */
2035 print_timestamp_time("InitScaledImages");
2036 InitBitmapPointers(); /* set standard size bitmap pointers */
2037 print_timestamp_time("InitBitmapPointers");
2038 InitFontGraphicInfo(); /* initialize text drawing functions */
2039 print_timestamp_time("InitFontGraphicInfo");
2040 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2041 print_timestamp_time("InitGlobalAnimGraphicInfo");
2043 InitImageTextures(); /* create textures for certain images */
2044 print_timestamp_time("InitImageTextures");
2046 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2047 print_timestamp_time("InitGraphicInfo_EM");
2049 InitGraphicCompatibilityInfo();
2050 print_timestamp_time("InitGraphicCompatibilityInfo");
2052 SetMainBackgroundImage(IMG_BACKGROUND);
2053 print_timestamp_time("SetMainBackgroundImage");
2054 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2055 print_timestamp_time("SetDoorBackgroundImage");
2058 print_timestamp_time("InitGadgets");
2060 print_timestamp_time("InitToons");
2062 print_timestamp_time("InitDoors");
2064 print_timestamp_done("ReinitializeGraphics");
2067 static void ReinitializeSounds()
2069 InitSoundInfo(); /* sound properties mapping */
2070 InitElementSoundInfo(); /* element game sound mapping */
2071 InitGameModeSoundInfo(); /* game mode sound mapping */
2073 InitPlayLevelSound(); /* internal game sound settings */
2076 static void ReinitializeMusic()
2078 InitMusicInfo(); /* music properties mapping */
2079 InitGameModeMusicInfo(); /* game mode music mapping */
2082 static int get_special_property_bit(int element, int property_bit_nr)
2084 struct PropertyBitInfo
2090 static struct PropertyBitInfo pb_can_move_into_acid[] =
2092 /* the player may be able fall into acid when gravity is activated */
2097 { EL_SP_MURPHY, 0 },
2098 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2100 /* all elements that can move may be able to also move into acid */
2103 { EL_BUG_RIGHT, 1 },
2106 { EL_SPACESHIP, 2 },
2107 { EL_SPACESHIP_LEFT, 2 },
2108 { EL_SPACESHIP_RIGHT, 2 },
2109 { EL_SPACESHIP_UP, 2 },
2110 { EL_SPACESHIP_DOWN, 2 },
2111 { EL_BD_BUTTERFLY, 3 },
2112 { EL_BD_BUTTERFLY_LEFT, 3 },
2113 { EL_BD_BUTTERFLY_RIGHT, 3 },
2114 { EL_BD_BUTTERFLY_UP, 3 },
2115 { EL_BD_BUTTERFLY_DOWN, 3 },
2116 { EL_BD_FIREFLY, 4 },
2117 { EL_BD_FIREFLY_LEFT, 4 },
2118 { EL_BD_FIREFLY_RIGHT, 4 },
2119 { EL_BD_FIREFLY_UP, 4 },
2120 { EL_BD_FIREFLY_DOWN, 4 },
2122 { EL_YAMYAM_LEFT, 5 },
2123 { EL_YAMYAM_RIGHT, 5 },
2124 { EL_YAMYAM_UP, 5 },
2125 { EL_YAMYAM_DOWN, 5 },
2126 { EL_DARK_YAMYAM, 6 },
2129 { EL_PACMAN_LEFT, 8 },
2130 { EL_PACMAN_RIGHT, 8 },
2131 { EL_PACMAN_UP, 8 },
2132 { EL_PACMAN_DOWN, 8 },
2134 { EL_MOLE_LEFT, 9 },
2135 { EL_MOLE_RIGHT, 9 },
2137 { EL_MOLE_DOWN, 9 },
2141 { EL_SATELLITE, 13 },
2142 { EL_SP_SNIKSNAK, 14 },
2143 { EL_SP_ELECTRON, 15 },
2146 { EL_EMC_ANDROID, 18 },
2151 static struct PropertyBitInfo pb_dont_collide_with[] =
2153 { EL_SP_SNIKSNAK, 0 },
2154 { EL_SP_ELECTRON, 1 },
2162 struct PropertyBitInfo *pb_info;
2165 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2166 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2171 struct PropertyBitInfo *pb_info = NULL;
2174 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2175 if (pb_definition[i].bit_nr == property_bit_nr)
2176 pb_info = pb_definition[i].pb_info;
2178 if (pb_info == NULL)
2181 for (i = 0; pb_info[i].element != -1; i++)
2182 if (pb_info[i].element == element)
2183 return pb_info[i].bit_nr;
2188 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2189 boolean property_value)
2191 int bit_nr = get_special_property_bit(element, property_bit_nr);
2196 *bitfield |= (1 << bit_nr);
2198 *bitfield &= ~(1 << bit_nr);
2202 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2204 int bit_nr = get_special_property_bit(element, property_bit_nr);
2207 return ((*bitfield & (1 << bit_nr)) != 0);
2212 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2214 static int group_nr;
2215 static struct ElementGroupInfo *group;
2216 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2219 if (actual_group == NULL) /* not yet initialized */
2222 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2224 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2225 group_element - EL_GROUP_START + 1);
2227 /* replace element which caused too deep recursion by question mark */
2228 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2233 if (recursion_depth == 0) /* initialization */
2235 group = actual_group;
2236 group_nr = GROUP_NR(group_element);
2238 group->num_elements_resolved = 0;
2239 group->choice_pos = 0;
2241 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2242 element_info[i].in_group[group_nr] = FALSE;
2245 for (i = 0; i < actual_group->num_elements; i++)
2247 int element = actual_group->element[i];
2249 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2252 if (IS_GROUP_ELEMENT(element))
2253 ResolveGroupElementExt(element, recursion_depth + 1);
2256 group->element_resolved[group->num_elements_resolved++] = element;
2257 element_info[element].in_group[group_nr] = TRUE;
2262 void ResolveGroupElement(int group_element)
2264 ResolveGroupElementExt(group_element, 0);
2267 void InitElementPropertiesStatic()
2269 static boolean clipboard_elements_initialized = FALSE;
2271 static int ep_diggable[] =
2276 EL_SP_BUGGY_BASE_ACTIVATING,
2279 EL_INVISIBLE_SAND_ACTIVE,
2282 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2283 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2288 EL_SP_BUGGY_BASE_ACTIVE,
2295 static int ep_collectible_only[] =
2317 EL_DYNABOMB_INCREASE_NUMBER,
2318 EL_DYNABOMB_INCREASE_SIZE,
2319 EL_DYNABOMB_INCREASE_POWER,
2337 /* !!! handle separately !!! */
2338 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2344 static int ep_dont_run_into[] =
2346 /* same elements as in 'ep_dont_touch' */
2352 /* same elements as in 'ep_dont_collide_with' */
2364 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2369 EL_SP_BUGGY_BASE_ACTIVE,
2376 static int ep_dont_collide_with[] =
2378 /* same elements as in 'ep_dont_touch' */
2395 static int ep_dont_touch[] =
2405 static int ep_indestructible[] =
2409 EL_ACID_POOL_TOPLEFT,
2410 EL_ACID_POOL_TOPRIGHT,
2411 EL_ACID_POOL_BOTTOMLEFT,
2412 EL_ACID_POOL_BOTTOM,
2413 EL_ACID_POOL_BOTTOMRIGHT,
2414 EL_SP_HARDWARE_GRAY,
2415 EL_SP_HARDWARE_GREEN,
2416 EL_SP_HARDWARE_BLUE,
2418 EL_SP_HARDWARE_YELLOW,
2419 EL_SP_HARDWARE_BASE_1,
2420 EL_SP_HARDWARE_BASE_2,
2421 EL_SP_HARDWARE_BASE_3,
2422 EL_SP_HARDWARE_BASE_4,
2423 EL_SP_HARDWARE_BASE_5,
2424 EL_SP_HARDWARE_BASE_6,
2425 EL_INVISIBLE_STEELWALL,
2426 EL_INVISIBLE_STEELWALL_ACTIVE,
2427 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2428 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2429 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2430 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2431 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2432 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2433 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2434 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2435 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2436 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2437 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2438 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2440 EL_LIGHT_SWITCH_ACTIVE,
2441 EL_SIGN_EXCLAMATION,
2442 EL_SIGN_RADIOACTIVITY,
2449 EL_SIGN_ENTRY_FORBIDDEN,
2450 EL_SIGN_EMERGENCY_EXIT,
2458 EL_STEEL_EXIT_CLOSED,
2460 EL_STEEL_EXIT_OPENING,
2461 EL_STEEL_EXIT_CLOSING,
2462 EL_EM_STEEL_EXIT_CLOSED,
2463 EL_EM_STEEL_EXIT_OPEN,
2464 EL_EM_STEEL_EXIT_OPENING,
2465 EL_EM_STEEL_EXIT_CLOSING,
2466 EL_DC_STEELWALL_1_LEFT,
2467 EL_DC_STEELWALL_1_RIGHT,
2468 EL_DC_STEELWALL_1_TOP,
2469 EL_DC_STEELWALL_1_BOTTOM,
2470 EL_DC_STEELWALL_1_HORIZONTAL,
2471 EL_DC_STEELWALL_1_VERTICAL,
2472 EL_DC_STEELWALL_1_TOPLEFT,
2473 EL_DC_STEELWALL_1_TOPRIGHT,
2474 EL_DC_STEELWALL_1_BOTTOMLEFT,
2475 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2476 EL_DC_STEELWALL_1_TOPLEFT_2,
2477 EL_DC_STEELWALL_1_TOPRIGHT_2,
2478 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2479 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2480 EL_DC_STEELWALL_2_LEFT,
2481 EL_DC_STEELWALL_2_RIGHT,
2482 EL_DC_STEELWALL_2_TOP,
2483 EL_DC_STEELWALL_2_BOTTOM,
2484 EL_DC_STEELWALL_2_HORIZONTAL,
2485 EL_DC_STEELWALL_2_VERTICAL,
2486 EL_DC_STEELWALL_2_MIDDLE,
2487 EL_DC_STEELWALL_2_SINGLE,
2488 EL_STEELWALL_SLIPPERY,
2502 EL_GATE_1_GRAY_ACTIVE,
2503 EL_GATE_2_GRAY_ACTIVE,
2504 EL_GATE_3_GRAY_ACTIVE,
2505 EL_GATE_4_GRAY_ACTIVE,
2514 EL_EM_GATE_1_GRAY_ACTIVE,
2515 EL_EM_GATE_2_GRAY_ACTIVE,
2516 EL_EM_GATE_3_GRAY_ACTIVE,
2517 EL_EM_GATE_4_GRAY_ACTIVE,
2526 EL_EMC_GATE_5_GRAY_ACTIVE,
2527 EL_EMC_GATE_6_GRAY_ACTIVE,
2528 EL_EMC_GATE_7_GRAY_ACTIVE,
2529 EL_EMC_GATE_8_GRAY_ACTIVE,
2531 EL_DC_GATE_WHITE_GRAY,
2532 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2533 EL_DC_GATE_FAKE_GRAY,
2535 EL_SWITCHGATE_OPENING,
2536 EL_SWITCHGATE_CLOSED,
2537 EL_SWITCHGATE_CLOSING,
2538 EL_DC_SWITCHGATE_SWITCH_UP,
2539 EL_DC_SWITCHGATE_SWITCH_DOWN,
2541 EL_TIMEGATE_OPENING,
2543 EL_TIMEGATE_CLOSING,
2544 EL_DC_TIMEGATE_SWITCH,
2545 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2549 EL_TUBE_VERTICAL_LEFT,
2550 EL_TUBE_VERTICAL_RIGHT,
2551 EL_TUBE_HORIZONTAL_UP,
2552 EL_TUBE_HORIZONTAL_DOWN,
2557 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2558 EL_EXPANDABLE_STEELWALL_VERTICAL,
2559 EL_EXPANDABLE_STEELWALL_ANY,
2564 static int ep_slippery[] =
2578 EL_ROBOT_WHEEL_ACTIVE,
2584 EL_ACID_POOL_TOPLEFT,
2585 EL_ACID_POOL_TOPRIGHT,
2595 EL_STEELWALL_SLIPPERY,
2598 EL_EMC_WALL_SLIPPERY_1,
2599 EL_EMC_WALL_SLIPPERY_2,
2600 EL_EMC_WALL_SLIPPERY_3,
2601 EL_EMC_WALL_SLIPPERY_4,
2603 EL_EMC_MAGIC_BALL_ACTIVE,
2608 static int ep_can_change[] =
2613 static int ep_can_move[] =
2615 /* same elements as in 'pb_can_move_into_acid' */
2638 static int ep_can_fall[] =
2652 EL_QUICKSAND_FAST_FULL,
2654 EL_BD_MAGIC_WALL_FULL,
2655 EL_DC_MAGIC_WALL_FULL,
2669 static int ep_can_smash_player[] =
2695 static int ep_can_smash_enemies[] =
2704 static int ep_can_smash_everything[] =
2713 static int ep_explodes_by_fire[] =
2715 /* same elements as in 'ep_explodes_impact' */
2720 /* same elements as in 'ep_explodes_smashed' */
2730 EL_EM_DYNAMITE_ACTIVE,
2731 EL_DYNABOMB_PLAYER_1_ACTIVE,
2732 EL_DYNABOMB_PLAYER_2_ACTIVE,
2733 EL_DYNABOMB_PLAYER_3_ACTIVE,
2734 EL_DYNABOMB_PLAYER_4_ACTIVE,
2735 EL_DYNABOMB_INCREASE_NUMBER,
2736 EL_DYNABOMB_INCREASE_SIZE,
2737 EL_DYNABOMB_INCREASE_POWER,
2738 EL_SP_DISK_RED_ACTIVE,
2752 static int ep_explodes_smashed[] =
2754 /* same elements as in 'ep_explodes_impact' */
2768 static int ep_explodes_impact[] =
2777 static int ep_walkable_over[] =
2781 EL_SOKOBAN_FIELD_EMPTY,
2788 EL_EM_STEEL_EXIT_OPEN,
2789 EL_EM_STEEL_EXIT_OPENING,
2798 EL_GATE_1_GRAY_ACTIVE,
2799 EL_GATE_2_GRAY_ACTIVE,
2800 EL_GATE_3_GRAY_ACTIVE,
2801 EL_GATE_4_GRAY_ACTIVE,
2809 static int ep_walkable_inside[] =
2814 EL_TUBE_VERTICAL_LEFT,
2815 EL_TUBE_VERTICAL_RIGHT,
2816 EL_TUBE_HORIZONTAL_UP,
2817 EL_TUBE_HORIZONTAL_DOWN,
2826 static int ep_walkable_under[] =
2831 static int ep_passable_over[] =
2841 EL_EM_GATE_1_GRAY_ACTIVE,
2842 EL_EM_GATE_2_GRAY_ACTIVE,
2843 EL_EM_GATE_3_GRAY_ACTIVE,
2844 EL_EM_GATE_4_GRAY_ACTIVE,
2853 EL_EMC_GATE_5_GRAY_ACTIVE,
2854 EL_EMC_GATE_6_GRAY_ACTIVE,
2855 EL_EMC_GATE_7_GRAY_ACTIVE,
2856 EL_EMC_GATE_8_GRAY_ACTIVE,
2858 EL_DC_GATE_WHITE_GRAY,
2859 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2866 static int ep_passable_inside[] =
2872 EL_SP_PORT_HORIZONTAL,
2873 EL_SP_PORT_VERTICAL,
2875 EL_SP_GRAVITY_PORT_LEFT,
2876 EL_SP_GRAVITY_PORT_RIGHT,
2877 EL_SP_GRAVITY_PORT_UP,
2878 EL_SP_GRAVITY_PORT_DOWN,
2879 EL_SP_GRAVITY_ON_PORT_LEFT,
2880 EL_SP_GRAVITY_ON_PORT_RIGHT,
2881 EL_SP_GRAVITY_ON_PORT_UP,
2882 EL_SP_GRAVITY_ON_PORT_DOWN,
2883 EL_SP_GRAVITY_OFF_PORT_LEFT,
2884 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2885 EL_SP_GRAVITY_OFF_PORT_UP,
2886 EL_SP_GRAVITY_OFF_PORT_DOWN,
2891 static int ep_passable_under[] =
2896 static int ep_droppable[] =
2901 static int ep_explodes_1x1_old[] =
2906 static int ep_pushable[] =
2918 EL_SOKOBAN_FIELD_FULL,
2927 static int ep_explodes_cross_old[] =
2932 static int ep_protected[] =
2934 /* same elements as in 'ep_walkable_inside' */
2938 EL_TUBE_VERTICAL_LEFT,
2939 EL_TUBE_VERTICAL_RIGHT,
2940 EL_TUBE_HORIZONTAL_UP,
2941 EL_TUBE_HORIZONTAL_DOWN,
2947 /* same elements as in 'ep_passable_over' */
2956 EL_EM_GATE_1_GRAY_ACTIVE,
2957 EL_EM_GATE_2_GRAY_ACTIVE,
2958 EL_EM_GATE_3_GRAY_ACTIVE,
2959 EL_EM_GATE_4_GRAY_ACTIVE,
2968 EL_EMC_GATE_5_GRAY_ACTIVE,
2969 EL_EMC_GATE_6_GRAY_ACTIVE,
2970 EL_EMC_GATE_7_GRAY_ACTIVE,
2971 EL_EMC_GATE_8_GRAY_ACTIVE,
2973 EL_DC_GATE_WHITE_GRAY,
2974 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2978 /* same elements as in 'ep_passable_inside' */
2983 EL_SP_PORT_HORIZONTAL,
2984 EL_SP_PORT_VERTICAL,
2986 EL_SP_GRAVITY_PORT_LEFT,
2987 EL_SP_GRAVITY_PORT_RIGHT,
2988 EL_SP_GRAVITY_PORT_UP,
2989 EL_SP_GRAVITY_PORT_DOWN,
2990 EL_SP_GRAVITY_ON_PORT_LEFT,
2991 EL_SP_GRAVITY_ON_PORT_RIGHT,
2992 EL_SP_GRAVITY_ON_PORT_UP,
2993 EL_SP_GRAVITY_ON_PORT_DOWN,
2994 EL_SP_GRAVITY_OFF_PORT_LEFT,
2995 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2996 EL_SP_GRAVITY_OFF_PORT_UP,
2997 EL_SP_GRAVITY_OFF_PORT_DOWN,
3002 static int ep_throwable[] =
3007 static int ep_can_explode[] =
3009 /* same elements as in 'ep_explodes_impact' */
3014 /* same elements as in 'ep_explodes_smashed' */
3020 /* elements that can explode by explosion or by dragonfire */
3024 EL_EM_DYNAMITE_ACTIVE,
3025 EL_DYNABOMB_PLAYER_1_ACTIVE,
3026 EL_DYNABOMB_PLAYER_2_ACTIVE,
3027 EL_DYNABOMB_PLAYER_3_ACTIVE,
3028 EL_DYNABOMB_PLAYER_4_ACTIVE,
3029 EL_DYNABOMB_INCREASE_NUMBER,
3030 EL_DYNABOMB_INCREASE_SIZE,
3031 EL_DYNABOMB_INCREASE_POWER,
3032 EL_SP_DISK_RED_ACTIVE,
3040 /* elements that can explode only by explosion */
3046 static int ep_gravity_reachable[] =
3052 EL_INVISIBLE_SAND_ACTIVE,
3057 EL_SP_PORT_HORIZONTAL,
3058 EL_SP_PORT_VERTICAL,
3060 EL_SP_GRAVITY_PORT_LEFT,
3061 EL_SP_GRAVITY_PORT_RIGHT,
3062 EL_SP_GRAVITY_PORT_UP,
3063 EL_SP_GRAVITY_PORT_DOWN,
3064 EL_SP_GRAVITY_ON_PORT_LEFT,
3065 EL_SP_GRAVITY_ON_PORT_RIGHT,
3066 EL_SP_GRAVITY_ON_PORT_UP,
3067 EL_SP_GRAVITY_ON_PORT_DOWN,
3068 EL_SP_GRAVITY_OFF_PORT_LEFT,
3069 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3070 EL_SP_GRAVITY_OFF_PORT_UP,
3071 EL_SP_GRAVITY_OFF_PORT_DOWN,
3077 static int ep_player[] =
3084 EL_SOKOBAN_FIELD_PLAYER,
3090 static int ep_can_pass_magic_wall[] =
3104 static int ep_can_pass_dc_magic_wall[] =
3120 static int ep_switchable[] =
3124 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3125 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3126 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3127 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3128 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3129 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3130 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3131 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3132 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3133 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3134 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3135 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3136 EL_SWITCHGATE_SWITCH_UP,
3137 EL_SWITCHGATE_SWITCH_DOWN,
3138 EL_DC_SWITCHGATE_SWITCH_UP,
3139 EL_DC_SWITCHGATE_SWITCH_DOWN,
3141 EL_LIGHT_SWITCH_ACTIVE,
3143 EL_DC_TIMEGATE_SWITCH,
3144 EL_BALLOON_SWITCH_LEFT,
3145 EL_BALLOON_SWITCH_RIGHT,
3146 EL_BALLOON_SWITCH_UP,
3147 EL_BALLOON_SWITCH_DOWN,
3148 EL_BALLOON_SWITCH_ANY,
3149 EL_BALLOON_SWITCH_NONE,
3152 EL_EMC_MAGIC_BALL_SWITCH,
3153 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3158 static int ep_bd_element[] =
3192 static int ep_sp_element[] =
3194 /* should always be valid */
3197 /* standard classic Supaplex elements */
3204 EL_SP_HARDWARE_GRAY,
3212 EL_SP_GRAVITY_PORT_RIGHT,
3213 EL_SP_GRAVITY_PORT_DOWN,
3214 EL_SP_GRAVITY_PORT_LEFT,
3215 EL_SP_GRAVITY_PORT_UP,
3220 EL_SP_PORT_VERTICAL,
3221 EL_SP_PORT_HORIZONTAL,
3227 EL_SP_HARDWARE_BASE_1,
3228 EL_SP_HARDWARE_GREEN,
3229 EL_SP_HARDWARE_BLUE,
3231 EL_SP_HARDWARE_YELLOW,
3232 EL_SP_HARDWARE_BASE_2,
3233 EL_SP_HARDWARE_BASE_3,
3234 EL_SP_HARDWARE_BASE_4,
3235 EL_SP_HARDWARE_BASE_5,
3236 EL_SP_HARDWARE_BASE_6,
3240 /* additional elements that appeared in newer Supaplex levels */
3243 /* additional gravity port elements (not switching, but setting gravity) */
3244 EL_SP_GRAVITY_ON_PORT_LEFT,
3245 EL_SP_GRAVITY_ON_PORT_RIGHT,
3246 EL_SP_GRAVITY_ON_PORT_UP,
3247 EL_SP_GRAVITY_ON_PORT_DOWN,
3248 EL_SP_GRAVITY_OFF_PORT_LEFT,
3249 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3250 EL_SP_GRAVITY_OFF_PORT_UP,
3251 EL_SP_GRAVITY_OFF_PORT_DOWN,
3253 /* more than one Murphy in a level results in an inactive clone */
3256 /* runtime Supaplex elements */
3257 EL_SP_DISK_RED_ACTIVE,
3258 EL_SP_TERMINAL_ACTIVE,
3259 EL_SP_BUGGY_BASE_ACTIVATING,
3260 EL_SP_BUGGY_BASE_ACTIVE,
3267 static int ep_sb_element[] =
3272 EL_SOKOBAN_FIELD_EMPTY,
3273 EL_SOKOBAN_FIELD_FULL,
3274 EL_SOKOBAN_FIELD_PLAYER,
3279 EL_INVISIBLE_STEELWALL,
3284 static int ep_gem[] =
3296 static int ep_food_dark_yamyam[] =
3324 static int ep_food_penguin[] =
3338 static int ep_food_pig[] =
3350 static int ep_historic_wall[] =
3361 EL_GATE_1_GRAY_ACTIVE,
3362 EL_GATE_2_GRAY_ACTIVE,
3363 EL_GATE_3_GRAY_ACTIVE,
3364 EL_GATE_4_GRAY_ACTIVE,
3373 EL_EM_GATE_1_GRAY_ACTIVE,
3374 EL_EM_GATE_2_GRAY_ACTIVE,
3375 EL_EM_GATE_3_GRAY_ACTIVE,
3376 EL_EM_GATE_4_GRAY_ACTIVE,
3383 EL_EXPANDABLE_WALL_HORIZONTAL,
3384 EL_EXPANDABLE_WALL_VERTICAL,
3385 EL_EXPANDABLE_WALL_ANY,
3386 EL_EXPANDABLE_WALL_GROWING,
3387 EL_BD_EXPANDABLE_WALL,
3394 EL_SP_HARDWARE_GRAY,
3395 EL_SP_HARDWARE_GREEN,
3396 EL_SP_HARDWARE_BLUE,
3398 EL_SP_HARDWARE_YELLOW,
3399 EL_SP_HARDWARE_BASE_1,
3400 EL_SP_HARDWARE_BASE_2,
3401 EL_SP_HARDWARE_BASE_3,
3402 EL_SP_HARDWARE_BASE_4,
3403 EL_SP_HARDWARE_BASE_5,
3404 EL_SP_HARDWARE_BASE_6,
3406 EL_SP_TERMINAL_ACTIVE,
3409 EL_INVISIBLE_STEELWALL,
3410 EL_INVISIBLE_STEELWALL_ACTIVE,
3412 EL_INVISIBLE_WALL_ACTIVE,
3413 EL_STEELWALL_SLIPPERY,
3430 static int ep_historic_solid[] =
3434 EL_EXPANDABLE_WALL_HORIZONTAL,
3435 EL_EXPANDABLE_WALL_VERTICAL,
3436 EL_EXPANDABLE_WALL_ANY,
3437 EL_BD_EXPANDABLE_WALL,
3450 EL_QUICKSAND_FILLING,
3451 EL_QUICKSAND_EMPTYING,
3453 EL_MAGIC_WALL_ACTIVE,
3454 EL_MAGIC_WALL_EMPTYING,
3455 EL_MAGIC_WALL_FILLING,
3459 EL_BD_MAGIC_WALL_ACTIVE,
3460 EL_BD_MAGIC_WALL_EMPTYING,
3461 EL_BD_MAGIC_WALL_FULL,
3462 EL_BD_MAGIC_WALL_FILLING,
3463 EL_BD_MAGIC_WALL_DEAD,
3472 EL_SP_TERMINAL_ACTIVE,
3476 EL_INVISIBLE_WALL_ACTIVE,
3477 EL_SWITCHGATE_SWITCH_UP,
3478 EL_SWITCHGATE_SWITCH_DOWN,
3479 EL_DC_SWITCHGATE_SWITCH_UP,
3480 EL_DC_SWITCHGATE_SWITCH_DOWN,
3482 EL_TIMEGATE_SWITCH_ACTIVE,
3483 EL_DC_TIMEGATE_SWITCH,
3484 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3496 /* the following elements are a direct copy of "indestructible" elements,
3497 except "EL_ACID", which is "indestructible", but not "solid"! */
3502 EL_ACID_POOL_TOPLEFT,
3503 EL_ACID_POOL_TOPRIGHT,
3504 EL_ACID_POOL_BOTTOMLEFT,
3505 EL_ACID_POOL_BOTTOM,
3506 EL_ACID_POOL_BOTTOMRIGHT,
3507 EL_SP_HARDWARE_GRAY,
3508 EL_SP_HARDWARE_GREEN,
3509 EL_SP_HARDWARE_BLUE,
3511 EL_SP_HARDWARE_YELLOW,
3512 EL_SP_HARDWARE_BASE_1,
3513 EL_SP_HARDWARE_BASE_2,
3514 EL_SP_HARDWARE_BASE_3,
3515 EL_SP_HARDWARE_BASE_4,
3516 EL_SP_HARDWARE_BASE_5,
3517 EL_SP_HARDWARE_BASE_6,
3518 EL_INVISIBLE_STEELWALL,
3519 EL_INVISIBLE_STEELWALL_ACTIVE,
3520 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3521 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3522 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3523 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3524 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3525 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3526 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3527 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3528 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3529 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3530 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3531 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3533 EL_LIGHT_SWITCH_ACTIVE,
3534 EL_SIGN_EXCLAMATION,
3535 EL_SIGN_RADIOACTIVITY,
3542 EL_SIGN_ENTRY_FORBIDDEN,
3543 EL_SIGN_EMERGENCY_EXIT,
3551 EL_STEEL_EXIT_CLOSED,
3553 EL_DC_STEELWALL_1_LEFT,
3554 EL_DC_STEELWALL_1_RIGHT,
3555 EL_DC_STEELWALL_1_TOP,
3556 EL_DC_STEELWALL_1_BOTTOM,
3557 EL_DC_STEELWALL_1_HORIZONTAL,
3558 EL_DC_STEELWALL_1_VERTICAL,
3559 EL_DC_STEELWALL_1_TOPLEFT,
3560 EL_DC_STEELWALL_1_TOPRIGHT,
3561 EL_DC_STEELWALL_1_BOTTOMLEFT,
3562 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3563 EL_DC_STEELWALL_1_TOPLEFT_2,
3564 EL_DC_STEELWALL_1_TOPRIGHT_2,
3565 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3566 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3567 EL_DC_STEELWALL_2_LEFT,
3568 EL_DC_STEELWALL_2_RIGHT,
3569 EL_DC_STEELWALL_2_TOP,
3570 EL_DC_STEELWALL_2_BOTTOM,
3571 EL_DC_STEELWALL_2_HORIZONTAL,
3572 EL_DC_STEELWALL_2_VERTICAL,
3573 EL_DC_STEELWALL_2_MIDDLE,
3574 EL_DC_STEELWALL_2_SINGLE,
3575 EL_STEELWALL_SLIPPERY,
3589 EL_GATE_1_GRAY_ACTIVE,
3590 EL_GATE_2_GRAY_ACTIVE,
3591 EL_GATE_3_GRAY_ACTIVE,
3592 EL_GATE_4_GRAY_ACTIVE,
3601 EL_EM_GATE_1_GRAY_ACTIVE,
3602 EL_EM_GATE_2_GRAY_ACTIVE,
3603 EL_EM_GATE_3_GRAY_ACTIVE,
3604 EL_EM_GATE_4_GRAY_ACTIVE,
3606 EL_SWITCHGATE_OPENING,
3607 EL_SWITCHGATE_CLOSED,
3608 EL_SWITCHGATE_CLOSING,
3610 EL_TIMEGATE_OPENING,
3612 EL_TIMEGATE_CLOSING,
3616 EL_TUBE_VERTICAL_LEFT,
3617 EL_TUBE_VERTICAL_RIGHT,
3618 EL_TUBE_HORIZONTAL_UP,
3619 EL_TUBE_HORIZONTAL_DOWN,
3628 static int ep_classic_enemy[] =
3645 static int ep_belt[] =
3647 EL_CONVEYOR_BELT_1_LEFT,
3648 EL_CONVEYOR_BELT_1_MIDDLE,
3649 EL_CONVEYOR_BELT_1_RIGHT,
3650 EL_CONVEYOR_BELT_2_LEFT,
3651 EL_CONVEYOR_BELT_2_MIDDLE,
3652 EL_CONVEYOR_BELT_2_RIGHT,
3653 EL_CONVEYOR_BELT_3_LEFT,
3654 EL_CONVEYOR_BELT_3_MIDDLE,
3655 EL_CONVEYOR_BELT_3_RIGHT,
3656 EL_CONVEYOR_BELT_4_LEFT,
3657 EL_CONVEYOR_BELT_4_MIDDLE,
3658 EL_CONVEYOR_BELT_4_RIGHT,
3663 static int ep_belt_active[] =
3665 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3666 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3667 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3668 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3669 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3670 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3671 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3672 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3673 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3674 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3675 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3676 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3681 static int ep_belt_switch[] =
3683 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3684 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3685 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3686 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3687 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3688 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3689 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3690 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3691 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3692 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3693 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3694 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3699 static int ep_tube[] =
3706 EL_TUBE_HORIZONTAL_UP,
3707 EL_TUBE_HORIZONTAL_DOWN,
3709 EL_TUBE_VERTICAL_LEFT,
3710 EL_TUBE_VERTICAL_RIGHT,
3716 static int ep_acid_pool[] =
3718 EL_ACID_POOL_TOPLEFT,
3719 EL_ACID_POOL_TOPRIGHT,
3720 EL_ACID_POOL_BOTTOMLEFT,
3721 EL_ACID_POOL_BOTTOM,
3722 EL_ACID_POOL_BOTTOMRIGHT,
3727 static int ep_keygate[] =
3737 EL_GATE_1_GRAY_ACTIVE,
3738 EL_GATE_2_GRAY_ACTIVE,
3739 EL_GATE_3_GRAY_ACTIVE,
3740 EL_GATE_4_GRAY_ACTIVE,
3749 EL_EM_GATE_1_GRAY_ACTIVE,
3750 EL_EM_GATE_2_GRAY_ACTIVE,
3751 EL_EM_GATE_3_GRAY_ACTIVE,
3752 EL_EM_GATE_4_GRAY_ACTIVE,
3761 EL_EMC_GATE_5_GRAY_ACTIVE,
3762 EL_EMC_GATE_6_GRAY_ACTIVE,
3763 EL_EMC_GATE_7_GRAY_ACTIVE,
3764 EL_EMC_GATE_8_GRAY_ACTIVE,
3766 EL_DC_GATE_WHITE_GRAY,
3767 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3772 static int ep_amoeboid[] =
3784 static int ep_amoebalive[] =
3795 static int ep_has_editor_content[] =
3801 EL_SOKOBAN_FIELD_PLAYER,
3818 static int ep_can_turn_each_move[] =
3820 /* !!! do something with this one !!! */
3824 static int ep_can_grow[] =
3838 static int ep_active_bomb[] =
3841 EL_EM_DYNAMITE_ACTIVE,
3842 EL_DYNABOMB_PLAYER_1_ACTIVE,
3843 EL_DYNABOMB_PLAYER_2_ACTIVE,
3844 EL_DYNABOMB_PLAYER_3_ACTIVE,
3845 EL_DYNABOMB_PLAYER_4_ACTIVE,
3846 EL_SP_DISK_RED_ACTIVE,
3851 static int ep_inactive[] =
3861 EL_QUICKSAND_FAST_EMPTY,
3884 EL_GATE_1_GRAY_ACTIVE,
3885 EL_GATE_2_GRAY_ACTIVE,
3886 EL_GATE_3_GRAY_ACTIVE,
3887 EL_GATE_4_GRAY_ACTIVE,
3896 EL_EM_GATE_1_GRAY_ACTIVE,
3897 EL_EM_GATE_2_GRAY_ACTIVE,
3898 EL_EM_GATE_3_GRAY_ACTIVE,
3899 EL_EM_GATE_4_GRAY_ACTIVE,
3908 EL_EMC_GATE_5_GRAY_ACTIVE,
3909 EL_EMC_GATE_6_GRAY_ACTIVE,
3910 EL_EMC_GATE_7_GRAY_ACTIVE,
3911 EL_EMC_GATE_8_GRAY_ACTIVE,
3913 EL_DC_GATE_WHITE_GRAY,
3914 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3915 EL_DC_GATE_FAKE_GRAY,
3918 EL_INVISIBLE_STEELWALL,
3926 EL_WALL_EMERALD_YELLOW,
3927 EL_DYNABOMB_INCREASE_NUMBER,
3928 EL_DYNABOMB_INCREASE_SIZE,
3929 EL_DYNABOMB_INCREASE_POWER,
3933 EL_SOKOBAN_FIELD_EMPTY,
3934 EL_SOKOBAN_FIELD_FULL,
3935 EL_WALL_EMERALD_RED,
3936 EL_WALL_EMERALD_PURPLE,
3937 EL_ACID_POOL_TOPLEFT,
3938 EL_ACID_POOL_TOPRIGHT,
3939 EL_ACID_POOL_BOTTOMLEFT,
3940 EL_ACID_POOL_BOTTOM,
3941 EL_ACID_POOL_BOTTOMRIGHT,
3945 EL_BD_MAGIC_WALL_DEAD,
3947 EL_DC_MAGIC_WALL_DEAD,
3948 EL_AMOEBA_TO_DIAMOND,
3956 EL_SP_GRAVITY_PORT_RIGHT,
3957 EL_SP_GRAVITY_PORT_DOWN,
3958 EL_SP_GRAVITY_PORT_LEFT,
3959 EL_SP_GRAVITY_PORT_UP,
3960 EL_SP_PORT_HORIZONTAL,
3961 EL_SP_PORT_VERTICAL,
3972 EL_SP_HARDWARE_GRAY,
3973 EL_SP_HARDWARE_GREEN,
3974 EL_SP_HARDWARE_BLUE,
3976 EL_SP_HARDWARE_YELLOW,
3977 EL_SP_HARDWARE_BASE_1,
3978 EL_SP_HARDWARE_BASE_2,
3979 EL_SP_HARDWARE_BASE_3,
3980 EL_SP_HARDWARE_BASE_4,
3981 EL_SP_HARDWARE_BASE_5,
3982 EL_SP_HARDWARE_BASE_6,
3983 EL_SP_GRAVITY_ON_PORT_LEFT,
3984 EL_SP_GRAVITY_ON_PORT_RIGHT,
3985 EL_SP_GRAVITY_ON_PORT_UP,
3986 EL_SP_GRAVITY_ON_PORT_DOWN,
3987 EL_SP_GRAVITY_OFF_PORT_LEFT,
3988 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3989 EL_SP_GRAVITY_OFF_PORT_UP,
3990 EL_SP_GRAVITY_OFF_PORT_DOWN,
3991 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3992 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3993 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3994 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3995 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3996 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3997 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3998 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3999 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4000 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4001 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4002 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4003 EL_SIGN_EXCLAMATION,
4004 EL_SIGN_RADIOACTIVITY,
4011 EL_SIGN_ENTRY_FORBIDDEN,
4012 EL_SIGN_EMERGENCY_EXIT,
4020 EL_DC_STEELWALL_1_LEFT,
4021 EL_DC_STEELWALL_1_RIGHT,
4022 EL_DC_STEELWALL_1_TOP,
4023 EL_DC_STEELWALL_1_BOTTOM,
4024 EL_DC_STEELWALL_1_HORIZONTAL,
4025 EL_DC_STEELWALL_1_VERTICAL,
4026 EL_DC_STEELWALL_1_TOPLEFT,
4027 EL_DC_STEELWALL_1_TOPRIGHT,
4028 EL_DC_STEELWALL_1_BOTTOMLEFT,
4029 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4030 EL_DC_STEELWALL_1_TOPLEFT_2,
4031 EL_DC_STEELWALL_1_TOPRIGHT_2,
4032 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4033 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4034 EL_DC_STEELWALL_2_LEFT,
4035 EL_DC_STEELWALL_2_RIGHT,
4036 EL_DC_STEELWALL_2_TOP,
4037 EL_DC_STEELWALL_2_BOTTOM,
4038 EL_DC_STEELWALL_2_HORIZONTAL,
4039 EL_DC_STEELWALL_2_VERTICAL,
4040 EL_DC_STEELWALL_2_MIDDLE,
4041 EL_DC_STEELWALL_2_SINGLE,
4042 EL_STEELWALL_SLIPPERY,
4047 EL_EMC_WALL_SLIPPERY_1,
4048 EL_EMC_WALL_SLIPPERY_2,
4049 EL_EMC_WALL_SLIPPERY_3,
4050 EL_EMC_WALL_SLIPPERY_4,
4071 static int ep_em_slippery_wall[] =
4076 static int ep_gfx_crumbled[] =
4087 static int ep_editor_cascade_active[] =
4089 EL_INTERNAL_CASCADE_BD_ACTIVE,
4090 EL_INTERNAL_CASCADE_EM_ACTIVE,
4091 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4092 EL_INTERNAL_CASCADE_RND_ACTIVE,
4093 EL_INTERNAL_CASCADE_SB_ACTIVE,
4094 EL_INTERNAL_CASCADE_SP_ACTIVE,
4095 EL_INTERNAL_CASCADE_DC_ACTIVE,
4096 EL_INTERNAL_CASCADE_DX_ACTIVE,
4097 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4098 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4099 EL_INTERNAL_CASCADE_CE_ACTIVE,
4100 EL_INTERNAL_CASCADE_GE_ACTIVE,
4101 EL_INTERNAL_CASCADE_REF_ACTIVE,
4102 EL_INTERNAL_CASCADE_USER_ACTIVE,
4103 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4108 static int ep_editor_cascade_inactive[] =
4110 EL_INTERNAL_CASCADE_BD,
4111 EL_INTERNAL_CASCADE_EM,
4112 EL_INTERNAL_CASCADE_EMC,
4113 EL_INTERNAL_CASCADE_RND,
4114 EL_INTERNAL_CASCADE_SB,
4115 EL_INTERNAL_CASCADE_SP,
4116 EL_INTERNAL_CASCADE_DC,
4117 EL_INTERNAL_CASCADE_DX,
4118 EL_INTERNAL_CASCADE_CHARS,
4119 EL_INTERNAL_CASCADE_STEEL_CHARS,
4120 EL_INTERNAL_CASCADE_CE,
4121 EL_INTERNAL_CASCADE_GE,
4122 EL_INTERNAL_CASCADE_REF,
4123 EL_INTERNAL_CASCADE_USER,
4124 EL_INTERNAL_CASCADE_DYNAMIC,
4129 static int ep_obsolete[] =
4133 EL_EM_KEY_1_FILE_OBSOLETE,
4134 EL_EM_KEY_2_FILE_OBSOLETE,
4135 EL_EM_KEY_3_FILE_OBSOLETE,
4136 EL_EM_KEY_4_FILE_OBSOLETE,
4137 EL_ENVELOPE_OBSOLETE,
4146 } element_properties[] =
4148 { ep_diggable, EP_DIGGABLE },
4149 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4150 { ep_dont_run_into, EP_DONT_RUN_INTO },
4151 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4152 { ep_dont_touch, EP_DONT_TOUCH },
4153 { ep_indestructible, EP_INDESTRUCTIBLE },
4154 { ep_slippery, EP_SLIPPERY },
4155 { ep_can_change, EP_CAN_CHANGE },
4156 { ep_can_move, EP_CAN_MOVE },
4157 { ep_can_fall, EP_CAN_FALL },
4158 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4159 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4160 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4161 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4162 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4163 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4164 { ep_walkable_over, EP_WALKABLE_OVER },
4165 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4166 { ep_walkable_under, EP_WALKABLE_UNDER },
4167 { ep_passable_over, EP_PASSABLE_OVER },
4168 { ep_passable_inside, EP_PASSABLE_INSIDE },
4169 { ep_passable_under, EP_PASSABLE_UNDER },
4170 { ep_droppable, EP_DROPPABLE },
4171 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4172 { ep_pushable, EP_PUSHABLE },
4173 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4174 { ep_protected, EP_PROTECTED },
4175 { ep_throwable, EP_THROWABLE },
4176 { ep_can_explode, EP_CAN_EXPLODE },
4177 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4179 { ep_player, EP_PLAYER },
4180 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4181 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4182 { ep_switchable, EP_SWITCHABLE },
4183 { ep_bd_element, EP_BD_ELEMENT },
4184 { ep_sp_element, EP_SP_ELEMENT },
4185 { ep_sb_element, EP_SB_ELEMENT },
4187 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4188 { ep_food_penguin, EP_FOOD_PENGUIN },
4189 { ep_food_pig, EP_FOOD_PIG },
4190 { ep_historic_wall, EP_HISTORIC_WALL },
4191 { ep_historic_solid, EP_HISTORIC_SOLID },
4192 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4193 { ep_belt, EP_BELT },
4194 { ep_belt_active, EP_BELT_ACTIVE },
4195 { ep_belt_switch, EP_BELT_SWITCH },
4196 { ep_tube, EP_TUBE },
4197 { ep_acid_pool, EP_ACID_POOL },
4198 { ep_keygate, EP_KEYGATE },
4199 { ep_amoeboid, EP_AMOEBOID },
4200 { ep_amoebalive, EP_AMOEBALIVE },
4201 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4202 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4203 { ep_can_grow, EP_CAN_GROW },
4204 { ep_active_bomb, EP_ACTIVE_BOMB },
4205 { ep_inactive, EP_INACTIVE },
4207 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4209 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4211 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4212 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4214 { ep_obsolete, EP_OBSOLETE },
4221 /* always start with reliable default values (element has no properties) */
4222 /* (but never initialize clipboard elements after the very first time) */
4223 /* (to be able to use clipboard elements between several levels) */
4224 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4225 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4226 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4227 SET_PROPERTY(i, j, FALSE);
4229 /* set all base element properties from above array definitions */
4230 for (i = 0; element_properties[i].elements != NULL; i++)
4231 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4232 SET_PROPERTY((element_properties[i].elements)[j],
4233 element_properties[i].property, TRUE);
4235 /* copy properties to some elements that are only stored in level file */
4236 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4237 for (j = 0; copy_properties[j][0] != -1; j++)
4238 if (HAS_PROPERTY(copy_properties[j][0], i))
4239 for (k = 1; k <= 4; k++)
4240 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4242 /* set static element properties that are not listed in array definitions */
4243 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4244 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4246 clipboard_elements_initialized = TRUE;
4249 void InitElementPropertiesEngine(int engine_version)
4251 static int no_wall_properties[] =
4254 EP_COLLECTIBLE_ONLY,
4256 EP_DONT_COLLIDE_WITH,
4259 EP_CAN_SMASH_PLAYER,
4260 EP_CAN_SMASH_ENEMIES,
4261 EP_CAN_SMASH_EVERYTHING,
4266 EP_FOOD_DARK_YAMYAM,
4282 /* important: after initialization in InitElementPropertiesStatic(), the
4283 elements are not again initialized to a default value; therefore all
4284 changes have to make sure that they leave the element with a defined
4285 property (which means that conditional property changes must be set to
4286 a reliable default value before) */
4288 /* resolve group elements */
4289 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4290 ResolveGroupElement(EL_GROUP_START + i);
4292 /* set all special, combined or engine dependent element properties */
4293 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4295 /* do not change (already initialized) clipboard elements here */
4296 if (IS_CLIPBOARD_ELEMENT(i))
4299 /* ---------- INACTIVE ------------------------------------------------- */
4300 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4301 i <= EL_CHAR_END) ||
4302 (i >= EL_STEEL_CHAR_START &&
4303 i <= EL_STEEL_CHAR_END)));
4305 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4306 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4307 IS_WALKABLE_INSIDE(i) ||
4308 IS_WALKABLE_UNDER(i)));
4310 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4311 IS_PASSABLE_INSIDE(i) ||
4312 IS_PASSABLE_UNDER(i)));
4314 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4315 IS_PASSABLE_OVER(i)));
4317 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4318 IS_PASSABLE_INSIDE(i)));
4320 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4321 IS_PASSABLE_UNDER(i)));
4323 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4326 /* ---------- COLLECTIBLE ---------------------------------------------- */
4327 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4331 /* ---------- SNAPPABLE ------------------------------------------------ */
4332 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4333 IS_COLLECTIBLE(i) ||
4337 /* ---------- WALL ----------------------------------------------------- */
4338 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4340 for (j = 0; no_wall_properties[j] != -1; j++)
4341 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4342 i >= EL_FIRST_RUNTIME_UNREAL)
4343 SET_PROPERTY(i, EP_WALL, FALSE);
4345 if (IS_HISTORIC_WALL(i))
4346 SET_PROPERTY(i, EP_WALL, TRUE);
4348 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4349 if (engine_version < VERSION_IDENT(2,2,0,0))
4350 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4352 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4354 !IS_COLLECTIBLE(i)));
4356 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4357 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4358 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4360 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4361 IS_INDESTRUCTIBLE(i)));
4363 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4365 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4366 else if (engine_version < VERSION_IDENT(2,2,0,0))
4367 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4369 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4373 if (IS_CUSTOM_ELEMENT(i))
4375 /* these are additional properties which are initially false when set */
4377 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4379 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4380 if (DONT_COLLIDE_WITH(i))
4381 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4383 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4384 if (CAN_SMASH_EVERYTHING(i))
4385 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4386 if (CAN_SMASH_ENEMIES(i))
4387 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4390 /* ---------- CAN_SMASH ------------------------------------------------ */
4391 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4392 CAN_SMASH_ENEMIES(i) ||
4393 CAN_SMASH_EVERYTHING(i)));
4395 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4396 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4397 EXPLODES_BY_FIRE(i)));
4399 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4400 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4401 EXPLODES_SMASHED(i)));
4403 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4404 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4405 EXPLODES_IMPACT(i)));
4407 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4408 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4410 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4411 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4412 i == EL_BLACK_ORB));
4414 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4415 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4417 IS_CUSTOM_ELEMENT(i)));
4419 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4420 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4421 i == EL_SP_ELECTRON));
4423 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4424 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4425 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4426 getMoveIntoAcidProperty(&level, i));
4428 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4429 if (MAYBE_DONT_COLLIDE_WITH(i))
4430 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4431 getDontCollideWithProperty(&level, i));
4433 /* ---------- SP_PORT -------------------------------------------------- */
4434 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4435 IS_PASSABLE_INSIDE(i)));
4437 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4438 for (j = 0; j < level.num_android_clone_elements; j++)
4439 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4441 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4443 /* ---------- CAN_CHANGE ----------------------------------------------- */
4444 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4445 for (j = 0; j < element_info[i].num_change_pages; j++)
4446 if (element_info[i].change_page[j].can_change)
4447 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4449 /* ---------- HAS_ACTION ----------------------------------------------- */
4450 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4451 for (j = 0; j < element_info[i].num_change_pages; j++)
4452 if (element_info[i].change_page[j].has_action)
4453 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4455 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4456 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4459 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4460 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4461 element_info[i].crumbled[ACTION_DEFAULT] !=
4462 element_info[i].graphic[ACTION_DEFAULT]);
4464 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4465 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4466 IS_EDITOR_CASCADE_INACTIVE(i)));
4469 /* dynamically adjust element properties according to game engine version */
4471 static int ep_em_slippery_wall[] =
4476 EL_EXPANDABLE_WALL_HORIZONTAL,
4477 EL_EXPANDABLE_WALL_VERTICAL,
4478 EL_EXPANDABLE_WALL_ANY,
4479 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4480 EL_EXPANDABLE_STEELWALL_VERTICAL,
4481 EL_EXPANDABLE_STEELWALL_ANY,
4482 EL_EXPANDABLE_STEELWALL_GROWING,
4486 static int ep_em_explodes_by_fire[] =
4489 EL_EM_DYNAMITE_ACTIVE,
4494 /* special EM style gems behaviour */
4495 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4496 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4497 level.em_slippery_gems);
4499 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4500 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4501 (level.em_slippery_gems &&
4502 engine_version > VERSION_IDENT(2,0,1,0)));
4504 /* special EM style explosion behaviour regarding chain reactions */
4505 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4506 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4507 level.em_explodes_by_fire);
4510 /* this is needed because some graphics depend on element properties */
4511 if (game_status == GAME_MODE_PLAYING)
4512 InitElementGraphicInfo();
4515 void InitElementPropertiesAfterLoading(int engine_version)
4519 /* set some other uninitialized values of custom elements in older levels */
4520 if (engine_version < VERSION_IDENT(3,1,0,0))
4522 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4524 int element = EL_CUSTOM_START + i;
4526 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4528 element_info[element].explosion_delay = 17;
4529 element_info[element].ignition_delay = 8;
4534 void InitElementPropertiesGfxElement()
4538 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4540 struct ElementInfo *ei = &element_info[i];
4542 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4546 static void InitGlobal()
4551 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4553 /* check if element_name_info entry defined for each element in "main.h" */
4554 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4555 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4557 element_info[i].token_name = element_name_info[i].token_name;
4558 element_info[i].class_name = element_name_info[i].class_name;
4559 element_info[i].editor_description= element_name_info[i].editor_description;
4562 /* create hash from image config list */
4563 image_config_hash = newSetupFileHash();
4564 for (i = 0; image_config[i].token != NULL; i++)
4565 setHashEntry(image_config_hash,
4566 image_config[i].token,
4567 image_config[i].value);
4569 /* create hash from element token list */
4570 element_token_hash = newSetupFileHash();
4571 for (i = 0; element_name_info[i].token_name != NULL; i++)
4572 setHashEntry(element_token_hash,
4573 element_name_info[i].token_name,
4576 /* create hash from graphic token list */
4577 graphic_token_hash = newSetupFileHash();
4578 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4579 if (strSuffix(image_config[i].value, ".png") ||
4580 strSuffix(image_config[i].value, ".pcx") ||
4581 strSuffix(image_config[i].value, ".wav") ||
4582 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4583 setHashEntry(graphic_token_hash,
4584 image_config[i].token,
4585 int2str(graphic++, 0));
4587 /* create hash from font token list */
4588 font_token_hash = newSetupFileHash();
4589 for (i = 0; font_info[i].token_name != NULL; i++)
4590 setHashEntry(font_token_hash,
4591 font_info[i].token_name,
4594 /* set default filenames for all cloned graphics in static configuration */
4595 for (i = 0; image_config[i].token != NULL; i++)
4597 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4599 char *token = image_config[i].token;
4600 char *token_clone_from = getStringCat2(token, ".clone_from");
4601 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4603 if (token_cloned != NULL)
4605 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4607 if (value_cloned != NULL)
4609 /* set default filename in static configuration */
4610 image_config[i].value = value_cloned;
4612 /* set default filename in image config hash */
4613 setHashEntry(image_config_hash, token, value_cloned);
4617 free(token_clone_from);
4621 /* always start with reliable default values (all elements) */
4622 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4623 ActiveElement[i] = i;
4625 /* now add all entries that have an active state (active elements) */
4626 for (i = 0; element_with_active_state[i].element != -1; i++)
4628 int element = element_with_active_state[i].element;
4629 int element_active = element_with_active_state[i].element_active;
4631 ActiveElement[element] = element_active;
4634 /* always start with reliable default values (all buttons) */
4635 for (i = 0; i < NUM_IMAGE_FILES; i++)
4636 ActiveButton[i] = i;
4638 /* now add all entries that have an active state (active buttons) */
4639 for (i = 0; button_with_active_state[i].button != -1; i++)
4641 int button = button_with_active_state[i].button;
4642 int button_active = button_with_active_state[i].button_active;
4644 ActiveButton[button] = button_active;
4647 /* always start with reliable default values (all fonts) */
4648 for (i = 0; i < NUM_FONTS; i++)
4651 /* now add all entries that have an active state (active fonts) */
4652 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4654 int font = font_with_active_state[i].font_nr;
4655 int font_active = font_with_active_state[i].font_nr_active;
4657 ActiveFont[font] = font_active;
4660 global.autoplay_leveldir = NULL;
4661 global.convert_leveldir = NULL;
4662 global.create_images_dir = NULL;
4664 global.frames_per_second = 0;
4666 global.border_status = GAME_MODE_MAIN;
4668 global.use_envelope_request = FALSE;
4671 void Execute_Command(char *command)
4675 if (strEqual(command, "print graphicsinfo.conf"))
4677 Print("# You can configure additional/alternative image files here.\n");
4678 Print("# (The entries below are default and therefore commented out.)\n");
4680 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4682 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4685 for (i = 0; image_config[i].token != NULL; i++)
4686 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4687 image_config[i].value));
4691 else if (strEqual(command, "print soundsinfo.conf"))
4693 Print("# You can configure additional/alternative sound files here.\n");
4694 Print("# (The entries below are default and therefore commented out.)\n");
4696 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4698 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4701 for (i = 0; sound_config[i].token != NULL; i++)
4702 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4703 sound_config[i].value));
4707 else if (strEqual(command, "print musicinfo.conf"))
4709 Print("# You can configure additional/alternative music files here.\n");
4710 Print("# (The entries below are default and therefore commented out.)\n");
4712 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4714 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4717 for (i = 0; music_config[i].token != NULL; i++)
4718 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4719 music_config[i].value));
4723 else if (strEqual(command, "print editorsetup.conf"))
4725 Print("# You can configure your personal editor element list here.\n");
4726 Print("# (The entries below are default and therefore commented out.)\n");
4729 /* this is needed to be able to check element list for cascade elements */
4730 InitElementPropertiesStatic();
4731 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4733 PrintEditorElementList();
4737 else if (strEqual(command, "print helpanim.conf"))
4739 Print("# You can configure different element help animations here.\n");
4740 Print("# (The entries below are default and therefore commented out.)\n");
4743 for (i = 0; helpanim_config[i].token != NULL; i++)
4745 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4746 helpanim_config[i].value));
4748 if (strEqual(helpanim_config[i].token, "end"))
4754 else if (strEqual(command, "print helptext.conf"))
4756 Print("# You can configure different element help text here.\n");
4757 Print("# (The entries below are default and therefore commented out.)\n");
4760 for (i = 0; helptext_config[i].token != NULL; i++)
4761 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4762 helptext_config[i].value));
4766 else if (strPrefix(command, "dump level "))
4768 char *filename = &command[11];
4770 if (!fileExists(filename))
4771 Error(ERR_EXIT, "cannot open file '%s'", filename);
4773 LoadLevelFromFilename(&level, filename);
4778 else if (strPrefix(command, "dump tape "))
4780 char *filename = &command[10];
4782 if (!fileExists(filename))
4783 Error(ERR_EXIT, "cannot open file '%s'", filename);
4785 LoadTapeFromFilename(filename);
4790 else if (strPrefix(command, "autotest ") ||
4791 strPrefix(command, "autoplay ") ||
4792 strPrefix(command, "autoffwd "))
4794 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4796 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4797 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4798 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4800 while (*str_ptr != '\0') /* continue parsing string */
4802 /* cut leading whitespace from string, replace it by string terminator */
4803 while (*str_ptr == ' ' || *str_ptr == '\t')
4806 if (*str_ptr == '\0') /* end of string reached */
4809 if (global.autoplay_leveldir == NULL) /* read level set string */
4811 global.autoplay_leveldir = str_ptr;
4812 global.autoplay_all = TRUE; /* default: play all tapes */
4814 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4815 global.autoplay_level[i] = FALSE;
4817 else /* read level number string */
4819 int level_nr = atoi(str_ptr); /* get level_nr value */
4821 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4822 global.autoplay_level[level_nr] = TRUE;
4824 global.autoplay_all = FALSE;
4827 /* advance string pointer to the next whitespace (or end of string) */
4828 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4832 else if (strPrefix(command, "convert "))
4834 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4835 char *str_ptr = strchr(str_copy, ' ');
4837 global.convert_leveldir = str_copy;
4838 global.convert_level_nr = -1;
4840 if (str_ptr != NULL) /* level number follows */
4842 *str_ptr++ = '\0'; /* terminate leveldir string */
4843 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4846 else if (strPrefix(command, "create images "))
4848 global.create_images_dir = getStringCopy(&command[14]);
4850 if (access(global.create_images_dir, W_OK) != 0)
4851 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4852 global.create_images_dir);
4854 else if (strPrefix(command, "create CE image "))
4856 CreateCustomElementImages(&command[16]);
4862 #if defined(TARGET_SDL2)
4863 else if (strEqual(command, "SDL_ListModes"))
4865 SDL_Init(SDL_INIT_VIDEO);
4867 int num_displays = SDL_GetNumVideoDisplays();
4869 // check if there are any displays available
4870 if (num_displays < 0)
4872 Print("No displays available: %s\n", SDL_GetError());
4877 for (i = 0; i < num_displays; i++)
4879 int num_modes = SDL_GetNumDisplayModes(i);
4882 Print("Available display modes for display %d:\n", i);
4884 // check if there are any display modes available for this display
4887 Print("No display modes available for display %d: %s\n",
4893 for (j = 0; j < num_modes; j++)
4895 SDL_DisplayMode mode;
4897 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4899 Print("Cannot get display mode %d for display %d: %s\n",
4900 j, i, SDL_GetError());
4905 Print("- %d x %d\n", mode.w, mode.h);
4911 #elif defined(TARGET_SDL)
4912 else if (strEqual(command, "SDL_ListModes"))
4917 SDL_Init(SDL_INIT_VIDEO);
4919 /* get available fullscreen/hardware modes */
4920 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4922 /* check if there are any modes available */
4925 Print("No modes available!\n");
4930 /* check if our resolution is restricted */
4931 if (modes == (SDL_Rect **)-1)
4933 Print("All resolutions available.\n");
4937 Print("Available display modes:\n");
4939 for (i = 0; modes[i]; i++)
4940 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4950 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4954 static void InitSetup()
4956 LoadSetup(); /* global setup info */
4958 /* set some options from setup file */
4960 if (setup.options.verbose)
4961 options.verbose = TRUE;
4964 static void InitGameInfo()
4966 game.restart_level = FALSE;
4969 static void InitPlayerInfo()
4973 /* choose default local player */
4974 local_player = &stored_player[0];
4976 for (i = 0; i < MAX_PLAYERS; i++)
4977 stored_player[i].connected = FALSE;
4979 local_player->connected = TRUE;
4982 static void InitArtworkInfo()
4987 static char *get_string_in_brackets(char *string)
4989 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4991 sprintf(string_in_brackets, "[%s]", string);
4993 return string_in_brackets;
4996 static char *get_level_id_suffix(int id_nr)
4998 char *id_suffix = checked_malloc(1 + 3 + 1);
5000 if (id_nr < 0 || id_nr > 999)
5003 sprintf(id_suffix, ".%03d", id_nr);
5008 static void InitArtworkConfig()
5010 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5012 NUM_GLOBAL_ANIM_TOKENS + 1];
5013 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5014 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5015 static char *action_id_suffix[NUM_ACTIONS + 1];
5016 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5017 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5018 static char *level_id_suffix[MAX_LEVELS + 1];
5019 static char *dummy[1] = { NULL };
5020 static char *ignore_generic_tokens[] =
5026 static char **ignore_image_tokens;
5027 static char **ignore_sound_tokens;
5028 static char **ignore_music_tokens;
5029 int num_ignore_generic_tokens;
5030 int num_ignore_image_tokens;
5031 int num_ignore_sound_tokens;
5032 int num_ignore_music_tokens;
5035 /* dynamically determine list of generic tokens to be ignored */
5036 num_ignore_generic_tokens = 0;
5037 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5038 num_ignore_generic_tokens++;
5040 /* dynamically determine list of image tokens to be ignored */
5041 num_ignore_image_tokens = num_ignore_generic_tokens;
5042 for (i = 0; image_config_vars[i].token != NULL; i++)
5043 num_ignore_image_tokens++;
5044 ignore_image_tokens =
5045 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5046 for (i = 0; i < num_ignore_generic_tokens; i++)
5047 ignore_image_tokens[i] = ignore_generic_tokens[i];
5048 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5049 ignore_image_tokens[num_ignore_generic_tokens + i] =
5050 image_config_vars[i].token;
5051 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5053 /* dynamically determine list of sound tokens to be ignored */
5054 num_ignore_sound_tokens = num_ignore_generic_tokens;
5055 ignore_sound_tokens =
5056 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5057 for (i = 0; i < num_ignore_generic_tokens; i++)
5058 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5059 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5061 /* dynamically determine list of music tokens to be ignored */
5062 num_ignore_music_tokens = num_ignore_generic_tokens;
5063 ignore_music_tokens =
5064 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5065 for (i = 0; i < num_ignore_generic_tokens; i++)
5066 ignore_music_tokens[i] = ignore_generic_tokens[i];
5067 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5069 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5070 image_id_prefix[i] = element_info[i].token_name;
5071 for (i = 0; i < NUM_FONTS; i++)
5072 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5073 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5074 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5075 global_anim_info[i].token_name;
5076 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5078 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5079 sound_id_prefix[i] = element_info[i].token_name;
5080 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5081 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5082 get_string_in_brackets(element_info[i].class_name);
5083 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5085 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5086 music_id_prefix[i] = music_prefix_info[i].prefix;
5087 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5089 for (i = 0; i < NUM_ACTIONS; i++)
5090 action_id_suffix[i] = element_action_info[i].suffix;
5091 action_id_suffix[NUM_ACTIONS] = NULL;
5093 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5094 direction_id_suffix[i] = element_direction_info[i].suffix;
5095 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5097 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5098 special_id_suffix[i] = special_suffix_info[i].suffix;
5099 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5101 for (i = 0; i < MAX_LEVELS; i++)
5102 level_id_suffix[i] = get_level_id_suffix(i);
5103 level_id_suffix[MAX_LEVELS] = NULL;
5105 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5106 image_id_prefix, action_id_suffix, direction_id_suffix,
5107 special_id_suffix, ignore_image_tokens);
5108 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5109 sound_id_prefix, action_id_suffix, dummy,
5110 special_id_suffix, ignore_sound_tokens);
5111 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5112 music_id_prefix, special_id_suffix, level_id_suffix,
5113 dummy, ignore_music_tokens);
5116 static void InitMixer()
5123 void InitGfxBuffers()
5125 static int win_xsize_last = -1;
5126 static int win_ysize_last = -1;
5128 /* create additional image buffers for double-buffering and cross-fading */
5130 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5132 /* may contain content for cross-fading -- only re-create if changed */
5133 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5134 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5136 win_xsize_last = WIN_XSIZE;
5137 win_ysize_last = WIN_YSIZE;
5140 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5141 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5142 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5143 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5144 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5146 /* initialize screen properties */
5147 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5148 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5150 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5151 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5152 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5153 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5154 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5155 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5157 /* required if door size definitions have changed */
5158 InitGraphicCompatibilityInfo_Doors();
5160 InitGfxBuffers_EM();
5161 InitGfxBuffers_SP();
5166 struct GraphicInfo *graphic_info_last = graphic_info;
5167 char *filename_font_initial = NULL;
5168 char *filename_anim_initial = NULL;
5169 Bitmap *bitmap_font_initial = NULL;
5173 /* determine settings for initial font (for displaying startup messages) */
5174 for (i = 0; image_config[i].token != NULL; i++)
5176 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5178 char font_token[128];
5181 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5182 len_font_token = strlen(font_token);
5184 if (strEqual(image_config[i].token, font_token))
5185 filename_font_initial = image_config[i].value;
5186 else if (strlen(image_config[i].token) > len_font_token &&
5187 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5189 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5190 font_initial[j].src_x = atoi(image_config[i].value);
5191 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5192 font_initial[j].src_y = atoi(image_config[i].value);
5193 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5194 font_initial[j].width = atoi(image_config[i].value);
5195 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5196 font_initial[j].height = atoi(image_config[i].value);
5201 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5203 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5204 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5207 if (filename_font_initial == NULL) /* should not happen */
5208 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5211 InitGfxCustomArtworkInfo();
5212 InitGfxOtherSettings();
5214 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5216 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5217 font_initial[j].bitmap = bitmap_font_initial;
5219 InitFontGraphicInfo();
5221 font_height = getFontHeight(FC_RED);
5223 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5224 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5225 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5228 DrawInitText("Loading graphics", 120, FC_GREEN);
5230 /* initialize settings for busy animation with default values */
5231 int parameter[NUM_GFX_ARGS];
5232 for (i = 0; i < NUM_GFX_ARGS; i++)
5233 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5234 image_config_suffix[i].token,
5235 image_config_suffix[i].type);
5237 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5238 int len_anim_token = strlen(anim_token);
5240 /* read settings for busy animation from default custom artwork config */
5241 char *gfx_config_filename = getPath3(options.graphics_directory,
5243 GRAPHICSINFO_FILENAME);
5245 if (fileExists(gfx_config_filename))
5247 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5249 if (setup_file_hash)
5251 char *filename = getHashEntry(setup_file_hash, anim_token);
5255 filename_anim_initial = getStringCopy(filename);
5257 for (j = 0; image_config_suffix[j].token != NULL; j++)
5259 int type = image_config_suffix[j].type;
5260 char *suffix = image_config_suffix[j].token;
5261 char *token = getStringCat2(anim_token, suffix);
5262 char *value = getHashEntry(setup_file_hash, token);
5264 checked_free(token);
5267 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5271 freeSetupFileHash(setup_file_hash);
5275 if (filename_anim_initial == NULL)
5277 /* read settings for busy animation from static default artwork config */
5278 for (i = 0; image_config[i].token != NULL; i++)
5280 if (strEqual(image_config[i].token, anim_token))
5281 filename_anim_initial = getStringCopy(image_config[i].value);
5282 else if (strlen(image_config[i].token) > len_anim_token &&
5283 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5285 for (j = 0; image_config_suffix[j].token != NULL; j++)
5287 if (strEqual(&image_config[i].token[len_anim_token],
5288 image_config_suffix[j].token))
5290 get_graphic_parameter_value(image_config[i].value,
5291 image_config_suffix[j].token,
5292 image_config_suffix[j].type);
5298 if (filename_anim_initial == NULL) /* should not happen */
5299 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5301 anim_initial.bitmaps =
5302 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5304 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5305 LoadCustomImage(filename_anim_initial);
5307 checked_free(filename_anim_initial);
5309 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5311 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5313 graphic_info = graphic_info_last;
5315 init.busy.width = anim_initial.width;
5316 init.busy.height = anim_initial.height;
5318 InitMenuDesignSettings_Static();
5320 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5321 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5323 /* use copy of busy animation to prevent change while reloading artwork */
5327 void InitGfxBackground()
5329 fieldbuffer = bitmap_db_field;
5330 SetDrawtoField(DRAW_BACKBUFFER);
5332 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5334 redraw_mask = REDRAW_ALL;
5337 static void InitLevelInfo()
5339 LoadLevelInfo(); /* global level info */
5340 LoadLevelSetup_LastSeries(); /* last played series info */
5341 LoadLevelSetup_SeriesInfo(); /* last played level info */
5343 if (global.autoplay_leveldir &&
5344 global.autoplay_mode != AUTOPLAY_TEST)
5346 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5347 global.autoplay_leveldir);
5348 if (leveldir_current == NULL)
5349 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5353 static void InitLevelArtworkInfo()
5355 LoadLevelArtworkInfo();
5358 static void InitImages()
5360 print_timestamp_init("InitImages");
5363 printf("::: leveldir_current->identifier == '%s'\n",
5364 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5365 printf("::: leveldir_current->graphics_path == '%s'\n",
5366 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5367 printf("::: leveldir_current->graphics_set == '%s'\n",
5368 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5369 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5370 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5373 setLevelArtworkDir(artwork.gfx_first);
5376 printf("::: leveldir_current->identifier == '%s'\n",
5377 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5378 printf("::: leveldir_current->graphics_path == '%s'\n",
5379 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5380 printf("::: leveldir_current->graphics_set == '%s'\n",
5381 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5382 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5383 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5387 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5388 leveldir_current->identifier,
5389 artwork.gfx_current_identifier,
5390 artwork.gfx_current->identifier,
5391 leveldir_current->graphics_set,
5392 leveldir_current->graphics_path);
5395 UPDATE_BUSY_STATE();
5397 ReloadCustomImages();
5398 print_timestamp_time("ReloadCustomImages");
5400 UPDATE_BUSY_STATE();
5402 LoadCustomElementDescriptions();
5403 print_timestamp_time("LoadCustomElementDescriptions");
5405 UPDATE_BUSY_STATE();
5407 LoadMenuDesignSettings();
5408 print_timestamp_time("LoadMenuDesignSettings");
5410 UPDATE_BUSY_STATE();
5412 ReinitializeGraphics();
5413 print_timestamp_time("ReinitializeGraphics");
5415 UPDATE_BUSY_STATE();
5417 print_timestamp_done("InitImages");
5420 static void InitSound(char *identifier)
5422 print_timestamp_init("InitSound");
5424 if (identifier == NULL)
5425 identifier = artwork.snd_current->identifier;
5427 /* set artwork path to send it to the sound server process */
5428 setLevelArtworkDir(artwork.snd_first);
5430 InitReloadCustomSounds(identifier);
5431 print_timestamp_time("InitReloadCustomSounds");
5433 ReinitializeSounds();
5434 print_timestamp_time("ReinitializeSounds");
5436 print_timestamp_done("InitSound");
5439 static void InitMusic(char *identifier)
5441 print_timestamp_init("InitMusic");
5443 if (identifier == NULL)
5444 identifier = artwork.mus_current->identifier;
5446 /* set artwork path to send it to the sound server process */
5447 setLevelArtworkDir(artwork.mus_first);
5449 InitReloadCustomMusic(identifier);
5450 print_timestamp_time("InitReloadCustomMusic");
5452 ReinitializeMusic();
5453 print_timestamp_time("ReinitializeMusic");
5455 print_timestamp_done("InitMusic");
5458 void InitNetworkServer()
5460 #if defined(NETWORK_AVALIABLE)
5464 if (!options.network)
5467 #if defined(NETWORK_AVALIABLE)
5468 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5470 if (!ConnectToServer(options.server_host, options.server_port))
5471 Error(ERR_EXIT, "cannot connect to network game server");
5473 SendToServer_PlayerName(setup.player_name);
5474 SendToServer_ProtocolVersion();
5477 SendToServer_NrWanted(nr_wanted);
5481 static boolean CheckArtworkConfigForCustomElements(char *filename)
5483 SetupFileHash *setup_file_hash;
5484 boolean redefined_ce_found = FALSE;
5486 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5488 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5490 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5492 char *token = HASH_ITERATION_TOKEN(itr);
5494 if (strPrefix(token, "custom_"))
5496 redefined_ce_found = TRUE;
5501 END_HASH_ITERATION(setup_file_hash, itr)
5503 freeSetupFileHash(setup_file_hash);
5506 return redefined_ce_found;
5509 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5511 char *filename_base, *filename_local;
5512 boolean redefined_ce_found = FALSE;
5514 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5517 printf("::: leveldir_current->identifier == '%s'\n",
5518 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5519 printf("::: leveldir_current->graphics_path == '%s'\n",
5520 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5521 printf("::: leveldir_current->graphics_set == '%s'\n",
5522 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5523 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5524 leveldir_current == NULL ? "[NULL]" :
5525 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5528 /* first look for special artwork configured in level series config */
5529 filename_base = getCustomArtworkLevelConfigFilename(type);
5532 printf("::: filename_base == '%s'\n", filename_base);
5535 if (fileExists(filename_base))
5536 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5538 filename_local = getCustomArtworkConfigFilename(type);
5541 printf("::: filename_local == '%s'\n", filename_local);
5544 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5545 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5548 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5551 return redefined_ce_found;
5554 static void InitOverrideArtwork()
5556 boolean redefined_ce_found = FALSE;
5558 /* to check if this level set redefines any CEs, do not use overriding */
5559 gfx.override_level_graphics = FALSE;
5560 gfx.override_level_sounds = FALSE;
5561 gfx.override_level_music = FALSE;
5563 /* now check if this level set has definitions for custom elements */
5564 if (setup.override_level_graphics == AUTO ||
5565 setup.override_level_sounds == AUTO ||
5566 setup.override_level_music == AUTO)
5567 redefined_ce_found =
5568 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5569 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5570 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5573 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5576 if (redefined_ce_found)
5578 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5579 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5580 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5581 gfx.override_level_music = (setup.override_level_music == TRUE);
5585 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5586 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5587 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5588 gfx.override_level_music = (setup.override_level_music != FALSE);
5592 printf("::: => %d, %d, %d\n",
5593 gfx.override_level_graphics,
5594 gfx.override_level_sounds,
5595 gfx.override_level_music);
5599 static char *getNewArtworkIdentifier(int type)
5601 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5602 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5603 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5604 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5605 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5606 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5607 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5608 char *leveldir_identifier = leveldir_current->identifier;
5609 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5610 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5611 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5612 char *artwork_current_identifier;
5613 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5615 /* leveldir_current may be invalid (level group, parent link) */
5616 if (!validLevelSeries(leveldir_current))
5619 /* 1st step: determine artwork set to be activated in descending order:
5620 --------------------------------------------------------------------
5621 1. setup artwork (when configured to override everything else)
5622 2. artwork set configured in "levelinfo.conf" of current level set
5623 (artwork in level directory will have priority when loading later)
5624 3. artwork in level directory (stored in artwork sub-directory)
5625 4. setup artwork (currently configured in setup menu) */
5627 if (setup_override_artwork)
5628 artwork_current_identifier = setup_artwork_set;
5629 else if (leveldir_artwork_set != NULL)
5630 artwork_current_identifier = leveldir_artwork_set;
5631 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5632 artwork_current_identifier = leveldir_identifier;
5634 artwork_current_identifier = setup_artwork_set;
5637 /* 2nd step: check if it is really needed to reload artwork set
5638 ------------------------------------------------------------ */
5640 /* ---------- reload if level set and also artwork set has changed ------- */
5641 if (leveldir_current_identifier[type] != leveldir_identifier &&
5642 (last_has_level_artwork_set[type] || has_level_artwork_set))
5643 artwork_new_identifier = artwork_current_identifier;
5645 leveldir_current_identifier[type] = leveldir_identifier;
5646 last_has_level_artwork_set[type] = has_level_artwork_set;
5648 /* ---------- reload if "override artwork" setting has changed ----------- */
5649 if (last_override_level_artwork[type] != setup_override_artwork)
5650 artwork_new_identifier = artwork_current_identifier;
5652 last_override_level_artwork[type] = setup_override_artwork;
5654 /* ---------- reload if current artwork identifier has changed ----------- */
5655 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5656 artwork_current_identifier))
5657 artwork_new_identifier = artwork_current_identifier;
5659 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5661 /* ---------- do not reload directly after starting ---------------------- */
5662 if (!initialized[type])
5663 artwork_new_identifier = NULL;
5665 initialized[type] = TRUE;
5667 return artwork_new_identifier;
5670 void ReloadCustomArtwork(int force_reload)
5672 int last_game_status = game_status; /* save current game status */
5673 char *gfx_new_identifier;
5674 char *snd_new_identifier;
5675 char *mus_new_identifier;
5676 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5677 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5678 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5679 boolean reload_needed;
5681 InitOverrideArtwork();
5683 force_reload_gfx |= AdjustGraphicsForEMC();
5685 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5686 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5687 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5689 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5690 snd_new_identifier != NULL || force_reload_snd ||
5691 mus_new_identifier != NULL || force_reload_mus);
5696 print_timestamp_init("ReloadCustomArtwork");
5698 game_status = GAME_MODE_LOADING;
5700 FadeOut(REDRAW_ALL);
5702 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5703 print_timestamp_time("ClearRectangle");
5707 if (gfx_new_identifier != NULL || force_reload_gfx)
5710 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5711 artwork.gfx_current_identifier,
5713 artwork.gfx_current->identifier,
5714 leveldir_current->graphics_set);
5718 print_timestamp_time("InitImages");
5721 if (snd_new_identifier != NULL || force_reload_snd)
5723 InitSound(snd_new_identifier);
5724 print_timestamp_time("InitSound");
5727 if (mus_new_identifier != NULL || force_reload_mus)
5729 InitMusic(mus_new_identifier);
5730 print_timestamp_time("InitMusic");
5733 game_status = last_game_status; /* restore current game status */
5735 init_last = init; /* switch to new busy animation */
5737 FadeOut(REDRAW_ALL);
5739 RedrawGlobalBorder();
5741 /* force redraw of (open or closed) door graphics */
5742 SetDoorState(DOOR_OPEN_ALL);
5743 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5745 FadeSetEnterScreen();
5746 FadeSkipNextFadeOut();
5748 print_timestamp_done("ReloadCustomArtwork");
5750 LimitScreenUpdates(FALSE);
5753 void KeyboardAutoRepeatOffUnlessAutoplay()
5755 if (global.autoplay_leveldir == NULL)
5756 KeyboardAutoRepeatOff();
5759 void DisplayExitMessage(char *format, va_list ap)
5761 // check if draw buffer and fonts for exit message are already available
5762 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5765 int font_1 = FC_RED;
5766 int font_2 = FC_YELLOW;
5767 int font_3 = FC_BLUE;
5768 int font_width = getFontWidth(font_2);
5769 int font_height = getFontHeight(font_2);
5772 int sxsize = WIN_XSIZE - 2 * sx;
5773 int sysize = WIN_YSIZE - 2 * sy;
5774 int line_length = sxsize / font_width;
5775 int max_lines = sysize / font_height;
5776 int num_lines_printed;
5780 gfx.sxsize = sxsize;
5781 gfx.sysize = sysize;
5785 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5787 DrawTextSCentered(sy, font_1, "Fatal error:");
5788 sy += 3 * font_height;;
5791 DrawTextBufferVA(sx, sy, format, ap, font_2,
5792 line_length, line_length, max_lines,
5793 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5794 sy += (num_lines_printed + 3) * font_height;
5796 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5797 sy += 3 * font_height;
5800 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5801 line_length, line_length, max_lines,
5802 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5804 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5806 redraw_mask = REDRAW_ALL;
5808 /* force drawing exit message even if screen updates are currently limited */
5809 LimitScreenUpdates(FALSE);
5813 /* deactivate toons on error message screen */
5814 setup.toons = FALSE;
5816 WaitForEventToContinue();
5820 /* ========================================================================= */
5822 /* ========================================================================= */
5826 print_timestamp_init("OpenAll");
5828 game_status = GAME_MODE_LOADING;
5832 InitGlobal(); /* initialize some global variables */
5834 print_timestamp_time("[init global stuff]");
5838 print_timestamp_time("[init setup/config stuff (1)]");
5840 if (options.execute_command)
5841 Execute_Command(options.execute_command);
5843 if (options.serveronly)
5845 #if defined(PLATFORM_UNIX)
5846 NetworkServer(options.server_port, options.serveronly);
5848 Error(ERR_WARN, "networking only supported in Unix version");
5851 exit(0); /* never reached, server loops forever */
5855 print_timestamp_time("[init setup/config stuff (2)]");
5857 print_timestamp_time("[init setup/config stuff (3)]");
5858 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5859 print_timestamp_time("[init setup/config stuff (4)]");
5860 InitArtworkConfig(); /* needed before forking sound child process */
5861 print_timestamp_time("[init setup/config stuff (5)]");
5863 print_timestamp_time("[init setup/config stuff (6)]");
5865 InitRND(NEW_RANDOMIZE);
5866 InitSimpleRandom(NEW_RANDOMIZE);
5870 print_timestamp_time("[init setup/config stuff]");
5873 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5875 InitEventFilter(FilterEvents);
5877 print_timestamp_time("[init video stuff]");
5879 InitElementPropertiesStatic();
5880 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5881 InitElementPropertiesGfxElement();
5883 print_timestamp_time("[init element properties stuff]");
5887 print_timestamp_time("InitGfx");
5890 print_timestamp_time("InitLevelInfo");
5892 InitLevelArtworkInfo();
5893 print_timestamp_time("InitLevelArtworkInfo");
5895 InitOverrideArtwork(); /* needs to know current level directory */
5896 print_timestamp_time("InitOverrideArtwork");
5898 InitImages(); /* needs to know current level directory */
5899 print_timestamp_time("InitImages");
5901 InitSound(NULL); /* needs to know current level directory */
5902 print_timestamp_time("InitSound");
5904 InitMusic(NULL); /* needs to know current level directory */
5905 print_timestamp_time("InitMusic");
5907 InitGfxBackground();
5912 if (global.autoplay_leveldir)
5917 else if (global.convert_leveldir)
5922 else if (global.create_images_dir)
5924 CreateLevelSketchImages();
5928 game_status = GAME_MODE_MAIN;
5930 FadeSetEnterScreen();
5931 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5932 FadeSkipNextFadeOut();
5934 print_timestamp_time("[post-artwork]");
5936 print_timestamp_done("OpenAll");
5940 InitNetworkServer();
5943 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5945 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5946 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5947 #if defined(PLATFORM_ANDROID)
5948 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5949 SDL_AndroidGetInternalStoragePath());
5950 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5951 SDL_AndroidGetExternalStoragePath());
5952 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5953 (SDL_AndroidGetExternalStorageState() ==
5954 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5955 SDL_AndroidGetExternalStorageState() ==
5956 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5961 void CloseAllAndExit(int exit_value)
5966 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5973 #if defined(TARGET_SDL)
5974 #if defined(TARGET_SDL2)
5976 // set a flag to tell the network server thread to quit and wait for it
5977 // using SDL_WaitThread()
5979 if (network_server) /* terminate network server */
5980 SDL_KillThread(server_thread);
5984 CloseVideoDisplay();
5985 ClosePlatformDependentStuff();
5987 if (exit_value != 0)
5989 /* fall back to default level set (current set may have caused an error) */
5990 SaveLevelSetup_LastSeries_Deactivate();
5992 /* tell user where to find error log file which may contain more details */
5993 // (error notification now directly displayed on screen inside R'n'D
5994 // NotifyUserAboutErrorFile(); /* currently only works for Windows */