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_delay = parameter[GFX_ARG_STEP_DELAY];
1341 /* this is only used for drawing font characters */
1342 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1343 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1345 /* this is only used for drawing envelope graphics */
1346 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1348 /* optional graphic for cloning all graphics settings */
1349 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1350 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1352 /* optional settings for drawing title screens and title messages */
1353 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1354 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1355 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1356 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1357 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1358 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1359 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1360 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1361 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1362 g->align = parameter[GFX_ARG_ALIGN];
1363 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1364 g->valign = parameter[GFX_ARG_VALIGN];
1365 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1366 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1368 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1369 g->class = parameter[GFX_ARG_CLASS];
1370 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1371 g->style = parameter[GFX_ARG_STYLE];
1373 /* this is only used for drawing menu buttons and text */
1374 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1375 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1376 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1377 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1380 static void set_graphic_parameters(int graphic)
1382 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1383 char **parameter_raw = image->parameter;
1384 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1385 int parameter[NUM_GFX_ARGS];
1388 /* if fallback to default artwork is done, also use the default parameters */
1389 if (image->fallback_to_default)
1390 parameter_raw = image->default_parameter;
1392 /* get integer values from string parameters */
1393 for (i = 0; i < NUM_GFX_ARGS; i++)
1394 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1395 image_config_suffix[i].token,
1396 image_config_suffix[i].type);
1398 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1400 UPDATE_BUSY_STATE();
1403 static void set_cloned_graphic_parameters(int graphic)
1405 int fallback_graphic = IMG_CHAR_EXCLAM;
1406 int max_num_images = getImageListSize();
1407 int clone_graphic = graphic_info[graphic].clone_from;
1408 int num_references_followed = 1;
1410 while (graphic_info[clone_graphic].clone_from != -1 &&
1411 num_references_followed < max_num_images)
1413 clone_graphic = graphic_info[clone_graphic].clone_from;
1415 num_references_followed++;
1418 if (num_references_followed >= max_num_images)
1420 Error(ERR_INFO_LINE, "-");
1421 Error(ERR_INFO, "warning: error found in config file:");
1422 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1423 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1424 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1425 Error(ERR_INFO, "custom graphic rejected for this element/action");
1427 if (graphic == fallback_graphic)
1428 Error(ERR_EXIT, "no fallback graphic available");
1430 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1431 Error(ERR_INFO_LINE, "-");
1433 graphic_info[graphic] = graphic_info[fallback_graphic];
1437 graphic_info[graphic] = graphic_info[clone_graphic];
1438 graphic_info[graphic].clone_from = clone_graphic;
1442 static void InitGraphicInfo()
1444 int fallback_graphic = IMG_CHAR_EXCLAM;
1445 int num_images = getImageListSize();
1448 /* use image size as default values for width and height for these images */
1449 static int full_size_graphics[] =
1452 IMG_GLOBAL_BORDER_MAIN,
1453 IMG_GLOBAL_BORDER_SCORES,
1454 IMG_GLOBAL_BORDER_EDITOR,
1455 IMG_GLOBAL_BORDER_PLAYING,
1458 IMG_BACKGROUND_ENVELOPE_1,
1459 IMG_BACKGROUND_ENVELOPE_2,
1460 IMG_BACKGROUND_ENVELOPE_3,
1461 IMG_BACKGROUND_ENVELOPE_4,
1462 IMG_BACKGROUND_REQUEST,
1465 IMG_BACKGROUND_TITLE_INITIAL,
1466 IMG_BACKGROUND_TITLE,
1467 IMG_BACKGROUND_MAIN,
1468 IMG_BACKGROUND_LEVELS,
1469 IMG_BACKGROUND_LEVELNR,
1470 IMG_BACKGROUND_SCORES,
1471 IMG_BACKGROUND_EDITOR,
1472 IMG_BACKGROUND_INFO,
1473 IMG_BACKGROUND_INFO_ELEMENTS,
1474 IMG_BACKGROUND_INFO_MUSIC,
1475 IMG_BACKGROUND_INFO_CREDITS,
1476 IMG_BACKGROUND_INFO_PROGRAM,
1477 IMG_BACKGROUND_INFO_VERSION,
1478 IMG_BACKGROUND_INFO_LEVELSET,
1479 IMG_BACKGROUND_SETUP,
1480 IMG_BACKGROUND_PLAYING,
1481 IMG_BACKGROUND_DOOR,
1482 IMG_BACKGROUND_TAPE,
1483 IMG_BACKGROUND_PANEL,
1484 IMG_BACKGROUND_PALETTE,
1485 IMG_BACKGROUND_TOOLBOX,
1487 IMG_TITLESCREEN_INITIAL_1,
1488 IMG_TITLESCREEN_INITIAL_2,
1489 IMG_TITLESCREEN_INITIAL_3,
1490 IMG_TITLESCREEN_INITIAL_4,
1491 IMG_TITLESCREEN_INITIAL_5,
1498 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1499 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1500 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1501 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1502 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1503 IMG_BACKGROUND_TITLEMESSAGE_1,
1504 IMG_BACKGROUND_TITLEMESSAGE_2,
1505 IMG_BACKGROUND_TITLEMESSAGE_3,
1506 IMG_BACKGROUND_TITLEMESSAGE_4,
1507 IMG_BACKGROUND_TITLEMESSAGE_5,
1512 checked_free(graphic_info);
1514 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1516 /* initialize "use_image_size" flag with default value */
1517 for (i = 0; i < num_images; i++)
1518 graphic_info[i].use_image_size = FALSE;
1520 /* initialize "use_image_size" flag from static configuration above */
1521 for (i = 0; full_size_graphics[i] != -1; i++)
1522 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1524 /* first set all graphic paramaters ... */
1525 for (i = 0; i < num_images; i++)
1526 set_graphic_parameters(i);
1528 /* ... then copy these parameters for cloned graphics */
1529 for (i = 0; i < num_images; i++)
1530 if (graphic_info[i].clone_from != -1)
1531 set_cloned_graphic_parameters(i);
1533 for (i = 0; i < num_images; i++)
1538 int first_frame, last_frame;
1539 int src_bitmap_width, src_bitmap_height;
1541 /* now check if no animation frames are outside of the loaded image */
1543 if (graphic_info[i].bitmap == NULL)
1544 continue; /* skip check for optional images that are undefined */
1546 /* get image size (this can differ from the standard element tile size!) */
1547 width = graphic_info[i].width;
1548 height = graphic_info[i].height;
1550 /* get final bitmap size (with scaling, but without small images) */
1551 src_bitmap_width = graphic_info[i].src_image_width;
1552 src_bitmap_height = graphic_info[i].src_image_height;
1554 /* check if first animation frame is inside specified bitmap */
1557 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1559 /* this avoids calculating wrong start position for out-of-bounds frame */
1560 src_x = graphic_info[i].src_x;
1561 src_y = graphic_info[i].src_y;
1563 if (src_x < 0 || src_y < 0 ||
1564 src_x + width > src_bitmap_width ||
1565 src_y + height > src_bitmap_height)
1567 Error(ERR_INFO_LINE, "-");
1568 Error(ERR_INFO, "warning: error found in config file:");
1569 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1570 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1571 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1573 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1574 src_x, src_y, src_bitmap_width, src_bitmap_height);
1575 Error(ERR_INFO, "custom graphic rejected for this element/action");
1577 if (i == fallback_graphic)
1578 Error(ERR_EXIT, "no fallback graphic available");
1580 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1581 Error(ERR_INFO_LINE, "-");
1583 graphic_info[i] = graphic_info[fallback_graphic];
1586 /* check if last animation frame is inside specified bitmap */
1588 last_frame = graphic_info[i].anim_frames - 1;
1589 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1591 if (src_x < 0 || src_y < 0 ||
1592 src_x + width > src_bitmap_width ||
1593 src_y + height > src_bitmap_height)
1595 Error(ERR_INFO_LINE, "-");
1596 Error(ERR_INFO, "warning: error found in config file:");
1597 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1598 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1599 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1601 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1602 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1603 Error(ERR_INFO, "::: %d, %d", width, height);
1604 Error(ERR_INFO, "custom graphic rejected for this element/action");
1606 if (i == fallback_graphic)
1607 Error(ERR_EXIT, "no fallback graphic available");
1609 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1610 Error(ERR_INFO_LINE, "-");
1612 graphic_info[i] = graphic_info[fallback_graphic];
1617 static void InitGraphicCompatibilityInfo()
1619 struct FileInfo *fi_global_door =
1620 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1621 int num_images = getImageListSize();
1624 /* the following compatibility handling is needed for the following case:
1625 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1626 graphics mainly used for door and panel graphics, like editor, tape and
1627 in-game buttons with hard-coded bitmap positions and button sizes; as
1628 these graphics now have individual definitions, redefining "global.door"
1629 to change all these graphics at once like before does not work anymore
1630 (because all those individual definitions still have their default values);
1631 to solve this, remap all those individual definitions that are not
1632 redefined to the new bitmap of "global.door" if it was redefined */
1634 /* special compatibility handling if image "global.door" was redefined */
1635 if (fi_global_door->redefined)
1637 for (i = 0; i < num_images; i++)
1639 struct FileInfo *fi = getImageListEntryFromImageID(i);
1641 /* process only those images that still use the default settings */
1644 /* process all images which default to same image as "global.door" */
1645 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1647 // printf("::: special treatment needed for token '%s'\n", fi->token);
1649 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1655 InitGraphicCompatibilityInfo_Doors();
1658 static void InitElementSoundInfo()
1660 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1661 int num_property_mappings = getSoundListPropertyMappingSize();
1664 /* set values to -1 to identify later as "uninitialized" values */
1665 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1666 for (act = 0; act < NUM_ACTIONS; act++)
1667 element_info[i].sound[act] = -1;
1669 /* initialize element/sound mapping from static configuration */
1670 for (i = 0; element_to_sound[i].element > -1; i++)
1672 int element = element_to_sound[i].element;
1673 int action = element_to_sound[i].action;
1674 int sound = element_to_sound[i].sound;
1675 boolean is_class = element_to_sound[i].is_class;
1678 action = ACTION_DEFAULT;
1681 element_info[element].sound[action] = sound;
1683 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1684 if (strEqual(element_info[j].class_name,
1685 element_info[element].class_name))
1686 element_info[j].sound[action] = sound;
1689 /* initialize element class/sound mapping from dynamic configuration */
1690 for (i = 0; i < num_property_mappings; i++)
1692 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1693 int action = property_mapping[i].ext1_index;
1694 int sound = property_mapping[i].artwork_index;
1696 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1700 action = ACTION_DEFAULT;
1702 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1703 if (strEqual(element_info[j].class_name,
1704 element_info[element_class].class_name))
1705 element_info[j].sound[action] = sound;
1708 /* initialize element/sound mapping from dynamic configuration */
1709 for (i = 0; i < num_property_mappings; i++)
1711 int element = property_mapping[i].base_index;
1712 int action = property_mapping[i].ext1_index;
1713 int sound = property_mapping[i].artwork_index;
1715 if (element >= MAX_NUM_ELEMENTS)
1719 action = ACTION_DEFAULT;
1721 element_info[element].sound[action] = sound;
1724 /* now set all '-1' values to element specific default values */
1725 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1727 for (act = 0; act < NUM_ACTIONS; act++)
1729 /* generic default action sound (defined by "[default]" directive) */
1730 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1732 /* look for special default action sound (classic game specific) */
1733 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1734 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1735 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1736 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1737 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1738 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1740 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1741 /* !!! make this better !!! */
1742 if (i == EL_EMPTY_SPACE)
1743 default_action_sound = element_info[EL_DEFAULT].sound[act];
1745 /* no sound for this specific action -- use default action sound */
1746 if (element_info[i].sound[act] == -1)
1747 element_info[i].sound[act] = default_action_sound;
1751 /* copy sound settings to some elements that are only stored in level file
1752 in native R'n'D levels, but are used by game engine in native EM levels */
1753 for (i = 0; copy_properties[i][0] != -1; i++)
1754 for (j = 1; j <= 4; j++)
1755 for (act = 0; act < NUM_ACTIONS; act++)
1756 element_info[copy_properties[i][j]].sound[act] =
1757 element_info[copy_properties[i][0]].sound[act];
1760 static void InitGameModeSoundInfo()
1764 /* set values to -1 to identify later as "uninitialized" values */
1765 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1768 /* initialize gamemode/sound mapping from static configuration */
1769 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1771 int gamemode = gamemode_to_sound[i].gamemode;
1772 int sound = gamemode_to_sound[i].sound;
1775 gamemode = GAME_MODE_DEFAULT;
1777 menu.sound[gamemode] = sound;
1780 /* now set all '-1' values to levelset specific default values */
1781 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1782 if (menu.sound[i] == -1)
1783 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1786 static void set_sound_parameters(int sound, char **parameter_raw)
1788 int parameter[NUM_SND_ARGS];
1791 /* get integer values from string parameters */
1792 for (i = 0; i < NUM_SND_ARGS; i++)
1794 get_parameter_value(parameter_raw[i],
1795 sound_config_suffix[i].token,
1796 sound_config_suffix[i].type);
1798 /* explicit loop mode setting in configuration overrides default value */
1799 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1800 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1802 /* sound volume to change the original volume when loading the sound file */
1803 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1805 /* sound priority to give certain sounds a higher or lower priority */
1806 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1809 static void InitSoundInfo()
1811 int *sound_effect_properties;
1812 int num_sounds = getSoundListSize();
1815 checked_free(sound_info);
1817 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1818 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1820 /* initialize sound effect for all elements to "no sound" */
1821 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1822 for (j = 0; j < NUM_ACTIONS; j++)
1823 element_info[i].sound[j] = SND_UNDEFINED;
1825 for (i = 0; i < num_sounds; i++)
1827 struct FileInfo *sound = getSoundListEntry(i);
1828 int len_effect_text = strlen(sound->token);
1830 sound_effect_properties[i] = ACTION_OTHER;
1831 sound_info[i].loop = FALSE; /* default: play sound only once */
1833 /* determine all loop sounds and identify certain sound classes */
1835 for (j = 0; element_action_info[j].suffix; j++)
1837 int len_action_text = strlen(element_action_info[j].suffix);
1839 if (len_action_text < len_effect_text &&
1840 strEqual(&sound->token[len_effect_text - len_action_text],
1841 element_action_info[j].suffix))
1843 sound_effect_properties[i] = element_action_info[j].value;
1844 sound_info[i].loop = element_action_info[j].is_loop_sound;
1850 /* associate elements and some selected sound actions */
1852 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1854 if (element_info[j].class_name)
1856 int len_class_text = strlen(element_info[j].class_name);
1858 if (len_class_text + 1 < len_effect_text &&
1859 strncmp(sound->token,
1860 element_info[j].class_name, len_class_text) == 0 &&
1861 sound->token[len_class_text] == '.')
1863 int sound_action_value = sound_effect_properties[i];
1865 element_info[j].sound[sound_action_value] = i;
1870 set_sound_parameters(i, sound->parameter);
1873 free(sound_effect_properties);
1876 static void InitGameModeMusicInfo()
1878 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1879 int num_property_mappings = getMusicListPropertyMappingSize();
1880 int default_levelset_music = -1;
1883 /* set values to -1 to identify later as "uninitialized" values */
1884 for (i = 0; i < MAX_LEVELS; i++)
1885 levelset.music[i] = -1;
1886 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1889 /* initialize gamemode/music mapping from static configuration */
1890 for (i = 0; gamemode_to_music[i].music > -1; i++)
1892 int gamemode = gamemode_to_music[i].gamemode;
1893 int music = gamemode_to_music[i].music;
1896 gamemode = GAME_MODE_DEFAULT;
1898 menu.music[gamemode] = music;
1901 /* initialize gamemode/music mapping from dynamic configuration */
1902 for (i = 0; i < num_property_mappings; i++)
1904 int prefix = property_mapping[i].base_index;
1905 int gamemode = property_mapping[i].ext1_index;
1906 int level = property_mapping[i].ext2_index;
1907 int music = property_mapping[i].artwork_index;
1909 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1913 gamemode = GAME_MODE_DEFAULT;
1915 /* level specific music only allowed for in-game music */
1916 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1917 gamemode = GAME_MODE_PLAYING;
1922 default_levelset_music = music;
1925 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1926 levelset.music[level] = music;
1927 if (gamemode != GAME_MODE_PLAYING)
1928 menu.music[gamemode] = music;
1931 /* now set all '-1' values to menu specific default values */
1932 /* (undefined values of "levelset.music[]" might stay at "-1" to
1933 allow dynamic selection of music files from music directory!) */
1934 for (i = 0; i < MAX_LEVELS; i++)
1935 if (levelset.music[i] == -1)
1936 levelset.music[i] = default_levelset_music;
1937 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1938 if (menu.music[i] == -1)
1939 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1942 static void set_music_parameters(int music, char **parameter_raw)
1944 int parameter[NUM_MUS_ARGS];
1947 /* get integer values from string parameters */
1948 for (i = 0; i < NUM_MUS_ARGS; i++)
1950 get_parameter_value(parameter_raw[i],
1951 music_config_suffix[i].token,
1952 music_config_suffix[i].type);
1954 /* explicit loop mode setting in configuration overrides default value */
1955 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1956 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1959 static void InitMusicInfo()
1961 int num_music = getMusicListSize();
1964 checked_free(music_info);
1966 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1968 for (i = 0; i < num_music; i++)
1970 struct FileInfo *music = getMusicListEntry(i);
1971 int len_music_text = strlen(music->token);
1973 music_info[i].loop = TRUE; /* default: play music in loop mode */
1975 /* determine all loop music */
1977 for (j = 0; music_prefix_info[j].prefix; j++)
1979 int len_prefix_text = strlen(music_prefix_info[j].prefix);
1981 if (len_prefix_text < len_music_text &&
1982 strncmp(music->token,
1983 music_prefix_info[j].prefix, len_prefix_text) == 0)
1985 music_info[i].loop = music_prefix_info[j].is_loop_music;
1991 set_music_parameters(i, music->parameter);
1995 static void ReinitializeGraphics()
1997 print_timestamp_init("ReinitializeGraphics");
1999 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2001 InitGraphicInfo(); /* graphic properties mapping */
2002 print_timestamp_time("InitGraphicInfo");
2003 InitElementGraphicInfo(); /* element game graphic mapping */
2004 print_timestamp_time("InitElementGraphicInfo");
2005 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2006 print_timestamp_time("InitElementSpecialGraphicInfo");
2008 InitElementSmallImages(); /* scale elements to all needed sizes */
2009 print_timestamp_time("InitElementSmallImages");
2010 InitScaledImages(); /* scale all other images, if needed */
2011 print_timestamp_time("InitScaledImages");
2012 InitBitmapPointers(); /* set standard size bitmap pointers */
2013 print_timestamp_time("InitBitmapPointers");
2014 InitFontGraphicInfo(); /* initialize text drawing functions */
2015 print_timestamp_time("InitFontGraphicInfo");
2016 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2017 print_timestamp_time("InitGlobalAnimGraphicInfo");
2018 InitGlobalAnimImages(); /* initialize global animation images */
2019 print_timestamp_time("InitGlobalAnimImages");
2021 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2022 print_timestamp_time("InitGraphicInfo_EM");
2024 InitGraphicCompatibilityInfo();
2025 print_timestamp_time("InitGraphicCompatibilityInfo");
2027 SetMainBackgroundImage(IMG_BACKGROUND);
2028 print_timestamp_time("SetMainBackgroundImage");
2029 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2030 print_timestamp_time("SetDoorBackgroundImage");
2033 print_timestamp_time("InitGadgets");
2035 print_timestamp_time("InitToons");
2037 print_timestamp_time("InitDoors");
2039 print_timestamp_done("ReinitializeGraphics");
2042 static void ReinitializeSounds()
2044 InitSoundInfo(); /* sound properties mapping */
2045 InitElementSoundInfo(); /* element game sound mapping */
2046 InitGameModeSoundInfo(); /* game mode sound mapping */
2048 InitPlayLevelSound(); /* internal game sound settings */
2051 static void ReinitializeMusic()
2053 InitMusicInfo(); /* music properties mapping */
2054 InitGameModeMusicInfo(); /* game mode music mapping */
2057 static int get_special_property_bit(int element, int property_bit_nr)
2059 struct PropertyBitInfo
2065 static struct PropertyBitInfo pb_can_move_into_acid[] =
2067 /* the player may be able fall into acid when gravity is activated */
2072 { EL_SP_MURPHY, 0 },
2073 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2075 /* all elements that can move may be able to also move into acid */
2078 { EL_BUG_RIGHT, 1 },
2081 { EL_SPACESHIP, 2 },
2082 { EL_SPACESHIP_LEFT, 2 },
2083 { EL_SPACESHIP_RIGHT, 2 },
2084 { EL_SPACESHIP_UP, 2 },
2085 { EL_SPACESHIP_DOWN, 2 },
2086 { EL_BD_BUTTERFLY, 3 },
2087 { EL_BD_BUTTERFLY_LEFT, 3 },
2088 { EL_BD_BUTTERFLY_RIGHT, 3 },
2089 { EL_BD_BUTTERFLY_UP, 3 },
2090 { EL_BD_BUTTERFLY_DOWN, 3 },
2091 { EL_BD_FIREFLY, 4 },
2092 { EL_BD_FIREFLY_LEFT, 4 },
2093 { EL_BD_FIREFLY_RIGHT, 4 },
2094 { EL_BD_FIREFLY_UP, 4 },
2095 { EL_BD_FIREFLY_DOWN, 4 },
2097 { EL_YAMYAM_LEFT, 5 },
2098 { EL_YAMYAM_RIGHT, 5 },
2099 { EL_YAMYAM_UP, 5 },
2100 { EL_YAMYAM_DOWN, 5 },
2101 { EL_DARK_YAMYAM, 6 },
2104 { EL_PACMAN_LEFT, 8 },
2105 { EL_PACMAN_RIGHT, 8 },
2106 { EL_PACMAN_UP, 8 },
2107 { EL_PACMAN_DOWN, 8 },
2109 { EL_MOLE_LEFT, 9 },
2110 { EL_MOLE_RIGHT, 9 },
2112 { EL_MOLE_DOWN, 9 },
2116 { EL_SATELLITE, 13 },
2117 { EL_SP_SNIKSNAK, 14 },
2118 { EL_SP_ELECTRON, 15 },
2121 { EL_EMC_ANDROID, 18 },
2126 static struct PropertyBitInfo pb_dont_collide_with[] =
2128 { EL_SP_SNIKSNAK, 0 },
2129 { EL_SP_ELECTRON, 1 },
2137 struct PropertyBitInfo *pb_info;
2140 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2141 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2146 struct PropertyBitInfo *pb_info = NULL;
2149 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2150 if (pb_definition[i].bit_nr == property_bit_nr)
2151 pb_info = pb_definition[i].pb_info;
2153 if (pb_info == NULL)
2156 for (i = 0; pb_info[i].element != -1; i++)
2157 if (pb_info[i].element == element)
2158 return pb_info[i].bit_nr;
2163 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2164 boolean property_value)
2166 int bit_nr = get_special_property_bit(element, property_bit_nr);
2171 *bitfield |= (1 << bit_nr);
2173 *bitfield &= ~(1 << bit_nr);
2177 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2179 int bit_nr = get_special_property_bit(element, property_bit_nr);
2182 return ((*bitfield & (1 << bit_nr)) != 0);
2187 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2189 static int group_nr;
2190 static struct ElementGroupInfo *group;
2191 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2194 if (actual_group == NULL) /* not yet initialized */
2197 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2199 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2200 group_element - EL_GROUP_START + 1);
2202 /* replace element which caused too deep recursion by question mark */
2203 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2208 if (recursion_depth == 0) /* initialization */
2210 group = actual_group;
2211 group_nr = GROUP_NR(group_element);
2213 group->num_elements_resolved = 0;
2214 group->choice_pos = 0;
2216 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2217 element_info[i].in_group[group_nr] = FALSE;
2220 for (i = 0; i < actual_group->num_elements; i++)
2222 int element = actual_group->element[i];
2224 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2227 if (IS_GROUP_ELEMENT(element))
2228 ResolveGroupElementExt(element, recursion_depth + 1);
2231 group->element_resolved[group->num_elements_resolved++] = element;
2232 element_info[element].in_group[group_nr] = TRUE;
2237 void ResolveGroupElement(int group_element)
2239 ResolveGroupElementExt(group_element, 0);
2242 void InitElementPropertiesStatic()
2244 static boolean clipboard_elements_initialized = FALSE;
2246 static int ep_diggable[] =
2251 EL_SP_BUGGY_BASE_ACTIVATING,
2254 EL_INVISIBLE_SAND_ACTIVE,
2257 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2258 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2263 EL_SP_BUGGY_BASE_ACTIVE,
2270 static int ep_collectible_only[] =
2292 EL_DYNABOMB_INCREASE_NUMBER,
2293 EL_DYNABOMB_INCREASE_SIZE,
2294 EL_DYNABOMB_INCREASE_POWER,
2312 /* !!! handle separately !!! */
2313 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2319 static int ep_dont_run_into[] =
2321 /* same elements as in 'ep_dont_touch' */
2327 /* same elements as in 'ep_dont_collide_with' */
2339 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2344 EL_SP_BUGGY_BASE_ACTIVE,
2351 static int ep_dont_collide_with[] =
2353 /* same elements as in 'ep_dont_touch' */
2370 static int ep_dont_touch[] =
2380 static int ep_indestructible[] =
2384 EL_ACID_POOL_TOPLEFT,
2385 EL_ACID_POOL_TOPRIGHT,
2386 EL_ACID_POOL_BOTTOMLEFT,
2387 EL_ACID_POOL_BOTTOM,
2388 EL_ACID_POOL_BOTTOMRIGHT,
2389 EL_SP_HARDWARE_GRAY,
2390 EL_SP_HARDWARE_GREEN,
2391 EL_SP_HARDWARE_BLUE,
2393 EL_SP_HARDWARE_YELLOW,
2394 EL_SP_HARDWARE_BASE_1,
2395 EL_SP_HARDWARE_BASE_2,
2396 EL_SP_HARDWARE_BASE_3,
2397 EL_SP_HARDWARE_BASE_4,
2398 EL_SP_HARDWARE_BASE_5,
2399 EL_SP_HARDWARE_BASE_6,
2400 EL_INVISIBLE_STEELWALL,
2401 EL_INVISIBLE_STEELWALL_ACTIVE,
2402 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2403 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2404 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2405 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2406 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2407 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2408 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2409 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2410 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2411 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2412 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2413 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2415 EL_LIGHT_SWITCH_ACTIVE,
2416 EL_SIGN_EXCLAMATION,
2417 EL_SIGN_RADIOACTIVITY,
2424 EL_SIGN_ENTRY_FORBIDDEN,
2425 EL_SIGN_EMERGENCY_EXIT,
2433 EL_STEEL_EXIT_CLOSED,
2435 EL_STEEL_EXIT_OPENING,
2436 EL_STEEL_EXIT_CLOSING,
2437 EL_EM_STEEL_EXIT_CLOSED,
2438 EL_EM_STEEL_EXIT_OPEN,
2439 EL_EM_STEEL_EXIT_OPENING,
2440 EL_EM_STEEL_EXIT_CLOSING,
2441 EL_DC_STEELWALL_1_LEFT,
2442 EL_DC_STEELWALL_1_RIGHT,
2443 EL_DC_STEELWALL_1_TOP,
2444 EL_DC_STEELWALL_1_BOTTOM,
2445 EL_DC_STEELWALL_1_HORIZONTAL,
2446 EL_DC_STEELWALL_1_VERTICAL,
2447 EL_DC_STEELWALL_1_TOPLEFT,
2448 EL_DC_STEELWALL_1_TOPRIGHT,
2449 EL_DC_STEELWALL_1_BOTTOMLEFT,
2450 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2451 EL_DC_STEELWALL_1_TOPLEFT_2,
2452 EL_DC_STEELWALL_1_TOPRIGHT_2,
2453 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2454 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2455 EL_DC_STEELWALL_2_LEFT,
2456 EL_DC_STEELWALL_2_RIGHT,
2457 EL_DC_STEELWALL_2_TOP,
2458 EL_DC_STEELWALL_2_BOTTOM,
2459 EL_DC_STEELWALL_2_HORIZONTAL,
2460 EL_DC_STEELWALL_2_VERTICAL,
2461 EL_DC_STEELWALL_2_MIDDLE,
2462 EL_DC_STEELWALL_2_SINGLE,
2463 EL_STEELWALL_SLIPPERY,
2477 EL_GATE_1_GRAY_ACTIVE,
2478 EL_GATE_2_GRAY_ACTIVE,
2479 EL_GATE_3_GRAY_ACTIVE,
2480 EL_GATE_4_GRAY_ACTIVE,
2489 EL_EM_GATE_1_GRAY_ACTIVE,
2490 EL_EM_GATE_2_GRAY_ACTIVE,
2491 EL_EM_GATE_3_GRAY_ACTIVE,
2492 EL_EM_GATE_4_GRAY_ACTIVE,
2501 EL_EMC_GATE_5_GRAY_ACTIVE,
2502 EL_EMC_GATE_6_GRAY_ACTIVE,
2503 EL_EMC_GATE_7_GRAY_ACTIVE,
2504 EL_EMC_GATE_8_GRAY_ACTIVE,
2506 EL_DC_GATE_WHITE_GRAY,
2507 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2508 EL_DC_GATE_FAKE_GRAY,
2510 EL_SWITCHGATE_OPENING,
2511 EL_SWITCHGATE_CLOSED,
2512 EL_SWITCHGATE_CLOSING,
2513 EL_DC_SWITCHGATE_SWITCH_UP,
2514 EL_DC_SWITCHGATE_SWITCH_DOWN,
2516 EL_TIMEGATE_OPENING,
2518 EL_TIMEGATE_CLOSING,
2519 EL_DC_TIMEGATE_SWITCH,
2520 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2524 EL_TUBE_VERTICAL_LEFT,
2525 EL_TUBE_VERTICAL_RIGHT,
2526 EL_TUBE_HORIZONTAL_UP,
2527 EL_TUBE_HORIZONTAL_DOWN,
2532 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2533 EL_EXPANDABLE_STEELWALL_VERTICAL,
2534 EL_EXPANDABLE_STEELWALL_ANY,
2539 static int ep_slippery[] =
2553 EL_ROBOT_WHEEL_ACTIVE,
2559 EL_ACID_POOL_TOPLEFT,
2560 EL_ACID_POOL_TOPRIGHT,
2570 EL_STEELWALL_SLIPPERY,
2573 EL_EMC_WALL_SLIPPERY_1,
2574 EL_EMC_WALL_SLIPPERY_2,
2575 EL_EMC_WALL_SLIPPERY_3,
2576 EL_EMC_WALL_SLIPPERY_4,
2578 EL_EMC_MAGIC_BALL_ACTIVE,
2583 static int ep_can_change[] =
2588 static int ep_can_move[] =
2590 /* same elements as in 'pb_can_move_into_acid' */
2613 static int ep_can_fall[] =
2627 EL_QUICKSAND_FAST_FULL,
2629 EL_BD_MAGIC_WALL_FULL,
2630 EL_DC_MAGIC_WALL_FULL,
2644 static int ep_can_smash_player[] =
2670 static int ep_can_smash_enemies[] =
2679 static int ep_can_smash_everything[] =
2688 static int ep_explodes_by_fire[] =
2690 /* same elements as in 'ep_explodes_impact' */
2695 /* same elements as in 'ep_explodes_smashed' */
2705 EL_EM_DYNAMITE_ACTIVE,
2706 EL_DYNABOMB_PLAYER_1_ACTIVE,
2707 EL_DYNABOMB_PLAYER_2_ACTIVE,
2708 EL_DYNABOMB_PLAYER_3_ACTIVE,
2709 EL_DYNABOMB_PLAYER_4_ACTIVE,
2710 EL_DYNABOMB_INCREASE_NUMBER,
2711 EL_DYNABOMB_INCREASE_SIZE,
2712 EL_DYNABOMB_INCREASE_POWER,
2713 EL_SP_DISK_RED_ACTIVE,
2727 static int ep_explodes_smashed[] =
2729 /* same elements as in 'ep_explodes_impact' */
2743 static int ep_explodes_impact[] =
2752 static int ep_walkable_over[] =
2756 EL_SOKOBAN_FIELD_EMPTY,
2763 EL_EM_STEEL_EXIT_OPEN,
2764 EL_EM_STEEL_EXIT_OPENING,
2773 EL_GATE_1_GRAY_ACTIVE,
2774 EL_GATE_2_GRAY_ACTIVE,
2775 EL_GATE_3_GRAY_ACTIVE,
2776 EL_GATE_4_GRAY_ACTIVE,
2784 static int ep_walkable_inside[] =
2789 EL_TUBE_VERTICAL_LEFT,
2790 EL_TUBE_VERTICAL_RIGHT,
2791 EL_TUBE_HORIZONTAL_UP,
2792 EL_TUBE_HORIZONTAL_DOWN,
2801 static int ep_walkable_under[] =
2806 static int ep_passable_over[] =
2816 EL_EM_GATE_1_GRAY_ACTIVE,
2817 EL_EM_GATE_2_GRAY_ACTIVE,
2818 EL_EM_GATE_3_GRAY_ACTIVE,
2819 EL_EM_GATE_4_GRAY_ACTIVE,
2828 EL_EMC_GATE_5_GRAY_ACTIVE,
2829 EL_EMC_GATE_6_GRAY_ACTIVE,
2830 EL_EMC_GATE_7_GRAY_ACTIVE,
2831 EL_EMC_GATE_8_GRAY_ACTIVE,
2833 EL_DC_GATE_WHITE_GRAY,
2834 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2841 static int ep_passable_inside[] =
2847 EL_SP_PORT_HORIZONTAL,
2848 EL_SP_PORT_VERTICAL,
2850 EL_SP_GRAVITY_PORT_LEFT,
2851 EL_SP_GRAVITY_PORT_RIGHT,
2852 EL_SP_GRAVITY_PORT_UP,
2853 EL_SP_GRAVITY_PORT_DOWN,
2854 EL_SP_GRAVITY_ON_PORT_LEFT,
2855 EL_SP_GRAVITY_ON_PORT_RIGHT,
2856 EL_SP_GRAVITY_ON_PORT_UP,
2857 EL_SP_GRAVITY_ON_PORT_DOWN,
2858 EL_SP_GRAVITY_OFF_PORT_LEFT,
2859 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2860 EL_SP_GRAVITY_OFF_PORT_UP,
2861 EL_SP_GRAVITY_OFF_PORT_DOWN,
2866 static int ep_passable_under[] =
2871 static int ep_droppable[] =
2876 static int ep_explodes_1x1_old[] =
2881 static int ep_pushable[] =
2893 EL_SOKOBAN_FIELD_FULL,
2902 static int ep_explodes_cross_old[] =
2907 static int ep_protected[] =
2909 /* same elements as in 'ep_walkable_inside' */
2913 EL_TUBE_VERTICAL_LEFT,
2914 EL_TUBE_VERTICAL_RIGHT,
2915 EL_TUBE_HORIZONTAL_UP,
2916 EL_TUBE_HORIZONTAL_DOWN,
2922 /* same elements as in 'ep_passable_over' */
2931 EL_EM_GATE_1_GRAY_ACTIVE,
2932 EL_EM_GATE_2_GRAY_ACTIVE,
2933 EL_EM_GATE_3_GRAY_ACTIVE,
2934 EL_EM_GATE_4_GRAY_ACTIVE,
2943 EL_EMC_GATE_5_GRAY_ACTIVE,
2944 EL_EMC_GATE_6_GRAY_ACTIVE,
2945 EL_EMC_GATE_7_GRAY_ACTIVE,
2946 EL_EMC_GATE_8_GRAY_ACTIVE,
2948 EL_DC_GATE_WHITE_GRAY,
2949 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2953 /* same elements as in 'ep_passable_inside' */
2958 EL_SP_PORT_HORIZONTAL,
2959 EL_SP_PORT_VERTICAL,
2961 EL_SP_GRAVITY_PORT_LEFT,
2962 EL_SP_GRAVITY_PORT_RIGHT,
2963 EL_SP_GRAVITY_PORT_UP,
2964 EL_SP_GRAVITY_PORT_DOWN,
2965 EL_SP_GRAVITY_ON_PORT_LEFT,
2966 EL_SP_GRAVITY_ON_PORT_RIGHT,
2967 EL_SP_GRAVITY_ON_PORT_UP,
2968 EL_SP_GRAVITY_ON_PORT_DOWN,
2969 EL_SP_GRAVITY_OFF_PORT_LEFT,
2970 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2971 EL_SP_GRAVITY_OFF_PORT_UP,
2972 EL_SP_GRAVITY_OFF_PORT_DOWN,
2977 static int ep_throwable[] =
2982 static int ep_can_explode[] =
2984 /* same elements as in 'ep_explodes_impact' */
2989 /* same elements as in 'ep_explodes_smashed' */
2995 /* elements that can explode by explosion or by dragonfire */
2999 EL_EM_DYNAMITE_ACTIVE,
3000 EL_DYNABOMB_PLAYER_1_ACTIVE,
3001 EL_DYNABOMB_PLAYER_2_ACTIVE,
3002 EL_DYNABOMB_PLAYER_3_ACTIVE,
3003 EL_DYNABOMB_PLAYER_4_ACTIVE,
3004 EL_DYNABOMB_INCREASE_NUMBER,
3005 EL_DYNABOMB_INCREASE_SIZE,
3006 EL_DYNABOMB_INCREASE_POWER,
3007 EL_SP_DISK_RED_ACTIVE,
3015 /* elements that can explode only by explosion */
3021 static int ep_gravity_reachable[] =
3027 EL_INVISIBLE_SAND_ACTIVE,
3032 EL_SP_PORT_HORIZONTAL,
3033 EL_SP_PORT_VERTICAL,
3035 EL_SP_GRAVITY_PORT_LEFT,
3036 EL_SP_GRAVITY_PORT_RIGHT,
3037 EL_SP_GRAVITY_PORT_UP,
3038 EL_SP_GRAVITY_PORT_DOWN,
3039 EL_SP_GRAVITY_ON_PORT_LEFT,
3040 EL_SP_GRAVITY_ON_PORT_RIGHT,
3041 EL_SP_GRAVITY_ON_PORT_UP,
3042 EL_SP_GRAVITY_ON_PORT_DOWN,
3043 EL_SP_GRAVITY_OFF_PORT_LEFT,
3044 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3045 EL_SP_GRAVITY_OFF_PORT_UP,
3046 EL_SP_GRAVITY_OFF_PORT_DOWN,
3052 static int ep_player[] =
3059 EL_SOKOBAN_FIELD_PLAYER,
3065 static int ep_can_pass_magic_wall[] =
3079 static int ep_can_pass_dc_magic_wall[] =
3095 static int ep_switchable[] =
3099 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3100 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3101 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3102 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3103 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3104 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3105 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3106 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3107 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3108 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3109 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3110 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3111 EL_SWITCHGATE_SWITCH_UP,
3112 EL_SWITCHGATE_SWITCH_DOWN,
3113 EL_DC_SWITCHGATE_SWITCH_UP,
3114 EL_DC_SWITCHGATE_SWITCH_DOWN,
3116 EL_LIGHT_SWITCH_ACTIVE,
3118 EL_DC_TIMEGATE_SWITCH,
3119 EL_BALLOON_SWITCH_LEFT,
3120 EL_BALLOON_SWITCH_RIGHT,
3121 EL_BALLOON_SWITCH_UP,
3122 EL_BALLOON_SWITCH_DOWN,
3123 EL_BALLOON_SWITCH_ANY,
3124 EL_BALLOON_SWITCH_NONE,
3127 EL_EMC_MAGIC_BALL_SWITCH,
3128 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3133 static int ep_bd_element[] =
3167 static int ep_sp_element[] =
3169 /* should always be valid */
3172 /* standard classic Supaplex elements */
3179 EL_SP_HARDWARE_GRAY,
3187 EL_SP_GRAVITY_PORT_RIGHT,
3188 EL_SP_GRAVITY_PORT_DOWN,
3189 EL_SP_GRAVITY_PORT_LEFT,
3190 EL_SP_GRAVITY_PORT_UP,
3195 EL_SP_PORT_VERTICAL,
3196 EL_SP_PORT_HORIZONTAL,
3202 EL_SP_HARDWARE_BASE_1,
3203 EL_SP_HARDWARE_GREEN,
3204 EL_SP_HARDWARE_BLUE,
3206 EL_SP_HARDWARE_YELLOW,
3207 EL_SP_HARDWARE_BASE_2,
3208 EL_SP_HARDWARE_BASE_3,
3209 EL_SP_HARDWARE_BASE_4,
3210 EL_SP_HARDWARE_BASE_5,
3211 EL_SP_HARDWARE_BASE_6,
3215 /* additional elements that appeared in newer Supaplex levels */
3218 /* additional gravity port elements (not switching, but setting gravity) */
3219 EL_SP_GRAVITY_ON_PORT_LEFT,
3220 EL_SP_GRAVITY_ON_PORT_RIGHT,
3221 EL_SP_GRAVITY_ON_PORT_UP,
3222 EL_SP_GRAVITY_ON_PORT_DOWN,
3223 EL_SP_GRAVITY_OFF_PORT_LEFT,
3224 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3225 EL_SP_GRAVITY_OFF_PORT_UP,
3226 EL_SP_GRAVITY_OFF_PORT_DOWN,
3228 /* more than one Murphy in a level results in an inactive clone */
3231 /* runtime Supaplex elements */
3232 EL_SP_DISK_RED_ACTIVE,
3233 EL_SP_TERMINAL_ACTIVE,
3234 EL_SP_BUGGY_BASE_ACTIVATING,
3235 EL_SP_BUGGY_BASE_ACTIVE,
3242 static int ep_sb_element[] =
3247 EL_SOKOBAN_FIELD_EMPTY,
3248 EL_SOKOBAN_FIELD_FULL,
3249 EL_SOKOBAN_FIELD_PLAYER,
3254 EL_INVISIBLE_STEELWALL,
3259 static int ep_gem[] =
3271 static int ep_food_dark_yamyam[] =
3299 static int ep_food_penguin[] =
3313 static int ep_food_pig[] =
3325 static int ep_historic_wall[] =
3336 EL_GATE_1_GRAY_ACTIVE,
3337 EL_GATE_2_GRAY_ACTIVE,
3338 EL_GATE_3_GRAY_ACTIVE,
3339 EL_GATE_4_GRAY_ACTIVE,
3348 EL_EM_GATE_1_GRAY_ACTIVE,
3349 EL_EM_GATE_2_GRAY_ACTIVE,
3350 EL_EM_GATE_3_GRAY_ACTIVE,
3351 EL_EM_GATE_4_GRAY_ACTIVE,
3358 EL_EXPANDABLE_WALL_HORIZONTAL,
3359 EL_EXPANDABLE_WALL_VERTICAL,
3360 EL_EXPANDABLE_WALL_ANY,
3361 EL_EXPANDABLE_WALL_GROWING,
3362 EL_BD_EXPANDABLE_WALL,
3369 EL_SP_HARDWARE_GRAY,
3370 EL_SP_HARDWARE_GREEN,
3371 EL_SP_HARDWARE_BLUE,
3373 EL_SP_HARDWARE_YELLOW,
3374 EL_SP_HARDWARE_BASE_1,
3375 EL_SP_HARDWARE_BASE_2,
3376 EL_SP_HARDWARE_BASE_3,
3377 EL_SP_HARDWARE_BASE_4,
3378 EL_SP_HARDWARE_BASE_5,
3379 EL_SP_HARDWARE_BASE_6,
3381 EL_SP_TERMINAL_ACTIVE,
3384 EL_INVISIBLE_STEELWALL,
3385 EL_INVISIBLE_STEELWALL_ACTIVE,
3387 EL_INVISIBLE_WALL_ACTIVE,
3388 EL_STEELWALL_SLIPPERY,
3405 static int ep_historic_solid[] =
3409 EL_EXPANDABLE_WALL_HORIZONTAL,
3410 EL_EXPANDABLE_WALL_VERTICAL,
3411 EL_EXPANDABLE_WALL_ANY,
3412 EL_BD_EXPANDABLE_WALL,
3425 EL_QUICKSAND_FILLING,
3426 EL_QUICKSAND_EMPTYING,
3428 EL_MAGIC_WALL_ACTIVE,
3429 EL_MAGIC_WALL_EMPTYING,
3430 EL_MAGIC_WALL_FILLING,
3434 EL_BD_MAGIC_WALL_ACTIVE,
3435 EL_BD_MAGIC_WALL_EMPTYING,
3436 EL_BD_MAGIC_WALL_FULL,
3437 EL_BD_MAGIC_WALL_FILLING,
3438 EL_BD_MAGIC_WALL_DEAD,
3447 EL_SP_TERMINAL_ACTIVE,
3451 EL_INVISIBLE_WALL_ACTIVE,
3452 EL_SWITCHGATE_SWITCH_UP,
3453 EL_SWITCHGATE_SWITCH_DOWN,
3454 EL_DC_SWITCHGATE_SWITCH_UP,
3455 EL_DC_SWITCHGATE_SWITCH_DOWN,
3457 EL_TIMEGATE_SWITCH_ACTIVE,
3458 EL_DC_TIMEGATE_SWITCH,
3459 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3471 /* the following elements are a direct copy of "indestructible" elements,
3472 except "EL_ACID", which is "indestructible", but not "solid"! */
3477 EL_ACID_POOL_TOPLEFT,
3478 EL_ACID_POOL_TOPRIGHT,
3479 EL_ACID_POOL_BOTTOMLEFT,
3480 EL_ACID_POOL_BOTTOM,
3481 EL_ACID_POOL_BOTTOMRIGHT,
3482 EL_SP_HARDWARE_GRAY,
3483 EL_SP_HARDWARE_GREEN,
3484 EL_SP_HARDWARE_BLUE,
3486 EL_SP_HARDWARE_YELLOW,
3487 EL_SP_HARDWARE_BASE_1,
3488 EL_SP_HARDWARE_BASE_2,
3489 EL_SP_HARDWARE_BASE_3,
3490 EL_SP_HARDWARE_BASE_4,
3491 EL_SP_HARDWARE_BASE_5,
3492 EL_SP_HARDWARE_BASE_6,
3493 EL_INVISIBLE_STEELWALL,
3494 EL_INVISIBLE_STEELWALL_ACTIVE,
3495 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3496 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3497 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3498 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3499 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3500 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3501 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3502 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3503 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3504 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3505 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3506 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3508 EL_LIGHT_SWITCH_ACTIVE,
3509 EL_SIGN_EXCLAMATION,
3510 EL_SIGN_RADIOACTIVITY,
3517 EL_SIGN_ENTRY_FORBIDDEN,
3518 EL_SIGN_EMERGENCY_EXIT,
3526 EL_STEEL_EXIT_CLOSED,
3528 EL_DC_STEELWALL_1_LEFT,
3529 EL_DC_STEELWALL_1_RIGHT,
3530 EL_DC_STEELWALL_1_TOP,
3531 EL_DC_STEELWALL_1_BOTTOM,
3532 EL_DC_STEELWALL_1_HORIZONTAL,
3533 EL_DC_STEELWALL_1_VERTICAL,
3534 EL_DC_STEELWALL_1_TOPLEFT,
3535 EL_DC_STEELWALL_1_TOPRIGHT,
3536 EL_DC_STEELWALL_1_BOTTOMLEFT,
3537 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3538 EL_DC_STEELWALL_1_TOPLEFT_2,
3539 EL_DC_STEELWALL_1_TOPRIGHT_2,
3540 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3541 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3542 EL_DC_STEELWALL_2_LEFT,
3543 EL_DC_STEELWALL_2_RIGHT,
3544 EL_DC_STEELWALL_2_TOP,
3545 EL_DC_STEELWALL_2_BOTTOM,
3546 EL_DC_STEELWALL_2_HORIZONTAL,
3547 EL_DC_STEELWALL_2_VERTICAL,
3548 EL_DC_STEELWALL_2_MIDDLE,
3549 EL_DC_STEELWALL_2_SINGLE,
3550 EL_STEELWALL_SLIPPERY,
3564 EL_GATE_1_GRAY_ACTIVE,
3565 EL_GATE_2_GRAY_ACTIVE,
3566 EL_GATE_3_GRAY_ACTIVE,
3567 EL_GATE_4_GRAY_ACTIVE,
3576 EL_EM_GATE_1_GRAY_ACTIVE,
3577 EL_EM_GATE_2_GRAY_ACTIVE,
3578 EL_EM_GATE_3_GRAY_ACTIVE,
3579 EL_EM_GATE_4_GRAY_ACTIVE,
3581 EL_SWITCHGATE_OPENING,
3582 EL_SWITCHGATE_CLOSED,
3583 EL_SWITCHGATE_CLOSING,
3585 EL_TIMEGATE_OPENING,
3587 EL_TIMEGATE_CLOSING,
3591 EL_TUBE_VERTICAL_LEFT,
3592 EL_TUBE_VERTICAL_RIGHT,
3593 EL_TUBE_HORIZONTAL_UP,
3594 EL_TUBE_HORIZONTAL_DOWN,
3603 static int ep_classic_enemy[] =
3620 static int ep_belt[] =
3622 EL_CONVEYOR_BELT_1_LEFT,
3623 EL_CONVEYOR_BELT_1_MIDDLE,
3624 EL_CONVEYOR_BELT_1_RIGHT,
3625 EL_CONVEYOR_BELT_2_LEFT,
3626 EL_CONVEYOR_BELT_2_MIDDLE,
3627 EL_CONVEYOR_BELT_2_RIGHT,
3628 EL_CONVEYOR_BELT_3_LEFT,
3629 EL_CONVEYOR_BELT_3_MIDDLE,
3630 EL_CONVEYOR_BELT_3_RIGHT,
3631 EL_CONVEYOR_BELT_4_LEFT,
3632 EL_CONVEYOR_BELT_4_MIDDLE,
3633 EL_CONVEYOR_BELT_4_RIGHT,
3638 static int ep_belt_active[] =
3640 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3641 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3642 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3643 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3644 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3645 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3646 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3647 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3648 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3649 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3650 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3651 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3656 static int ep_belt_switch[] =
3658 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3659 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3660 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3661 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3662 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3663 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3664 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3665 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3666 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3667 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3668 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3669 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3674 static int ep_tube[] =
3681 EL_TUBE_HORIZONTAL_UP,
3682 EL_TUBE_HORIZONTAL_DOWN,
3684 EL_TUBE_VERTICAL_LEFT,
3685 EL_TUBE_VERTICAL_RIGHT,
3691 static int ep_acid_pool[] =
3693 EL_ACID_POOL_TOPLEFT,
3694 EL_ACID_POOL_TOPRIGHT,
3695 EL_ACID_POOL_BOTTOMLEFT,
3696 EL_ACID_POOL_BOTTOM,
3697 EL_ACID_POOL_BOTTOMRIGHT,
3702 static int ep_keygate[] =
3712 EL_GATE_1_GRAY_ACTIVE,
3713 EL_GATE_2_GRAY_ACTIVE,
3714 EL_GATE_3_GRAY_ACTIVE,
3715 EL_GATE_4_GRAY_ACTIVE,
3724 EL_EM_GATE_1_GRAY_ACTIVE,
3725 EL_EM_GATE_2_GRAY_ACTIVE,
3726 EL_EM_GATE_3_GRAY_ACTIVE,
3727 EL_EM_GATE_4_GRAY_ACTIVE,
3736 EL_EMC_GATE_5_GRAY_ACTIVE,
3737 EL_EMC_GATE_6_GRAY_ACTIVE,
3738 EL_EMC_GATE_7_GRAY_ACTIVE,
3739 EL_EMC_GATE_8_GRAY_ACTIVE,
3741 EL_DC_GATE_WHITE_GRAY,
3742 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3747 static int ep_amoeboid[] =
3759 static int ep_amoebalive[] =
3770 static int ep_has_editor_content[] =
3776 EL_SOKOBAN_FIELD_PLAYER,
3793 static int ep_can_turn_each_move[] =
3795 /* !!! do something with this one !!! */
3799 static int ep_can_grow[] =
3813 static int ep_active_bomb[] =
3816 EL_EM_DYNAMITE_ACTIVE,
3817 EL_DYNABOMB_PLAYER_1_ACTIVE,
3818 EL_DYNABOMB_PLAYER_2_ACTIVE,
3819 EL_DYNABOMB_PLAYER_3_ACTIVE,
3820 EL_DYNABOMB_PLAYER_4_ACTIVE,
3821 EL_SP_DISK_RED_ACTIVE,
3826 static int ep_inactive[] =
3836 EL_QUICKSAND_FAST_EMPTY,
3859 EL_GATE_1_GRAY_ACTIVE,
3860 EL_GATE_2_GRAY_ACTIVE,
3861 EL_GATE_3_GRAY_ACTIVE,
3862 EL_GATE_4_GRAY_ACTIVE,
3871 EL_EM_GATE_1_GRAY_ACTIVE,
3872 EL_EM_GATE_2_GRAY_ACTIVE,
3873 EL_EM_GATE_3_GRAY_ACTIVE,
3874 EL_EM_GATE_4_GRAY_ACTIVE,
3883 EL_EMC_GATE_5_GRAY_ACTIVE,
3884 EL_EMC_GATE_6_GRAY_ACTIVE,
3885 EL_EMC_GATE_7_GRAY_ACTIVE,
3886 EL_EMC_GATE_8_GRAY_ACTIVE,
3888 EL_DC_GATE_WHITE_GRAY,
3889 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3890 EL_DC_GATE_FAKE_GRAY,
3893 EL_INVISIBLE_STEELWALL,
3901 EL_WALL_EMERALD_YELLOW,
3902 EL_DYNABOMB_INCREASE_NUMBER,
3903 EL_DYNABOMB_INCREASE_SIZE,
3904 EL_DYNABOMB_INCREASE_POWER,
3908 EL_SOKOBAN_FIELD_EMPTY,
3909 EL_SOKOBAN_FIELD_FULL,
3910 EL_WALL_EMERALD_RED,
3911 EL_WALL_EMERALD_PURPLE,
3912 EL_ACID_POOL_TOPLEFT,
3913 EL_ACID_POOL_TOPRIGHT,
3914 EL_ACID_POOL_BOTTOMLEFT,
3915 EL_ACID_POOL_BOTTOM,
3916 EL_ACID_POOL_BOTTOMRIGHT,
3920 EL_BD_MAGIC_WALL_DEAD,
3922 EL_DC_MAGIC_WALL_DEAD,
3923 EL_AMOEBA_TO_DIAMOND,
3931 EL_SP_GRAVITY_PORT_RIGHT,
3932 EL_SP_GRAVITY_PORT_DOWN,
3933 EL_SP_GRAVITY_PORT_LEFT,
3934 EL_SP_GRAVITY_PORT_UP,
3935 EL_SP_PORT_HORIZONTAL,
3936 EL_SP_PORT_VERTICAL,
3947 EL_SP_HARDWARE_GRAY,
3948 EL_SP_HARDWARE_GREEN,
3949 EL_SP_HARDWARE_BLUE,
3951 EL_SP_HARDWARE_YELLOW,
3952 EL_SP_HARDWARE_BASE_1,
3953 EL_SP_HARDWARE_BASE_2,
3954 EL_SP_HARDWARE_BASE_3,
3955 EL_SP_HARDWARE_BASE_4,
3956 EL_SP_HARDWARE_BASE_5,
3957 EL_SP_HARDWARE_BASE_6,
3958 EL_SP_GRAVITY_ON_PORT_LEFT,
3959 EL_SP_GRAVITY_ON_PORT_RIGHT,
3960 EL_SP_GRAVITY_ON_PORT_UP,
3961 EL_SP_GRAVITY_ON_PORT_DOWN,
3962 EL_SP_GRAVITY_OFF_PORT_LEFT,
3963 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3964 EL_SP_GRAVITY_OFF_PORT_UP,
3965 EL_SP_GRAVITY_OFF_PORT_DOWN,
3966 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3967 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3968 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3969 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3970 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3971 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3972 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3973 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3974 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3975 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3976 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3977 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3978 EL_SIGN_EXCLAMATION,
3979 EL_SIGN_RADIOACTIVITY,
3986 EL_SIGN_ENTRY_FORBIDDEN,
3987 EL_SIGN_EMERGENCY_EXIT,
3995 EL_DC_STEELWALL_1_LEFT,
3996 EL_DC_STEELWALL_1_RIGHT,
3997 EL_DC_STEELWALL_1_TOP,
3998 EL_DC_STEELWALL_1_BOTTOM,
3999 EL_DC_STEELWALL_1_HORIZONTAL,
4000 EL_DC_STEELWALL_1_VERTICAL,
4001 EL_DC_STEELWALL_1_TOPLEFT,
4002 EL_DC_STEELWALL_1_TOPRIGHT,
4003 EL_DC_STEELWALL_1_BOTTOMLEFT,
4004 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4005 EL_DC_STEELWALL_1_TOPLEFT_2,
4006 EL_DC_STEELWALL_1_TOPRIGHT_2,
4007 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4008 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4009 EL_DC_STEELWALL_2_LEFT,
4010 EL_DC_STEELWALL_2_RIGHT,
4011 EL_DC_STEELWALL_2_TOP,
4012 EL_DC_STEELWALL_2_BOTTOM,
4013 EL_DC_STEELWALL_2_HORIZONTAL,
4014 EL_DC_STEELWALL_2_VERTICAL,
4015 EL_DC_STEELWALL_2_MIDDLE,
4016 EL_DC_STEELWALL_2_SINGLE,
4017 EL_STEELWALL_SLIPPERY,
4022 EL_EMC_WALL_SLIPPERY_1,
4023 EL_EMC_WALL_SLIPPERY_2,
4024 EL_EMC_WALL_SLIPPERY_3,
4025 EL_EMC_WALL_SLIPPERY_4,
4046 static int ep_em_slippery_wall[] =
4051 static int ep_gfx_crumbled[] =
4062 static int ep_editor_cascade_active[] =
4064 EL_INTERNAL_CASCADE_BD_ACTIVE,
4065 EL_INTERNAL_CASCADE_EM_ACTIVE,
4066 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4067 EL_INTERNAL_CASCADE_RND_ACTIVE,
4068 EL_INTERNAL_CASCADE_SB_ACTIVE,
4069 EL_INTERNAL_CASCADE_SP_ACTIVE,
4070 EL_INTERNAL_CASCADE_DC_ACTIVE,
4071 EL_INTERNAL_CASCADE_DX_ACTIVE,
4072 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4073 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4074 EL_INTERNAL_CASCADE_CE_ACTIVE,
4075 EL_INTERNAL_CASCADE_GE_ACTIVE,
4076 EL_INTERNAL_CASCADE_REF_ACTIVE,
4077 EL_INTERNAL_CASCADE_USER_ACTIVE,
4078 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4083 static int ep_editor_cascade_inactive[] =
4085 EL_INTERNAL_CASCADE_BD,
4086 EL_INTERNAL_CASCADE_EM,
4087 EL_INTERNAL_CASCADE_EMC,
4088 EL_INTERNAL_CASCADE_RND,
4089 EL_INTERNAL_CASCADE_SB,
4090 EL_INTERNAL_CASCADE_SP,
4091 EL_INTERNAL_CASCADE_DC,
4092 EL_INTERNAL_CASCADE_DX,
4093 EL_INTERNAL_CASCADE_CHARS,
4094 EL_INTERNAL_CASCADE_STEEL_CHARS,
4095 EL_INTERNAL_CASCADE_CE,
4096 EL_INTERNAL_CASCADE_GE,
4097 EL_INTERNAL_CASCADE_REF,
4098 EL_INTERNAL_CASCADE_USER,
4099 EL_INTERNAL_CASCADE_DYNAMIC,
4104 static int ep_obsolete[] =
4108 EL_EM_KEY_1_FILE_OBSOLETE,
4109 EL_EM_KEY_2_FILE_OBSOLETE,
4110 EL_EM_KEY_3_FILE_OBSOLETE,
4111 EL_EM_KEY_4_FILE_OBSOLETE,
4112 EL_ENVELOPE_OBSOLETE,
4121 } element_properties[] =
4123 { ep_diggable, EP_DIGGABLE },
4124 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4125 { ep_dont_run_into, EP_DONT_RUN_INTO },
4126 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4127 { ep_dont_touch, EP_DONT_TOUCH },
4128 { ep_indestructible, EP_INDESTRUCTIBLE },
4129 { ep_slippery, EP_SLIPPERY },
4130 { ep_can_change, EP_CAN_CHANGE },
4131 { ep_can_move, EP_CAN_MOVE },
4132 { ep_can_fall, EP_CAN_FALL },
4133 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4134 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4135 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4136 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4137 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4138 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4139 { ep_walkable_over, EP_WALKABLE_OVER },
4140 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4141 { ep_walkable_under, EP_WALKABLE_UNDER },
4142 { ep_passable_over, EP_PASSABLE_OVER },
4143 { ep_passable_inside, EP_PASSABLE_INSIDE },
4144 { ep_passable_under, EP_PASSABLE_UNDER },
4145 { ep_droppable, EP_DROPPABLE },
4146 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4147 { ep_pushable, EP_PUSHABLE },
4148 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4149 { ep_protected, EP_PROTECTED },
4150 { ep_throwable, EP_THROWABLE },
4151 { ep_can_explode, EP_CAN_EXPLODE },
4152 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4154 { ep_player, EP_PLAYER },
4155 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4156 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4157 { ep_switchable, EP_SWITCHABLE },
4158 { ep_bd_element, EP_BD_ELEMENT },
4159 { ep_sp_element, EP_SP_ELEMENT },
4160 { ep_sb_element, EP_SB_ELEMENT },
4162 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4163 { ep_food_penguin, EP_FOOD_PENGUIN },
4164 { ep_food_pig, EP_FOOD_PIG },
4165 { ep_historic_wall, EP_HISTORIC_WALL },
4166 { ep_historic_solid, EP_HISTORIC_SOLID },
4167 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4168 { ep_belt, EP_BELT },
4169 { ep_belt_active, EP_BELT_ACTIVE },
4170 { ep_belt_switch, EP_BELT_SWITCH },
4171 { ep_tube, EP_TUBE },
4172 { ep_acid_pool, EP_ACID_POOL },
4173 { ep_keygate, EP_KEYGATE },
4174 { ep_amoeboid, EP_AMOEBOID },
4175 { ep_amoebalive, EP_AMOEBALIVE },
4176 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4177 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4178 { ep_can_grow, EP_CAN_GROW },
4179 { ep_active_bomb, EP_ACTIVE_BOMB },
4180 { ep_inactive, EP_INACTIVE },
4182 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4184 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4186 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4187 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4189 { ep_obsolete, EP_OBSOLETE },
4196 /* always start with reliable default values (element has no properties) */
4197 /* (but never initialize clipboard elements after the very first time) */
4198 /* (to be able to use clipboard elements between several levels) */
4199 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4200 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4201 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4202 SET_PROPERTY(i, j, FALSE);
4204 /* set all base element properties from above array definitions */
4205 for (i = 0; element_properties[i].elements != NULL; i++)
4206 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4207 SET_PROPERTY((element_properties[i].elements)[j],
4208 element_properties[i].property, TRUE);
4210 /* copy properties to some elements that are only stored in level file */
4211 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4212 for (j = 0; copy_properties[j][0] != -1; j++)
4213 if (HAS_PROPERTY(copy_properties[j][0], i))
4214 for (k = 1; k <= 4; k++)
4215 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4217 /* set static element properties that are not listed in array definitions */
4218 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4219 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4221 clipboard_elements_initialized = TRUE;
4224 void InitElementPropertiesEngine(int engine_version)
4226 static int no_wall_properties[] =
4229 EP_COLLECTIBLE_ONLY,
4231 EP_DONT_COLLIDE_WITH,
4234 EP_CAN_SMASH_PLAYER,
4235 EP_CAN_SMASH_ENEMIES,
4236 EP_CAN_SMASH_EVERYTHING,
4241 EP_FOOD_DARK_YAMYAM,
4257 /* important: after initialization in InitElementPropertiesStatic(), the
4258 elements are not again initialized to a default value; therefore all
4259 changes have to make sure that they leave the element with a defined
4260 property (which means that conditional property changes must be set to
4261 a reliable default value before) */
4263 /* resolve group elements */
4264 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4265 ResolveGroupElement(EL_GROUP_START + i);
4267 /* set all special, combined or engine dependent element properties */
4268 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4270 /* do not change (already initialized) clipboard elements here */
4271 if (IS_CLIPBOARD_ELEMENT(i))
4274 /* ---------- INACTIVE ------------------------------------------------- */
4275 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4276 i <= EL_CHAR_END) ||
4277 (i >= EL_STEEL_CHAR_START &&
4278 i <= EL_STEEL_CHAR_END)));
4280 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4281 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4282 IS_WALKABLE_INSIDE(i) ||
4283 IS_WALKABLE_UNDER(i)));
4285 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4286 IS_PASSABLE_INSIDE(i) ||
4287 IS_PASSABLE_UNDER(i)));
4289 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4290 IS_PASSABLE_OVER(i)));
4292 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4293 IS_PASSABLE_INSIDE(i)));
4295 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4296 IS_PASSABLE_UNDER(i)));
4298 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4301 /* ---------- COLLECTIBLE ---------------------------------------------- */
4302 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4306 /* ---------- SNAPPABLE ------------------------------------------------ */
4307 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4308 IS_COLLECTIBLE(i) ||
4312 /* ---------- WALL ----------------------------------------------------- */
4313 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4315 for (j = 0; no_wall_properties[j] != -1; j++)
4316 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4317 i >= EL_FIRST_RUNTIME_UNREAL)
4318 SET_PROPERTY(i, EP_WALL, FALSE);
4320 if (IS_HISTORIC_WALL(i))
4321 SET_PROPERTY(i, EP_WALL, TRUE);
4323 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4324 if (engine_version < VERSION_IDENT(2,2,0,0))
4325 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4327 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4329 !IS_COLLECTIBLE(i)));
4331 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4332 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4333 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4335 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4336 IS_INDESTRUCTIBLE(i)));
4338 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4340 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4341 else if (engine_version < VERSION_IDENT(2,2,0,0))
4342 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4344 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4348 if (IS_CUSTOM_ELEMENT(i))
4350 /* these are additional properties which are initially false when set */
4352 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4354 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4355 if (DONT_COLLIDE_WITH(i))
4356 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4358 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4359 if (CAN_SMASH_EVERYTHING(i))
4360 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4361 if (CAN_SMASH_ENEMIES(i))
4362 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4365 /* ---------- CAN_SMASH ------------------------------------------------ */
4366 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4367 CAN_SMASH_ENEMIES(i) ||
4368 CAN_SMASH_EVERYTHING(i)));
4370 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4371 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4372 EXPLODES_BY_FIRE(i)));
4374 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4375 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4376 EXPLODES_SMASHED(i)));
4378 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4379 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4380 EXPLODES_IMPACT(i)));
4382 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4383 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4385 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4386 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4387 i == EL_BLACK_ORB));
4389 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4390 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4392 IS_CUSTOM_ELEMENT(i)));
4394 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4395 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4396 i == EL_SP_ELECTRON));
4398 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4399 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4400 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4401 getMoveIntoAcidProperty(&level, i));
4403 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4404 if (MAYBE_DONT_COLLIDE_WITH(i))
4405 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4406 getDontCollideWithProperty(&level, i));
4408 /* ---------- SP_PORT -------------------------------------------------- */
4409 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4410 IS_PASSABLE_INSIDE(i)));
4412 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4413 for (j = 0; j < level.num_android_clone_elements; j++)
4414 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4416 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4418 /* ---------- CAN_CHANGE ----------------------------------------------- */
4419 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4420 for (j = 0; j < element_info[i].num_change_pages; j++)
4421 if (element_info[i].change_page[j].can_change)
4422 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4424 /* ---------- HAS_ACTION ----------------------------------------------- */
4425 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4426 for (j = 0; j < element_info[i].num_change_pages; j++)
4427 if (element_info[i].change_page[j].has_action)
4428 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4430 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4431 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4434 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4435 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4436 element_info[i].crumbled[ACTION_DEFAULT] !=
4437 element_info[i].graphic[ACTION_DEFAULT]);
4439 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4440 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4441 IS_EDITOR_CASCADE_INACTIVE(i)));
4444 /* dynamically adjust element properties according to game engine version */
4446 static int ep_em_slippery_wall[] =
4451 EL_EXPANDABLE_WALL_HORIZONTAL,
4452 EL_EXPANDABLE_WALL_VERTICAL,
4453 EL_EXPANDABLE_WALL_ANY,
4454 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4455 EL_EXPANDABLE_STEELWALL_VERTICAL,
4456 EL_EXPANDABLE_STEELWALL_ANY,
4457 EL_EXPANDABLE_STEELWALL_GROWING,
4461 static int ep_em_explodes_by_fire[] =
4464 EL_EM_DYNAMITE_ACTIVE,
4469 /* special EM style gems behaviour */
4470 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4471 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4472 level.em_slippery_gems);
4474 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4475 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4476 (level.em_slippery_gems &&
4477 engine_version > VERSION_IDENT(2,0,1,0)));
4479 /* special EM style explosion behaviour regarding chain reactions */
4480 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4481 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4482 level.em_explodes_by_fire);
4485 /* this is needed because some graphics depend on element properties */
4486 if (game_status == GAME_MODE_PLAYING)
4487 InitElementGraphicInfo();
4490 void InitElementPropertiesAfterLoading(int engine_version)
4494 /* set some other uninitialized values of custom elements in older levels */
4495 if (engine_version < VERSION_IDENT(3,1,0,0))
4497 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4499 int element = EL_CUSTOM_START + i;
4501 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4503 element_info[element].explosion_delay = 17;
4504 element_info[element].ignition_delay = 8;
4509 void InitElementPropertiesGfxElement()
4513 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4515 struct ElementInfo *ei = &element_info[i];
4517 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4521 static void InitGlobal()
4526 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4528 /* check if element_name_info entry defined for each element in "main.h" */
4529 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4530 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4532 element_info[i].token_name = element_name_info[i].token_name;
4533 element_info[i].class_name = element_name_info[i].class_name;
4534 element_info[i].editor_description= element_name_info[i].editor_description;
4537 /* create hash from image config list */
4538 image_config_hash = newSetupFileHash();
4539 for (i = 0; image_config[i].token != NULL; i++)
4540 setHashEntry(image_config_hash,
4541 image_config[i].token,
4542 image_config[i].value);
4544 /* create hash from element token list */
4545 element_token_hash = newSetupFileHash();
4546 for (i = 0; element_name_info[i].token_name != NULL; i++)
4547 setHashEntry(element_token_hash,
4548 element_name_info[i].token_name,
4551 /* create hash from graphic token list */
4552 graphic_token_hash = newSetupFileHash();
4553 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4554 if (strSuffix(image_config[i].value, ".png") ||
4555 strSuffix(image_config[i].value, ".pcx") ||
4556 strSuffix(image_config[i].value, ".wav") ||
4557 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4558 setHashEntry(graphic_token_hash,
4559 image_config[i].token,
4560 int2str(graphic++, 0));
4562 /* create hash from font token list */
4563 font_token_hash = newSetupFileHash();
4564 for (i = 0; font_info[i].token_name != NULL; i++)
4565 setHashEntry(font_token_hash,
4566 font_info[i].token_name,
4569 /* set default filenames for all cloned graphics in static configuration */
4570 for (i = 0; image_config[i].token != NULL; i++)
4572 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4574 char *token = image_config[i].token;
4575 char *token_clone_from = getStringCat2(token, ".clone_from");
4576 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4578 if (token_cloned != NULL)
4580 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4582 if (value_cloned != NULL)
4584 /* set default filename in static configuration */
4585 image_config[i].value = value_cloned;
4587 /* set default filename in image config hash */
4588 setHashEntry(image_config_hash, token, value_cloned);
4592 free(token_clone_from);
4596 /* always start with reliable default values (all elements) */
4597 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4598 ActiveElement[i] = i;
4600 /* now add all entries that have an active state (active elements) */
4601 for (i = 0; element_with_active_state[i].element != -1; i++)
4603 int element = element_with_active_state[i].element;
4604 int element_active = element_with_active_state[i].element_active;
4606 ActiveElement[element] = element_active;
4609 /* always start with reliable default values (all buttons) */
4610 for (i = 0; i < NUM_IMAGE_FILES; i++)
4611 ActiveButton[i] = i;
4613 /* now add all entries that have an active state (active buttons) */
4614 for (i = 0; button_with_active_state[i].button != -1; i++)
4616 int button = button_with_active_state[i].button;
4617 int button_active = button_with_active_state[i].button_active;
4619 ActiveButton[button] = button_active;
4622 /* always start with reliable default values (all fonts) */
4623 for (i = 0; i < NUM_FONTS; i++)
4626 /* now add all entries that have an active state (active fonts) */
4627 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4629 int font = font_with_active_state[i].font_nr;
4630 int font_active = font_with_active_state[i].font_nr_active;
4632 ActiveFont[font] = font_active;
4635 global.autoplay_leveldir = NULL;
4636 global.convert_leveldir = NULL;
4637 global.create_images_dir = NULL;
4639 global.frames_per_second = 0;
4641 global.border_status = GAME_MODE_MAIN;
4643 global.use_envelope_request = FALSE;
4646 void Execute_Command(char *command)
4650 if (strEqual(command, "print graphicsinfo.conf"))
4652 Print("# You can configure additional/alternative image files here.\n");
4653 Print("# (The entries below are default and therefore commented out.)\n");
4655 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4657 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4660 for (i = 0; image_config[i].token != NULL; i++)
4661 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4662 image_config[i].value));
4666 else if (strEqual(command, "print soundsinfo.conf"))
4668 Print("# You can configure additional/alternative sound files here.\n");
4669 Print("# (The entries below are default and therefore commented out.)\n");
4671 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4673 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4676 for (i = 0; sound_config[i].token != NULL; i++)
4677 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4678 sound_config[i].value));
4682 else if (strEqual(command, "print musicinfo.conf"))
4684 Print("# You can configure additional/alternative music files here.\n");
4685 Print("# (The entries below are default and therefore commented out.)\n");
4687 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4689 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4692 for (i = 0; music_config[i].token != NULL; i++)
4693 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4694 music_config[i].value));
4698 else if (strEqual(command, "print editorsetup.conf"))
4700 Print("# You can configure your personal editor element list here.\n");
4701 Print("# (The entries below are default and therefore commented out.)\n");
4704 /* this is needed to be able to check element list for cascade elements */
4705 InitElementPropertiesStatic();
4706 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4708 PrintEditorElementList();
4712 else if (strEqual(command, "print helpanim.conf"))
4714 Print("# You can configure different element help animations here.\n");
4715 Print("# (The entries below are default and therefore commented out.)\n");
4718 for (i = 0; helpanim_config[i].token != NULL; i++)
4720 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4721 helpanim_config[i].value));
4723 if (strEqual(helpanim_config[i].token, "end"))
4729 else if (strEqual(command, "print helptext.conf"))
4731 Print("# You can configure different element help text here.\n");
4732 Print("# (The entries below are default and therefore commented out.)\n");
4735 for (i = 0; helptext_config[i].token != NULL; i++)
4736 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4737 helptext_config[i].value));
4741 else if (strPrefix(command, "dump level "))
4743 char *filename = &command[11];
4745 if (!fileExists(filename))
4746 Error(ERR_EXIT, "cannot open file '%s'", filename);
4748 LoadLevelFromFilename(&level, filename);
4753 else if (strPrefix(command, "dump tape "))
4755 char *filename = &command[10];
4757 if (!fileExists(filename))
4758 Error(ERR_EXIT, "cannot open file '%s'", filename);
4760 LoadTapeFromFilename(filename);
4765 else if (strPrefix(command, "autotest ") ||
4766 strPrefix(command, "autoplay ") ||
4767 strPrefix(command, "autoffwd "))
4769 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4771 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4772 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4773 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4775 while (*str_ptr != '\0') /* continue parsing string */
4777 /* cut leading whitespace from string, replace it by string terminator */
4778 while (*str_ptr == ' ' || *str_ptr == '\t')
4781 if (*str_ptr == '\0') /* end of string reached */
4784 if (global.autoplay_leveldir == NULL) /* read level set string */
4786 global.autoplay_leveldir = str_ptr;
4787 global.autoplay_all = TRUE; /* default: play all tapes */
4789 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4790 global.autoplay_level[i] = FALSE;
4792 else /* read level number string */
4794 int level_nr = atoi(str_ptr); /* get level_nr value */
4796 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4797 global.autoplay_level[level_nr] = TRUE;
4799 global.autoplay_all = FALSE;
4802 /* advance string pointer to the next whitespace (or end of string) */
4803 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4807 else if (strPrefix(command, "convert "))
4809 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4810 char *str_ptr = strchr(str_copy, ' ');
4812 global.convert_leveldir = str_copy;
4813 global.convert_level_nr = -1;
4815 if (str_ptr != NULL) /* level number follows */
4817 *str_ptr++ = '\0'; /* terminate leveldir string */
4818 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4821 else if (strPrefix(command, "create images "))
4823 global.create_images_dir = getStringCopy(&command[14]);
4825 if (access(global.create_images_dir, W_OK) != 0)
4826 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4827 global.create_images_dir);
4829 else if (strPrefix(command, "create CE image "))
4831 CreateCustomElementImages(&command[16]);
4837 #if defined(TARGET_SDL2)
4838 else if (strEqual(command, "SDL_ListModes"))
4840 SDL_Init(SDL_INIT_VIDEO);
4842 int num_displays = SDL_GetNumVideoDisplays();
4844 // check if there are any displays available
4845 if (num_displays < 0)
4847 Print("No displays available: %s\n", SDL_GetError());
4852 for (i = 0; i < num_displays; i++)
4854 int num_modes = SDL_GetNumDisplayModes(i);
4857 Print("Available display modes for display %d:\n", i);
4859 // check if there are any display modes available for this display
4862 Print("No display modes available for display %d: %s\n",
4868 for (j = 0; j < num_modes; j++)
4870 SDL_DisplayMode mode;
4872 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4874 Print("Cannot get display mode %d for display %d: %s\n",
4875 j, i, SDL_GetError());
4880 Print("- %d x %d\n", mode.w, mode.h);
4886 #elif defined(TARGET_SDL)
4887 else if (strEqual(command, "SDL_ListModes"))
4892 SDL_Init(SDL_INIT_VIDEO);
4894 /* get available fullscreen/hardware modes */
4895 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4897 /* check if there are any modes available */
4900 Print("No modes available!\n");
4905 /* check if our resolution is restricted */
4906 if (modes == (SDL_Rect **)-1)
4908 Print("All resolutions available.\n");
4912 Print("Available display modes:\n");
4914 for (i = 0; modes[i]; i++)
4915 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4925 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4929 static void InitSetup()
4931 LoadSetup(); /* global setup info */
4933 /* set some options from setup file */
4935 if (setup.options.verbose)
4936 options.verbose = TRUE;
4939 static void InitGameInfo()
4941 game.restart_level = FALSE;
4944 static void InitPlayerInfo()
4948 /* choose default local player */
4949 local_player = &stored_player[0];
4951 for (i = 0; i < MAX_PLAYERS; i++)
4952 stored_player[i].connected = FALSE;
4954 local_player->connected = TRUE;
4957 static void InitArtworkInfo()
4962 static char *get_string_in_brackets(char *string)
4964 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4966 sprintf(string_in_brackets, "[%s]", string);
4968 return string_in_brackets;
4971 static char *get_level_id_suffix(int id_nr)
4973 char *id_suffix = checked_malloc(1 + 3 + 1);
4975 if (id_nr < 0 || id_nr > 999)
4978 sprintf(id_suffix, ".%03d", id_nr);
4983 static void InitArtworkConfig()
4985 static char *image_id_prefix[MAX_NUM_ELEMENTS +
4987 NUM_GLOBAL_ANIMS + 1];
4988 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4989 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4990 static char *action_id_suffix[NUM_ACTIONS + 1];
4991 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4992 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4993 static char *level_id_suffix[MAX_LEVELS + 1];
4994 static char *dummy[1] = { NULL };
4995 static char *ignore_generic_tokens[] =
5001 static char **ignore_image_tokens;
5002 static char **ignore_sound_tokens;
5003 static char **ignore_music_tokens;
5004 int num_ignore_generic_tokens;
5005 int num_ignore_image_tokens;
5006 int num_ignore_sound_tokens;
5007 int num_ignore_music_tokens;
5010 /* dynamically determine list of generic tokens to be ignored */
5011 num_ignore_generic_tokens = 0;
5012 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5013 num_ignore_generic_tokens++;
5015 /* dynamically determine list of image tokens to be ignored */
5016 num_ignore_image_tokens = num_ignore_generic_tokens;
5017 for (i = 0; image_config_vars[i].token != NULL; i++)
5018 num_ignore_image_tokens++;
5019 ignore_image_tokens =
5020 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5021 for (i = 0; i < num_ignore_generic_tokens; i++)
5022 ignore_image_tokens[i] = ignore_generic_tokens[i];
5023 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5024 ignore_image_tokens[num_ignore_generic_tokens + i] =
5025 image_config_vars[i].token;
5026 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5028 /* dynamically determine list of sound tokens to be ignored */
5029 num_ignore_sound_tokens = num_ignore_generic_tokens;
5030 ignore_sound_tokens =
5031 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5032 for (i = 0; i < num_ignore_generic_tokens; i++)
5033 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5034 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5036 /* dynamically determine list of music tokens to be ignored */
5037 num_ignore_music_tokens = num_ignore_generic_tokens;
5038 ignore_music_tokens =
5039 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5040 for (i = 0; i < num_ignore_generic_tokens; i++)
5041 ignore_music_tokens[i] = ignore_generic_tokens[i];
5042 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5044 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5045 image_id_prefix[i] = element_info[i].token_name;
5046 for (i = 0; i < NUM_FONTS; i++)
5047 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5048 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
5049 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5050 global_anim_info[i].token_name;
5051 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIMS] = NULL;
5053 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5054 sound_id_prefix[i] = element_info[i].token_name;
5055 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5056 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5057 get_string_in_brackets(element_info[i].class_name);
5058 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5060 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5061 music_id_prefix[i] = music_prefix_info[i].prefix;
5062 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5064 for (i = 0; i < NUM_ACTIONS; i++)
5065 action_id_suffix[i] = element_action_info[i].suffix;
5066 action_id_suffix[NUM_ACTIONS] = NULL;
5068 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5069 direction_id_suffix[i] = element_direction_info[i].suffix;
5070 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5072 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5073 special_id_suffix[i] = special_suffix_info[i].suffix;
5074 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5076 for (i = 0; i < MAX_LEVELS; i++)
5077 level_id_suffix[i] = get_level_id_suffix(i);
5078 level_id_suffix[MAX_LEVELS] = NULL;
5080 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5081 image_id_prefix, action_id_suffix, direction_id_suffix,
5082 special_id_suffix, ignore_image_tokens);
5083 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5084 sound_id_prefix, action_id_suffix, dummy,
5085 special_id_suffix, ignore_sound_tokens);
5086 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5087 music_id_prefix, special_id_suffix, level_id_suffix,
5088 dummy, ignore_music_tokens);
5091 static void InitMixer()
5098 void InitGfxBuffers()
5100 static int win_xsize_last = -1;
5101 static int win_ysize_last = -1;
5103 /* create additional image buffers for double-buffering and cross-fading */
5105 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5107 /* may contain content for cross-fading -- only re-create if changed */
5108 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5109 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5111 win_xsize_last = WIN_XSIZE;
5112 win_ysize_last = WIN_YSIZE;
5115 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5116 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5117 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5118 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5119 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5121 /* initialize screen properties */
5122 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5123 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5125 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5126 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5127 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5128 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5129 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5130 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5132 /* required if door size definitions have changed */
5133 InitGraphicCompatibilityInfo_Doors();
5135 InitGfxBuffers_EM();
5136 InitGfxBuffers_SP();
5141 struct GraphicInfo *graphic_info_last = graphic_info;
5142 char *filename_font_initial = NULL;
5143 char *filename_anim_initial = NULL;
5144 Bitmap *bitmap_font_initial = NULL;
5148 /* determine settings for initial font (for displaying startup messages) */
5149 for (i = 0; image_config[i].token != NULL; i++)
5151 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5153 char font_token[128];
5156 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5157 len_font_token = strlen(font_token);
5159 if (strEqual(image_config[i].token, font_token))
5160 filename_font_initial = image_config[i].value;
5161 else if (strlen(image_config[i].token) > len_font_token &&
5162 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5164 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5165 font_initial[j].src_x = atoi(image_config[i].value);
5166 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5167 font_initial[j].src_y = atoi(image_config[i].value);
5168 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5169 font_initial[j].width = atoi(image_config[i].value);
5170 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5171 font_initial[j].height = atoi(image_config[i].value);
5176 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5178 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5179 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5182 if (filename_font_initial == NULL) /* should not happen */
5183 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5186 InitGfxCustomArtworkInfo();
5187 InitGfxOtherSettings();
5189 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5191 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5192 font_initial[j].bitmap = bitmap_font_initial;
5194 InitFontGraphicInfo();
5196 font_height = getFontHeight(FC_RED);
5198 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5199 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5200 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5203 DrawInitText("Loading graphics", 120, FC_GREEN);
5205 /* initialize settings for busy animation with default values */
5206 int parameter[NUM_GFX_ARGS];
5207 for (i = 0; i < NUM_GFX_ARGS; i++)
5208 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5209 image_config_suffix[i].token,
5210 image_config_suffix[i].type);
5212 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5213 int len_anim_token = strlen(anim_token);
5215 /* read settings for busy animation from default custom artwork config */
5216 char *gfx_config_filename = getPath3(options.graphics_directory,
5218 GRAPHICSINFO_FILENAME);
5220 if (fileExists(gfx_config_filename))
5222 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5224 if (setup_file_hash)
5226 char *filename = getHashEntry(setup_file_hash, anim_token);
5230 filename_anim_initial = getStringCopy(filename);
5232 for (j = 0; image_config_suffix[j].token != NULL; j++)
5234 int type = image_config_suffix[j].type;
5235 char *suffix = image_config_suffix[j].token;
5236 char *token = getStringCat2(anim_token, suffix);
5237 char *value = getHashEntry(setup_file_hash, token);
5239 checked_free(token);
5242 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5246 freeSetupFileHash(setup_file_hash);
5250 if (filename_anim_initial == NULL)
5252 /* read settings for busy animation from static default artwork config */
5253 for (i = 0; image_config[i].token != NULL; i++)
5255 if (strEqual(image_config[i].token, anim_token))
5256 filename_anim_initial = getStringCopy(image_config[i].value);
5257 else if (strlen(image_config[i].token) > len_anim_token &&
5258 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5260 for (j = 0; image_config_suffix[j].token != NULL; j++)
5262 if (strEqual(&image_config[i].token[len_anim_token],
5263 image_config_suffix[j].token))
5265 get_graphic_parameter_value(image_config[i].value,
5266 image_config_suffix[j].token,
5267 image_config_suffix[j].type);
5273 if (filename_anim_initial == NULL) /* should not happen */
5274 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5276 anim_initial.bitmaps =
5277 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5279 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5280 LoadCustomImage(filename_anim_initial);
5282 checked_free(filename_anim_initial);
5284 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5286 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5288 graphic_info = graphic_info_last;
5290 init.busy.width = anim_initial.width;
5291 init.busy.height = anim_initial.height;
5293 InitMenuDesignSettings_Static();
5295 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5296 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5298 /* use copy of busy animation to prevent change while reloading artwork */
5302 void InitGfxBackground()
5304 fieldbuffer = bitmap_db_field;
5305 SetDrawtoField(DRAW_BACKBUFFER);
5307 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5309 redraw_mask = REDRAW_ALL;
5312 static void InitLevelInfo()
5314 LoadLevelInfo(); /* global level info */
5315 LoadLevelSetup_LastSeries(); /* last played series info */
5316 LoadLevelSetup_SeriesInfo(); /* last played level info */
5318 if (global.autoplay_leveldir &&
5319 global.autoplay_mode != AUTOPLAY_TEST)
5321 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5322 global.autoplay_leveldir);
5323 if (leveldir_current == NULL)
5324 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5328 static void InitLevelArtworkInfo()
5330 LoadLevelArtworkInfo();
5333 static void InitImages()
5335 print_timestamp_init("InitImages");
5338 printf("::: leveldir_current->identifier == '%s'\n",
5339 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5340 printf("::: leveldir_current->graphics_path == '%s'\n",
5341 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5342 printf("::: leveldir_current->graphics_set == '%s'\n",
5343 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5344 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5345 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5348 setLevelArtworkDir(artwork.gfx_first);
5351 printf("::: leveldir_current->identifier == '%s'\n",
5352 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5353 printf("::: leveldir_current->graphics_path == '%s'\n",
5354 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5355 printf("::: leveldir_current->graphics_set == '%s'\n",
5356 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5357 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5358 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5362 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5363 leveldir_current->identifier,
5364 artwork.gfx_current_identifier,
5365 artwork.gfx_current->identifier,
5366 leveldir_current->graphics_set,
5367 leveldir_current->graphics_path);
5370 UPDATE_BUSY_STATE();
5372 ReloadCustomImages();
5373 print_timestamp_time("ReloadCustomImages");
5375 UPDATE_BUSY_STATE();
5377 LoadCustomElementDescriptions();
5378 print_timestamp_time("LoadCustomElementDescriptions");
5380 UPDATE_BUSY_STATE();
5382 LoadMenuDesignSettings();
5383 print_timestamp_time("LoadMenuDesignSettings");
5385 UPDATE_BUSY_STATE();
5387 ReinitializeGraphics();
5388 print_timestamp_time("ReinitializeGraphics");
5390 UPDATE_BUSY_STATE();
5392 print_timestamp_done("InitImages");
5395 static void InitSound(char *identifier)
5397 print_timestamp_init("InitSound");
5399 if (identifier == NULL)
5400 identifier = artwork.snd_current->identifier;
5402 /* set artwork path to send it to the sound server process */
5403 setLevelArtworkDir(artwork.snd_first);
5405 InitReloadCustomSounds(identifier);
5406 print_timestamp_time("InitReloadCustomSounds");
5408 ReinitializeSounds();
5409 print_timestamp_time("ReinitializeSounds");
5411 print_timestamp_done("InitSound");
5414 static void InitMusic(char *identifier)
5416 print_timestamp_init("InitMusic");
5418 if (identifier == NULL)
5419 identifier = artwork.mus_current->identifier;
5421 /* set artwork path to send it to the sound server process */
5422 setLevelArtworkDir(artwork.mus_first);
5424 InitReloadCustomMusic(identifier);
5425 print_timestamp_time("InitReloadCustomMusic");
5427 ReinitializeMusic();
5428 print_timestamp_time("ReinitializeMusic");
5430 print_timestamp_done("InitMusic");
5433 void InitNetworkServer()
5435 #if defined(NETWORK_AVALIABLE)
5439 if (!options.network)
5442 #if defined(NETWORK_AVALIABLE)
5443 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5445 if (!ConnectToServer(options.server_host, options.server_port))
5446 Error(ERR_EXIT, "cannot connect to network game server");
5448 SendToServer_PlayerName(setup.player_name);
5449 SendToServer_ProtocolVersion();
5452 SendToServer_NrWanted(nr_wanted);
5456 static boolean CheckArtworkConfigForCustomElements(char *filename)
5458 SetupFileHash *setup_file_hash;
5459 boolean redefined_ce_found = FALSE;
5461 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5463 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5465 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5467 char *token = HASH_ITERATION_TOKEN(itr);
5469 if (strPrefix(token, "custom_"))
5471 redefined_ce_found = TRUE;
5476 END_HASH_ITERATION(setup_file_hash, itr)
5478 freeSetupFileHash(setup_file_hash);
5481 return redefined_ce_found;
5484 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5486 char *filename_base, *filename_local;
5487 boolean redefined_ce_found = FALSE;
5489 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5492 printf("::: leveldir_current->identifier == '%s'\n",
5493 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5494 printf("::: leveldir_current->graphics_path == '%s'\n",
5495 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5496 printf("::: leveldir_current->graphics_set == '%s'\n",
5497 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5498 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5499 leveldir_current == NULL ? "[NULL]" :
5500 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5503 /* first look for special artwork configured in level series config */
5504 filename_base = getCustomArtworkLevelConfigFilename(type);
5507 printf("::: filename_base == '%s'\n", filename_base);
5510 if (fileExists(filename_base))
5511 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5513 filename_local = getCustomArtworkConfigFilename(type);
5516 printf("::: filename_local == '%s'\n", filename_local);
5519 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5520 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5523 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5526 return redefined_ce_found;
5529 static void InitOverrideArtwork()
5531 boolean redefined_ce_found = FALSE;
5533 /* to check if this level set redefines any CEs, do not use overriding */
5534 gfx.override_level_graphics = FALSE;
5535 gfx.override_level_sounds = FALSE;
5536 gfx.override_level_music = FALSE;
5538 /* now check if this level set has definitions for custom elements */
5539 if (setup.override_level_graphics == AUTO ||
5540 setup.override_level_sounds == AUTO ||
5541 setup.override_level_music == AUTO)
5542 redefined_ce_found =
5543 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5544 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5545 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5548 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5551 if (redefined_ce_found)
5553 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5554 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5555 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5556 gfx.override_level_music = (setup.override_level_music == TRUE);
5560 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5561 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5562 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5563 gfx.override_level_music = (setup.override_level_music != FALSE);
5567 printf("::: => %d, %d, %d\n",
5568 gfx.override_level_graphics,
5569 gfx.override_level_sounds,
5570 gfx.override_level_music);
5574 static char *getNewArtworkIdentifier(int type)
5576 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5577 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5578 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5579 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5580 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5581 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5582 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5583 char *leveldir_identifier = leveldir_current->identifier;
5584 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5585 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5586 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5587 char *artwork_current_identifier;
5588 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5590 /* leveldir_current may be invalid (level group, parent link) */
5591 if (!validLevelSeries(leveldir_current))
5594 /* 1st step: determine artwork set to be activated in descending order:
5595 --------------------------------------------------------------------
5596 1. setup artwork (when configured to override everything else)
5597 2. artwork set configured in "levelinfo.conf" of current level set
5598 (artwork in level directory will have priority when loading later)
5599 3. artwork in level directory (stored in artwork sub-directory)
5600 4. setup artwork (currently configured in setup menu) */
5602 if (setup_override_artwork)
5603 artwork_current_identifier = setup_artwork_set;
5604 else if (leveldir_artwork_set != NULL)
5605 artwork_current_identifier = leveldir_artwork_set;
5606 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5607 artwork_current_identifier = leveldir_identifier;
5609 artwork_current_identifier = setup_artwork_set;
5612 /* 2nd step: check if it is really needed to reload artwork set
5613 ------------------------------------------------------------ */
5615 /* ---------- reload if level set and also artwork set has changed ------- */
5616 if (leveldir_current_identifier[type] != leveldir_identifier &&
5617 (last_has_level_artwork_set[type] || has_level_artwork_set))
5618 artwork_new_identifier = artwork_current_identifier;
5620 leveldir_current_identifier[type] = leveldir_identifier;
5621 last_has_level_artwork_set[type] = has_level_artwork_set;
5623 /* ---------- reload if "override artwork" setting has changed ----------- */
5624 if (last_override_level_artwork[type] != setup_override_artwork)
5625 artwork_new_identifier = artwork_current_identifier;
5627 last_override_level_artwork[type] = setup_override_artwork;
5629 /* ---------- reload if current artwork identifier has changed ----------- */
5630 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5631 artwork_current_identifier))
5632 artwork_new_identifier = artwork_current_identifier;
5634 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5636 /* ---------- do not reload directly after starting ---------------------- */
5637 if (!initialized[type])
5638 artwork_new_identifier = NULL;
5640 initialized[type] = TRUE;
5642 return artwork_new_identifier;
5645 void ReloadCustomArtwork(int force_reload)
5647 int last_game_status = game_status; /* save current game status */
5648 char *gfx_new_identifier;
5649 char *snd_new_identifier;
5650 char *mus_new_identifier;
5651 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5652 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5653 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5654 boolean reload_needed;
5656 InitOverrideArtwork();
5658 force_reload_gfx |= AdjustGraphicsForEMC();
5660 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5661 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5662 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5664 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5665 snd_new_identifier != NULL || force_reload_snd ||
5666 mus_new_identifier != NULL || force_reload_mus);
5671 print_timestamp_init("ReloadCustomArtwork");
5673 game_status = GAME_MODE_LOADING;
5675 FadeOut(REDRAW_ALL);
5677 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5678 print_timestamp_time("ClearRectangle");
5682 if (gfx_new_identifier != NULL || force_reload_gfx)
5685 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5686 artwork.gfx_current_identifier,
5688 artwork.gfx_current->identifier,
5689 leveldir_current->graphics_set);
5693 print_timestamp_time("InitImages");
5696 if (snd_new_identifier != NULL || force_reload_snd)
5698 InitSound(snd_new_identifier);
5699 print_timestamp_time("InitSound");
5702 if (mus_new_identifier != NULL || force_reload_mus)
5704 InitMusic(mus_new_identifier);
5705 print_timestamp_time("InitMusic");
5708 game_status = last_game_status; /* restore current game status */
5710 init_last = init; /* switch to new busy animation */
5712 FadeOut(REDRAW_ALL);
5714 RedrawGlobalBorder();
5716 /* force redraw of (open or closed) door graphics */
5717 SetDoorState(DOOR_OPEN_ALL);
5718 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5720 FadeSetEnterScreen();
5721 FadeSkipNextFadeOut();
5723 print_timestamp_done("ReloadCustomArtwork");
5725 LimitScreenUpdates(FALSE);
5728 void KeyboardAutoRepeatOffUnlessAutoplay()
5730 if (global.autoplay_leveldir == NULL)
5731 KeyboardAutoRepeatOff();
5734 void DisplayExitMessage(char *format, va_list ap)
5736 // check if draw buffer and fonts for exit message are already available
5737 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5740 int font_1 = FC_RED;
5741 int font_2 = FC_YELLOW;
5742 int font_3 = FC_BLUE;
5743 int font_width = getFontWidth(font_2);
5744 int font_height = getFontHeight(font_2);
5747 int sxsize = WIN_XSIZE - 2 * sx;
5748 int sysize = WIN_YSIZE - 2 * sy;
5749 int line_length = sxsize / font_width;
5750 int max_lines = sysize / font_height;
5751 int num_lines_printed;
5755 gfx.sxsize = sxsize;
5756 gfx.sysize = sysize;
5760 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5762 DrawTextSCentered(sy, font_1, "Fatal error:");
5763 sy += 3 * font_height;;
5766 DrawTextBufferVA(sx, sy, format, ap, font_2,
5767 line_length, line_length, max_lines,
5768 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5769 sy += (num_lines_printed + 3) * font_height;
5771 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5772 sy += 3 * font_height;
5775 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5776 line_length, line_length, max_lines,
5777 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5779 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5781 redraw_mask = REDRAW_ALL;
5783 /* force drawing exit message even if screen updates are currently limited */
5784 LimitScreenUpdates(FALSE);
5788 /* deactivate toons on error message screen */
5789 setup.toons = FALSE;
5791 WaitForEventToContinue();
5795 /* ========================================================================= */
5797 /* ========================================================================= */
5801 print_timestamp_init("OpenAll");
5803 game_status = GAME_MODE_LOADING;
5807 InitGlobal(); /* initialize some global variables */
5809 print_timestamp_time("[init global stuff]");
5813 print_timestamp_time("[init setup/config stuff (1)]");
5815 if (options.execute_command)
5816 Execute_Command(options.execute_command);
5818 if (options.serveronly)
5820 #if defined(PLATFORM_UNIX)
5821 NetworkServer(options.server_port, options.serveronly);
5823 Error(ERR_WARN, "networking only supported in Unix version");
5826 exit(0); /* never reached, server loops forever */
5830 print_timestamp_time("[init setup/config stuff (2)]");
5832 print_timestamp_time("[init setup/config stuff (3)]");
5833 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5834 print_timestamp_time("[init setup/config stuff (4)]");
5835 InitArtworkConfig(); /* needed before forking sound child process */
5836 print_timestamp_time("[init setup/config stuff (5)]");
5838 print_timestamp_time("[init setup/config stuff (6)]");
5840 InitRND(NEW_RANDOMIZE);
5841 InitSimpleRandom(NEW_RANDOMIZE);
5845 print_timestamp_time("[init setup/config stuff]");
5848 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5850 InitEventFilter(FilterEvents);
5852 print_timestamp_time("[init video stuff]");
5854 InitElementPropertiesStatic();
5855 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5856 InitElementPropertiesGfxElement();
5858 print_timestamp_time("[init element properties stuff]");
5862 print_timestamp_time("InitGfx");
5865 print_timestamp_time("InitLevelInfo");
5867 InitLevelArtworkInfo();
5868 print_timestamp_time("InitLevelArtworkInfo");
5870 InitOverrideArtwork(); /* needs to know current level directory */
5871 print_timestamp_time("InitOverrideArtwork");
5873 InitImages(); /* needs to know current level directory */
5874 print_timestamp_time("InitImages");
5876 InitSound(NULL); /* needs to know current level directory */
5877 print_timestamp_time("InitSound");
5879 InitMusic(NULL); /* needs to know current level directory */
5880 print_timestamp_time("InitMusic");
5882 InitGfxBackground();
5887 if (global.autoplay_leveldir)
5892 else if (global.convert_leveldir)
5897 else if (global.create_images_dir)
5899 CreateLevelSketchImages();
5903 game_status = GAME_MODE_MAIN;
5905 FadeSetEnterScreen();
5906 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5907 FadeSkipNextFadeOut();
5909 print_timestamp_time("[post-artwork]");
5911 print_timestamp_done("OpenAll");
5915 InitNetworkServer();
5918 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5920 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5921 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5922 #if defined(PLATFORM_ANDROID)
5923 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5924 SDL_AndroidGetInternalStoragePath());
5925 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5926 SDL_AndroidGetExternalStoragePath());
5927 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5928 (SDL_AndroidGetExternalStorageState() ==
5929 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5930 SDL_AndroidGetExternalStorageState() ==
5931 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5936 void CloseAllAndExit(int exit_value)
5941 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5948 #if defined(TARGET_SDL)
5949 #if defined(TARGET_SDL2)
5951 // set a flag to tell the network server thread to quit and wait for it
5952 // using SDL_WaitThread()
5954 if (network_server) /* terminate network server */
5955 SDL_KillThread(server_thread);
5959 CloseVideoDisplay();
5960 ClosePlatformDependentStuff();
5962 if (exit_value != 0)
5964 /* fall back to default level set (current set may have caused an error) */
5965 SaveLevelSetup_LastSeries_Deactivate();
5967 /* tell user where to find error log file which may contain more details */
5968 // (error notification now directly displayed on screen inside R'n'D
5969 // NotifyUserAboutErrorFile(); /* currently only works for Windows */