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 static void InitGlobalAnimImages()
233 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
235 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS; j++)
237 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
239 int graphic = global_anim_info[i].graphic[j][k];
241 if (graphic == IMG_UNDEFINED)
244 // create textures from images for fast GPU blitting, if possible
245 CreateImageTextures(graphic);
252 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
253 void SetBitmaps_EM(Bitmap **em_bitmap)
255 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
256 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
261 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
262 void SetBitmaps_SP(Bitmap **sp_bitmap)
264 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
268 static int getFontBitmapID(int font_nr)
272 /* (special case: do not use special font for GAME_MODE_LOADING) */
273 if (game_status >= GAME_MODE_TITLE_INITIAL &&
274 game_status <= GAME_MODE_PSEUDO_PREVIEW)
275 special = game_status;
276 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
277 special = GFX_SPECIAL_ARG_MAIN;
280 return font_info[font_nr].special_bitmap_id[special];
285 static int getFontFromToken(char *token)
287 char *value = getHashEntry(font_token_hash, token);
292 /* if font not found, use reliable default value */
293 return FONT_INITIAL_1;
296 void InitFontGraphicInfo()
298 static struct FontBitmapInfo *font_bitmap_info = NULL;
299 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
300 int num_property_mappings = getImageListPropertyMappingSize();
301 int num_font_bitmaps = NUM_FONTS;
304 if (graphic_info == NULL) /* still at startup phase */
306 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
307 getFontBitmapID, getFontFromToken);
312 /* ---------- initialize font graphic definitions ---------- */
314 /* always start with reliable default values (normal font graphics) */
315 for (i = 0; i < NUM_FONTS; i++)
316 font_info[i].graphic = IMG_FONT_INITIAL_1;
318 /* initialize normal font/graphic mapping from static configuration */
319 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
321 int font_nr = font_to_graphic[i].font_nr;
322 int special = font_to_graphic[i].special;
323 int graphic = font_to_graphic[i].graphic;
328 font_info[font_nr].graphic = graphic;
331 /* always start with reliable default values (special font graphics) */
332 for (i = 0; i < NUM_FONTS; i++)
334 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
336 font_info[i].special_graphic[j] = font_info[i].graphic;
337 font_info[i].special_bitmap_id[j] = i;
341 /* initialize special font/graphic mapping from static configuration */
342 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
344 int font_nr = font_to_graphic[i].font_nr;
345 int special = font_to_graphic[i].special;
346 int graphic = font_to_graphic[i].graphic;
347 int base_graphic = font2baseimg(font_nr);
349 if (IS_SPECIAL_GFX_ARG(special))
351 boolean base_redefined =
352 getImageListEntryFromImageID(base_graphic)->redefined;
353 boolean special_redefined =
354 getImageListEntryFromImageID(graphic)->redefined;
355 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
357 /* if the base font ("font.title_1", for example) has been redefined,
358 but not the special font ("font.title_1.LEVELS", for example), do not
359 use an existing (in this case considered obsolete) special font
360 anymore, but use the automatically determined default font */
361 /* special case: cloned special fonts must be explicitly redefined,
362 but are not automatically redefined by redefining base font */
363 if (base_redefined && !special_redefined && !special_cloned)
366 font_info[font_nr].special_graphic[special] = graphic;
367 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
372 /* initialize special font/graphic mapping from dynamic configuration */
373 for (i = 0; i < num_property_mappings; i++)
375 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
376 int special = property_mapping[i].ext3_index;
377 int graphic = property_mapping[i].artwork_index;
382 if (IS_SPECIAL_GFX_ARG(special))
384 font_info[font_nr].special_graphic[special] = graphic;
385 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
390 /* correct special font/graphic mapping for cloned fonts for downwards
391 compatibility of PREVIEW fonts -- this is only needed for implicit
392 redefinition of special font by redefined base font, and only if other
393 fonts are cloned from this special font (like in the "Zelda" level set) */
394 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
396 int font_nr = font_to_graphic[i].font_nr;
397 int special = font_to_graphic[i].special;
398 int graphic = font_to_graphic[i].graphic;
400 if (IS_SPECIAL_GFX_ARG(special))
402 boolean special_redefined =
403 getImageListEntryFromImageID(graphic)->redefined;
404 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
406 if (special_cloned && !special_redefined)
410 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
412 int font_nr2 = font_to_graphic[j].font_nr;
413 int special2 = font_to_graphic[j].special;
414 int graphic2 = font_to_graphic[j].graphic;
416 if (IS_SPECIAL_GFX_ARG(special2) &&
417 graphic2 == graphic_info[graphic].clone_from)
419 font_info[font_nr].special_graphic[special] =
420 font_info[font_nr2].special_graphic[special2];
421 font_info[font_nr].special_bitmap_id[special] =
422 font_info[font_nr2].special_bitmap_id[special2];
429 /* reset non-redefined ".active" font graphics if normal font is redefined */
430 /* (this different treatment is needed because normal and active fonts are
431 independently defined ("active" is not a property of font definitions!) */
432 for (i = 0; i < NUM_FONTS; i++)
434 int font_nr_base = i;
435 int font_nr_active = FONT_ACTIVE(font_nr_base);
437 /* check only those fonts with exist as normal and ".active" variant */
438 if (font_nr_base != font_nr_active)
440 int base_graphic = font_info[font_nr_base].graphic;
441 int active_graphic = font_info[font_nr_active].graphic;
442 boolean base_redefined =
443 getImageListEntryFromImageID(base_graphic)->redefined;
444 boolean active_redefined =
445 getImageListEntryFromImageID(active_graphic)->redefined;
447 /* if the base font ("font.menu_1", for example) has been redefined,
448 but not the active font ("font.menu_1.active", for example), do not
449 use an existing (in this case considered obsolete) active font
450 anymore, but use the automatically determined default font */
451 if (base_redefined && !active_redefined)
452 font_info[font_nr_active].graphic = base_graphic;
454 /* now also check each "special" font (which may be the same as above) */
455 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
457 int base_graphic = font_info[font_nr_base].special_graphic[j];
458 int active_graphic = font_info[font_nr_active].special_graphic[j];
459 boolean base_redefined =
460 getImageListEntryFromImageID(base_graphic)->redefined;
461 boolean active_redefined =
462 getImageListEntryFromImageID(active_graphic)->redefined;
464 /* same as above, but check special graphic definitions, for example:
465 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
466 if (base_redefined && !active_redefined)
468 font_info[font_nr_active].special_graphic[j] =
469 font_info[font_nr_base].special_graphic[j];
470 font_info[font_nr_active].special_bitmap_id[j] =
471 font_info[font_nr_base].special_bitmap_id[j];
477 /* ---------- initialize font bitmap array ---------- */
479 if (font_bitmap_info != NULL)
480 FreeFontInfo(font_bitmap_info);
483 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
485 /* ---------- initialize font bitmap definitions ---------- */
487 for (i = 0; i < NUM_FONTS; i++)
489 if (i < NUM_INITIAL_FONTS)
491 font_bitmap_info[i] = font_initial[i];
495 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
497 int font_bitmap_id = font_info[i].special_bitmap_id[j];
498 int graphic = font_info[i].special_graphic[j];
500 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
501 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
503 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
504 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
507 /* copy font relevant information from graphics information */
508 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
509 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
510 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
511 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
512 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
514 font_bitmap_info[font_bitmap_id].draw_xoffset =
515 graphic_info[graphic].draw_xoffset;
516 font_bitmap_info[font_bitmap_id].draw_yoffset =
517 graphic_info[graphic].draw_yoffset;
519 font_bitmap_info[font_bitmap_id].num_chars =
520 graphic_info[graphic].anim_frames;
521 font_bitmap_info[font_bitmap_id].num_chars_per_line =
522 graphic_info[graphic].anim_frames_per_line;
526 InitFontInfo(font_bitmap_info, num_font_bitmaps,
527 getFontBitmapID, getFontFromToken);
530 void InitGlobalAnimGraphicInfo()
532 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
533 int num_property_mappings = getImageListPropertyMappingSize();
536 if (graphic_info == NULL) /* still at startup phase */
539 /* always start with reliable default values (no global animations) */
540 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
541 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS; j++)
542 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
543 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
545 /* initialize global animation definitions from static configuration */
546 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
547 global_anim_info[i].graphic[0][GFX_SPECIAL_ARG_DEFAULT] =
548 IMG_GLOBAL_ANIM_1 + i;
550 /* initialize global animation definitions from dynamic configuration */
551 for (i = 0; i < num_property_mappings; i++)
553 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
554 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
555 int special = property_mapping[i].ext3_index;
556 int graphic = property_mapping[i].artwork_index;
558 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIMS)
561 /* map animation part to first part, if not specified */
565 /* map animation screen to default, if not specified */
566 if (!IS_SPECIAL_GFX_ARG(special))
567 special = GFX_SPECIAL_ARG_DEFAULT;
569 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
573 printf("::: InitGlobalAnimGraphicInfo\n");
575 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
576 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS; j++)
577 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
578 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
579 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
580 printf("::: %d, %d, %d => %d\n",
581 i, j, k, global_anim_info[i].graphic[j][k]);
585 void InitElementGraphicInfo()
587 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
588 int num_property_mappings = getImageListPropertyMappingSize();
591 if (graphic_info == NULL) /* still at startup phase */
594 /* set values to -1 to identify later as "uninitialized" values */
595 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
597 for (act = 0; act < NUM_ACTIONS; act++)
599 element_info[i].graphic[act] = -1;
600 element_info[i].crumbled[act] = -1;
602 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
604 element_info[i].direction_graphic[act][dir] = -1;
605 element_info[i].direction_crumbled[act][dir] = -1;
612 /* initialize normal element/graphic mapping from static configuration */
613 for (i = 0; element_to_graphic[i].element > -1; i++)
615 int element = element_to_graphic[i].element;
616 int action = element_to_graphic[i].action;
617 int direction = element_to_graphic[i].direction;
618 boolean crumbled = element_to_graphic[i].crumbled;
619 int graphic = element_to_graphic[i].graphic;
620 int base_graphic = el2baseimg(element);
622 if (graphic_info[graphic].bitmap == NULL)
625 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
628 boolean base_redefined =
629 getImageListEntryFromImageID(base_graphic)->redefined;
630 boolean act_dir_redefined =
631 getImageListEntryFromImageID(graphic)->redefined;
633 /* if the base graphic ("emerald", for example) has been redefined,
634 but not the action graphic ("emerald.falling", for example), do not
635 use an existing (in this case considered obsolete) action graphic
636 anymore, but use the automatically determined default graphic */
637 if (base_redefined && !act_dir_redefined)
642 action = ACTION_DEFAULT;
647 element_info[element].direction_crumbled[action][direction] = graphic;
649 element_info[element].crumbled[action] = graphic;
654 element_info[element].direction_graphic[action][direction] = graphic;
656 element_info[element].graphic[action] = graphic;
660 /* initialize normal element/graphic mapping from dynamic configuration */
661 for (i = 0; i < num_property_mappings; i++)
663 int element = property_mapping[i].base_index;
664 int action = property_mapping[i].ext1_index;
665 int direction = property_mapping[i].ext2_index;
666 int special = property_mapping[i].ext3_index;
667 int graphic = property_mapping[i].artwork_index;
668 boolean crumbled = FALSE;
670 if (special == GFX_SPECIAL_ARG_CRUMBLED)
676 if (graphic_info[graphic].bitmap == NULL)
679 if (element >= MAX_NUM_ELEMENTS || special != -1)
683 action = ACTION_DEFAULT;
688 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
689 element_info[element].direction_crumbled[action][dir] = -1;
692 element_info[element].direction_crumbled[action][direction] = graphic;
694 element_info[element].crumbled[action] = graphic;
699 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
700 element_info[element].direction_graphic[action][dir] = -1;
703 element_info[element].direction_graphic[action][direction] = graphic;
705 element_info[element].graphic[action] = graphic;
709 /* now copy all graphics that are defined to be cloned from other graphics */
710 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
712 int graphic = element_info[i].graphic[ACTION_DEFAULT];
713 int crumbled_like, diggable_like;
718 crumbled_like = graphic_info[graphic].crumbled_like;
719 diggable_like = graphic_info[graphic].diggable_like;
721 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
723 for (act = 0; act < NUM_ACTIONS; act++)
724 element_info[i].crumbled[act] =
725 element_info[crumbled_like].crumbled[act];
726 for (act = 0; act < NUM_ACTIONS; act++)
727 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
728 element_info[i].direction_crumbled[act][dir] =
729 element_info[crumbled_like].direction_crumbled[act][dir];
732 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
734 element_info[i].graphic[ACTION_DIGGING] =
735 element_info[diggable_like].graphic[ACTION_DIGGING];
736 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
737 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
738 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
742 /* set hardcoded definitions for some runtime elements without graphic */
743 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
745 /* set hardcoded definitions for some internal elements without graphic */
746 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
748 if (IS_EDITOR_CASCADE_INACTIVE(i))
749 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
750 else if (IS_EDITOR_CASCADE_ACTIVE(i))
751 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
754 /* now set all undefined/invalid graphics to -1 to set to default after it */
755 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
757 for (act = 0; act < NUM_ACTIONS; act++)
761 graphic = element_info[i].graphic[act];
762 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
763 element_info[i].graphic[act] = -1;
765 graphic = element_info[i].crumbled[act];
766 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
767 element_info[i].crumbled[act] = -1;
769 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
771 graphic = element_info[i].direction_graphic[act][dir];
772 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
773 element_info[i].direction_graphic[act][dir] = -1;
775 graphic = element_info[i].direction_crumbled[act][dir];
776 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
777 element_info[i].direction_crumbled[act][dir] = -1;
784 /* adjust graphics with 2nd tile for movement according to direction
785 (do this before correcting '-1' values to minimize calculations) */
786 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
788 for (act = 0; act < NUM_ACTIONS; act++)
790 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
792 int graphic = element_info[i].direction_graphic[act][dir];
793 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
795 if (act == ACTION_FALLING) /* special case */
796 graphic = element_info[i].graphic[act];
799 graphic_info[graphic].double_movement &&
800 graphic_info[graphic].swap_double_tiles != 0)
802 struct GraphicInfo *g = &graphic_info[graphic];
803 int src_x_front = g->src_x;
804 int src_y_front = g->src_y;
805 int src_x_back = g->src_x + g->offset2_x;
806 int src_y_back = g->src_y + g->offset2_y;
807 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
809 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
810 src_y_front < src_y_back);
811 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
812 boolean swap_movement_tiles_autodetected =
813 (!frames_are_ordered_diagonally &&
814 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
815 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
816 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
817 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
820 /* swap frontside and backside graphic tile coordinates, if needed */
821 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
823 /* get current (wrong) backside tile coordinates */
824 getFixedGraphicSourceExt(graphic, 0, &dummy,
825 &src_x_back, &src_y_back, TRUE);
827 /* set frontside tile coordinates to backside tile coordinates */
828 g->src_x = src_x_back;
829 g->src_y = src_y_back;
831 /* invert tile offset to point to new backside tile coordinates */
835 /* do not swap front and backside tiles again after correction */
836 g->swap_double_tiles = 0;
845 /* now set all '-1' values to element specific default values */
846 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
848 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
849 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
850 int default_direction_graphic[NUM_DIRECTIONS_FULL];
851 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
853 if (default_graphic == -1)
854 default_graphic = IMG_UNKNOWN;
856 if (default_crumbled == -1)
857 default_crumbled = default_graphic;
859 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
861 default_direction_graphic[dir] =
862 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
863 default_direction_crumbled[dir] =
864 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
866 if (default_direction_graphic[dir] == -1)
867 default_direction_graphic[dir] = default_graphic;
869 if (default_direction_crumbled[dir] == -1)
870 default_direction_crumbled[dir] = default_direction_graphic[dir];
873 for (act = 0; act < NUM_ACTIONS; act++)
875 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
876 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
877 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
878 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
879 act == ACTION_TURNING_FROM_RIGHT ||
880 act == ACTION_TURNING_FROM_UP ||
881 act == ACTION_TURNING_FROM_DOWN);
883 /* generic default action graphic (defined by "[default]" directive) */
884 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
885 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
886 int default_remove_graphic = IMG_EMPTY;
888 if (act_remove && default_action_graphic != -1)
889 default_remove_graphic = default_action_graphic;
891 /* look for special default action graphic (classic game specific) */
892 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
893 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
894 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
895 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
896 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
897 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
899 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
900 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
901 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
902 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
903 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
904 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
906 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
907 /* !!! make this better !!! */
908 if (i == EL_EMPTY_SPACE)
910 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
911 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
914 if (default_action_graphic == -1)
915 default_action_graphic = default_graphic;
917 if (default_action_crumbled == -1)
918 default_action_crumbled = default_action_graphic;
920 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
922 /* use action graphic as the default direction graphic, if undefined */
923 int default_action_direction_graphic = element_info[i].graphic[act];
924 int default_action_direction_crumbled = element_info[i].crumbled[act];
926 /* no graphic for current action -- use default direction graphic */
927 if (default_action_direction_graphic == -1)
928 default_action_direction_graphic =
929 (act_remove ? default_remove_graphic :
931 element_info[i].direction_graphic[ACTION_TURNING][dir] :
932 default_action_graphic != default_graphic ?
933 default_action_graphic :
934 default_direction_graphic[dir]);
936 if (element_info[i].direction_graphic[act][dir] == -1)
937 element_info[i].direction_graphic[act][dir] =
938 default_action_direction_graphic;
940 if (default_action_direction_crumbled == -1)
941 default_action_direction_crumbled =
942 element_info[i].direction_graphic[act][dir];
944 if (element_info[i].direction_crumbled[act][dir] == -1)
945 element_info[i].direction_crumbled[act][dir] =
946 default_action_direction_crumbled;
949 /* no graphic for this specific action -- use default action graphic */
950 if (element_info[i].graphic[act] == -1)
951 element_info[i].graphic[act] =
952 (act_remove ? default_remove_graphic :
953 act_turning ? element_info[i].graphic[ACTION_TURNING] :
954 default_action_graphic);
956 if (element_info[i].crumbled[act] == -1)
957 element_info[i].crumbled[act] = element_info[i].graphic[act];
964 void InitElementSpecialGraphicInfo()
966 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
967 int num_property_mappings = getImageListPropertyMappingSize();
970 /* always start with reliable default values */
971 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
972 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
973 element_info[i].special_graphic[j] =
974 element_info[i].graphic[ACTION_DEFAULT];
976 /* initialize special element/graphic mapping from static configuration */
977 for (i = 0; element_to_special_graphic[i].element > -1; i++)
979 int element = element_to_special_graphic[i].element;
980 int special = element_to_special_graphic[i].special;
981 int graphic = element_to_special_graphic[i].graphic;
982 int base_graphic = el2baseimg(element);
983 boolean base_redefined =
984 getImageListEntryFromImageID(base_graphic)->redefined;
985 boolean special_redefined =
986 getImageListEntryFromImageID(graphic)->redefined;
988 /* if the base graphic ("emerald", for example) has been redefined,
989 but not the special graphic ("emerald.EDITOR", for example), do not
990 use an existing (in this case considered obsolete) special graphic
991 anymore, but use the automatically created (down-scaled) graphic */
992 if (base_redefined && !special_redefined)
995 element_info[element].special_graphic[special] = graphic;
998 /* initialize special element/graphic mapping from dynamic configuration */
999 for (i = 0; i < num_property_mappings; i++)
1001 int element = property_mapping[i].base_index;
1002 int action = property_mapping[i].ext1_index;
1003 int direction = property_mapping[i].ext2_index;
1004 int special = property_mapping[i].ext3_index;
1005 int graphic = property_mapping[i].artwork_index;
1007 /* for action ".active", replace element with active element, if exists */
1008 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1010 element = ELEMENT_ACTIVE(element);
1014 if (element >= MAX_NUM_ELEMENTS)
1017 /* do not change special graphic if action or direction was specified */
1018 if (action != -1 || direction != -1)
1021 if (IS_SPECIAL_GFX_ARG(special))
1022 element_info[element].special_graphic[special] = graphic;
1025 /* now set all undefined/invalid graphics to default */
1026 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1027 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1028 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1029 element_info[i].special_graphic[j] =
1030 element_info[i].graphic[ACTION_DEFAULT];
1033 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1035 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1036 return get_parameter_value(value_raw, suffix, type);
1038 if (strEqual(value_raw, ARG_UNDEFINED))
1039 return ARG_UNDEFINED_VALUE;
1041 if (type == TYPE_ELEMENT)
1043 char *value = getHashEntry(element_token_hash, value_raw);
1047 Error(ERR_INFO_LINE, "-");
1048 Error(ERR_INFO, "warning: error found in config file:");
1049 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1050 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1051 Error(ERR_INFO, "custom graphic rejected for this element/action");
1052 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1053 Error(ERR_INFO_LINE, "-");
1056 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1058 else if (type == TYPE_GRAPHIC)
1060 char *value = getHashEntry(graphic_token_hash, value_raw);
1061 int fallback_graphic = IMG_CHAR_EXCLAM;
1065 Error(ERR_INFO_LINE, "-");
1066 Error(ERR_INFO, "warning: error found in config file:");
1067 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1068 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1069 Error(ERR_INFO, "custom graphic rejected for this element/action");
1070 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1071 Error(ERR_INFO_LINE, "-");
1074 return (value != NULL ? atoi(value) : fallback_graphic);
1080 static int get_scaled_graphic_width(int graphic)
1082 int original_width = getOriginalImageWidthFromImageID(graphic);
1083 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1085 return original_width * scale_up_factor;
1088 static int get_scaled_graphic_height(int graphic)
1090 int original_height = getOriginalImageHeightFromImageID(graphic);
1091 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1093 return original_height * scale_up_factor;
1096 static void set_graphic_parameters_ext(int graphic, int *parameter,
1097 Bitmap **src_bitmaps)
1099 struct GraphicInfo *g = &graphic_info[graphic];
1100 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1101 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1102 int anim_frames_per_line = 1;
1104 /* always start with reliable default values */
1105 g->src_image_width = 0;
1106 g->src_image_height = 0;
1109 g->width = TILEX; /* default for element graphics */
1110 g->height = TILEY; /* default for element graphics */
1111 g->offset_x = 0; /* one or both of these values ... */
1112 g->offset_y = 0; /* ... will be corrected later */
1113 g->offset2_x = 0; /* one or both of these values ... */
1114 g->offset2_y = 0; /* ... will be corrected later */
1115 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1116 g->crumbled_like = -1; /* do not use clone element */
1117 g->diggable_like = -1; /* do not use clone element */
1118 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1119 g->scale_up_factor = 1; /* default: no scaling up */
1120 g->tile_size = TILESIZE; /* default: standard tile size */
1121 g->clone_from = -1; /* do not use clone graphic */
1122 g->anim_delay_fixed = 0;
1123 g->anim_delay_random = 0;
1124 g->post_delay_fixed = 0;
1125 g->post_delay_random = 0;
1126 g->fade_mode = FADE_MODE_DEFAULT;
1130 g->align = ALIGN_CENTER; /* default for title screens */
1131 g->valign = VALIGN_MIDDLE; /* default for title screens */
1132 g->sort_priority = 0; /* default for title screens */
1134 g->style = STYLE_DEFAULT;
1136 g->bitmaps = src_bitmaps;
1137 g->bitmap = src_bitmap;
1139 /* optional zoom factor for scaling up the image to a larger size */
1140 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1141 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1142 if (g->scale_up_factor < 1)
1143 g->scale_up_factor = 1; /* no scaling */
1145 /* optional tile size for using non-standard image size */
1146 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1148 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1151 // CHECK: should tile sizes less than standard tile size be allowed?
1152 if (g->tile_size < TILESIZE)
1153 g->tile_size = TILESIZE; /* standard tile size */
1156 // when setting tile size, also set width and height accordingly
1157 g->width = g->tile_size;
1158 g->height = g->tile_size;
1161 if (g->use_image_size)
1163 /* set new default bitmap size (with scaling, but without small images) */
1164 g->width = get_scaled_graphic_width(graphic);
1165 g->height = get_scaled_graphic_height(graphic);
1168 /* optional width and height of each animation frame */
1169 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1170 g->width = parameter[GFX_ARG_WIDTH];
1171 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1172 g->height = parameter[GFX_ARG_HEIGHT];
1174 /* optional x and y tile position of animation frame sequence */
1175 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1176 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1177 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1178 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1180 /* optional x and y pixel position of animation frame sequence */
1181 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1182 g->src_x = parameter[GFX_ARG_X];
1183 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1184 g->src_y = parameter[GFX_ARG_Y];
1190 Error(ERR_INFO_LINE, "-");
1191 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1192 g->width, getTokenFromImageID(graphic), TILEX);
1193 Error(ERR_INFO_LINE, "-");
1195 g->width = TILEX; /* will be checked to be inside bitmap later */
1200 Error(ERR_INFO_LINE, "-");
1201 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1202 g->height, getTokenFromImageID(graphic), TILEY);
1203 Error(ERR_INFO_LINE, "-");
1205 g->height = TILEY; /* will be checked to be inside bitmap later */
1211 /* get final bitmap size (with scaling, but without small images) */
1212 int src_image_width = get_scaled_graphic_width(graphic);
1213 int src_image_height = get_scaled_graphic_height(graphic);
1215 if (src_image_width == 0 || src_image_height == 0)
1217 /* only happens when loaded outside artwork system (like "global.busy") */
1218 src_image_width = src_bitmap->width;
1219 src_image_height = src_bitmap->height;
1222 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1224 anim_frames_per_row = src_image_width / g->tile_size;
1225 anim_frames_per_col = src_image_height / g->tile_size;
1229 anim_frames_per_row = src_image_width / g->width;
1230 anim_frames_per_col = src_image_height / g->height;
1233 g->src_image_width = src_image_width;
1234 g->src_image_height = src_image_height;
1237 /* correct x or y offset dependent of vertical or horizontal frame order */
1238 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1240 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1241 parameter[GFX_ARG_OFFSET] : g->height);
1242 anim_frames_per_line = anim_frames_per_col;
1244 else /* frames are ordered horizontally */
1246 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1247 parameter[GFX_ARG_OFFSET] : g->width);
1248 anim_frames_per_line = anim_frames_per_row;
1251 /* optionally, the x and y offset of frames can be specified directly */
1252 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1253 g->offset_x = parameter[GFX_ARG_XOFFSET];
1254 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1255 g->offset_y = parameter[GFX_ARG_YOFFSET];
1257 /* optionally, moving animations may have separate start and end graphics */
1258 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1260 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1261 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1263 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1264 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1265 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1266 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1267 else /* frames are ordered horizontally */
1268 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1269 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1271 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1272 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1273 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1274 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1275 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1277 /* optionally, the second movement tile can be specified as start tile */
1278 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1279 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1281 /* automatically determine correct number of frames, if not defined */
1282 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1283 g->anim_frames = parameter[GFX_ARG_FRAMES];
1284 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1285 g->anim_frames = anim_frames_per_row;
1286 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1287 g->anim_frames = anim_frames_per_col;
1291 if (g->anim_frames == 0) /* frames must be at least 1 */
1294 g->anim_frames_per_line =
1295 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1296 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1298 g->anim_delay = parameter[GFX_ARG_DELAY];
1299 if (g->anim_delay == 0) /* delay must be at least 1 */
1302 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1304 /* automatically determine correct start frame, if not defined */
1305 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1306 g->anim_start_frame = 0;
1307 else if (g->anim_mode & ANIM_REVERSE)
1308 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1310 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1312 /* animation synchronized with global frame counter, not move position */
1313 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1315 /* optional element for cloning crumble graphics */
1316 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1317 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1319 /* optional element for cloning digging graphics */
1320 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1321 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1323 /* optional border size for "crumbling" diggable graphics */
1324 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1325 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1327 /* this is only used for player "boring" and "sleeping" actions */
1328 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1329 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1330 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1331 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1332 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1333 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1334 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1335 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1337 /* this is only used for toon animations */
1338 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1339 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1340 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1341 g->step_frames = parameter[GFX_ARG_STEP_FRAMES];
1342 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1343 g->direction = parameter[GFX_ARG_DIRECTION];
1344 g->position = parameter[GFX_ARG_POSITION];
1346 /* this is only used for drawing font characters */
1347 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1348 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1350 /* this is only used for drawing envelope graphics */
1351 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1353 /* optional graphic for cloning all graphics settings */
1354 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1355 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1357 /* optional settings for drawing title screens and title messages */
1358 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1359 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1360 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1361 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1362 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1363 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1364 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1365 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1366 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1367 g->align = parameter[GFX_ARG_ALIGN];
1368 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1369 g->valign = parameter[GFX_ARG_VALIGN];
1370 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1371 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1373 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1374 g->class = parameter[GFX_ARG_CLASS];
1375 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1376 g->style = parameter[GFX_ARG_STYLE];
1378 /* this is only used for drawing menu buttons and text */
1379 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1380 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1381 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1382 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1385 static void set_graphic_parameters(int graphic)
1387 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1388 char **parameter_raw = image->parameter;
1389 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1390 int parameter[NUM_GFX_ARGS];
1393 /* if fallback to default artwork is done, also use the default parameters */
1394 if (image->fallback_to_default)
1395 parameter_raw = image->default_parameter;
1397 /* get integer values from string parameters */
1398 for (i = 0; i < NUM_GFX_ARGS; i++)
1399 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1400 image_config_suffix[i].token,
1401 image_config_suffix[i].type);
1403 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1405 UPDATE_BUSY_STATE();
1408 static void set_cloned_graphic_parameters(int graphic)
1410 int fallback_graphic = IMG_CHAR_EXCLAM;
1411 int max_num_images = getImageListSize();
1412 int clone_graphic = graphic_info[graphic].clone_from;
1413 int num_references_followed = 1;
1415 while (graphic_info[clone_graphic].clone_from != -1 &&
1416 num_references_followed < max_num_images)
1418 clone_graphic = graphic_info[clone_graphic].clone_from;
1420 num_references_followed++;
1423 if (num_references_followed >= max_num_images)
1425 Error(ERR_INFO_LINE, "-");
1426 Error(ERR_INFO, "warning: error found in config file:");
1427 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1428 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1429 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1430 Error(ERR_INFO, "custom graphic rejected for this element/action");
1432 if (graphic == fallback_graphic)
1433 Error(ERR_EXIT, "no fallback graphic available");
1435 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1436 Error(ERR_INFO_LINE, "-");
1438 graphic_info[graphic] = graphic_info[fallback_graphic];
1442 graphic_info[graphic] = graphic_info[clone_graphic];
1443 graphic_info[graphic].clone_from = clone_graphic;
1447 static void InitGraphicInfo()
1449 int fallback_graphic = IMG_CHAR_EXCLAM;
1450 int num_images = getImageListSize();
1453 /* use image size as default values for width and height for these images */
1454 static int full_size_graphics[] =
1457 IMG_GLOBAL_BORDER_MAIN,
1458 IMG_GLOBAL_BORDER_SCORES,
1459 IMG_GLOBAL_BORDER_EDITOR,
1460 IMG_GLOBAL_BORDER_PLAYING,
1463 IMG_BACKGROUND_ENVELOPE_1,
1464 IMG_BACKGROUND_ENVELOPE_2,
1465 IMG_BACKGROUND_ENVELOPE_3,
1466 IMG_BACKGROUND_ENVELOPE_4,
1467 IMG_BACKGROUND_REQUEST,
1470 IMG_BACKGROUND_TITLE_INITIAL,
1471 IMG_BACKGROUND_TITLE,
1472 IMG_BACKGROUND_MAIN,
1473 IMG_BACKGROUND_LEVELS,
1474 IMG_BACKGROUND_LEVELNR,
1475 IMG_BACKGROUND_SCORES,
1476 IMG_BACKGROUND_EDITOR,
1477 IMG_BACKGROUND_INFO,
1478 IMG_BACKGROUND_INFO_ELEMENTS,
1479 IMG_BACKGROUND_INFO_MUSIC,
1480 IMG_BACKGROUND_INFO_CREDITS,
1481 IMG_BACKGROUND_INFO_PROGRAM,
1482 IMG_BACKGROUND_INFO_VERSION,
1483 IMG_BACKGROUND_INFO_LEVELSET,
1484 IMG_BACKGROUND_SETUP,
1485 IMG_BACKGROUND_PLAYING,
1486 IMG_BACKGROUND_DOOR,
1487 IMG_BACKGROUND_TAPE,
1488 IMG_BACKGROUND_PANEL,
1489 IMG_BACKGROUND_PALETTE,
1490 IMG_BACKGROUND_TOOLBOX,
1492 IMG_TITLESCREEN_INITIAL_1,
1493 IMG_TITLESCREEN_INITIAL_2,
1494 IMG_TITLESCREEN_INITIAL_3,
1495 IMG_TITLESCREEN_INITIAL_4,
1496 IMG_TITLESCREEN_INITIAL_5,
1503 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1504 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1505 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1506 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1507 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1508 IMG_BACKGROUND_TITLEMESSAGE_1,
1509 IMG_BACKGROUND_TITLEMESSAGE_2,
1510 IMG_BACKGROUND_TITLEMESSAGE_3,
1511 IMG_BACKGROUND_TITLEMESSAGE_4,
1512 IMG_BACKGROUND_TITLEMESSAGE_5,
1517 checked_free(graphic_info);
1519 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1521 /* initialize "use_image_size" flag with default value */
1522 for (i = 0; i < num_images; i++)
1523 graphic_info[i].use_image_size = FALSE;
1525 /* initialize "use_image_size" flag from static configuration above */
1526 for (i = 0; full_size_graphics[i] != -1; i++)
1527 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1529 /* first set all graphic paramaters ... */
1530 for (i = 0; i < num_images; i++)
1531 set_graphic_parameters(i);
1533 /* ... then copy these parameters for cloned graphics */
1534 for (i = 0; i < num_images; i++)
1535 if (graphic_info[i].clone_from != -1)
1536 set_cloned_graphic_parameters(i);
1538 for (i = 0; i < num_images; i++)
1543 int first_frame, last_frame;
1544 int src_bitmap_width, src_bitmap_height;
1546 /* now check if no animation frames are outside of the loaded image */
1548 if (graphic_info[i].bitmap == NULL)
1549 continue; /* skip check for optional images that are undefined */
1551 /* get image size (this can differ from the standard element tile size!) */
1552 width = graphic_info[i].width;
1553 height = graphic_info[i].height;
1555 /* get final bitmap size (with scaling, but without small images) */
1556 src_bitmap_width = graphic_info[i].src_image_width;
1557 src_bitmap_height = graphic_info[i].src_image_height;
1559 /* check if first animation frame is inside specified bitmap */
1562 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1564 /* this avoids calculating wrong start position for out-of-bounds frame */
1565 src_x = graphic_info[i].src_x;
1566 src_y = graphic_info[i].src_y;
1568 if (src_x < 0 || src_y < 0 ||
1569 src_x + width > src_bitmap_width ||
1570 src_y + height > src_bitmap_height)
1572 Error(ERR_INFO_LINE, "-");
1573 Error(ERR_INFO, "warning: error found in config file:");
1574 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1575 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1576 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1578 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1579 src_x, src_y, src_bitmap_width, src_bitmap_height);
1580 Error(ERR_INFO, "custom graphic rejected for this element/action");
1582 if (i == fallback_graphic)
1583 Error(ERR_EXIT, "no fallback graphic available");
1585 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1586 Error(ERR_INFO_LINE, "-");
1588 graphic_info[i] = graphic_info[fallback_graphic];
1591 /* check if last animation frame is inside specified bitmap */
1593 last_frame = graphic_info[i].anim_frames - 1;
1594 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1596 if (src_x < 0 || src_y < 0 ||
1597 src_x + width > src_bitmap_width ||
1598 src_y + height > src_bitmap_height)
1600 Error(ERR_INFO_LINE, "-");
1601 Error(ERR_INFO, "warning: error found in config file:");
1602 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1603 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1604 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1606 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1607 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1608 Error(ERR_INFO, "::: %d, %d", width, height);
1609 Error(ERR_INFO, "custom graphic rejected for this element/action");
1611 if (i == fallback_graphic)
1612 Error(ERR_EXIT, "no fallback graphic available");
1614 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1615 Error(ERR_INFO_LINE, "-");
1617 graphic_info[i] = graphic_info[fallback_graphic];
1622 static void InitGraphicCompatibilityInfo()
1624 struct FileInfo *fi_global_door =
1625 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1626 int num_images = getImageListSize();
1629 /* the following compatibility handling is needed for the following case:
1630 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1631 graphics mainly used for door and panel graphics, like editor, tape and
1632 in-game buttons with hard-coded bitmap positions and button sizes; as
1633 these graphics now have individual definitions, redefining "global.door"
1634 to change all these graphics at once like before does not work anymore
1635 (because all those individual definitions still have their default values);
1636 to solve this, remap all those individual definitions that are not
1637 redefined to the new bitmap of "global.door" if it was redefined */
1639 /* special compatibility handling if image "global.door" was redefined */
1640 if (fi_global_door->redefined)
1642 for (i = 0; i < num_images; i++)
1644 struct FileInfo *fi = getImageListEntryFromImageID(i);
1646 /* process only those images that still use the default settings */
1649 /* process all images which default to same image as "global.door" */
1650 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1652 // printf("::: special treatment needed for token '%s'\n", fi->token);
1654 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1660 InitGraphicCompatibilityInfo_Doors();
1663 static void InitElementSoundInfo()
1665 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1666 int num_property_mappings = getSoundListPropertyMappingSize();
1669 /* set values to -1 to identify later as "uninitialized" values */
1670 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1671 for (act = 0; act < NUM_ACTIONS; act++)
1672 element_info[i].sound[act] = -1;
1674 /* initialize element/sound mapping from static configuration */
1675 for (i = 0; element_to_sound[i].element > -1; i++)
1677 int element = element_to_sound[i].element;
1678 int action = element_to_sound[i].action;
1679 int sound = element_to_sound[i].sound;
1680 boolean is_class = element_to_sound[i].is_class;
1683 action = ACTION_DEFAULT;
1686 element_info[element].sound[action] = sound;
1688 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1689 if (strEqual(element_info[j].class_name,
1690 element_info[element].class_name))
1691 element_info[j].sound[action] = sound;
1694 /* initialize element class/sound mapping from dynamic configuration */
1695 for (i = 0; i < num_property_mappings; i++)
1697 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1698 int action = property_mapping[i].ext1_index;
1699 int sound = property_mapping[i].artwork_index;
1701 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1705 action = ACTION_DEFAULT;
1707 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1708 if (strEqual(element_info[j].class_name,
1709 element_info[element_class].class_name))
1710 element_info[j].sound[action] = sound;
1713 /* initialize element/sound mapping from dynamic configuration */
1714 for (i = 0; i < num_property_mappings; i++)
1716 int element = property_mapping[i].base_index;
1717 int action = property_mapping[i].ext1_index;
1718 int sound = property_mapping[i].artwork_index;
1720 if (element >= MAX_NUM_ELEMENTS)
1724 action = ACTION_DEFAULT;
1726 element_info[element].sound[action] = sound;
1729 /* now set all '-1' values to element specific default values */
1730 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1732 for (act = 0; act < NUM_ACTIONS; act++)
1734 /* generic default action sound (defined by "[default]" directive) */
1735 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1737 /* look for special default action sound (classic game specific) */
1738 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1739 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1740 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1741 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1742 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1743 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1745 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1746 /* !!! make this better !!! */
1747 if (i == EL_EMPTY_SPACE)
1748 default_action_sound = element_info[EL_DEFAULT].sound[act];
1750 /* no sound for this specific action -- use default action sound */
1751 if (element_info[i].sound[act] == -1)
1752 element_info[i].sound[act] = default_action_sound;
1756 /* copy sound settings to some elements that are only stored in level file
1757 in native R'n'D levels, but are used by game engine in native EM levels */
1758 for (i = 0; copy_properties[i][0] != -1; i++)
1759 for (j = 1; j <= 4; j++)
1760 for (act = 0; act < NUM_ACTIONS; act++)
1761 element_info[copy_properties[i][j]].sound[act] =
1762 element_info[copy_properties[i][0]].sound[act];
1765 static void InitGameModeSoundInfo()
1769 /* set values to -1 to identify later as "uninitialized" values */
1770 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1773 /* initialize gamemode/sound mapping from static configuration */
1774 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1776 int gamemode = gamemode_to_sound[i].gamemode;
1777 int sound = gamemode_to_sound[i].sound;
1780 gamemode = GAME_MODE_DEFAULT;
1782 menu.sound[gamemode] = sound;
1785 /* now set all '-1' values to levelset specific default values */
1786 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1787 if (menu.sound[i] == -1)
1788 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1791 static void set_sound_parameters(int sound, char **parameter_raw)
1793 int parameter[NUM_SND_ARGS];
1796 /* get integer values from string parameters */
1797 for (i = 0; i < NUM_SND_ARGS; i++)
1799 get_parameter_value(parameter_raw[i],
1800 sound_config_suffix[i].token,
1801 sound_config_suffix[i].type);
1803 /* explicit loop mode setting in configuration overrides default value */
1804 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1805 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1807 /* sound volume to change the original volume when loading the sound file */
1808 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1810 /* sound priority to give certain sounds a higher or lower priority */
1811 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1814 static void InitSoundInfo()
1816 int *sound_effect_properties;
1817 int num_sounds = getSoundListSize();
1820 checked_free(sound_info);
1822 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1823 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1825 /* initialize sound effect for all elements to "no sound" */
1826 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1827 for (j = 0; j < NUM_ACTIONS; j++)
1828 element_info[i].sound[j] = SND_UNDEFINED;
1830 for (i = 0; i < num_sounds; i++)
1832 struct FileInfo *sound = getSoundListEntry(i);
1833 int len_effect_text = strlen(sound->token);
1835 sound_effect_properties[i] = ACTION_OTHER;
1836 sound_info[i].loop = FALSE; /* default: play sound only once */
1838 /* determine all loop sounds and identify certain sound classes */
1840 for (j = 0; element_action_info[j].suffix; j++)
1842 int len_action_text = strlen(element_action_info[j].suffix);
1844 if (len_action_text < len_effect_text &&
1845 strEqual(&sound->token[len_effect_text - len_action_text],
1846 element_action_info[j].suffix))
1848 sound_effect_properties[i] = element_action_info[j].value;
1849 sound_info[i].loop = element_action_info[j].is_loop_sound;
1855 /* associate elements and some selected sound actions */
1857 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1859 if (element_info[j].class_name)
1861 int len_class_text = strlen(element_info[j].class_name);
1863 if (len_class_text + 1 < len_effect_text &&
1864 strncmp(sound->token,
1865 element_info[j].class_name, len_class_text) == 0 &&
1866 sound->token[len_class_text] == '.')
1868 int sound_action_value = sound_effect_properties[i];
1870 element_info[j].sound[sound_action_value] = i;
1875 set_sound_parameters(i, sound->parameter);
1878 free(sound_effect_properties);
1881 static void InitGameModeMusicInfo()
1883 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1884 int num_property_mappings = getMusicListPropertyMappingSize();
1885 int default_levelset_music = -1;
1888 /* set values to -1 to identify later as "uninitialized" values */
1889 for (i = 0; i < MAX_LEVELS; i++)
1890 levelset.music[i] = -1;
1891 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1894 /* initialize gamemode/music mapping from static configuration */
1895 for (i = 0; gamemode_to_music[i].music > -1; i++)
1897 int gamemode = gamemode_to_music[i].gamemode;
1898 int music = gamemode_to_music[i].music;
1901 gamemode = GAME_MODE_DEFAULT;
1903 menu.music[gamemode] = music;
1906 /* initialize gamemode/music mapping from dynamic configuration */
1907 for (i = 0; i < num_property_mappings; i++)
1909 int prefix = property_mapping[i].base_index;
1910 int gamemode = property_mapping[i].ext1_index;
1911 int level = property_mapping[i].ext2_index;
1912 int music = property_mapping[i].artwork_index;
1914 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1918 gamemode = GAME_MODE_DEFAULT;
1920 /* level specific music only allowed for in-game music */
1921 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1922 gamemode = GAME_MODE_PLAYING;
1927 default_levelset_music = music;
1930 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1931 levelset.music[level] = music;
1932 if (gamemode != GAME_MODE_PLAYING)
1933 menu.music[gamemode] = music;
1936 /* now set all '-1' values to menu specific default values */
1937 /* (undefined values of "levelset.music[]" might stay at "-1" to
1938 allow dynamic selection of music files from music directory!) */
1939 for (i = 0; i < MAX_LEVELS; i++)
1940 if (levelset.music[i] == -1)
1941 levelset.music[i] = default_levelset_music;
1942 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1943 if (menu.music[i] == -1)
1944 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1947 static void set_music_parameters(int music, char **parameter_raw)
1949 int parameter[NUM_MUS_ARGS];
1952 /* get integer values from string parameters */
1953 for (i = 0; i < NUM_MUS_ARGS; i++)
1955 get_parameter_value(parameter_raw[i],
1956 music_config_suffix[i].token,
1957 music_config_suffix[i].type);
1959 /* explicit loop mode setting in configuration overrides default value */
1960 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1961 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1964 static void InitMusicInfo()
1966 int num_music = getMusicListSize();
1969 checked_free(music_info);
1971 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1973 for (i = 0; i < num_music; i++)
1975 struct FileInfo *music = getMusicListEntry(i);
1976 int len_music_text = strlen(music->token);
1978 music_info[i].loop = TRUE; /* default: play music in loop mode */
1980 /* determine all loop music */
1982 for (j = 0; music_prefix_info[j].prefix; j++)
1984 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1986 if (len_prefix_text < len_music_text &&
1987 strncmp(music->token,
1988 music_prefix_info[j].prefix, len_prefix_text) == 0)
1990 music_info[i].loop = music_prefix_info[j].is_loop_music;
1996 set_music_parameters(i, music->parameter);
2000 static void ReinitializeGraphics()
2002 print_timestamp_init("ReinitializeGraphics");
2004 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2006 InitGraphicInfo(); /* graphic properties mapping */
2007 print_timestamp_time("InitGraphicInfo");
2008 InitElementGraphicInfo(); /* element game graphic mapping */
2009 print_timestamp_time("InitElementGraphicInfo");
2010 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2011 print_timestamp_time("InitElementSpecialGraphicInfo");
2013 InitElementSmallImages(); /* scale elements to all needed sizes */
2014 print_timestamp_time("InitElementSmallImages");
2015 InitScaledImages(); /* scale all other images, if needed */
2016 print_timestamp_time("InitScaledImages");
2017 InitBitmapPointers(); /* set standard size bitmap pointers */
2018 print_timestamp_time("InitBitmapPointers");
2019 InitFontGraphicInfo(); /* initialize text drawing functions */
2020 print_timestamp_time("InitFontGraphicInfo");
2021 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2022 print_timestamp_time("InitGlobalAnimGraphicInfo");
2023 InitGlobalAnimImages(); /* initialize global animation images */
2024 print_timestamp_time("InitGlobalAnimImages");
2026 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2027 print_timestamp_time("InitGraphicInfo_EM");
2029 InitGraphicCompatibilityInfo();
2030 print_timestamp_time("InitGraphicCompatibilityInfo");
2032 SetMainBackgroundImage(IMG_BACKGROUND);
2033 print_timestamp_time("SetMainBackgroundImage");
2034 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2035 print_timestamp_time("SetDoorBackgroundImage");
2038 print_timestamp_time("InitGadgets");
2040 print_timestamp_time("InitToons");
2042 print_timestamp_time("InitDoors");
2044 print_timestamp_done("ReinitializeGraphics");
2047 static void ReinitializeSounds()
2049 InitSoundInfo(); /* sound properties mapping */
2050 InitElementSoundInfo(); /* element game sound mapping */
2051 InitGameModeSoundInfo(); /* game mode sound mapping */
2053 InitPlayLevelSound(); /* internal game sound settings */
2056 static void ReinitializeMusic()
2058 InitMusicInfo(); /* music properties mapping */
2059 InitGameModeMusicInfo(); /* game mode music mapping */
2062 static int get_special_property_bit(int element, int property_bit_nr)
2064 struct PropertyBitInfo
2070 static struct PropertyBitInfo pb_can_move_into_acid[] =
2072 /* the player may be able fall into acid when gravity is activated */
2077 { EL_SP_MURPHY, 0 },
2078 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2080 /* all elements that can move may be able to also move into acid */
2083 { EL_BUG_RIGHT, 1 },
2086 { EL_SPACESHIP, 2 },
2087 { EL_SPACESHIP_LEFT, 2 },
2088 { EL_SPACESHIP_RIGHT, 2 },
2089 { EL_SPACESHIP_UP, 2 },
2090 { EL_SPACESHIP_DOWN, 2 },
2091 { EL_BD_BUTTERFLY, 3 },
2092 { EL_BD_BUTTERFLY_LEFT, 3 },
2093 { EL_BD_BUTTERFLY_RIGHT, 3 },
2094 { EL_BD_BUTTERFLY_UP, 3 },
2095 { EL_BD_BUTTERFLY_DOWN, 3 },
2096 { EL_BD_FIREFLY, 4 },
2097 { EL_BD_FIREFLY_LEFT, 4 },
2098 { EL_BD_FIREFLY_RIGHT, 4 },
2099 { EL_BD_FIREFLY_UP, 4 },
2100 { EL_BD_FIREFLY_DOWN, 4 },
2102 { EL_YAMYAM_LEFT, 5 },
2103 { EL_YAMYAM_RIGHT, 5 },
2104 { EL_YAMYAM_UP, 5 },
2105 { EL_YAMYAM_DOWN, 5 },
2106 { EL_DARK_YAMYAM, 6 },
2109 { EL_PACMAN_LEFT, 8 },
2110 { EL_PACMAN_RIGHT, 8 },
2111 { EL_PACMAN_UP, 8 },
2112 { EL_PACMAN_DOWN, 8 },
2114 { EL_MOLE_LEFT, 9 },
2115 { EL_MOLE_RIGHT, 9 },
2117 { EL_MOLE_DOWN, 9 },
2121 { EL_SATELLITE, 13 },
2122 { EL_SP_SNIKSNAK, 14 },
2123 { EL_SP_ELECTRON, 15 },
2126 { EL_EMC_ANDROID, 18 },
2131 static struct PropertyBitInfo pb_dont_collide_with[] =
2133 { EL_SP_SNIKSNAK, 0 },
2134 { EL_SP_ELECTRON, 1 },
2142 struct PropertyBitInfo *pb_info;
2145 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2146 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2151 struct PropertyBitInfo *pb_info = NULL;
2154 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2155 if (pb_definition[i].bit_nr == property_bit_nr)
2156 pb_info = pb_definition[i].pb_info;
2158 if (pb_info == NULL)
2161 for (i = 0; pb_info[i].element != -1; i++)
2162 if (pb_info[i].element == element)
2163 return pb_info[i].bit_nr;
2168 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2169 boolean property_value)
2171 int bit_nr = get_special_property_bit(element, property_bit_nr);
2176 *bitfield |= (1 << bit_nr);
2178 *bitfield &= ~(1 << bit_nr);
2182 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2184 int bit_nr = get_special_property_bit(element, property_bit_nr);
2187 return ((*bitfield & (1 << bit_nr)) != 0);
2192 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2194 static int group_nr;
2195 static struct ElementGroupInfo *group;
2196 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2199 if (actual_group == NULL) /* not yet initialized */
2202 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2204 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2205 group_element - EL_GROUP_START + 1);
2207 /* replace element which caused too deep recursion by question mark */
2208 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2213 if (recursion_depth == 0) /* initialization */
2215 group = actual_group;
2216 group_nr = GROUP_NR(group_element);
2218 group->num_elements_resolved = 0;
2219 group->choice_pos = 0;
2221 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2222 element_info[i].in_group[group_nr] = FALSE;
2225 for (i = 0; i < actual_group->num_elements; i++)
2227 int element = actual_group->element[i];
2229 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2232 if (IS_GROUP_ELEMENT(element))
2233 ResolveGroupElementExt(element, recursion_depth + 1);
2236 group->element_resolved[group->num_elements_resolved++] = element;
2237 element_info[element].in_group[group_nr] = TRUE;
2242 void ResolveGroupElement(int group_element)
2244 ResolveGroupElementExt(group_element, 0);
2247 void InitElementPropertiesStatic()
2249 static boolean clipboard_elements_initialized = FALSE;
2251 static int ep_diggable[] =
2256 EL_SP_BUGGY_BASE_ACTIVATING,
2259 EL_INVISIBLE_SAND_ACTIVE,
2262 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2263 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2268 EL_SP_BUGGY_BASE_ACTIVE,
2275 static int ep_collectible_only[] =
2297 EL_DYNABOMB_INCREASE_NUMBER,
2298 EL_DYNABOMB_INCREASE_SIZE,
2299 EL_DYNABOMB_INCREASE_POWER,
2317 /* !!! handle separately !!! */
2318 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2324 static int ep_dont_run_into[] =
2326 /* same elements as in 'ep_dont_touch' */
2332 /* same elements as in 'ep_dont_collide_with' */
2344 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2349 EL_SP_BUGGY_BASE_ACTIVE,
2356 static int ep_dont_collide_with[] =
2358 /* same elements as in 'ep_dont_touch' */
2375 static int ep_dont_touch[] =
2385 static int ep_indestructible[] =
2389 EL_ACID_POOL_TOPLEFT,
2390 EL_ACID_POOL_TOPRIGHT,
2391 EL_ACID_POOL_BOTTOMLEFT,
2392 EL_ACID_POOL_BOTTOM,
2393 EL_ACID_POOL_BOTTOMRIGHT,
2394 EL_SP_HARDWARE_GRAY,
2395 EL_SP_HARDWARE_GREEN,
2396 EL_SP_HARDWARE_BLUE,
2398 EL_SP_HARDWARE_YELLOW,
2399 EL_SP_HARDWARE_BASE_1,
2400 EL_SP_HARDWARE_BASE_2,
2401 EL_SP_HARDWARE_BASE_3,
2402 EL_SP_HARDWARE_BASE_4,
2403 EL_SP_HARDWARE_BASE_5,
2404 EL_SP_HARDWARE_BASE_6,
2405 EL_INVISIBLE_STEELWALL,
2406 EL_INVISIBLE_STEELWALL_ACTIVE,
2407 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2408 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2409 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2410 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2411 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2412 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2413 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2414 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2415 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2416 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2417 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2418 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2420 EL_LIGHT_SWITCH_ACTIVE,
2421 EL_SIGN_EXCLAMATION,
2422 EL_SIGN_RADIOACTIVITY,
2429 EL_SIGN_ENTRY_FORBIDDEN,
2430 EL_SIGN_EMERGENCY_EXIT,
2438 EL_STEEL_EXIT_CLOSED,
2440 EL_STEEL_EXIT_OPENING,
2441 EL_STEEL_EXIT_CLOSING,
2442 EL_EM_STEEL_EXIT_CLOSED,
2443 EL_EM_STEEL_EXIT_OPEN,
2444 EL_EM_STEEL_EXIT_OPENING,
2445 EL_EM_STEEL_EXIT_CLOSING,
2446 EL_DC_STEELWALL_1_LEFT,
2447 EL_DC_STEELWALL_1_RIGHT,
2448 EL_DC_STEELWALL_1_TOP,
2449 EL_DC_STEELWALL_1_BOTTOM,
2450 EL_DC_STEELWALL_1_HORIZONTAL,
2451 EL_DC_STEELWALL_1_VERTICAL,
2452 EL_DC_STEELWALL_1_TOPLEFT,
2453 EL_DC_STEELWALL_1_TOPRIGHT,
2454 EL_DC_STEELWALL_1_BOTTOMLEFT,
2455 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2456 EL_DC_STEELWALL_1_TOPLEFT_2,
2457 EL_DC_STEELWALL_1_TOPRIGHT_2,
2458 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2459 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2460 EL_DC_STEELWALL_2_LEFT,
2461 EL_DC_STEELWALL_2_RIGHT,
2462 EL_DC_STEELWALL_2_TOP,
2463 EL_DC_STEELWALL_2_BOTTOM,
2464 EL_DC_STEELWALL_2_HORIZONTAL,
2465 EL_DC_STEELWALL_2_VERTICAL,
2466 EL_DC_STEELWALL_2_MIDDLE,
2467 EL_DC_STEELWALL_2_SINGLE,
2468 EL_STEELWALL_SLIPPERY,
2482 EL_GATE_1_GRAY_ACTIVE,
2483 EL_GATE_2_GRAY_ACTIVE,
2484 EL_GATE_3_GRAY_ACTIVE,
2485 EL_GATE_4_GRAY_ACTIVE,
2494 EL_EM_GATE_1_GRAY_ACTIVE,
2495 EL_EM_GATE_2_GRAY_ACTIVE,
2496 EL_EM_GATE_3_GRAY_ACTIVE,
2497 EL_EM_GATE_4_GRAY_ACTIVE,
2506 EL_EMC_GATE_5_GRAY_ACTIVE,
2507 EL_EMC_GATE_6_GRAY_ACTIVE,
2508 EL_EMC_GATE_7_GRAY_ACTIVE,
2509 EL_EMC_GATE_8_GRAY_ACTIVE,
2511 EL_DC_GATE_WHITE_GRAY,
2512 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2513 EL_DC_GATE_FAKE_GRAY,
2515 EL_SWITCHGATE_OPENING,
2516 EL_SWITCHGATE_CLOSED,
2517 EL_SWITCHGATE_CLOSING,
2518 EL_DC_SWITCHGATE_SWITCH_UP,
2519 EL_DC_SWITCHGATE_SWITCH_DOWN,
2521 EL_TIMEGATE_OPENING,
2523 EL_TIMEGATE_CLOSING,
2524 EL_DC_TIMEGATE_SWITCH,
2525 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2529 EL_TUBE_VERTICAL_LEFT,
2530 EL_TUBE_VERTICAL_RIGHT,
2531 EL_TUBE_HORIZONTAL_UP,
2532 EL_TUBE_HORIZONTAL_DOWN,
2537 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2538 EL_EXPANDABLE_STEELWALL_VERTICAL,
2539 EL_EXPANDABLE_STEELWALL_ANY,
2544 static int ep_slippery[] =
2558 EL_ROBOT_WHEEL_ACTIVE,
2564 EL_ACID_POOL_TOPLEFT,
2565 EL_ACID_POOL_TOPRIGHT,
2575 EL_STEELWALL_SLIPPERY,
2578 EL_EMC_WALL_SLIPPERY_1,
2579 EL_EMC_WALL_SLIPPERY_2,
2580 EL_EMC_WALL_SLIPPERY_3,
2581 EL_EMC_WALL_SLIPPERY_4,
2583 EL_EMC_MAGIC_BALL_ACTIVE,
2588 static int ep_can_change[] =
2593 static int ep_can_move[] =
2595 /* same elements as in 'pb_can_move_into_acid' */
2618 static int ep_can_fall[] =
2632 EL_QUICKSAND_FAST_FULL,
2634 EL_BD_MAGIC_WALL_FULL,
2635 EL_DC_MAGIC_WALL_FULL,
2649 static int ep_can_smash_player[] =
2675 static int ep_can_smash_enemies[] =
2684 static int ep_can_smash_everything[] =
2693 static int ep_explodes_by_fire[] =
2695 /* same elements as in 'ep_explodes_impact' */
2700 /* same elements as in 'ep_explodes_smashed' */
2710 EL_EM_DYNAMITE_ACTIVE,
2711 EL_DYNABOMB_PLAYER_1_ACTIVE,
2712 EL_DYNABOMB_PLAYER_2_ACTIVE,
2713 EL_DYNABOMB_PLAYER_3_ACTIVE,
2714 EL_DYNABOMB_PLAYER_4_ACTIVE,
2715 EL_DYNABOMB_INCREASE_NUMBER,
2716 EL_DYNABOMB_INCREASE_SIZE,
2717 EL_DYNABOMB_INCREASE_POWER,
2718 EL_SP_DISK_RED_ACTIVE,
2732 static int ep_explodes_smashed[] =
2734 /* same elements as in 'ep_explodes_impact' */
2748 static int ep_explodes_impact[] =
2757 static int ep_walkable_over[] =
2761 EL_SOKOBAN_FIELD_EMPTY,
2768 EL_EM_STEEL_EXIT_OPEN,
2769 EL_EM_STEEL_EXIT_OPENING,
2778 EL_GATE_1_GRAY_ACTIVE,
2779 EL_GATE_2_GRAY_ACTIVE,
2780 EL_GATE_3_GRAY_ACTIVE,
2781 EL_GATE_4_GRAY_ACTIVE,
2789 static int ep_walkable_inside[] =
2794 EL_TUBE_VERTICAL_LEFT,
2795 EL_TUBE_VERTICAL_RIGHT,
2796 EL_TUBE_HORIZONTAL_UP,
2797 EL_TUBE_HORIZONTAL_DOWN,
2806 static int ep_walkable_under[] =
2811 static int ep_passable_over[] =
2821 EL_EM_GATE_1_GRAY_ACTIVE,
2822 EL_EM_GATE_2_GRAY_ACTIVE,
2823 EL_EM_GATE_3_GRAY_ACTIVE,
2824 EL_EM_GATE_4_GRAY_ACTIVE,
2833 EL_EMC_GATE_5_GRAY_ACTIVE,
2834 EL_EMC_GATE_6_GRAY_ACTIVE,
2835 EL_EMC_GATE_7_GRAY_ACTIVE,
2836 EL_EMC_GATE_8_GRAY_ACTIVE,
2838 EL_DC_GATE_WHITE_GRAY,
2839 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2846 static int ep_passable_inside[] =
2852 EL_SP_PORT_HORIZONTAL,
2853 EL_SP_PORT_VERTICAL,
2855 EL_SP_GRAVITY_PORT_LEFT,
2856 EL_SP_GRAVITY_PORT_RIGHT,
2857 EL_SP_GRAVITY_PORT_UP,
2858 EL_SP_GRAVITY_PORT_DOWN,
2859 EL_SP_GRAVITY_ON_PORT_LEFT,
2860 EL_SP_GRAVITY_ON_PORT_RIGHT,
2861 EL_SP_GRAVITY_ON_PORT_UP,
2862 EL_SP_GRAVITY_ON_PORT_DOWN,
2863 EL_SP_GRAVITY_OFF_PORT_LEFT,
2864 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2865 EL_SP_GRAVITY_OFF_PORT_UP,
2866 EL_SP_GRAVITY_OFF_PORT_DOWN,
2871 static int ep_passable_under[] =
2876 static int ep_droppable[] =
2881 static int ep_explodes_1x1_old[] =
2886 static int ep_pushable[] =
2898 EL_SOKOBAN_FIELD_FULL,
2907 static int ep_explodes_cross_old[] =
2912 static int ep_protected[] =
2914 /* same elements as in 'ep_walkable_inside' */
2918 EL_TUBE_VERTICAL_LEFT,
2919 EL_TUBE_VERTICAL_RIGHT,
2920 EL_TUBE_HORIZONTAL_UP,
2921 EL_TUBE_HORIZONTAL_DOWN,
2927 /* same elements as in 'ep_passable_over' */
2936 EL_EM_GATE_1_GRAY_ACTIVE,
2937 EL_EM_GATE_2_GRAY_ACTIVE,
2938 EL_EM_GATE_3_GRAY_ACTIVE,
2939 EL_EM_GATE_4_GRAY_ACTIVE,
2948 EL_EMC_GATE_5_GRAY_ACTIVE,
2949 EL_EMC_GATE_6_GRAY_ACTIVE,
2950 EL_EMC_GATE_7_GRAY_ACTIVE,
2951 EL_EMC_GATE_8_GRAY_ACTIVE,
2953 EL_DC_GATE_WHITE_GRAY,
2954 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2958 /* same elements as in 'ep_passable_inside' */
2963 EL_SP_PORT_HORIZONTAL,
2964 EL_SP_PORT_VERTICAL,
2966 EL_SP_GRAVITY_PORT_LEFT,
2967 EL_SP_GRAVITY_PORT_RIGHT,
2968 EL_SP_GRAVITY_PORT_UP,
2969 EL_SP_GRAVITY_PORT_DOWN,
2970 EL_SP_GRAVITY_ON_PORT_LEFT,
2971 EL_SP_GRAVITY_ON_PORT_RIGHT,
2972 EL_SP_GRAVITY_ON_PORT_UP,
2973 EL_SP_GRAVITY_ON_PORT_DOWN,
2974 EL_SP_GRAVITY_OFF_PORT_LEFT,
2975 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2976 EL_SP_GRAVITY_OFF_PORT_UP,
2977 EL_SP_GRAVITY_OFF_PORT_DOWN,
2982 static int ep_throwable[] =
2987 static int ep_can_explode[] =
2989 /* same elements as in 'ep_explodes_impact' */
2994 /* same elements as in 'ep_explodes_smashed' */
3000 /* elements that can explode by explosion or by dragonfire */
3004 EL_EM_DYNAMITE_ACTIVE,
3005 EL_DYNABOMB_PLAYER_1_ACTIVE,
3006 EL_DYNABOMB_PLAYER_2_ACTIVE,
3007 EL_DYNABOMB_PLAYER_3_ACTIVE,
3008 EL_DYNABOMB_PLAYER_4_ACTIVE,
3009 EL_DYNABOMB_INCREASE_NUMBER,
3010 EL_DYNABOMB_INCREASE_SIZE,
3011 EL_DYNABOMB_INCREASE_POWER,
3012 EL_SP_DISK_RED_ACTIVE,
3020 /* elements that can explode only by explosion */
3026 static int ep_gravity_reachable[] =
3032 EL_INVISIBLE_SAND_ACTIVE,
3037 EL_SP_PORT_HORIZONTAL,
3038 EL_SP_PORT_VERTICAL,
3040 EL_SP_GRAVITY_PORT_LEFT,
3041 EL_SP_GRAVITY_PORT_RIGHT,
3042 EL_SP_GRAVITY_PORT_UP,
3043 EL_SP_GRAVITY_PORT_DOWN,
3044 EL_SP_GRAVITY_ON_PORT_LEFT,
3045 EL_SP_GRAVITY_ON_PORT_RIGHT,
3046 EL_SP_GRAVITY_ON_PORT_UP,
3047 EL_SP_GRAVITY_ON_PORT_DOWN,
3048 EL_SP_GRAVITY_OFF_PORT_LEFT,
3049 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3050 EL_SP_GRAVITY_OFF_PORT_UP,
3051 EL_SP_GRAVITY_OFF_PORT_DOWN,
3057 static int ep_player[] =
3064 EL_SOKOBAN_FIELD_PLAYER,
3070 static int ep_can_pass_magic_wall[] =
3084 static int ep_can_pass_dc_magic_wall[] =
3100 static int ep_switchable[] =
3104 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3105 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3106 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3107 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3108 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3109 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3110 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3111 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3112 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3113 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3114 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3115 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3116 EL_SWITCHGATE_SWITCH_UP,
3117 EL_SWITCHGATE_SWITCH_DOWN,
3118 EL_DC_SWITCHGATE_SWITCH_UP,
3119 EL_DC_SWITCHGATE_SWITCH_DOWN,
3121 EL_LIGHT_SWITCH_ACTIVE,
3123 EL_DC_TIMEGATE_SWITCH,
3124 EL_BALLOON_SWITCH_LEFT,
3125 EL_BALLOON_SWITCH_RIGHT,
3126 EL_BALLOON_SWITCH_UP,
3127 EL_BALLOON_SWITCH_DOWN,
3128 EL_BALLOON_SWITCH_ANY,
3129 EL_BALLOON_SWITCH_NONE,
3132 EL_EMC_MAGIC_BALL_SWITCH,
3133 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3138 static int ep_bd_element[] =
3172 static int ep_sp_element[] =
3174 /* should always be valid */
3177 /* standard classic Supaplex elements */
3184 EL_SP_HARDWARE_GRAY,
3192 EL_SP_GRAVITY_PORT_RIGHT,
3193 EL_SP_GRAVITY_PORT_DOWN,
3194 EL_SP_GRAVITY_PORT_LEFT,
3195 EL_SP_GRAVITY_PORT_UP,
3200 EL_SP_PORT_VERTICAL,
3201 EL_SP_PORT_HORIZONTAL,
3207 EL_SP_HARDWARE_BASE_1,
3208 EL_SP_HARDWARE_GREEN,
3209 EL_SP_HARDWARE_BLUE,
3211 EL_SP_HARDWARE_YELLOW,
3212 EL_SP_HARDWARE_BASE_2,
3213 EL_SP_HARDWARE_BASE_3,
3214 EL_SP_HARDWARE_BASE_4,
3215 EL_SP_HARDWARE_BASE_5,
3216 EL_SP_HARDWARE_BASE_6,
3220 /* additional elements that appeared in newer Supaplex levels */
3223 /* additional gravity port elements (not switching, but setting gravity) */
3224 EL_SP_GRAVITY_ON_PORT_LEFT,
3225 EL_SP_GRAVITY_ON_PORT_RIGHT,
3226 EL_SP_GRAVITY_ON_PORT_UP,
3227 EL_SP_GRAVITY_ON_PORT_DOWN,
3228 EL_SP_GRAVITY_OFF_PORT_LEFT,
3229 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3230 EL_SP_GRAVITY_OFF_PORT_UP,
3231 EL_SP_GRAVITY_OFF_PORT_DOWN,
3233 /* more than one Murphy in a level results in an inactive clone */
3236 /* runtime Supaplex elements */
3237 EL_SP_DISK_RED_ACTIVE,
3238 EL_SP_TERMINAL_ACTIVE,
3239 EL_SP_BUGGY_BASE_ACTIVATING,
3240 EL_SP_BUGGY_BASE_ACTIVE,
3247 static int ep_sb_element[] =
3252 EL_SOKOBAN_FIELD_EMPTY,
3253 EL_SOKOBAN_FIELD_FULL,
3254 EL_SOKOBAN_FIELD_PLAYER,
3259 EL_INVISIBLE_STEELWALL,
3264 static int ep_gem[] =
3276 static int ep_food_dark_yamyam[] =
3304 static int ep_food_penguin[] =
3318 static int ep_food_pig[] =
3330 static int ep_historic_wall[] =
3341 EL_GATE_1_GRAY_ACTIVE,
3342 EL_GATE_2_GRAY_ACTIVE,
3343 EL_GATE_3_GRAY_ACTIVE,
3344 EL_GATE_4_GRAY_ACTIVE,
3353 EL_EM_GATE_1_GRAY_ACTIVE,
3354 EL_EM_GATE_2_GRAY_ACTIVE,
3355 EL_EM_GATE_3_GRAY_ACTIVE,
3356 EL_EM_GATE_4_GRAY_ACTIVE,
3363 EL_EXPANDABLE_WALL_HORIZONTAL,
3364 EL_EXPANDABLE_WALL_VERTICAL,
3365 EL_EXPANDABLE_WALL_ANY,
3366 EL_EXPANDABLE_WALL_GROWING,
3367 EL_BD_EXPANDABLE_WALL,
3374 EL_SP_HARDWARE_GRAY,
3375 EL_SP_HARDWARE_GREEN,
3376 EL_SP_HARDWARE_BLUE,
3378 EL_SP_HARDWARE_YELLOW,
3379 EL_SP_HARDWARE_BASE_1,
3380 EL_SP_HARDWARE_BASE_2,
3381 EL_SP_HARDWARE_BASE_3,
3382 EL_SP_HARDWARE_BASE_4,
3383 EL_SP_HARDWARE_BASE_5,
3384 EL_SP_HARDWARE_BASE_6,
3386 EL_SP_TERMINAL_ACTIVE,
3389 EL_INVISIBLE_STEELWALL,
3390 EL_INVISIBLE_STEELWALL_ACTIVE,
3392 EL_INVISIBLE_WALL_ACTIVE,
3393 EL_STEELWALL_SLIPPERY,
3410 static int ep_historic_solid[] =
3414 EL_EXPANDABLE_WALL_HORIZONTAL,
3415 EL_EXPANDABLE_WALL_VERTICAL,
3416 EL_EXPANDABLE_WALL_ANY,
3417 EL_BD_EXPANDABLE_WALL,
3430 EL_QUICKSAND_FILLING,
3431 EL_QUICKSAND_EMPTYING,
3433 EL_MAGIC_WALL_ACTIVE,
3434 EL_MAGIC_WALL_EMPTYING,
3435 EL_MAGIC_WALL_FILLING,
3439 EL_BD_MAGIC_WALL_ACTIVE,
3440 EL_BD_MAGIC_WALL_EMPTYING,
3441 EL_BD_MAGIC_WALL_FULL,
3442 EL_BD_MAGIC_WALL_FILLING,
3443 EL_BD_MAGIC_WALL_DEAD,
3452 EL_SP_TERMINAL_ACTIVE,
3456 EL_INVISIBLE_WALL_ACTIVE,
3457 EL_SWITCHGATE_SWITCH_UP,
3458 EL_SWITCHGATE_SWITCH_DOWN,
3459 EL_DC_SWITCHGATE_SWITCH_UP,
3460 EL_DC_SWITCHGATE_SWITCH_DOWN,
3462 EL_TIMEGATE_SWITCH_ACTIVE,
3463 EL_DC_TIMEGATE_SWITCH,
3464 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3476 /* the following elements are a direct copy of "indestructible" elements,
3477 except "EL_ACID", which is "indestructible", but not "solid"! */
3482 EL_ACID_POOL_TOPLEFT,
3483 EL_ACID_POOL_TOPRIGHT,
3484 EL_ACID_POOL_BOTTOMLEFT,
3485 EL_ACID_POOL_BOTTOM,
3486 EL_ACID_POOL_BOTTOMRIGHT,
3487 EL_SP_HARDWARE_GRAY,
3488 EL_SP_HARDWARE_GREEN,
3489 EL_SP_HARDWARE_BLUE,
3491 EL_SP_HARDWARE_YELLOW,
3492 EL_SP_HARDWARE_BASE_1,
3493 EL_SP_HARDWARE_BASE_2,
3494 EL_SP_HARDWARE_BASE_3,
3495 EL_SP_HARDWARE_BASE_4,
3496 EL_SP_HARDWARE_BASE_5,
3497 EL_SP_HARDWARE_BASE_6,
3498 EL_INVISIBLE_STEELWALL,
3499 EL_INVISIBLE_STEELWALL_ACTIVE,
3500 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3501 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3502 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3503 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3504 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3505 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3506 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3507 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3508 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3509 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3510 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3511 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3513 EL_LIGHT_SWITCH_ACTIVE,
3514 EL_SIGN_EXCLAMATION,
3515 EL_SIGN_RADIOACTIVITY,
3522 EL_SIGN_ENTRY_FORBIDDEN,
3523 EL_SIGN_EMERGENCY_EXIT,
3531 EL_STEEL_EXIT_CLOSED,
3533 EL_DC_STEELWALL_1_LEFT,
3534 EL_DC_STEELWALL_1_RIGHT,
3535 EL_DC_STEELWALL_1_TOP,
3536 EL_DC_STEELWALL_1_BOTTOM,
3537 EL_DC_STEELWALL_1_HORIZONTAL,
3538 EL_DC_STEELWALL_1_VERTICAL,
3539 EL_DC_STEELWALL_1_TOPLEFT,
3540 EL_DC_STEELWALL_1_TOPRIGHT,
3541 EL_DC_STEELWALL_1_BOTTOMLEFT,
3542 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3543 EL_DC_STEELWALL_1_TOPLEFT_2,
3544 EL_DC_STEELWALL_1_TOPRIGHT_2,
3545 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3546 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3547 EL_DC_STEELWALL_2_LEFT,
3548 EL_DC_STEELWALL_2_RIGHT,
3549 EL_DC_STEELWALL_2_TOP,
3550 EL_DC_STEELWALL_2_BOTTOM,
3551 EL_DC_STEELWALL_2_HORIZONTAL,
3552 EL_DC_STEELWALL_2_VERTICAL,
3553 EL_DC_STEELWALL_2_MIDDLE,
3554 EL_DC_STEELWALL_2_SINGLE,
3555 EL_STEELWALL_SLIPPERY,
3569 EL_GATE_1_GRAY_ACTIVE,
3570 EL_GATE_2_GRAY_ACTIVE,
3571 EL_GATE_3_GRAY_ACTIVE,
3572 EL_GATE_4_GRAY_ACTIVE,
3581 EL_EM_GATE_1_GRAY_ACTIVE,
3582 EL_EM_GATE_2_GRAY_ACTIVE,
3583 EL_EM_GATE_3_GRAY_ACTIVE,
3584 EL_EM_GATE_4_GRAY_ACTIVE,
3586 EL_SWITCHGATE_OPENING,
3587 EL_SWITCHGATE_CLOSED,
3588 EL_SWITCHGATE_CLOSING,
3590 EL_TIMEGATE_OPENING,
3592 EL_TIMEGATE_CLOSING,
3596 EL_TUBE_VERTICAL_LEFT,
3597 EL_TUBE_VERTICAL_RIGHT,
3598 EL_TUBE_HORIZONTAL_UP,
3599 EL_TUBE_HORIZONTAL_DOWN,
3608 static int ep_classic_enemy[] =
3625 static int ep_belt[] =
3627 EL_CONVEYOR_BELT_1_LEFT,
3628 EL_CONVEYOR_BELT_1_MIDDLE,
3629 EL_CONVEYOR_BELT_1_RIGHT,
3630 EL_CONVEYOR_BELT_2_LEFT,
3631 EL_CONVEYOR_BELT_2_MIDDLE,
3632 EL_CONVEYOR_BELT_2_RIGHT,
3633 EL_CONVEYOR_BELT_3_LEFT,
3634 EL_CONVEYOR_BELT_3_MIDDLE,
3635 EL_CONVEYOR_BELT_3_RIGHT,
3636 EL_CONVEYOR_BELT_4_LEFT,
3637 EL_CONVEYOR_BELT_4_MIDDLE,
3638 EL_CONVEYOR_BELT_4_RIGHT,
3643 static int ep_belt_active[] =
3645 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3646 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3647 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3648 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3649 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3650 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3651 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3652 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3653 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3654 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3655 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3656 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3661 static int ep_belt_switch[] =
3663 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3664 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3665 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3666 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3667 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3668 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3669 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3670 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3671 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3672 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3673 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3674 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3679 static int ep_tube[] =
3686 EL_TUBE_HORIZONTAL_UP,
3687 EL_TUBE_HORIZONTAL_DOWN,
3689 EL_TUBE_VERTICAL_LEFT,
3690 EL_TUBE_VERTICAL_RIGHT,
3696 static int ep_acid_pool[] =
3698 EL_ACID_POOL_TOPLEFT,
3699 EL_ACID_POOL_TOPRIGHT,
3700 EL_ACID_POOL_BOTTOMLEFT,
3701 EL_ACID_POOL_BOTTOM,
3702 EL_ACID_POOL_BOTTOMRIGHT,
3707 static int ep_keygate[] =
3717 EL_GATE_1_GRAY_ACTIVE,
3718 EL_GATE_2_GRAY_ACTIVE,
3719 EL_GATE_3_GRAY_ACTIVE,
3720 EL_GATE_4_GRAY_ACTIVE,
3729 EL_EM_GATE_1_GRAY_ACTIVE,
3730 EL_EM_GATE_2_GRAY_ACTIVE,
3731 EL_EM_GATE_3_GRAY_ACTIVE,
3732 EL_EM_GATE_4_GRAY_ACTIVE,
3741 EL_EMC_GATE_5_GRAY_ACTIVE,
3742 EL_EMC_GATE_6_GRAY_ACTIVE,
3743 EL_EMC_GATE_7_GRAY_ACTIVE,
3744 EL_EMC_GATE_8_GRAY_ACTIVE,
3746 EL_DC_GATE_WHITE_GRAY,
3747 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3752 static int ep_amoeboid[] =
3764 static int ep_amoebalive[] =
3775 static int ep_has_editor_content[] =
3781 EL_SOKOBAN_FIELD_PLAYER,
3798 static int ep_can_turn_each_move[] =
3800 /* !!! do something with this one !!! */
3804 static int ep_can_grow[] =
3818 static int ep_active_bomb[] =
3821 EL_EM_DYNAMITE_ACTIVE,
3822 EL_DYNABOMB_PLAYER_1_ACTIVE,
3823 EL_DYNABOMB_PLAYER_2_ACTIVE,
3824 EL_DYNABOMB_PLAYER_3_ACTIVE,
3825 EL_DYNABOMB_PLAYER_4_ACTIVE,
3826 EL_SP_DISK_RED_ACTIVE,
3831 static int ep_inactive[] =
3841 EL_QUICKSAND_FAST_EMPTY,
3864 EL_GATE_1_GRAY_ACTIVE,
3865 EL_GATE_2_GRAY_ACTIVE,
3866 EL_GATE_3_GRAY_ACTIVE,
3867 EL_GATE_4_GRAY_ACTIVE,
3876 EL_EM_GATE_1_GRAY_ACTIVE,
3877 EL_EM_GATE_2_GRAY_ACTIVE,
3878 EL_EM_GATE_3_GRAY_ACTIVE,
3879 EL_EM_GATE_4_GRAY_ACTIVE,
3888 EL_EMC_GATE_5_GRAY_ACTIVE,
3889 EL_EMC_GATE_6_GRAY_ACTIVE,
3890 EL_EMC_GATE_7_GRAY_ACTIVE,
3891 EL_EMC_GATE_8_GRAY_ACTIVE,
3893 EL_DC_GATE_WHITE_GRAY,
3894 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3895 EL_DC_GATE_FAKE_GRAY,
3898 EL_INVISIBLE_STEELWALL,
3906 EL_WALL_EMERALD_YELLOW,
3907 EL_DYNABOMB_INCREASE_NUMBER,
3908 EL_DYNABOMB_INCREASE_SIZE,
3909 EL_DYNABOMB_INCREASE_POWER,
3913 EL_SOKOBAN_FIELD_EMPTY,
3914 EL_SOKOBAN_FIELD_FULL,
3915 EL_WALL_EMERALD_RED,
3916 EL_WALL_EMERALD_PURPLE,
3917 EL_ACID_POOL_TOPLEFT,
3918 EL_ACID_POOL_TOPRIGHT,
3919 EL_ACID_POOL_BOTTOMLEFT,
3920 EL_ACID_POOL_BOTTOM,
3921 EL_ACID_POOL_BOTTOMRIGHT,
3925 EL_BD_MAGIC_WALL_DEAD,
3927 EL_DC_MAGIC_WALL_DEAD,
3928 EL_AMOEBA_TO_DIAMOND,
3936 EL_SP_GRAVITY_PORT_RIGHT,
3937 EL_SP_GRAVITY_PORT_DOWN,
3938 EL_SP_GRAVITY_PORT_LEFT,
3939 EL_SP_GRAVITY_PORT_UP,
3940 EL_SP_PORT_HORIZONTAL,
3941 EL_SP_PORT_VERTICAL,
3952 EL_SP_HARDWARE_GRAY,
3953 EL_SP_HARDWARE_GREEN,
3954 EL_SP_HARDWARE_BLUE,
3956 EL_SP_HARDWARE_YELLOW,
3957 EL_SP_HARDWARE_BASE_1,
3958 EL_SP_HARDWARE_BASE_2,
3959 EL_SP_HARDWARE_BASE_3,
3960 EL_SP_HARDWARE_BASE_4,
3961 EL_SP_HARDWARE_BASE_5,
3962 EL_SP_HARDWARE_BASE_6,
3963 EL_SP_GRAVITY_ON_PORT_LEFT,
3964 EL_SP_GRAVITY_ON_PORT_RIGHT,
3965 EL_SP_GRAVITY_ON_PORT_UP,
3966 EL_SP_GRAVITY_ON_PORT_DOWN,
3967 EL_SP_GRAVITY_OFF_PORT_LEFT,
3968 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3969 EL_SP_GRAVITY_OFF_PORT_UP,
3970 EL_SP_GRAVITY_OFF_PORT_DOWN,
3971 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3972 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3973 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3974 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3975 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3976 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3977 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3978 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3979 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3980 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3981 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3982 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3983 EL_SIGN_EXCLAMATION,
3984 EL_SIGN_RADIOACTIVITY,
3991 EL_SIGN_ENTRY_FORBIDDEN,
3992 EL_SIGN_EMERGENCY_EXIT,
4000 EL_DC_STEELWALL_1_LEFT,
4001 EL_DC_STEELWALL_1_RIGHT,
4002 EL_DC_STEELWALL_1_TOP,
4003 EL_DC_STEELWALL_1_BOTTOM,
4004 EL_DC_STEELWALL_1_HORIZONTAL,
4005 EL_DC_STEELWALL_1_VERTICAL,
4006 EL_DC_STEELWALL_1_TOPLEFT,
4007 EL_DC_STEELWALL_1_TOPRIGHT,
4008 EL_DC_STEELWALL_1_BOTTOMLEFT,
4009 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4010 EL_DC_STEELWALL_1_TOPLEFT_2,
4011 EL_DC_STEELWALL_1_TOPRIGHT_2,
4012 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4013 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4014 EL_DC_STEELWALL_2_LEFT,
4015 EL_DC_STEELWALL_2_RIGHT,
4016 EL_DC_STEELWALL_2_TOP,
4017 EL_DC_STEELWALL_2_BOTTOM,
4018 EL_DC_STEELWALL_2_HORIZONTAL,
4019 EL_DC_STEELWALL_2_VERTICAL,
4020 EL_DC_STEELWALL_2_MIDDLE,
4021 EL_DC_STEELWALL_2_SINGLE,
4022 EL_STEELWALL_SLIPPERY,
4027 EL_EMC_WALL_SLIPPERY_1,
4028 EL_EMC_WALL_SLIPPERY_2,
4029 EL_EMC_WALL_SLIPPERY_3,
4030 EL_EMC_WALL_SLIPPERY_4,
4051 static int ep_em_slippery_wall[] =
4056 static int ep_gfx_crumbled[] =
4067 static int ep_editor_cascade_active[] =
4069 EL_INTERNAL_CASCADE_BD_ACTIVE,
4070 EL_INTERNAL_CASCADE_EM_ACTIVE,
4071 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4072 EL_INTERNAL_CASCADE_RND_ACTIVE,
4073 EL_INTERNAL_CASCADE_SB_ACTIVE,
4074 EL_INTERNAL_CASCADE_SP_ACTIVE,
4075 EL_INTERNAL_CASCADE_DC_ACTIVE,
4076 EL_INTERNAL_CASCADE_DX_ACTIVE,
4077 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4078 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4079 EL_INTERNAL_CASCADE_CE_ACTIVE,
4080 EL_INTERNAL_CASCADE_GE_ACTIVE,
4081 EL_INTERNAL_CASCADE_REF_ACTIVE,
4082 EL_INTERNAL_CASCADE_USER_ACTIVE,
4083 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4088 static int ep_editor_cascade_inactive[] =
4090 EL_INTERNAL_CASCADE_BD,
4091 EL_INTERNAL_CASCADE_EM,
4092 EL_INTERNAL_CASCADE_EMC,
4093 EL_INTERNAL_CASCADE_RND,
4094 EL_INTERNAL_CASCADE_SB,
4095 EL_INTERNAL_CASCADE_SP,
4096 EL_INTERNAL_CASCADE_DC,
4097 EL_INTERNAL_CASCADE_DX,
4098 EL_INTERNAL_CASCADE_CHARS,
4099 EL_INTERNAL_CASCADE_STEEL_CHARS,
4100 EL_INTERNAL_CASCADE_CE,
4101 EL_INTERNAL_CASCADE_GE,
4102 EL_INTERNAL_CASCADE_REF,
4103 EL_INTERNAL_CASCADE_USER,
4104 EL_INTERNAL_CASCADE_DYNAMIC,
4109 static int ep_obsolete[] =
4113 EL_EM_KEY_1_FILE_OBSOLETE,
4114 EL_EM_KEY_2_FILE_OBSOLETE,
4115 EL_EM_KEY_3_FILE_OBSOLETE,
4116 EL_EM_KEY_4_FILE_OBSOLETE,
4117 EL_ENVELOPE_OBSOLETE,
4126 } element_properties[] =
4128 { ep_diggable, EP_DIGGABLE },
4129 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4130 { ep_dont_run_into, EP_DONT_RUN_INTO },
4131 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4132 { ep_dont_touch, EP_DONT_TOUCH },
4133 { ep_indestructible, EP_INDESTRUCTIBLE },
4134 { ep_slippery, EP_SLIPPERY },
4135 { ep_can_change, EP_CAN_CHANGE },
4136 { ep_can_move, EP_CAN_MOVE },
4137 { ep_can_fall, EP_CAN_FALL },
4138 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4139 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4140 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4141 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4142 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4143 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4144 { ep_walkable_over, EP_WALKABLE_OVER },
4145 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4146 { ep_walkable_under, EP_WALKABLE_UNDER },
4147 { ep_passable_over, EP_PASSABLE_OVER },
4148 { ep_passable_inside, EP_PASSABLE_INSIDE },
4149 { ep_passable_under, EP_PASSABLE_UNDER },
4150 { ep_droppable, EP_DROPPABLE },
4151 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4152 { ep_pushable, EP_PUSHABLE },
4153 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4154 { ep_protected, EP_PROTECTED },
4155 { ep_throwable, EP_THROWABLE },
4156 { ep_can_explode, EP_CAN_EXPLODE },
4157 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4159 { ep_player, EP_PLAYER },
4160 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4161 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4162 { ep_switchable, EP_SWITCHABLE },
4163 { ep_bd_element, EP_BD_ELEMENT },
4164 { ep_sp_element, EP_SP_ELEMENT },
4165 { ep_sb_element, EP_SB_ELEMENT },
4167 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4168 { ep_food_penguin, EP_FOOD_PENGUIN },
4169 { ep_food_pig, EP_FOOD_PIG },
4170 { ep_historic_wall, EP_HISTORIC_WALL },
4171 { ep_historic_solid, EP_HISTORIC_SOLID },
4172 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4173 { ep_belt, EP_BELT },
4174 { ep_belt_active, EP_BELT_ACTIVE },
4175 { ep_belt_switch, EP_BELT_SWITCH },
4176 { ep_tube, EP_TUBE },
4177 { ep_acid_pool, EP_ACID_POOL },
4178 { ep_keygate, EP_KEYGATE },
4179 { ep_amoeboid, EP_AMOEBOID },
4180 { ep_amoebalive, EP_AMOEBALIVE },
4181 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4182 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4183 { ep_can_grow, EP_CAN_GROW },
4184 { ep_active_bomb, EP_ACTIVE_BOMB },
4185 { ep_inactive, EP_INACTIVE },
4187 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4189 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4191 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4192 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4194 { ep_obsolete, EP_OBSOLETE },
4201 /* always start with reliable default values (element has no properties) */
4202 /* (but never initialize clipboard elements after the very first time) */
4203 /* (to be able to use clipboard elements between several levels) */
4204 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4205 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4206 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4207 SET_PROPERTY(i, j, FALSE);
4209 /* set all base element properties from above array definitions */
4210 for (i = 0; element_properties[i].elements != NULL; i++)
4211 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4212 SET_PROPERTY((element_properties[i].elements)[j],
4213 element_properties[i].property, TRUE);
4215 /* copy properties to some elements that are only stored in level file */
4216 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4217 for (j = 0; copy_properties[j][0] != -1; j++)
4218 if (HAS_PROPERTY(copy_properties[j][0], i))
4219 for (k = 1; k <= 4; k++)
4220 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4222 /* set static element properties that are not listed in array definitions */
4223 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4224 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4226 clipboard_elements_initialized = TRUE;
4229 void InitElementPropertiesEngine(int engine_version)
4231 static int no_wall_properties[] =
4234 EP_COLLECTIBLE_ONLY,
4236 EP_DONT_COLLIDE_WITH,
4239 EP_CAN_SMASH_PLAYER,
4240 EP_CAN_SMASH_ENEMIES,
4241 EP_CAN_SMASH_EVERYTHING,
4246 EP_FOOD_DARK_YAMYAM,
4262 /* important: after initialization in InitElementPropertiesStatic(), the
4263 elements are not again initialized to a default value; therefore all
4264 changes have to make sure that they leave the element with a defined
4265 property (which means that conditional property changes must be set to
4266 a reliable default value before) */
4268 /* resolve group elements */
4269 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4270 ResolveGroupElement(EL_GROUP_START + i);
4272 /* set all special, combined or engine dependent element properties */
4273 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4275 /* do not change (already initialized) clipboard elements here */
4276 if (IS_CLIPBOARD_ELEMENT(i))
4279 /* ---------- INACTIVE ------------------------------------------------- */
4280 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4281 i <= EL_CHAR_END) ||
4282 (i >= EL_STEEL_CHAR_START &&
4283 i <= EL_STEEL_CHAR_END)));
4285 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4286 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4287 IS_WALKABLE_INSIDE(i) ||
4288 IS_WALKABLE_UNDER(i)));
4290 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4291 IS_PASSABLE_INSIDE(i) ||
4292 IS_PASSABLE_UNDER(i)));
4294 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4295 IS_PASSABLE_OVER(i)));
4297 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4298 IS_PASSABLE_INSIDE(i)));
4300 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4301 IS_PASSABLE_UNDER(i)));
4303 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4306 /* ---------- COLLECTIBLE ---------------------------------------------- */
4307 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4311 /* ---------- SNAPPABLE ------------------------------------------------ */
4312 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4313 IS_COLLECTIBLE(i) ||
4317 /* ---------- WALL ----------------------------------------------------- */
4318 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4320 for (j = 0; no_wall_properties[j] != -1; j++)
4321 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4322 i >= EL_FIRST_RUNTIME_UNREAL)
4323 SET_PROPERTY(i, EP_WALL, FALSE);
4325 if (IS_HISTORIC_WALL(i))
4326 SET_PROPERTY(i, EP_WALL, TRUE);
4328 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4329 if (engine_version < VERSION_IDENT(2,2,0,0))
4330 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4332 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4334 !IS_COLLECTIBLE(i)));
4336 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4337 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4338 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4340 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4341 IS_INDESTRUCTIBLE(i)));
4343 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4345 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4346 else if (engine_version < VERSION_IDENT(2,2,0,0))
4347 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4349 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4353 if (IS_CUSTOM_ELEMENT(i))
4355 /* these are additional properties which are initially false when set */
4357 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4359 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4360 if (DONT_COLLIDE_WITH(i))
4361 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4363 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4364 if (CAN_SMASH_EVERYTHING(i))
4365 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4366 if (CAN_SMASH_ENEMIES(i))
4367 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4370 /* ---------- CAN_SMASH ------------------------------------------------ */
4371 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4372 CAN_SMASH_ENEMIES(i) ||
4373 CAN_SMASH_EVERYTHING(i)));
4375 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4376 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4377 EXPLODES_BY_FIRE(i)));
4379 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4380 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4381 EXPLODES_SMASHED(i)));
4383 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4384 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4385 EXPLODES_IMPACT(i)));
4387 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4388 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4390 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4391 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4392 i == EL_BLACK_ORB));
4394 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4395 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4397 IS_CUSTOM_ELEMENT(i)));
4399 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4400 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4401 i == EL_SP_ELECTRON));
4403 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4404 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4405 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4406 getMoveIntoAcidProperty(&level, i));
4408 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4409 if (MAYBE_DONT_COLLIDE_WITH(i))
4410 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4411 getDontCollideWithProperty(&level, i));
4413 /* ---------- SP_PORT -------------------------------------------------- */
4414 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4415 IS_PASSABLE_INSIDE(i)));
4417 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4418 for (j = 0; j < level.num_android_clone_elements; j++)
4419 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4421 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4423 /* ---------- CAN_CHANGE ----------------------------------------------- */
4424 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4425 for (j = 0; j < element_info[i].num_change_pages; j++)
4426 if (element_info[i].change_page[j].can_change)
4427 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4429 /* ---------- HAS_ACTION ----------------------------------------------- */
4430 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4431 for (j = 0; j < element_info[i].num_change_pages; j++)
4432 if (element_info[i].change_page[j].has_action)
4433 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4435 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4436 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4439 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4440 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4441 element_info[i].crumbled[ACTION_DEFAULT] !=
4442 element_info[i].graphic[ACTION_DEFAULT]);
4444 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4445 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4446 IS_EDITOR_CASCADE_INACTIVE(i)));
4449 /* dynamically adjust element properties according to game engine version */
4451 static int ep_em_slippery_wall[] =
4456 EL_EXPANDABLE_WALL_HORIZONTAL,
4457 EL_EXPANDABLE_WALL_VERTICAL,
4458 EL_EXPANDABLE_WALL_ANY,
4459 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4460 EL_EXPANDABLE_STEELWALL_VERTICAL,
4461 EL_EXPANDABLE_STEELWALL_ANY,
4462 EL_EXPANDABLE_STEELWALL_GROWING,
4466 static int ep_em_explodes_by_fire[] =
4469 EL_EM_DYNAMITE_ACTIVE,
4474 /* special EM style gems behaviour */
4475 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4476 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4477 level.em_slippery_gems);
4479 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4480 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4481 (level.em_slippery_gems &&
4482 engine_version > VERSION_IDENT(2,0,1,0)));
4484 /* special EM style explosion behaviour regarding chain reactions */
4485 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4486 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4487 level.em_explodes_by_fire);
4490 /* this is needed because some graphics depend on element properties */
4491 if (game_status == GAME_MODE_PLAYING)
4492 InitElementGraphicInfo();
4495 void InitElementPropertiesAfterLoading(int engine_version)
4499 /* set some other uninitialized values of custom elements in older levels */
4500 if (engine_version < VERSION_IDENT(3,1,0,0))
4502 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4504 int element = EL_CUSTOM_START + i;
4506 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4508 element_info[element].explosion_delay = 17;
4509 element_info[element].ignition_delay = 8;
4514 void InitElementPropertiesGfxElement()
4518 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4520 struct ElementInfo *ei = &element_info[i];
4522 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4526 static void InitGlobal()
4531 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4533 /* check if element_name_info entry defined for each element in "main.h" */
4534 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4535 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4537 element_info[i].token_name = element_name_info[i].token_name;
4538 element_info[i].class_name = element_name_info[i].class_name;
4539 element_info[i].editor_description= element_name_info[i].editor_description;
4542 /* create hash from image config list */
4543 image_config_hash = newSetupFileHash();
4544 for (i = 0; image_config[i].token != NULL; i++)
4545 setHashEntry(image_config_hash,
4546 image_config[i].token,
4547 image_config[i].value);
4549 /* create hash from element token list */
4550 element_token_hash = newSetupFileHash();
4551 for (i = 0; element_name_info[i].token_name != NULL; i++)
4552 setHashEntry(element_token_hash,
4553 element_name_info[i].token_name,
4556 /* create hash from graphic token list */
4557 graphic_token_hash = newSetupFileHash();
4558 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4559 if (strSuffix(image_config[i].value, ".png") ||
4560 strSuffix(image_config[i].value, ".pcx") ||
4561 strSuffix(image_config[i].value, ".wav") ||
4562 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4563 setHashEntry(graphic_token_hash,
4564 image_config[i].token,
4565 int2str(graphic++, 0));
4567 /* create hash from font token list */
4568 font_token_hash = newSetupFileHash();
4569 for (i = 0; font_info[i].token_name != NULL; i++)
4570 setHashEntry(font_token_hash,
4571 font_info[i].token_name,
4574 /* set default filenames for all cloned graphics in static configuration */
4575 for (i = 0; image_config[i].token != NULL; i++)
4577 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4579 char *token = image_config[i].token;
4580 char *token_clone_from = getStringCat2(token, ".clone_from");
4581 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4583 if (token_cloned != NULL)
4585 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4587 if (value_cloned != NULL)
4589 /* set default filename in static configuration */
4590 image_config[i].value = value_cloned;
4592 /* set default filename in image config hash */
4593 setHashEntry(image_config_hash, token, value_cloned);
4597 free(token_clone_from);
4601 /* always start with reliable default values (all elements) */
4602 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4603 ActiveElement[i] = i;
4605 /* now add all entries that have an active state (active elements) */
4606 for (i = 0; element_with_active_state[i].element != -1; i++)
4608 int element = element_with_active_state[i].element;
4609 int element_active = element_with_active_state[i].element_active;
4611 ActiveElement[element] = element_active;
4614 /* always start with reliable default values (all buttons) */
4615 for (i = 0; i < NUM_IMAGE_FILES; i++)
4616 ActiveButton[i] = i;
4618 /* now add all entries that have an active state (active buttons) */
4619 for (i = 0; button_with_active_state[i].button != -1; i++)
4621 int button = button_with_active_state[i].button;
4622 int button_active = button_with_active_state[i].button_active;
4624 ActiveButton[button] = button_active;
4627 /* always start with reliable default values (all fonts) */
4628 for (i = 0; i < NUM_FONTS; i++)
4631 /* now add all entries that have an active state (active fonts) */
4632 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4634 int font = font_with_active_state[i].font_nr;
4635 int font_active = font_with_active_state[i].font_nr_active;
4637 ActiveFont[font] = font_active;
4640 global.autoplay_leveldir = NULL;
4641 global.convert_leveldir = NULL;
4642 global.create_images_dir = NULL;
4644 global.frames_per_second = 0;
4646 global.border_status = GAME_MODE_MAIN;
4648 global.use_envelope_request = FALSE;
4651 void Execute_Command(char *command)
4655 if (strEqual(command, "print graphicsinfo.conf"))
4657 Print("# You can configure additional/alternative image files here.\n");
4658 Print("# (The entries below are default and therefore commented out.)\n");
4660 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4662 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4665 for (i = 0; image_config[i].token != NULL; i++)
4666 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4667 image_config[i].value));
4671 else if (strEqual(command, "print soundsinfo.conf"))
4673 Print("# You can configure additional/alternative sound files here.\n");
4674 Print("# (The entries below are default and therefore commented out.)\n");
4676 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4678 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4681 for (i = 0; sound_config[i].token != NULL; i++)
4682 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4683 sound_config[i].value));
4687 else if (strEqual(command, "print musicinfo.conf"))
4689 Print("# You can configure additional/alternative music files here.\n");
4690 Print("# (The entries below are default and therefore commented out.)\n");
4692 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4694 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4697 for (i = 0; music_config[i].token != NULL; i++)
4698 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4699 music_config[i].value));
4703 else if (strEqual(command, "print editorsetup.conf"))
4705 Print("# You can configure your personal editor element list here.\n");
4706 Print("# (The entries below are default and therefore commented out.)\n");
4709 /* this is needed to be able to check element list for cascade elements */
4710 InitElementPropertiesStatic();
4711 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4713 PrintEditorElementList();
4717 else if (strEqual(command, "print helpanim.conf"))
4719 Print("# You can configure different element help animations here.\n");
4720 Print("# (The entries below are default and therefore commented out.)\n");
4723 for (i = 0; helpanim_config[i].token != NULL; i++)
4725 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4726 helpanim_config[i].value));
4728 if (strEqual(helpanim_config[i].token, "end"))
4734 else if (strEqual(command, "print helptext.conf"))
4736 Print("# You can configure different element help text here.\n");
4737 Print("# (The entries below are default and therefore commented out.)\n");
4740 for (i = 0; helptext_config[i].token != NULL; i++)
4741 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4742 helptext_config[i].value));
4746 else if (strPrefix(command, "dump level "))
4748 char *filename = &command[11];
4750 if (!fileExists(filename))
4751 Error(ERR_EXIT, "cannot open file '%s'", filename);
4753 LoadLevelFromFilename(&level, filename);
4758 else if (strPrefix(command, "dump tape "))
4760 char *filename = &command[10];
4762 if (!fileExists(filename))
4763 Error(ERR_EXIT, "cannot open file '%s'", filename);
4765 LoadTapeFromFilename(filename);
4770 else if (strPrefix(command, "autotest ") ||
4771 strPrefix(command, "autoplay ") ||
4772 strPrefix(command, "autoffwd "))
4774 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4776 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4777 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4778 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4780 while (*str_ptr != '\0') /* continue parsing string */
4782 /* cut leading whitespace from string, replace it by string terminator */
4783 while (*str_ptr == ' ' || *str_ptr == '\t')
4786 if (*str_ptr == '\0') /* end of string reached */
4789 if (global.autoplay_leveldir == NULL) /* read level set string */
4791 global.autoplay_leveldir = str_ptr;
4792 global.autoplay_all = TRUE; /* default: play all tapes */
4794 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4795 global.autoplay_level[i] = FALSE;
4797 else /* read level number string */
4799 int level_nr = atoi(str_ptr); /* get level_nr value */
4801 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4802 global.autoplay_level[level_nr] = TRUE;
4804 global.autoplay_all = FALSE;
4807 /* advance string pointer to the next whitespace (or end of string) */
4808 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4812 else if (strPrefix(command, "convert "))
4814 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4815 char *str_ptr = strchr(str_copy, ' ');
4817 global.convert_leveldir = str_copy;
4818 global.convert_level_nr = -1;
4820 if (str_ptr != NULL) /* level number follows */
4822 *str_ptr++ = '\0'; /* terminate leveldir string */
4823 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4826 else if (strPrefix(command, "create images "))
4828 global.create_images_dir = getStringCopy(&command[14]);
4830 if (access(global.create_images_dir, W_OK) != 0)
4831 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4832 global.create_images_dir);
4834 else if (strPrefix(command, "create CE image "))
4836 CreateCustomElementImages(&command[16]);
4842 #if defined(TARGET_SDL2)
4843 else if (strEqual(command, "SDL_ListModes"))
4845 SDL_Init(SDL_INIT_VIDEO);
4847 int num_displays = SDL_GetNumVideoDisplays();
4849 // check if there are any displays available
4850 if (num_displays < 0)
4852 Print("No displays available: %s\n", SDL_GetError());
4857 for (i = 0; i < num_displays; i++)
4859 int num_modes = SDL_GetNumDisplayModes(i);
4862 Print("Available display modes for display %d:\n", i);
4864 // check if there are any display modes available for this display
4867 Print("No display modes available for display %d: %s\n",
4873 for (j = 0; j < num_modes; j++)
4875 SDL_DisplayMode mode;
4877 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4879 Print("Cannot get display mode %d for display %d: %s\n",
4880 j, i, SDL_GetError());
4885 Print("- %d x %d\n", mode.w, mode.h);
4891 #elif defined(TARGET_SDL)
4892 else if (strEqual(command, "SDL_ListModes"))
4897 SDL_Init(SDL_INIT_VIDEO);
4899 /* get available fullscreen/hardware modes */
4900 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4902 /* check if there are any modes available */
4905 Print("No modes available!\n");
4910 /* check if our resolution is restricted */
4911 if (modes == (SDL_Rect **)-1)
4913 Print("All resolutions available.\n");
4917 Print("Available display modes:\n");
4919 for (i = 0; modes[i]; i++)
4920 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4930 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4934 static void InitSetup()
4936 LoadSetup(); /* global setup info */
4938 /* set some options from setup file */
4940 if (setup.options.verbose)
4941 options.verbose = TRUE;
4944 static void InitGameInfo()
4946 game.restart_level = FALSE;
4949 static void InitPlayerInfo()
4953 /* choose default local player */
4954 local_player = &stored_player[0];
4956 for (i = 0; i < MAX_PLAYERS; i++)
4957 stored_player[i].connected = FALSE;
4959 local_player->connected = TRUE;
4962 static void InitArtworkInfo()
4967 static char *get_string_in_brackets(char *string)
4969 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4971 sprintf(string_in_brackets, "[%s]", string);
4973 return string_in_brackets;
4976 static char *get_level_id_suffix(int id_nr)
4978 char *id_suffix = checked_malloc(1 + 3 + 1);
4980 if (id_nr < 0 || id_nr > 999)
4983 sprintf(id_suffix, ".%03d", id_nr);
4988 static void InitArtworkConfig()
4990 static char *image_id_prefix[MAX_NUM_ELEMENTS +
4992 NUM_GLOBAL_ANIMS + 1];
4993 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4994 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4995 static char *action_id_suffix[NUM_ACTIONS + 1];
4996 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4997 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4998 static char *level_id_suffix[MAX_LEVELS + 1];
4999 static char *dummy[1] = { NULL };
5000 static char *ignore_generic_tokens[] =
5006 static char **ignore_image_tokens;
5007 static char **ignore_sound_tokens;
5008 static char **ignore_music_tokens;
5009 int num_ignore_generic_tokens;
5010 int num_ignore_image_tokens;
5011 int num_ignore_sound_tokens;
5012 int num_ignore_music_tokens;
5015 /* dynamically determine list of generic tokens to be ignored */
5016 num_ignore_generic_tokens = 0;
5017 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5018 num_ignore_generic_tokens++;
5020 /* dynamically determine list of image tokens to be ignored */
5021 num_ignore_image_tokens = num_ignore_generic_tokens;
5022 for (i = 0; image_config_vars[i].token != NULL; i++)
5023 num_ignore_image_tokens++;
5024 ignore_image_tokens =
5025 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5026 for (i = 0; i < num_ignore_generic_tokens; i++)
5027 ignore_image_tokens[i] = ignore_generic_tokens[i];
5028 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5029 ignore_image_tokens[num_ignore_generic_tokens + i] =
5030 image_config_vars[i].token;
5031 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5033 /* dynamically determine list of sound tokens to be ignored */
5034 num_ignore_sound_tokens = num_ignore_generic_tokens;
5035 ignore_sound_tokens =
5036 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5037 for (i = 0; i < num_ignore_generic_tokens; i++)
5038 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5039 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5041 /* dynamically determine list of music tokens to be ignored */
5042 num_ignore_music_tokens = num_ignore_generic_tokens;
5043 ignore_music_tokens =
5044 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5045 for (i = 0; i < num_ignore_generic_tokens; i++)
5046 ignore_music_tokens[i] = ignore_generic_tokens[i];
5047 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5049 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5050 image_id_prefix[i] = element_info[i].token_name;
5051 for (i = 0; i < NUM_FONTS; i++)
5052 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5053 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
5054 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5055 global_anim_info[i].token_name;
5056 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIMS] = NULL;
5058 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5059 sound_id_prefix[i] = element_info[i].token_name;
5060 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5061 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5062 get_string_in_brackets(element_info[i].class_name);
5063 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5065 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5066 music_id_prefix[i] = music_prefix_info[i].prefix;
5067 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5069 for (i = 0; i < NUM_ACTIONS; i++)
5070 action_id_suffix[i] = element_action_info[i].suffix;
5071 action_id_suffix[NUM_ACTIONS] = NULL;
5073 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5074 direction_id_suffix[i] = element_direction_info[i].suffix;
5075 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5077 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5078 special_id_suffix[i] = special_suffix_info[i].suffix;
5079 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5081 for (i = 0; i < MAX_LEVELS; i++)
5082 level_id_suffix[i] = get_level_id_suffix(i);
5083 level_id_suffix[MAX_LEVELS] = NULL;
5085 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5086 image_id_prefix, action_id_suffix, direction_id_suffix,
5087 special_id_suffix, ignore_image_tokens);
5088 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5089 sound_id_prefix, action_id_suffix, dummy,
5090 special_id_suffix, ignore_sound_tokens);
5091 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5092 music_id_prefix, special_id_suffix, level_id_suffix,
5093 dummy, ignore_music_tokens);
5096 static void InitMixer()
5103 void InitGfxBuffers()
5105 static int win_xsize_last = -1;
5106 static int win_ysize_last = -1;
5108 /* create additional image buffers for double-buffering and cross-fading */
5110 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5112 /* may contain content for cross-fading -- only re-create if changed */
5113 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5114 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5116 win_xsize_last = WIN_XSIZE;
5117 win_ysize_last = WIN_YSIZE;
5120 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5121 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5122 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5123 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5124 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5126 /* initialize screen properties */
5127 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5128 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5130 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5131 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5132 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5133 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5134 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5135 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5137 /* required if door size definitions have changed */
5138 InitGraphicCompatibilityInfo_Doors();
5140 InitGfxBuffers_EM();
5141 InitGfxBuffers_SP();
5146 struct GraphicInfo *graphic_info_last = graphic_info;
5147 char *filename_font_initial = NULL;
5148 char *filename_anim_initial = NULL;
5149 Bitmap *bitmap_font_initial = NULL;
5153 /* determine settings for initial font (for displaying startup messages) */
5154 for (i = 0; image_config[i].token != NULL; i++)
5156 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5158 char font_token[128];
5161 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5162 len_font_token = strlen(font_token);
5164 if (strEqual(image_config[i].token, font_token))
5165 filename_font_initial = image_config[i].value;
5166 else if (strlen(image_config[i].token) > len_font_token &&
5167 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5169 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5170 font_initial[j].src_x = atoi(image_config[i].value);
5171 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5172 font_initial[j].src_y = atoi(image_config[i].value);
5173 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5174 font_initial[j].width = atoi(image_config[i].value);
5175 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5176 font_initial[j].height = atoi(image_config[i].value);
5181 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5183 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5184 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5187 if (filename_font_initial == NULL) /* should not happen */
5188 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5191 InitGfxCustomArtworkInfo();
5192 InitGfxOtherSettings();
5194 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5196 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5197 font_initial[j].bitmap = bitmap_font_initial;
5199 InitFontGraphicInfo();
5201 font_height = getFontHeight(FC_RED);
5203 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5204 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5205 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5208 DrawInitText("Loading graphics", 120, FC_GREEN);
5210 /* initialize settings for busy animation with default values */
5211 int parameter[NUM_GFX_ARGS];
5212 for (i = 0; i < NUM_GFX_ARGS; i++)
5213 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5214 image_config_suffix[i].token,
5215 image_config_suffix[i].type);
5217 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5218 int len_anim_token = strlen(anim_token);
5220 /* read settings for busy animation from default custom artwork config */
5221 char *gfx_config_filename = getPath3(options.graphics_directory,
5223 GRAPHICSINFO_FILENAME);
5225 if (fileExists(gfx_config_filename))
5227 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5229 if (setup_file_hash)
5231 char *filename = getHashEntry(setup_file_hash, anim_token);
5235 filename_anim_initial = getStringCopy(filename);
5237 for (j = 0; image_config_suffix[j].token != NULL; j++)
5239 int type = image_config_suffix[j].type;
5240 char *suffix = image_config_suffix[j].token;
5241 char *token = getStringCat2(anim_token, suffix);
5242 char *value = getHashEntry(setup_file_hash, token);
5244 checked_free(token);
5247 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5251 freeSetupFileHash(setup_file_hash);
5255 if (filename_anim_initial == NULL)
5257 /* read settings for busy animation from static default artwork config */
5258 for (i = 0; image_config[i].token != NULL; i++)
5260 if (strEqual(image_config[i].token, anim_token))
5261 filename_anim_initial = getStringCopy(image_config[i].value);
5262 else if (strlen(image_config[i].token) > len_anim_token &&
5263 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5265 for (j = 0; image_config_suffix[j].token != NULL; j++)
5267 if (strEqual(&image_config[i].token[len_anim_token],
5268 image_config_suffix[j].token))
5270 get_graphic_parameter_value(image_config[i].value,
5271 image_config_suffix[j].token,
5272 image_config_suffix[j].type);
5278 if (filename_anim_initial == NULL) /* should not happen */
5279 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5281 anim_initial.bitmaps =
5282 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5284 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5285 LoadCustomImage(filename_anim_initial);
5287 checked_free(filename_anim_initial);
5289 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5291 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5293 graphic_info = graphic_info_last;
5295 init.busy.width = anim_initial.width;
5296 init.busy.height = anim_initial.height;
5298 InitMenuDesignSettings_Static();
5300 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5301 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5303 /* use copy of busy animation to prevent change while reloading artwork */
5307 void InitGfxBackground()
5309 fieldbuffer = bitmap_db_field;
5310 SetDrawtoField(DRAW_BACKBUFFER);
5312 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5314 redraw_mask = REDRAW_ALL;
5317 static void InitLevelInfo()
5319 LoadLevelInfo(); /* global level info */
5320 LoadLevelSetup_LastSeries(); /* last played series info */
5321 LoadLevelSetup_SeriesInfo(); /* last played level info */
5323 if (global.autoplay_leveldir &&
5324 global.autoplay_mode != AUTOPLAY_TEST)
5326 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5327 global.autoplay_leveldir);
5328 if (leveldir_current == NULL)
5329 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5333 static void InitLevelArtworkInfo()
5335 LoadLevelArtworkInfo();
5338 static void InitImages()
5340 print_timestamp_init("InitImages");
5343 printf("::: leveldir_current->identifier == '%s'\n",
5344 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5345 printf("::: leveldir_current->graphics_path == '%s'\n",
5346 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5347 printf("::: leveldir_current->graphics_set == '%s'\n",
5348 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5349 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5350 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5353 setLevelArtworkDir(artwork.gfx_first);
5356 printf("::: leveldir_current->identifier == '%s'\n",
5357 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5358 printf("::: leveldir_current->graphics_path == '%s'\n",
5359 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5360 printf("::: leveldir_current->graphics_set == '%s'\n",
5361 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5362 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5363 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5367 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5368 leveldir_current->identifier,
5369 artwork.gfx_current_identifier,
5370 artwork.gfx_current->identifier,
5371 leveldir_current->graphics_set,
5372 leveldir_current->graphics_path);
5375 UPDATE_BUSY_STATE();
5377 ReloadCustomImages();
5378 print_timestamp_time("ReloadCustomImages");
5380 UPDATE_BUSY_STATE();
5382 LoadCustomElementDescriptions();
5383 print_timestamp_time("LoadCustomElementDescriptions");
5385 UPDATE_BUSY_STATE();
5387 LoadMenuDesignSettings();
5388 print_timestamp_time("LoadMenuDesignSettings");
5390 UPDATE_BUSY_STATE();
5392 ReinitializeGraphics();
5393 print_timestamp_time("ReinitializeGraphics");
5395 UPDATE_BUSY_STATE();
5397 print_timestamp_done("InitImages");
5400 static void InitSound(char *identifier)
5402 print_timestamp_init("InitSound");
5404 if (identifier == NULL)
5405 identifier = artwork.snd_current->identifier;
5407 /* set artwork path to send it to the sound server process */
5408 setLevelArtworkDir(artwork.snd_first);
5410 InitReloadCustomSounds(identifier);
5411 print_timestamp_time("InitReloadCustomSounds");
5413 ReinitializeSounds();
5414 print_timestamp_time("ReinitializeSounds");
5416 print_timestamp_done("InitSound");
5419 static void InitMusic(char *identifier)
5421 print_timestamp_init("InitMusic");
5423 if (identifier == NULL)
5424 identifier = artwork.mus_current->identifier;
5426 /* set artwork path to send it to the sound server process */
5427 setLevelArtworkDir(artwork.mus_first);
5429 InitReloadCustomMusic(identifier);
5430 print_timestamp_time("InitReloadCustomMusic");
5432 ReinitializeMusic();
5433 print_timestamp_time("ReinitializeMusic");
5435 print_timestamp_done("InitMusic");
5438 void InitNetworkServer()
5440 #if defined(NETWORK_AVALIABLE)
5444 if (!options.network)
5447 #if defined(NETWORK_AVALIABLE)
5448 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5450 if (!ConnectToServer(options.server_host, options.server_port))
5451 Error(ERR_EXIT, "cannot connect to network game server");
5453 SendToServer_PlayerName(setup.player_name);
5454 SendToServer_ProtocolVersion();
5457 SendToServer_NrWanted(nr_wanted);
5461 static boolean CheckArtworkConfigForCustomElements(char *filename)
5463 SetupFileHash *setup_file_hash;
5464 boolean redefined_ce_found = FALSE;
5466 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5468 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5470 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5472 char *token = HASH_ITERATION_TOKEN(itr);
5474 if (strPrefix(token, "custom_"))
5476 redefined_ce_found = TRUE;
5481 END_HASH_ITERATION(setup_file_hash, itr)
5483 freeSetupFileHash(setup_file_hash);
5486 return redefined_ce_found;
5489 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5491 char *filename_base, *filename_local;
5492 boolean redefined_ce_found = FALSE;
5494 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5497 printf("::: leveldir_current->identifier == '%s'\n",
5498 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5499 printf("::: leveldir_current->graphics_path == '%s'\n",
5500 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5501 printf("::: leveldir_current->graphics_set == '%s'\n",
5502 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5503 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5504 leveldir_current == NULL ? "[NULL]" :
5505 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5508 /* first look for special artwork configured in level series config */
5509 filename_base = getCustomArtworkLevelConfigFilename(type);
5512 printf("::: filename_base == '%s'\n", filename_base);
5515 if (fileExists(filename_base))
5516 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5518 filename_local = getCustomArtworkConfigFilename(type);
5521 printf("::: filename_local == '%s'\n", filename_local);
5524 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5525 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5528 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5531 return redefined_ce_found;
5534 static void InitOverrideArtwork()
5536 boolean redefined_ce_found = FALSE;
5538 /* to check if this level set redefines any CEs, do not use overriding */
5539 gfx.override_level_graphics = FALSE;
5540 gfx.override_level_sounds = FALSE;
5541 gfx.override_level_music = FALSE;
5543 /* now check if this level set has definitions for custom elements */
5544 if (setup.override_level_graphics == AUTO ||
5545 setup.override_level_sounds == AUTO ||
5546 setup.override_level_music == AUTO)
5547 redefined_ce_found =
5548 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5549 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5550 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5553 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5556 if (redefined_ce_found)
5558 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5559 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5560 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5561 gfx.override_level_music = (setup.override_level_music == TRUE);
5565 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5566 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5567 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5568 gfx.override_level_music = (setup.override_level_music != FALSE);
5572 printf("::: => %d, %d, %d\n",
5573 gfx.override_level_graphics,
5574 gfx.override_level_sounds,
5575 gfx.override_level_music);
5579 static char *getNewArtworkIdentifier(int type)
5581 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5582 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5583 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5584 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5585 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5586 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5587 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5588 char *leveldir_identifier = leveldir_current->identifier;
5589 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5590 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5591 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5592 char *artwork_current_identifier;
5593 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5595 /* leveldir_current may be invalid (level group, parent link) */
5596 if (!validLevelSeries(leveldir_current))
5599 /* 1st step: determine artwork set to be activated in descending order:
5600 --------------------------------------------------------------------
5601 1. setup artwork (when configured to override everything else)
5602 2. artwork set configured in "levelinfo.conf" of current level set
5603 (artwork in level directory will have priority when loading later)
5604 3. artwork in level directory (stored in artwork sub-directory)
5605 4. setup artwork (currently configured in setup menu) */
5607 if (setup_override_artwork)
5608 artwork_current_identifier = setup_artwork_set;
5609 else if (leveldir_artwork_set != NULL)
5610 artwork_current_identifier = leveldir_artwork_set;
5611 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5612 artwork_current_identifier = leveldir_identifier;
5614 artwork_current_identifier = setup_artwork_set;
5617 /* 2nd step: check if it is really needed to reload artwork set
5618 ------------------------------------------------------------ */
5620 /* ---------- reload if level set and also artwork set has changed ------- */
5621 if (leveldir_current_identifier[type] != leveldir_identifier &&
5622 (last_has_level_artwork_set[type] || has_level_artwork_set))
5623 artwork_new_identifier = artwork_current_identifier;
5625 leveldir_current_identifier[type] = leveldir_identifier;
5626 last_has_level_artwork_set[type] = has_level_artwork_set;
5628 /* ---------- reload if "override artwork" setting has changed ----------- */
5629 if (last_override_level_artwork[type] != setup_override_artwork)
5630 artwork_new_identifier = artwork_current_identifier;
5632 last_override_level_artwork[type] = setup_override_artwork;
5634 /* ---------- reload if current artwork identifier has changed ----------- */
5635 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5636 artwork_current_identifier))
5637 artwork_new_identifier = artwork_current_identifier;
5639 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5641 /* ---------- do not reload directly after starting ---------------------- */
5642 if (!initialized[type])
5643 artwork_new_identifier = NULL;
5645 initialized[type] = TRUE;
5647 return artwork_new_identifier;
5650 void ReloadCustomArtwork(int force_reload)
5652 int last_game_status = game_status; /* save current game status */
5653 char *gfx_new_identifier;
5654 char *snd_new_identifier;
5655 char *mus_new_identifier;
5656 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5657 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5658 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5659 boolean reload_needed;
5661 InitOverrideArtwork();
5663 force_reload_gfx |= AdjustGraphicsForEMC();
5665 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5666 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5667 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5669 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5670 snd_new_identifier != NULL || force_reload_snd ||
5671 mus_new_identifier != NULL || force_reload_mus);
5676 print_timestamp_init("ReloadCustomArtwork");
5678 game_status = GAME_MODE_LOADING;
5680 FadeOut(REDRAW_ALL);
5682 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5683 print_timestamp_time("ClearRectangle");
5687 if (gfx_new_identifier != NULL || force_reload_gfx)
5690 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5691 artwork.gfx_current_identifier,
5693 artwork.gfx_current->identifier,
5694 leveldir_current->graphics_set);
5698 print_timestamp_time("InitImages");
5701 if (snd_new_identifier != NULL || force_reload_snd)
5703 InitSound(snd_new_identifier);
5704 print_timestamp_time("InitSound");
5707 if (mus_new_identifier != NULL || force_reload_mus)
5709 InitMusic(mus_new_identifier);
5710 print_timestamp_time("InitMusic");
5713 game_status = last_game_status; /* restore current game status */
5715 init_last = init; /* switch to new busy animation */
5717 FadeOut(REDRAW_ALL);
5719 RedrawGlobalBorder();
5721 /* force redraw of (open or closed) door graphics */
5722 SetDoorState(DOOR_OPEN_ALL);
5723 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5725 FadeSetEnterScreen();
5726 FadeSkipNextFadeOut();
5728 print_timestamp_done("ReloadCustomArtwork");
5730 LimitScreenUpdates(FALSE);
5733 void KeyboardAutoRepeatOffUnlessAutoplay()
5735 if (global.autoplay_leveldir == NULL)
5736 KeyboardAutoRepeatOff();
5739 void DisplayExitMessage(char *format, va_list ap)
5741 // check if draw buffer and fonts for exit message are already available
5742 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5745 int font_1 = FC_RED;
5746 int font_2 = FC_YELLOW;
5747 int font_3 = FC_BLUE;
5748 int font_width = getFontWidth(font_2);
5749 int font_height = getFontHeight(font_2);
5752 int sxsize = WIN_XSIZE - 2 * sx;
5753 int sysize = WIN_YSIZE - 2 * sy;
5754 int line_length = sxsize / font_width;
5755 int max_lines = sysize / font_height;
5756 int num_lines_printed;
5760 gfx.sxsize = sxsize;
5761 gfx.sysize = sysize;
5765 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5767 DrawTextSCentered(sy, font_1, "Fatal error:");
5768 sy += 3 * font_height;;
5771 DrawTextBufferVA(sx, sy, format, ap, font_2,
5772 line_length, line_length, max_lines,
5773 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5774 sy += (num_lines_printed + 3) * font_height;
5776 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5777 sy += 3 * font_height;
5780 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5781 line_length, line_length, max_lines,
5782 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5784 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5786 redraw_mask = REDRAW_ALL;
5788 /* force drawing exit message even if screen updates are currently limited */
5789 LimitScreenUpdates(FALSE);
5793 /* deactivate toons on error message screen */
5794 setup.toons = FALSE;
5796 WaitForEventToContinue();
5800 /* ========================================================================= */
5802 /* ========================================================================= */
5806 print_timestamp_init("OpenAll");
5808 game_status = GAME_MODE_LOADING;
5812 InitGlobal(); /* initialize some global variables */
5814 print_timestamp_time("[init global stuff]");
5818 print_timestamp_time("[init setup/config stuff (1)]");
5820 if (options.execute_command)
5821 Execute_Command(options.execute_command);
5823 if (options.serveronly)
5825 #if defined(PLATFORM_UNIX)
5826 NetworkServer(options.server_port, options.serveronly);
5828 Error(ERR_WARN, "networking only supported in Unix version");
5831 exit(0); /* never reached, server loops forever */
5835 print_timestamp_time("[init setup/config stuff (2)]");
5837 print_timestamp_time("[init setup/config stuff (3)]");
5838 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5839 print_timestamp_time("[init setup/config stuff (4)]");
5840 InitArtworkConfig(); /* needed before forking sound child process */
5841 print_timestamp_time("[init setup/config stuff (5)]");
5843 print_timestamp_time("[init setup/config stuff (6)]");
5845 InitRND(NEW_RANDOMIZE);
5846 InitSimpleRandom(NEW_RANDOMIZE);
5850 print_timestamp_time("[init setup/config stuff]");
5853 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5855 InitEventFilter(FilterEvents);
5857 print_timestamp_time("[init video stuff]");
5859 InitElementPropertiesStatic();
5860 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5861 InitElementPropertiesGfxElement();
5863 print_timestamp_time("[init element properties stuff]");
5867 print_timestamp_time("InitGfx");
5870 print_timestamp_time("InitLevelInfo");
5872 InitLevelArtworkInfo();
5873 print_timestamp_time("InitLevelArtworkInfo");
5875 InitOverrideArtwork(); /* needs to know current level directory */
5876 print_timestamp_time("InitOverrideArtwork");
5878 InitImages(); /* needs to know current level directory */
5879 print_timestamp_time("InitImages");
5881 InitSound(NULL); /* needs to know current level directory */
5882 print_timestamp_time("InitSound");
5884 InitMusic(NULL); /* needs to know current level directory */
5885 print_timestamp_time("InitMusic");
5887 InitGfxBackground();
5892 if (global.autoplay_leveldir)
5897 else if (global.convert_leveldir)
5902 else if (global.create_images_dir)
5904 CreateLevelSketchImages();
5908 game_status = GAME_MODE_MAIN;
5910 FadeSetEnterScreen();
5911 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5912 FadeSkipNextFadeOut();
5914 print_timestamp_time("[post-artwork]");
5916 print_timestamp_done("OpenAll");
5920 InitNetworkServer();
5923 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5925 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5926 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5927 #if defined(PLATFORM_ANDROID)
5928 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5929 SDL_AndroidGetInternalStoragePath());
5930 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5931 SDL_AndroidGetExternalStoragePath());
5932 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5933 (SDL_AndroidGetExternalStorageState() ==
5934 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5935 SDL_AndroidGetExternalStorageState() ==
5936 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5941 void CloseAllAndExit(int exit_value)
5946 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5953 #if defined(TARGET_SDL)
5954 #if defined(TARGET_SDL2)
5956 // set a flag to tell the network server thread to quit and wait for it
5957 // using SDL_WaitThread()
5959 if (network_server) /* terminate network server */
5960 SDL_KillThread(server_thread);
5964 CloseVideoDisplay();
5965 ClosePlatformDependentStuff();
5967 if (exit_value != 0)
5969 /* fall back to default level set (current set may have caused an error) */
5970 SaveLevelSetup_LastSeries_Deactivate();
5972 /* tell user where to find error log file which may contain more details */
5973 // (error notification now directly displayed on screen inside R'n'D
5974 // NotifyUserAboutErrorFile(); /* currently only works for Windows */