1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
27 #include "conf_e2g.c" /* include auto-generated data structure definitions */
28 #include "conf_esg.c" /* include auto-generated data structure definitions */
29 #include "conf_e2s.c" /* include auto-generated data structure definitions */
30 #include "conf_fnt.c" /* include auto-generated data structure definitions */
31 #include "conf_g2s.c" /* include auto-generated data structure definitions */
32 #include "conf_g2m.c" /* include auto-generated data structure definitions */
33 #include "conf_act.c" /* include auto-generated data structure definitions */
36 #define CONFIG_TOKEN_FONT_INITIAL "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY "global.busy"
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41 static struct GraphicInfo anim_initial;
43 static int copy_properties[][5] =
47 EL_BUG_LEFT, EL_BUG_RIGHT,
48 EL_BUG_UP, EL_BUG_DOWN
52 EL_SPACESHIP_LEFT, EL_SPACESHIP_RIGHT,
53 EL_SPACESHIP_UP, EL_SPACESHIP_DOWN
57 EL_BD_BUTTERFLY_LEFT, EL_BD_BUTTERFLY_RIGHT,
58 EL_BD_BUTTERFLY_UP, EL_BD_BUTTERFLY_DOWN
62 EL_BD_FIREFLY_LEFT, EL_BD_FIREFLY_RIGHT,
63 EL_BD_FIREFLY_UP, EL_BD_FIREFLY_DOWN
67 EL_PACMAN_LEFT, EL_PACMAN_RIGHT,
68 EL_PACMAN_UP, EL_PACMAN_DOWN
72 EL_YAMYAM_LEFT, EL_YAMYAM_RIGHT,
73 EL_YAMYAM_UP, EL_YAMYAM_DOWN
77 EL_MOLE_LEFT, EL_MOLE_RIGHT,
78 EL_MOLE_UP, EL_MOLE_DOWN
89 struct GraphicInfo *graphic_info_last = graphic_info;
91 static unsigned int action_delay = 0;
92 unsigned int action_delay_value = GameFrameDelay;
93 int sync_frame = FrameCounter;
96 if (game_status != GAME_MODE_LOADING)
99 if (anim_initial.bitmap == NULL || window == NULL)
102 if (!DelayReached(&action_delay, action_delay_value))
105 if (init_last.busy.x == -1)
106 init_last.busy.x = WIN_XSIZE / 2;
107 if (init_last.busy.y == -1)
108 init_last.busy.y = WIN_YSIZE / 2;
110 x = ALIGNED_TEXT_XPOS(&init_last.busy);
111 y = ALIGNED_TEXT_YPOS(&init_last.busy);
113 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
115 if (sync_frame % anim_initial.anim_delay == 0)
119 int width = graphic_info[graphic].width;
120 int height = graphic_info[graphic].height;
121 int frame = getGraphicAnimationFrame(graphic, sync_frame);
123 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
124 BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
127 graphic_info = graphic_info_last;
134 FreeLevelEditorGadgets();
143 static boolean gadgets_initialized = FALSE;
145 if (gadgets_initialized)
148 CreateLevelEditorGadgets();
152 CreateScreenGadgets();
154 InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
156 gadgets_initialized = TRUE;
159 inline static void InitElementSmallImagesScaledUp(int graphic)
161 struct GraphicInfo *g = &graphic_info[graphic];
163 // create small and game tile sized bitmaps (and scale up, if needed)
164 CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
167 void InitElementSmallImages()
169 print_timestamp_init("InitElementSmallImages");
171 static int special_graphics[] =
173 IMG_EDITOR_ELEMENT_BORDER,
174 IMG_EDITOR_ELEMENT_BORDER_INPUT,
175 IMG_EDITOR_CASCADE_LIST,
176 IMG_EDITOR_CASCADE_LIST_ACTIVE,
179 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
180 int num_property_mappings = getImageListPropertyMappingSize();
183 print_timestamp_time("getImageListPropertyMapping/Size");
185 print_timestamp_init("InitElementSmallImagesScaledUp (1)");
186 /* initialize normal images from static configuration */
187 for (i = 0; element_to_graphic[i].element > -1; i++)
188 InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
189 print_timestamp_done("InitElementSmallImagesScaledUp (1)");
191 /* initialize special images from static configuration */
192 for (i = 0; element_to_special_graphic[i].element > -1; i++)
193 InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
194 print_timestamp_time("InitElementSmallImagesScaledUp (2)");
196 /* initialize images from dynamic configuration (may be elements or other) */
197 for (i = 0; i < num_property_mappings; i++)
198 InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
199 print_timestamp_time("InitElementSmallImagesScaledUp (3)");
201 /* initialize special images from above list (non-element images) */
202 for (i = 0; special_graphics[i] > -1; i++)
203 InitElementSmallImagesScaledUp(special_graphics[i]);
204 print_timestamp_time("InitElementSmallImagesScaledUp (4)");
206 print_timestamp_done("InitElementSmallImages");
209 void InitScaledImages()
213 /* scale normal images from static configuration, if not already scaled */
214 for (i = 0; i < NUM_IMAGE_FILES; i++)
215 ScaleImage(i, graphic_info[i].scale_up_factor);
218 void InitBitmapPointers()
220 int num_images = getImageListSize();
223 // standard size bitmap may have changed -- update default bitmap pointer
224 for (i = 0; i < num_images; i++)
225 if (graphic_info[i].bitmaps)
226 graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
229 void InitImageTextures()
233 FreeAllImageTextures();
235 for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
236 CreateImageTextures(i);
238 for (i = 0; i < MAX_NUM_TOONS; i++)
239 CreateImageTextures(IMG_TOON_1 + i);
241 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
243 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
245 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
247 int graphic = global_anim_info[i].graphic[j][k];
249 if (graphic == IMG_UNDEFINED)
252 CreateImageTextures(graphic);
259 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
260 void SetBitmaps_EM(Bitmap **em_bitmap)
262 em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
263 em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
268 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
269 void SetBitmaps_SP(Bitmap **sp_bitmap)
271 *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
275 static int getFontBitmapID(int font_nr)
279 /* (special case: do not use special font for GAME_MODE_LOADING) */
280 if (game_status >= GAME_MODE_TITLE_INITIAL &&
281 game_status <= GAME_MODE_PSEUDO_PREVIEW)
282 special = game_status;
283 else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
284 special = GFX_SPECIAL_ARG_MAIN;
287 return font_info[font_nr].special_bitmap_id[special];
292 static int getFontFromToken(char *token)
294 char *value = getHashEntry(font_token_hash, token);
299 /* if font not found, use reliable default value */
300 return FONT_INITIAL_1;
303 void InitFontGraphicInfo()
305 static struct FontBitmapInfo *font_bitmap_info = NULL;
306 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
307 int num_property_mappings = getImageListPropertyMappingSize();
308 int num_font_bitmaps = NUM_FONTS;
311 if (graphic_info == NULL) /* still at startup phase */
313 InitFontInfo(font_initial, NUM_INITIAL_FONTS,
314 getFontBitmapID, getFontFromToken);
319 /* ---------- initialize font graphic definitions ---------- */
321 /* always start with reliable default values (normal font graphics) */
322 for (i = 0; i < NUM_FONTS; i++)
323 font_info[i].graphic = IMG_FONT_INITIAL_1;
325 /* initialize normal font/graphic mapping from static configuration */
326 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
328 int font_nr = font_to_graphic[i].font_nr;
329 int special = font_to_graphic[i].special;
330 int graphic = font_to_graphic[i].graphic;
335 font_info[font_nr].graphic = graphic;
338 /* always start with reliable default values (special font graphics) */
339 for (i = 0; i < NUM_FONTS; i++)
341 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
343 font_info[i].special_graphic[j] = font_info[i].graphic;
344 font_info[i].special_bitmap_id[j] = i;
348 /* initialize special font/graphic mapping from static configuration */
349 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
351 int font_nr = font_to_graphic[i].font_nr;
352 int special = font_to_graphic[i].special;
353 int graphic = font_to_graphic[i].graphic;
354 int base_graphic = font2baseimg(font_nr);
356 if (IS_SPECIAL_GFX_ARG(special))
358 boolean base_redefined =
359 getImageListEntryFromImageID(base_graphic)->redefined;
360 boolean special_redefined =
361 getImageListEntryFromImageID(graphic)->redefined;
362 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
364 /* if the base font ("font.title_1", for example) has been redefined,
365 but not the special font ("font.title_1.LEVELS", for example), do not
366 use an existing (in this case considered obsolete) special font
367 anymore, but use the automatically determined default font */
368 /* special case: cloned special fonts must be explicitly redefined,
369 but are not automatically redefined by redefining base font */
370 if (base_redefined && !special_redefined && !special_cloned)
373 font_info[font_nr].special_graphic[special] = graphic;
374 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
379 /* initialize special font/graphic mapping from dynamic configuration */
380 for (i = 0; i < num_property_mappings; i++)
382 int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
383 int special = property_mapping[i].ext3_index;
384 int graphic = property_mapping[i].artwork_index;
389 if (IS_SPECIAL_GFX_ARG(special))
391 font_info[font_nr].special_graphic[special] = graphic;
392 font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
397 /* correct special font/graphic mapping for cloned fonts for downwards
398 compatibility of PREVIEW fonts -- this is only needed for implicit
399 redefinition of special font by redefined base font, and only if other
400 fonts are cloned from this special font (like in the "Zelda" level set) */
401 for (i = 0; font_to_graphic[i].font_nr > -1; i++)
403 int font_nr = font_to_graphic[i].font_nr;
404 int special = font_to_graphic[i].special;
405 int graphic = font_to_graphic[i].graphic;
407 if (IS_SPECIAL_GFX_ARG(special))
409 boolean special_redefined =
410 getImageListEntryFromImageID(graphic)->redefined;
411 boolean special_cloned = (graphic_info[graphic].clone_from != -1);
413 if (special_cloned && !special_redefined)
417 for (j = 0; font_to_graphic[j].font_nr > -1; j++)
419 int font_nr2 = font_to_graphic[j].font_nr;
420 int special2 = font_to_graphic[j].special;
421 int graphic2 = font_to_graphic[j].graphic;
423 if (IS_SPECIAL_GFX_ARG(special2) &&
424 graphic2 == graphic_info[graphic].clone_from)
426 font_info[font_nr].special_graphic[special] =
427 font_info[font_nr2].special_graphic[special2];
428 font_info[font_nr].special_bitmap_id[special] =
429 font_info[font_nr2].special_bitmap_id[special2];
436 /* reset non-redefined ".active" font graphics if normal font is redefined */
437 /* (this different treatment is needed because normal and active fonts are
438 independently defined ("active" is not a property of font definitions!) */
439 for (i = 0; i < NUM_FONTS; i++)
441 int font_nr_base = i;
442 int font_nr_active = FONT_ACTIVE(font_nr_base);
444 /* check only those fonts with exist as normal and ".active" variant */
445 if (font_nr_base != font_nr_active)
447 int base_graphic = font_info[font_nr_base].graphic;
448 int active_graphic = font_info[font_nr_active].graphic;
449 boolean base_redefined =
450 getImageListEntryFromImageID(base_graphic)->redefined;
451 boolean active_redefined =
452 getImageListEntryFromImageID(active_graphic)->redefined;
454 /* if the base font ("font.menu_1", for example) has been redefined,
455 but not the active font ("font.menu_1.active", for example), do not
456 use an existing (in this case considered obsolete) active font
457 anymore, but use the automatically determined default font */
458 if (base_redefined && !active_redefined)
459 font_info[font_nr_active].graphic = base_graphic;
461 /* now also check each "special" font (which may be the same as above) */
462 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
464 int base_graphic = font_info[font_nr_base].special_graphic[j];
465 int active_graphic = font_info[font_nr_active].special_graphic[j];
466 boolean base_redefined =
467 getImageListEntryFromImageID(base_graphic)->redefined;
468 boolean active_redefined =
469 getImageListEntryFromImageID(active_graphic)->redefined;
471 /* same as above, but check special graphic definitions, for example:
472 redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
473 if (base_redefined && !active_redefined)
475 font_info[font_nr_active].special_graphic[j] =
476 font_info[font_nr_base].special_graphic[j];
477 font_info[font_nr_active].special_bitmap_id[j] =
478 font_info[font_nr_base].special_bitmap_id[j];
484 /* ---------- initialize font bitmap array ---------- */
486 if (font_bitmap_info != NULL)
487 FreeFontInfo(font_bitmap_info);
490 checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
492 /* ---------- initialize font bitmap definitions ---------- */
494 for (i = 0; i < NUM_FONTS; i++)
496 if (i < NUM_INITIAL_FONTS)
498 font_bitmap_info[i] = font_initial[i];
502 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
504 int font_bitmap_id = font_info[i].special_bitmap_id[j];
505 int graphic = font_info[i].special_graphic[j];
507 /* set 'graphic_info' for font entries, if uninitialized (guessed) */
508 if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
510 graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
511 graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
514 /* copy font relevant information from graphics information */
515 font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
516 font_bitmap_info[font_bitmap_id].src_x = graphic_info[graphic].src_x;
517 font_bitmap_info[font_bitmap_id].src_y = graphic_info[graphic].src_y;
518 font_bitmap_info[font_bitmap_id].width = graphic_info[graphic].width;
519 font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
521 font_bitmap_info[font_bitmap_id].draw_xoffset =
522 graphic_info[graphic].draw_xoffset;
523 font_bitmap_info[font_bitmap_id].draw_yoffset =
524 graphic_info[graphic].draw_yoffset;
526 font_bitmap_info[font_bitmap_id].num_chars =
527 graphic_info[graphic].anim_frames;
528 font_bitmap_info[font_bitmap_id].num_chars_per_line =
529 graphic_info[graphic].anim_frames_per_line;
533 InitFontInfo(font_bitmap_info, num_font_bitmaps,
534 getFontBitmapID, getFontFromToken);
537 void InitGlobalAnimGraphicInfo()
539 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
540 int num_property_mappings = getImageListPropertyMappingSize();
543 if (graphic_info == NULL) /* still at startup phase */
546 /* always start with reliable default values (no global animations) */
547 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
548 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
549 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
550 global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
552 /* initialize global animation definitions from static configuration */
553 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
555 int j = GLOBAL_ANIM_ID_PART_BASE;
556 int k = GFX_SPECIAL_ARG_DEFAULT;
558 global_anim_info[i].graphic[j][k] = IMG_GLOBAL_ANIM_1_GFX + i;
561 /* initialize global animation definitions from dynamic configuration */
562 for (i = 0; i < num_property_mappings; i++)
564 int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
565 int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
566 int special = property_mapping[i].ext3_index;
567 int graphic = property_mapping[i].artwork_index;
569 if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
572 /* set animation part to base part, if not specified */
573 if (!IS_GLOBAL_ANIM_PART(part_nr))
574 part_nr = GLOBAL_ANIM_ID_PART_BASE;
576 /* set animation screen to default, if not specified */
577 if (!IS_SPECIAL_GFX_ARG(special))
578 special = GFX_SPECIAL_ARG_DEFAULT;
580 global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
584 printf("::: InitGlobalAnimGraphicInfo\n");
586 for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
587 for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
588 for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
589 if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
590 graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
591 printf("::: - anim %d, part %d, mode %d => %d\n",
592 i, j, k, global_anim_info[i].graphic[j][k]);
596 void InitElementGraphicInfo()
598 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
599 int num_property_mappings = getImageListPropertyMappingSize();
602 if (graphic_info == NULL) /* still at startup phase */
605 /* set values to -1 to identify later as "uninitialized" values */
606 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
608 for (act = 0; act < NUM_ACTIONS; act++)
610 element_info[i].graphic[act] = -1;
611 element_info[i].crumbled[act] = -1;
613 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
615 element_info[i].direction_graphic[act][dir] = -1;
616 element_info[i].direction_crumbled[act][dir] = -1;
623 /* initialize normal element/graphic mapping from static configuration */
624 for (i = 0; element_to_graphic[i].element > -1; i++)
626 int element = element_to_graphic[i].element;
627 int action = element_to_graphic[i].action;
628 int direction = element_to_graphic[i].direction;
629 boolean crumbled = element_to_graphic[i].crumbled;
630 int graphic = element_to_graphic[i].graphic;
631 int base_graphic = el2baseimg(element);
633 if (graphic_info[graphic].bitmap == NULL)
636 if ((action > -1 || direction > -1 || crumbled == TRUE) &&
639 boolean base_redefined =
640 getImageListEntryFromImageID(base_graphic)->redefined;
641 boolean act_dir_redefined =
642 getImageListEntryFromImageID(graphic)->redefined;
644 /* if the base graphic ("emerald", for example) has been redefined,
645 but not the action graphic ("emerald.falling", for example), do not
646 use an existing (in this case considered obsolete) action graphic
647 anymore, but use the automatically determined default graphic */
648 if (base_redefined && !act_dir_redefined)
653 action = ACTION_DEFAULT;
658 element_info[element].direction_crumbled[action][direction] = graphic;
660 element_info[element].crumbled[action] = graphic;
665 element_info[element].direction_graphic[action][direction] = graphic;
667 element_info[element].graphic[action] = graphic;
671 /* initialize normal element/graphic mapping from dynamic configuration */
672 for (i = 0; i < num_property_mappings; i++)
674 int element = property_mapping[i].base_index;
675 int action = property_mapping[i].ext1_index;
676 int direction = property_mapping[i].ext2_index;
677 int special = property_mapping[i].ext3_index;
678 int graphic = property_mapping[i].artwork_index;
679 boolean crumbled = FALSE;
681 if (special == GFX_SPECIAL_ARG_CRUMBLED)
687 if (graphic_info[graphic].bitmap == NULL)
690 if (element >= MAX_NUM_ELEMENTS || special != -1)
694 action = ACTION_DEFAULT;
699 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
700 element_info[element].direction_crumbled[action][dir] = -1;
703 element_info[element].direction_crumbled[action][direction] = graphic;
705 element_info[element].crumbled[action] = graphic;
710 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
711 element_info[element].direction_graphic[action][dir] = -1;
714 element_info[element].direction_graphic[action][direction] = graphic;
716 element_info[element].graphic[action] = graphic;
720 /* now copy all graphics that are defined to be cloned from other graphics */
721 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
723 int graphic = element_info[i].graphic[ACTION_DEFAULT];
724 int crumbled_like, diggable_like;
729 crumbled_like = graphic_info[graphic].crumbled_like;
730 diggable_like = graphic_info[graphic].diggable_like;
732 if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
734 for (act = 0; act < NUM_ACTIONS; act++)
735 element_info[i].crumbled[act] =
736 element_info[crumbled_like].crumbled[act];
737 for (act = 0; act < NUM_ACTIONS; act++)
738 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
739 element_info[i].direction_crumbled[act][dir] =
740 element_info[crumbled_like].direction_crumbled[act][dir];
743 if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
745 element_info[i].graphic[ACTION_DIGGING] =
746 element_info[diggable_like].graphic[ACTION_DIGGING];
747 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
748 element_info[i].direction_graphic[ACTION_DIGGING][dir] =
749 element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
753 /* set hardcoded definitions for some runtime elements without graphic */
754 element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
756 /* set hardcoded definitions for some internal elements without graphic */
757 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
759 if (IS_EDITOR_CASCADE_INACTIVE(i))
760 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
761 else if (IS_EDITOR_CASCADE_ACTIVE(i))
762 element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
765 /* now set all undefined/invalid graphics to -1 to set to default after it */
766 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
768 for (act = 0; act < NUM_ACTIONS; act++)
772 graphic = element_info[i].graphic[act];
773 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
774 element_info[i].graphic[act] = -1;
776 graphic = element_info[i].crumbled[act];
777 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
778 element_info[i].crumbled[act] = -1;
780 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
782 graphic = element_info[i].direction_graphic[act][dir];
783 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
784 element_info[i].direction_graphic[act][dir] = -1;
786 graphic = element_info[i].direction_crumbled[act][dir];
787 if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
788 element_info[i].direction_crumbled[act][dir] = -1;
795 /* adjust graphics with 2nd tile for movement according to direction
796 (do this before correcting '-1' values to minimize calculations) */
797 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
799 for (act = 0; act < NUM_ACTIONS; act++)
801 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
803 int graphic = element_info[i].direction_graphic[act][dir];
804 int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
806 if (act == ACTION_FALLING) /* special case */
807 graphic = element_info[i].graphic[act];
810 graphic_info[graphic].double_movement &&
811 graphic_info[graphic].swap_double_tiles != 0)
813 struct GraphicInfo *g = &graphic_info[graphic];
814 int src_x_front = g->src_x;
815 int src_y_front = g->src_y;
816 int src_x_back = g->src_x + g->offset2_x;
817 int src_y_back = g->src_y + g->offset2_y;
818 boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
820 boolean front_is_left_or_upper = (src_x_front < src_x_back ||
821 src_y_front < src_y_back);
822 boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
823 boolean swap_movement_tiles_autodetected =
824 (!frames_are_ordered_diagonally &&
825 ((move_dir == MV_BIT_LEFT && !front_is_left_or_upper) ||
826 (move_dir == MV_BIT_UP && !front_is_left_or_upper) ||
827 (move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
828 (move_dir == MV_BIT_DOWN && front_is_left_or_upper)));
831 /* swap frontside and backside graphic tile coordinates, if needed */
832 if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
834 /* get current (wrong) backside tile coordinates */
835 getFixedGraphicSourceExt(graphic, 0, &dummy,
836 &src_x_back, &src_y_back, TRUE);
838 /* set frontside tile coordinates to backside tile coordinates */
839 g->src_x = src_x_back;
840 g->src_y = src_y_back;
842 /* invert tile offset to point to new backside tile coordinates */
846 /* do not swap front and backside tiles again after correction */
847 g->swap_double_tiles = 0;
856 /* now set all '-1' values to element specific default values */
857 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
859 int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
860 int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
861 int default_direction_graphic[NUM_DIRECTIONS_FULL];
862 int default_direction_crumbled[NUM_DIRECTIONS_FULL];
864 if (default_graphic == -1)
865 default_graphic = IMG_UNKNOWN;
867 if (default_crumbled == -1)
868 default_crumbled = default_graphic;
870 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
872 default_direction_graphic[dir] =
873 element_info[i].direction_graphic[ACTION_DEFAULT][dir];
874 default_direction_crumbled[dir] =
875 element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
877 if (default_direction_graphic[dir] == -1)
878 default_direction_graphic[dir] = default_graphic;
880 if (default_direction_crumbled[dir] == -1)
881 default_direction_crumbled[dir] = default_direction_graphic[dir];
884 for (act = 0; act < NUM_ACTIONS; act++)
886 boolean act_remove = ((IS_DIGGABLE(i) && act == ACTION_DIGGING) ||
887 (IS_SNAPPABLE(i) && act == ACTION_SNAPPING) ||
888 (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
889 boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
890 act == ACTION_TURNING_FROM_RIGHT ||
891 act == ACTION_TURNING_FROM_UP ||
892 act == ACTION_TURNING_FROM_DOWN);
894 /* generic default action graphic (defined by "[default]" directive) */
895 int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
896 int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
897 int default_remove_graphic = IMG_EMPTY;
899 if (act_remove && default_action_graphic != -1)
900 default_remove_graphic = default_action_graphic;
902 /* look for special default action graphic (classic game specific) */
903 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
904 default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
905 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
906 default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
907 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
908 default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
910 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
911 default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
912 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
913 default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
914 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
915 default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
917 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
918 /* !!! make this better !!! */
919 if (i == EL_EMPTY_SPACE)
921 default_action_graphic = element_info[EL_DEFAULT].graphic[act];
922 default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
925 if (default_action_graphic == -1)
926 default_action_graphic = default_graphic;
928 if (default_action_crumbled == -1)
929 default_action_crumbled = default_action_graphic;
931 for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
933 /* use action graphic as the default direction graphic, if undefined */
934 int default_action_direction_graphic = element_info[i].graphic[act];
935 int default_action_direction_crumbled = element_info[i].crumbled[act];
937 /* no graphic for current action -- use default direction graphic */
938 if (default_action_direction_graphic == -1)
939 default_action_direction_graphic =
940 (act_remove ? default_remove_graphic :
942 element_info[i].direction_graphic[ACTION_TURNING][dir] :
943 default_action_graphic != default_graphic ?
944 default_action_graphic :
945 default_direction_graphic[dir]);
947 if (element_info[i].direction_graphic[act][dir] == -1)
948 element_info[i].direction_graphic[act][dir] =
949 default_action_direction_graphic;
951 if (default_action_direction_crumbled == -1)
952 default_action_direction_crumbled =
953 element_info[i].direction_graphic[act][dir];
955 if (element_info[i].direction_crumbled[act][dir] == -1)
956 element_info[i].direction_crumbled[act][dir] =
957 default_action_direction_crumbled;
960 /* no graphic for this specific action -- use default action graphic */
961 if (element_info[i].graphic[act] == -1)
962 element_info[i].graphic[act] =
963 (act_remove ? default_remove_graphic :
964 act_turning ? element_info[i].graphic[ACTION_TURNING] :
965 default_action_graphic);
967 if (element_info[i].crumbled[act] == -1)
968 element_info[i].crumbled[act] = element_info[i].graphic[act];
975 void InitElementSpecialGraphicInfo()
977 struct PropertyMapping *property_mapping = getImageListPropertyMapping();
978 int num_property_mappings = getImageListPropertyMappingSize();
981 /* always start with reliable default values */
982 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
983 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
984 element_info[i].special_graphic[j] =
985 element_info[i].graphic[ACTION_DEFAULT];
987 /* initialize special element/graphic mapping from static configuration */
988 for (i = 0; element_to_special_graphic[i].element > -1; i++)
990 int element = element_to_special_graphic[i].element;
991 int special = element_to_special_graphic[i].special;
992 int graphic = element_to_special_graphic[i].graphic;
993 int base_graphic = el2baseimg(element);
994 boolean base_redefined =
995 getImageListEntryFromImageID(base_graphic)->redefined;
996 boolean special_redefined =
997 getImageListEntryFromImageID(graphic)->redefined;
999 /* if the base graphic ("emerald", for example) has been redefined,
1000 but not the special graphic ("emerald.EDITOR", for example), do not
1001 use an existing (in this case considered obsolete) special graphic
1002 anymore, but use the automatically created (down-scaled) graphic */
1003 if (base_redefined && !special_redefined)
1006 element_info[element].special_graphic[special] = graphic;
1009 /* initialize special element/graphic mapping from dynamic configuration */
1010 for (i = 0; i < num_property_mappings; i++)
1012 int element = property_mapping[i].base_index;
1013 int action = property_mapping[i].ext1_index;
1014 int direction = property_mapping[i].ext2_index;
1015 int special = property_mapping[i].ext3_index;
1016 int graphic = property_mapping[i].artwork_index;
1018 /* for action ".active", replace element with active element, if exists */
1019 if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1021 element = ELEMENT_ACTIVE(element);
1025 if (element >= MAX_NUM_ELEMENTS)
1028 /* do not change special graphic if action or direction was specified */
1029 if (action != -1 || direction != -1)
1032 if (IS_SPECIAL_GFX_ARG(special))
1033 element_info[element].special_graphic[special] = graphic;
1036 /* now set all undefined/invalid graphics to default */
1037 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1038 for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1039 if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1040 element_info[i].special_graphic[j] =
1041 element_info[i].graphic[ACTION_DEFAULT];
1044 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1046 if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1047 return get_parameter_value(value_raw, suffix, type);
1049 if (strEqual(value_raw, ARG_UNDEFINED))
1050 return ARG_UNDEFINED_VALUE;
1052 if (type == TYPE_ELEMENT)
1054 char *value = getHashEntry(element_token_hash, value_raw);
1058 Error(ERR_INFO_LINE, "-");
1059 Error(ERR_INFO, "warning: error found in config file:");
1060 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1061 Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1062 Error(ERR_INFO, "custom graphic rejected for this element/action");
1063 Error(ERR_INFO, "fallback done to undefined element for this graphic");
1064 Error(ERR_INFO_LINE, "-");
1067 return (value != NULL ? atoi(value) : EL_UNDEFINED);
1069 else if (type == TYPE_GRAPHIC)
1071 char *value = getHashEntry(graphic_token_hash, value_raw);
1072 int fallback_graphic = IMG_CHAR_EXCLAM;
1076 Error(ERR_INFO_LINE, "-");
1077 Error(ERR_INFO, "warning: error found in config file:");
1078 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1079 Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1080 Error(ERR_INFO, "custom graphic rejected for this element/action");
1081 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1082 Error(ERR_INFO_LINE, "-");
1085 return (value != NULL ? atoi(value) : fallback_graphic);
1091 static int get_scaled_graphic_width(int graphic)
1093 int original_width = getOriginalImageWidthFromImageID(graphic);
1094 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1096 return original_width * scale_up_factor;
1099 static int get_scaled_graphic_height(int graphic)
1101 int original_height = getOriginalImageHeightFromImageID(graphic);
1102 int scale_up_factor = graphic_info[graphic].scale_up_factor;
1104 return original_height * scale_up_factor;
1107 static void set_graphic_parameters_ext(int graphic, int *parameter,
1108 Bitmap **src_bitmaps)
1110 struct GraphicInfo *g = &graphic_info[graphic];
1111 Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1112 int anim_frames_per_row = 1, anim_frames_per_col = 1;
1113 int anim_frames_per_line = 1;
1115 /* always start with reliable default values */
1116 g->src_image_width = 0;
1117 g->src_image_height = 0;
1120 g->width = TILEX; /* default for element graphics */
1121 g->height = TILEY; /* default for element graphics */
1122 g->offset_x = 0; /* one or both of these values ... */
1123 g->offset_y = 0; /* ... will be corrected later */
1124 g->offset2_x = 0; /* one or both of these values ... */
1125 g->offset2_y = 0; /* ... will be corrected later */
1126 g->swap_double_tiles = -1; /* auto-detect tile swapping */
1127 g->crumbled_like = -1; /* do not use clone element */
1128 g->diggable_like = -1; /* do not use clone element */
1129 g->border_size = TILEX / 8; /* "CRUMBLED" border size */
1130 g->scale_up_factor = 1; /* default: no scaling up */
1131 g->tile_size = TILESIZE; /* default: standard tile size */
1132 g->clone_from = -1; /* do not use clone graphic */
1133 g->init_delay_fixed = 0;
1134 g->init_delay_random = 0;
1135 g->anim_delay_fixed = 0;
1136 g->anim_delay_random = 0;
1137 g->post_delay_fixed = 0;
1138 g->post_delay_random = 0;
1140 g->fade_mode = FADE_MODE_DEFAULT;
1144 g->align = ALIGN_CENTER; /* default for title screens */
1145 g->valign = VALIGN_MIDDLE; /* default for title screens */
1146 g->sort_priority = 0; /* default for title screens */
1148 g->style = STYLE_DEFAULT;
1150 g->bitmaps = src_bitmaps;
1151 g->bitmap = src_bitmap;
1153 /* optional zoom factor for scaling up the image to a larger size */
1154 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1155 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1156 if (g->scale_up_factor < 1)
1157 g->scale_up_factor = 1; /* no scaling */
1159 /* optional tile size for using non-standard image size */
1160 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1162 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1165 // CHECK: should tile sizes less than standard tile size be allowed?
1166 if (g->tile_size < TILESIZE)
1167 g->tile_size = TILESIZE; /* standard tile size */
1170 // when setting tile size, also set width and height accordingly
1171 g->width = g->tile_size;
1172 g->height = g->tile_size;
1175 if (g->use_image_size)
1177 /* set new default bitmap size (with scaling, but without small images) */
1178 g->width = get_scaled_graphic_width(graphic);
1179 g->height = get_scaled_graphic_height(graphic);
1182 /* optional width and height of each animation frame */
1183 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1184 g->width = parameter[GFX_ARG_WIDTH];
1185 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1186 g->height = parameter[GFX_ARG_HEIGHT];
1188 /* optional x and y tile position of animation frame sequence */
1189 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1190 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1191 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1192 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1194 /* optional x and y pixel position of animation frame sequence */
1195 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1196 g->src_x = parameter[GFX_ARG_X];
1197 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1198 g->src_y = parameter[GFX_ARG_Y];
1204 Error(ERR_INFO_LINE, "-");
1205 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1206 g->width, getTokenFromImageID(graphic), TILEX);
1207 Error(ERR_INFO_LINE, "-");
1209 g->width = TILEX; /* will be checked to be inside bitmap later */
1214 Error(ERR_INFO_LINE, "-");
1215 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1216 g->height, getTokenFromImageID(graphic), TILEY);
1217 Error(ERR_INFO_LINE, "-");
1219 g->height = TILEY; /* will be checked to be inside bitmap later */
1225 /* get final bitmap size (with scaling, but without small images) */
1226 int src_image_width = get_scaled_graphic_width(graphic);
1227 int src_image_height = get_scaled_graphic_height(graphic);
1229 if (src_image_width == 0 || src_image_height == 0)
1231 /* only happens when loaded outside artwork system (like "global.busy") */
1232 src_image_width = src_bitmap->width;
1233 src_image_height = src_bitmap->height;
1236 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1238 anim_frames_per_row = src_image_width / g->tile_size;
1239 anim_frames_per_col = src_image_height / g->tile_size;
1243 anim_frames_per_row = src_image_width / g->width;
1244 anim_frames_per_col = src_image_height / g->height;
1247 g->src_image_width = src_image_width;
1248 g->src_image_height = src_image_height;
1251 /* correct x or y offset dependent of vertical or horizontal frame order */
1252 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1254 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1255 parameter[GFX_ARG_OFFSET] : g->height);
1256 anim_frames_per_line = anim_frames_per_col;
1258 else /* frames are ordered horizontally */
1260 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1261 parameter[GFX_ARG_OFFSET] : g->width);
1262 anim_frames_per_line = anim_frames_per_row;
1265 /* optionally, the x and y offset of frames can be specified directly */
1266 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1267 g->offset_x = parameter[GFX_ARG_XOFFSET];
1268 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1269 g->offset_y = parameter[GFX_ARG_YOFFSET];
1271 /* optionally, moving animations may have separate start and end graphics */
1272 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1274 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1275 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1277 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1278 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1279 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1280 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1281 else /* frames are ordered horizontally */
1282 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1283 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1285 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1286 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1287 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1288 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1289 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1291 /* optionally, the second movement tile can be specified as start tile */
1292 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1293 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1295 /* automatically determine correct number of frames, if not defined */
1296 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1297 g->anim_frames = parameter[GFX_ARG_FRAMES];
1298 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1299 g->anim_frames = anim_frames_per_row;
1300 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1301 g->anim_frames = anim_frames_per_col;
1305 if (g->anim_frames == 0) /* frames must be at least 1 */
1308 g->anim_frames_per_line =
1309 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1310 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1312 g->anim_delay = parameter[GFX_ARG_DELAY];
1313 if (g->anim_delay == 0) /* delay must be at least 1 */
1316 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1318 /* automatically determine correct start frame, if not defined */
1319 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1320 g->anim_start_frame = 0;
1321 else if (g->anim_mode & ANIM_REVERSE)
1322 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1324 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1326 /* animation synchronized with global frame counter, not move position */
1327 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1329 /* optional element for cloning crumble graphics */
1330 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1331 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1333 /* optional element for cloning digging graphics */
1334 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1335 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1337 /* optional border size for "crumbling" diggable graphics */
1338 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1339 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1341 /* used for global animations and player "boring" and "sleeping" actions */
1342 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1343 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1344 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1345 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1346 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1347 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1348 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1349 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1350 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1351 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1352 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1353 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1355 /* used for toon animations and global animations */
1356 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1357 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1358 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1359 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1360 g->direction = parameter[GFX_ARG_DIRECTION];
1361 g->position = parameter[GFX_ARG_POSITION];
1362 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1363 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1365 /* this is only used for drawing font characters */
1366 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1367 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1369 /* this is only used for drawing envelope graphics */
1370 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1372 /* used for toon animations and global animations */
1373 if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1374 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1376 /* optional graphic for cloning all graphics settings */
1377 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1378 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1380 /* optional settings for drawing title screens and title messages */
1381 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1382 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1383 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1384 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1385 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1386 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1387 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1388 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1389 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1390 g->align = parameter[GFX_ARG_ALIGN];
1391 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1392 g->valign = parameter[GFX_ARG_VALIGN];
1393 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1394 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1396 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1397 g->class = parameter[GFX_ARG_CLASS];
1398 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1399 g->style = parameter[GFX_ARG_STYLE];
1401 /* this is only used for drawing menu buttons and text */
1402 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1403 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1404 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1405 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1408 static void set_graphic_parameters(int graphic)
1410 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1411 char **parameter_raw = image->parameter;
1412 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1413 int parameter[NUM_GFX_ARGS];
1416 /* if fallback to default artwork is done, also use the default parameters */
1417 if (image->fallback_to_default)
1418 parameter_raw = image->default_parameter;
1420 /* get integer values from string parameters */
1421 for (i = 0; i < NUM_GFX_ARGS; i++)
1422 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1423 image_config_suffix[i].token,
1424 image_config_suffix[i].type);
1426 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1428 UPDATE_BUSY_STATE();
1431 static void set_cloned_graphic_parameters(int graphic)
1433 int fallback_graphic = IMG_CHAR_EXCLAM;
1434 int max_num_images = getImageListSize();
1435 int clone_graphic = graphic_info[graphic].clone_from;
1436 int num_references_followed = 1;
1438 while (graphic_info[clone_graphic].clone_from != -1 &&
1439 num_references_followed < max_num_images)
1441 clone_graphic = graphic_info[clone_graphic].clone_from;
1443 num_references_followed++;
1446 if (num_references_followed >= max_num_images)
1448 Error(ERR_INFO_LINE, "-");
1449 Error(ERR_INFO, "warning: error found in config file:");
1450 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1451 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1452 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1453 Error(ERR_INFO, "custom graphic rejected for this element/action");
1455 if (graphic == fallback_graphic)
1456 Error(ERR_EXIT, "no fallback graphic available");
1458 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1459 Error(ERR_INFO_LINE, "-");
1461 graphic_info[graphic] = graphic_info[fallback_graphic];
1465 graphic_info[graphic] = graphic_info[clone_graphic];
1466 graphic_info[graphic].clone_from = clone_graphic;
1470 static void InitGraphicInfo()
1472 int fallback_graphic = IMG_CHAR_EXCLAM;
1473 int num_images = getImageListSize();
1476 /* use image size as default values for width and height for these images */
1477 static int full_size_graphics[] =
1480 IMG_GLOBAL_BORDER_MAIN,
1481 IMG_GLOBAL_BORDER_SCORES,
1482 IMG_GLOBAL_BORDER_EDITOR,
1483 IMG_GLOBAL_BORDER_PLAYING,
1486 IMG_BACKGROUND_ENVELOPE_1,
1487 IMG_BACKGROUND_ENVELOPE_2,
1488 IMG_BACKGROUND_ENVELOPE_3,
1489 IMG_BACKGROUND_ENVELOPE_4,
1490 IMG_BACKGROUND_REQUEST,
1493 IMG_BACKGROUND_TITLE_INITIAL,
1494 IMG_BACKGROUND_TITLE,
1495 IMG_BACKGROUND_MAIN,
1496 IMG_BACKGROUND_LEVELS,
1497 IMG_BACKGROUND_LEVELNR,
1498 IMG_BACKGROUND_SCORES,
1499 IMG_BACKGROUND_EDITOR,
1500 IMG_BACKGROUND_INFO,
1501 IMG_BACKGROUND_INFO_ELEMENTS,
1502 IMG_BACKGROUND_INFO_MUSIC,
1503 IMG_BACKGROUND_INFO_CREDITS,
1504 IMG_BACKGROUND_INFO_PROGRAM,
1505 IMG_BACKGROUND_INFO_VERSION,
1506 IMG_BACKGROUND_INFO_LEVELSET,
1507 IMG_BACKGROUND_SETUP,
1508 IMG_BACKGROUND_PLAYING,
1509 IMG_BACKGROUND_DOOR,
1510 IMG_BACKGROUND_TAPE,
1511 IMG_BACKGROUND_PANEL,
1512 IMG_BACKGROUND_PALETTE,
1513 IMG_BACKGROUND_TOOLBOX,
1515 IMG_TITLESCREEN_INITIAL_1,
1516 IMG_TITLESCREEN_INITIAL_2,
1517 IMG_TITLESCREEN_INITIAL_3,
1518 IMG_TITLESCREEN_INITIAL_4,
1519 IMG_TITLESCREEN_INITIAL_5,
1526 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1527 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1528 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1529 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1530 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1531 IMG_BACKGROUND_TITLEMESSAGE_1,
1532 IMG_BACKGROUND_TITLEMESSAGE_2,
1533 IMG_BACKGROUND_TITLEMESSAGE_3,
1534 IMG_BACKGROUND_TITLEMESSAGE_4,
1535 IMG_BACKGROUND_TITLEMESSAGE_5,
1540 checked_free(graphic_info);
1542 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1544 /* initialize "use_image_size" flag with default value */
1545 for (i = 0; i < num_images; i++)
1546 graphic_info[i].use_image_size = FALSE;
1548 /* initialize "use_image_size" flag from static configuration above */
1549 for (i = 0; full_size_graphics[i] != -1; i++)
1550 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1552 /* first set all graphic paramaters ... */
1553 for (i = 0; i < num_images; i++)
1554 set_graphic_parameters(i);
1556 /* ... then copy these parameters for cloned graphics */
1557 for (i = 0; i < num_images; i++)
1558 if (graphic_info[i].clone_from != -1)
1559 set_cloned_graphic_parameters(i);
1561 for (i = 0; i < num_images; i++)
1566 int first_frame, last_frame;
1567 int src_bitmap_width, src_bitmap_height;
1569 /* now check if no animation frames are outside of the loaded image */
1571 if (graphic_info[i].bitmap == NULL)
1572 continue; /* skip check for optional images that are undefined */
1574 /* get image size (this can differ from the standard element tile size!) */
1575 width = graphic_info[i].width;
1576 height = graphic_info[i].height;
1578 /* get final bitmap size (with scaling, but without small images) */
1579 src_bitmap_width = graphic_info[i].src_image_width;
1580 src_bitmap_height = graphic_info[i].src_image_height;
1582 /* check if first animation frame is inside specified bitmap */
1585 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1587 /* this avoids calculating wrong start position for out-of-bounds frame */
1588 src_x = graphic_info[i].src_x;
1589 src_y = graphic_info[i].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: first animation frame out of bounds (%d, %d) [%d, %d]",
1602 src_x, src_y, src_bitmap_width, src_bitmap_height);
1603 Error(ERR_INFO, "custom graphic rejected for this element/action");
1605 if (i == fallback_graphic)
1606 Error(ERR_EXIT, "no fallback graphic available");
1608 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1609 Error(ERR_INFO_LINE, "-");
1611 graphic_info[i] = graphic_info[fallback_graphic];
1614 /* check if last animation frame is inside specified bitmap */
1616 last_frame = graphic_info[i].anim_frames - 1;
1617 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1619 if (src_x < 0 || src_y < 0 ||
1620 src_x + width > src_bitmap_width ||
1621 src_y + height > src_bitmap_height)
1623 Error(ERR_INFO_LINE, "-");
1624 Error(ERR_INFO, "warning: error found in config file:");
1625 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1626 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1627 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1629 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1630 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1631 Error(ERR_INFO, "::: %d, %d", width, height);
1632 Error(ERR_INFO, "custom graphic rejected for this element/action");
1634 if (i == fallback_graphic)
1635 Error(ERR_EXIT, "no fallback graphic available");
1637 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1638 Error(ERR_INFO_LINE, "-");
1640 graphic_info[i] = graphic_info[fallback_graphic];
1645 static void InitGraphicCompatibilityInfo()
1647 struct FileInfo *fi_global_door =
1648 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1649 int num_images = getImageListSize();
1652 /* the following compatibility handling is needed for the following case:
1653 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1654 graphics mainly used for door and panel graphics, like editor, tape and
1655 in-game buttons with hard-coded bitmap positions and button sizes; as
1656 these graphics now have individual definitions, redefining "global.door"
1657 to change all these graphics at once like before does not work anymore
1658 (because all those individual definitions still have their default values);
1659 to solve this, remap all those individual definitions that are not
1660 redefined to the new bitmap of "global.door" if it was redefined */
1662 /* special compatibility handling if image "global.door" was redefined */
1663 if (fi_global_door->redefined)
1665 for (i = 0; i < num_images; i++)
1667 struct FileInfo *fi = getImageListEntryFromImageID(i);
1669 /* process only those images that still use the default settings */
1672 /* process all images which default to same image as "global.door" */
1673 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1675 // printf("::: special treatment needed for token '%s'\n", fi->token);
1677 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1683 InitGraphicCompatibilityInfo_Doors();
1686 static void InitElementSoundInfo()
1688 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1689 int num_property_mappings = getSoundListPropertyMappingSize();
1692 /* set values to -1 to identify later as "uninitialized" values */
1693 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1694 for (act = 0; act < NUM_ACTIONS; act++)
1695 element_info[i].sound[act] = -1;
1697 /* initialize element/sound mapping from static configuration */
1698 for (i = 0; element_to_sound[i].element > -1; i++)
1700 int element = element_to_sound[i].element;
1701 int action = element_to_sound[i].action;
1702 int sound = element_to_sound[i].sound;
1703 boolean is_class = element_to_sound[i].is_class;
1706 action = ACTION_DEFAULT;
1709 element_info[element].sound[action] = sound;
1711 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1712 if (strEqual(element_info[j].class_name,
1713 element_info[element].class_name))
1714 element_info[j].sound[action] = sound;
1717 /* initialize element class/sound mapping from dynamic configuration */
1718 for (i = 0; i < num_property_mappings; i++)
1720 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1721 int action = property_mapping[i].ext1_index;
1722 int sound = property_mapping[i].artwork_index;
1724 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1728 action = ACTION_DEFAULT;
1730 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1731 if (strEqual(element_info[j].class_name,
1732 element_info[element_class].class_name))
1733 element_info[j].sound[action] = sound;
1736 /* initialize element/sound mapping from dynamic configuration */
1737 for (i = 0; i < num_property_mappings; i++)
1739 int element = property_mapping[i].base_index;
1740 int action = property_mapping[i].ext1_index;
1741 int sound = property_mapping[i].artwork_index;
1743 if (element >= MAX_NUM_ELEMENTS)
1747 action = ACTION_DEFAULT;
1749 element_info[element].sound[action] = sound;
1752 /* now set all '-1' values to element specific default values */
1753 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1755 for (act = 0; act < NUM_ACTIONS; act++)
1757 /* generic default action sound (defined by "[default]" directive) */
1758 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1760 /* look for special default action sound (classic game specific) */
1761 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1762 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1763 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1764 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1765 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1766 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1768 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1769 /* !!! make this better !!! */
1770 if (i == EL_EMPTY_SPACE)
1771 default_action_sound = element_info[EL_DEFAULT].sound[act];
1773 /* no sound for this specific action -- use default action sound */
1774 if (element_info[i].sound[act] == -1)
1775 element_info[i].sound[act] = default_action_sound;
1779 /* copy sound settings to some elements that are only stored in level file
1780 in native R'n'D levels, but are used by game engine in native EM levels */
1781 for (i = 0; copy_properties[i][0] != -1; i++)
1782 for (j = 1; j <= 4; j++)
1783 for (act = 0; act < NUM_ACTIONS; act++)
1784 element_info[copy_properties[i][j]].sound[act] =
1785 element_info[copy_properties[i][0]].sound[act];
1788 static void InitGameModeSoundInfo()
1792 /* set values to -1 to identify later as "uninitialized" values */
1793 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1796 /* initialize gamemode/sound mapping from static configuration */
1797 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1799 int gamemode = gamemode_to_sound[i].gamemode;
1800 int sound = gamemode_to_sound[i].sound;
1803 gamemode = GAME_MODE_DEFAULT;
1805 menu.sound[gamemode] = sound;
1808 /* now set all '-1' values to levelset specific default values */
1809 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1810 if (menu.sound[i] == -1)
1811 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1814 static void set_sound_parameters(int sound, char **parameter_raw)
1816 int parameter[NUM_SND_ARGS];
1819 /* get integer values from string parameters */
1820 for (i = 0; i < NUM_SND_ARGS; i++)
1822 get_parameter_value(parameter_raw[i],
1823 sound_config_suffix[i].token,
1824 sound_config_suffix[i].type);
1826 /* explicit loop mode setting in configuration overrides default value */
1827 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1828 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1830 /* sound volume to change the original volume when loading the sound file */
1831 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1833 /* sound priority to give certain sounds a higher or lower priority */
1834 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1837 static void InitSoundInfo()
1839 int *sound_effect_properties;
1840 int num_sounds = getSoundListSize();
1843 checked_free(sound_info);
1845 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1846 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1848 /* initialize sound effect for all elements to "no sound" */
1849 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1850 for (j = 0; j < NUM_ACTIONS; j++)
1851 element_info[i].sound[j] = SND_UNDEFINED;
1853 for (i = 0; i < num_sounds; i++)
1855 struct FileInfo *sound = getSoundListEntry(i);
1856 int len_effect_text = strlen(sound->token);
1858 sound_effect_properties[i] = ACTION_OTHER;
1859 sound_info[i].loop = FALSE; /* default: play sound only once */
1861 /* determine all loop sounds and identify certain sound classes */
1863 for (j = 0; element_action_info[j].suffix; j++)
1865 int len_action_text = strlen(element_action_info[j].suffix);
1867 if (len_action_text < len_effect_text &&
1868 strEqual(&sound->token[len_effect_text - len_action_text],
1869 element_action_info[j].suffix))
1871 sound_effect_properties[i] = element_action_info[j].value;
1872 sound_info[i].loop = element_action_info[j].is_loop_sound;
1878 /* associate elements and some selected sound actions */
1880 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1882 if (element_info[j].class_name)
1884 int len_class_text = strlen(element_info[j].class_name);
1886 if (len_class_text + 1 < len_effect_text &&
1887 strncmp(sound->token,
1888 element_info[j].class_name, len_class_text) == 0 &&
1889 sound->token[len_class_text] == '.')
1891 int sound_action_value = sound_effect_properties[i];
1893 element_info[j].sound[sound_action_value] = i;
1898 set_sound_parameters(i, sound->parameter);
1901 free(sound_effect_properties);
1904 static void InitGameModeMusicInfo()
1906 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1907 int num_property_mappings = getMusicListPropertyMappingSize();
1908 int default_levelset_music = -1;
1911 /* set values to -1 to identify later as "uninitialized" values */
1912 for (i = 0; i < MAX_LEVELS; i++)
1913 levelset.music[i] = -1;
1914 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1917 /* initialize gamemode/music mapping from static configuration */
1918 for (i = 0; gamemode_to_music[i].music > -1; i++)
1920 int gamemode = gamemode_to_music[i].gamemode;
1921 int music = gamemode_to_music[i].music;
1924 gamemode = GAME_MODE_DEFAULT;
1926 menu.music[gamemode] = music;
1929 /* initialize gamemode/music mapping from dynamic configuration */
1930 for (i = 0; i < num_property_mappings; i++)
1932 int prefix = property_mapping[i].base_index;
1933 int gamemode = property_mapping[i].ext1_index;
1934 int level = property_mapping[i].ext2_index;
1935 int music = property_mapping[i].artwork_index;
1937 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1941 gamemode = GAME_MODE_DEFAULT;
1943 /* level specific music only allowed for in-game music */
1944 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1945 gamemode = GAME_MODE_PLAYING;
1950 default_levelset_music = music;
1953 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1954 levelset.music[level] = music;
1955 if (gamemode != GAME_MODE_PLAYING)
1956 menu.music[gamemode] = music;
1959 /* now set all '-1' values to menu specific default values */
1960 /* (undefined values of "levelset.music[]" might stay at "-1" to
1961 allow dynamic selection of music files from music directory!) */
1962 for (i = 0; i < MAX_LEVELS; i++)
1963 if (levelset.music[i] == -1)
1964 levelset.music[i] = default_levelset_music;
1965 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1966 if (menu.music[i] == -1)
1967 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1970 static void set_music_parameters(int music, char **parameter_raw)
1972 int parameter[NUM_MUS_ARGS];
1975 /* get integer values from string parameters */
1976 for (i = 0; i < NUM_MUS_ARGS; i++)
1978 get_parameter_value(parameter_raw[i],
1979 music_config_suffix[i].token,
1980 music_config_suffix[i].type);
1982 /* explicit loop mode setting in configuration overrides default value */
1983 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1984 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1987 static void InitMusicInfo()
1989 int num_music = getMusicListSize();
1992 checked_free(music_info);
1994 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1996 for (i = 0; i < num_music; i++)
1998 struct FileInfo *music = getMusicListEntry(i);
1999 int len_music_text = strlen(music->token);
2001 music_info[i].loop = TRUE; /* default: play music in loop mode */
2003 /* determine all loop music */
2005 for (j = 0; music_prefix_info[j].prefix; j++)
2007 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2009 if (len_prefix_text < len_music_text &&
2010 strncmp(music->token,
2011 music_prefix_info[j].prefix, len_prefix_text) == 0)
2013 music_info[i].loop = music_prefix_info[j].is_loop_music;
2019 set_music_parameters(i, music->parameter);
2023 static void ReinitializeGraphics()
2025 print_timestamp_init("ReinitializeGraphics");
2027 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2029 InitGraphicInfo(); /* graphic properties mapping */
2030 print_timestamp_time("InitGraphicInfo");
2031 InitElementGraphicInfo(); /* element game graphic mapping */
2032 print_timestamp_time("InitElementGraphicInfo");
2033 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2034 print_timestamp_time("InitElementSpecialGraphicInfo");
2036 InitElementSmallImages(); /* scale elements to all needed sizes */
2037 print_timestamp_time("InitElementSmallImages");
2038 InitScaledImages(); /* scale all other images, if needed */
2039 print_timestamp_time("InitScaledImages");
2040 InitBitmapPointers(); /* set standard size bitmap pointers */
2041 print_timestamp_time("InitBitmapPointers");
2042 InitFontGraphicInfo(); /* initialize text drawing functions */
2043 print_timestamp_time("InitFontGraphicInfo");
2044 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2045 print_timestamp_time("InitGlobalAnimGraphicInfo");
2047 InitImageTextures(); /* create textures for certain images */
2048 print_timestamp_time("InitImageTextures");
2050 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2051 print_timestamp_time("InitGraphicInfo_EM");
2053 InitGraphicCompatibilityInfo();
2054 print_timestamp_time("InitGraphicCompatibilityInfo");
2056 SetMainBackgroundImage(IMG_BACKGROUND);
2057 print_timestamp_time("SetMainBackgroundImage");
2058 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2059 print_timestamp_time("SetDoorBackgroundImage");
2062 print_timestamp_time("InitGadgets");
2064 InitGlobalAnimations();
2065 print_timestamp_time("InitToons");
2067 print_timestamp_time("InitDoors");
2069 print_timestamp_done("ReinitializeGraphics");
2072 static void ReinitializeSounds()
2074 InitSoundInfo(); /* sound properties mapping */
2075 InitElementSoundInfo(); /* element game sound mapping */
2076 InitGameModeSoundInfo(); /* game mode sound mapping */
2078 InitPlayLevelSound(); /* internal game sound settings */
2081 static void ReinitializeMusic()
2083 InitMusicInfo(); /* music properties mapping */
2084 InitGameModeMusicInfo(); /* game mode music mapping */
2087 static int get_special_property_bit(int element, int property_bit_nr)
2089 struct PropertyBitInfo
2095 static struct PropertyBitInfo pb_can_move_into_acid[] =
2097 /* the player may be able fall into acid when gravity is activated */
2102 { EL_SP_MURPHY, 0 },
2103 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2105 /* all elements that can move may be able to also move into acid */
2108 { EL_BUG_RIGHT, 1 },
2111 { EL_SPACESHIP, 2 },
2112 { EL_SPACESHIP_LEFT, 2 },
2113 { EL_SPACESHIP_RIGHT, 2 },
2114 { EL_SPACESHIP_UP, 2 },
2115 { EL_SPACESHIP_DOWN, 2 },
2116 { EL_BD_BUTTERFLY, 3 },
2117 { EL_BD_BUTTERFLY_LEFT, 3 },
2118 { EL_BD_BUTTERFLY_RIGHT, 3 },
2119 { EL_BD_BUTTERFLY_UP, 3 },
2120 { EL_BD_BUTTERFLY_DOWN, 3 },
2121 { EL_BD_FIREFLY, 4 },
2122 { EL_BD_FIREFLY_LEFT, 4 },
2123 { EL_BD_FIREFLY_RIGHT, 4 },
2124 { EL_BD_FIREFLY_UP, 4 },
2125 { EL_BD_FIREFLY_DOWN, 4 },
2127 { EL_YAMYAM_LEFT, 5 },
2128 { EL_YAMYAM_RIGHT, 5 },
2129 { EL_YAMYAM_UP, 5 },
2130 { EL_YAMYAM_DOWN, 5 },
2131 { EL_DARK_YAMYAM, 6 },
2134 { EL_PACMAN_LEFT, 8 },
2135 { EL_PACMAN_RIGHT, 8 },
2136 { EL_PACMAN_UP, 8 },
2137 { EL_PACMAN_DOWN, 8 },
2139 { EL_MOLE_LEFT, 9 },
2140 { EL_MOLE_RIGHT, 9 },
2142 { EL_MOLE_DOWN, 9 },
2146 { EL_SATELLITE, 13 },
2147 { EL_SP_SNIKSNAK, 14 },
2148 { EL_SP_ELECTRON, 15 },
2151 { EL_EMC_ANDROID, 18 },
2156 static struct PropertyBitInfo pb_dont_collide_with[] =
2158 { EL_SP_SNIKSNAK, 0 },
2159 { EL_SP_ELECTRON, 1 },
2167 struct PropertyBitInfo *pb_info;
2170 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2171 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2176 struct PropertyBitInfo *pb_info = NULL;
2179 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2180 if (pb_definition[i].bit_nr == property_bit_nr)
2181 pb_info = pb_definition[i].pb_info;
2183 if (pb_info == NULL)
2186 for (i = 0; pb_info[i].element != -1; i++)
2187 if (pb_info[i].element == element)
2188 return pb_info[i].bit_nr;
2193 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2194 boolean property_value)
2196 int bit_nr = get_special_property_bit(element, property_bit_nr);
2201 *bitfield |= (1 << bit_nr);
2203 *bitfield &= ~(1 << bit_nr);
2207 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2209 int bit_nr = get_special_property_bit(element, property_bit_nr);
2212 return ((*bitfield & (1 << bit_nr)) != 0);
2217 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2219 static int group_nr;
2220 static struct ElementGroupInfo *group;
2221 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2224 if (actual_group == NULL) /* not yet initialized */
2227 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2229 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2230 group_element - EL_GROUP_START + 1);
2232 /* replace element which caused too deep recursion by question mark */
2233 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2238 if (recursion_depth == 0) /* initialization */
2240 group = actual_group;
2241 group_nr = GROUP_NR(group_element);
2243 group->num_elements_resolved = 0;
2244 group->choice_pos = 0;
2246 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2247 element_info[i].in_group[group_nr] = FALSE;
2250 for (i = 0; i < actual_group->num_elements; i++)
2252 int element = actual_group->element[i];
2254 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2257 if (IS_GROUP_ELEMENT(element))
2258 ResolveGroupElementExt(element, recursion_depth + 1);
2261 group->element_resolved[group->num_elements_resolved++] = element;
2262 element_info[element].in_group[group_nr] = TRUE;
2267 void ResolveGroupElement(int group_element)
2269 ResolveGroupElementExt(group_element, 0);
2272 void InitElementPropertiesStatic()
2274 static boolean clipboard_elements_initialized = FALSE;
2276 static int ep_diggable[] =
2281 EL_SP_BUGGY_BASE_ACTIVATING,
2284 EL_INVISIBLE_SAND_ACTIVE,
2287 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2288 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2293 EL_SP_BUGGY_BASE_ACTIVE,
2300 static int ep_collectible_only[] =
2322 EL_DYNABOMB_INCREASE_NUMBER,
2323 EL_DYNABOMB_INCREASE_SIZE,
2324 EL_DYNABOMB_INCREASE_POWER,
2342 /* !!! handle separately !!! */
2343 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2349 static int ep_dont_run_into[] =
2351 /* same elements as in 'ep_dont_touch' */
2357 /* same elements as in 'ep_dont_collide_with' */
2369 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2374 EL_SP_BUGGY_BASE_ACTIVE,
2381 static int ep_dont_collide_with[] =
2383 /* same elements as in 'ep_dont_touch' */
2400 static int ep_dont_touch[] =
2410 static int ep_indestructible[] =
2414 EL_ACID_POOL_TOPLEFT,
2415 EL_ACID_POOL_TOPRIGHT,
2416 EL_ACID_POOL_BOTTOMLEFT,
2417 EL_ACID_POOL_BOTTOM,
2418 EL_ACID_POOL_BOTTOMRIGHT,
2419 EL_SP_HARDWARE_GRAY,
2420 EL_SP_HARDWARE_GREEN,
2421 EL_SP_HARDWARE_BLUE,
2423 EL_SP_HARDWARE_YELLOW,
2424 EL_SP_HARDWARE_BASE_1,
2425 EL_SP_HARDWARE_BASE_2,
2426 EL_SP_HARDWARE_BASE_3,
2427 EL_SP_HARDWARE_BASE_4,
2428 EL_SP_HARDWARE_BASE_5,
2429 EL_SP_HARDWARE_BASE_6,
2430 EL_INVISIBLE_STEELWALL,
2431 EL_INVISIBLE_STEELWALL_ACTIVE,
2432 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2433 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2434 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2435 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2436 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2437 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2438 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2439 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2440 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2441 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2442 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2443 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2445 EL_LIGHT_SWITCH_ACTIVE,
2446 EL_SIGN_EXCLAMATION,
2447 EL_SIGN_RADIOACTIVITY,
2454 EL_SIGN_ENTRY_FORBIDDEN,
2455 EL_SIGN_EMERGENCY_EXIT,
2463 EL_STEEL_EXIT_CLOSED,
2465 EL_STEEL_EXIT_OPENING,
2466 EL_STEEL_EXIT_CLOSING,
2467 EL_EM_STEEL_EXIT_CLOSED,
2468 EL_EM_STEEL_EXIT_OPEN,
2469 EL_EM_STEEL_EXIT_OPENING,
2470 EL_EM_STEEL_EXIT_CLOSING,
2471 EL_DC_STEELWALL_1_LEFT,
2472 EL_DC_STEELWALL_1_RIGHT,
2473 EL_DC_STEELWALL_1_TOP,
2474 EL_DC_STEELWALL_1_BOTTOM,
2475 EL_DC_STEELWALL_1_HORIZONTAL,
2476 EL_DC_STEELWALL_1_VERTICAL,
2477 EL_DC_STEELWALL_1_TOPLEFT,
2478 EL_DC_STEELWALL_1_TOPRIGHT,
2479 EL_DC_STEELWALL_1_BOTTOMLEFT,
2480 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2481 EL_DC_STEELWALL_1_TOPLEFT_2,
2482 EL_DC_STEELWALL_1_TOPRIGHT_2,
2483 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2484 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2485 EL_DC_STEELWALL_2_LEFT,
2486 EL_DC_STEELWALL_2_RIGHT,
2487 EL_DC_STEELWALL_2_TOP,
2488 EL_DC_STEELWALL_2_BOTTOM,
2489 EL_DC_STEELWALL_2_HORIZONTAL,
2490 EL_DC_STEELWALL_2_VERTICAL,
2491 EL_DC_STEELWALL_2_MIDDLE,
2492 EL_DC_STEELWALL_2_SINGLE,
2493 EL_STEELWALL_SLIPPERY,
2507 EL_GATE_1_GRAY_ACTIVE,
2508 EL_GATE_2_GRAY_ACTIVE,
2509 EL_GATE_3_GRAY_ACTIVE,
2510 EL_GATE_4_GRAY_ACTIVE,
2519 EL_EM_GATE_1_GRAY_ACTIVE,
2520 EL_EM_GATE_2_GRAY_ACTIVE,
2521 EL_EM_GATE_3_GRAY_ACTIVE,
2522 EL_EM_GATE_4_GRAY_ACTIVE,
2531 EL_EMC_GATE_5_GRAY_ACTIVE,
2532 EL_EMC_GATE_6_GRAY_ACTIVE,
2533 EL_EMC_GATE_7_GRAY_ACTIVE,
2534 EL_EMC_GATE_8_GRAY_ACTIVE,
2536 EL_DC_GATE_WHITE_GRAY,
2537 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2538 EL_DC_GATE_FAKE_GRAY,
2540 EL_SWITCHGATE_OPENING,
2541 EL_SWITCHGATE_CLOSED,
2542 EL_SWITCHGATE_CLOSING,
2543 EL_DC_SWITCHGATE_SWITCH_UP,
2544 EL_DC_SWITCHGATE_SWITCH_DOWN,
2546 EL_TIMEGATE_OPENING,
2548 EL_TIMEGATE_CLOSING,
2549 EL_DC_TIMEGATE_SWITCH,
2550 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2554 EL_TUBE_VERTICAL_LEFT,
2555 EL_TUBE_VERTICAL_RIGHT,
2556 EL_TUBE_HORIZONTAL_UP,
2557 EL_TUBE_HORIZONTAL_DOWN,
2562 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2563 EL_EXPANDABLE_STEELWALL_VERTICAL,
2564 EL_EXPANDABLE_STEELWALL_ANY,
2569 static int ep_slippery[] =
2583 EL_ROBOT_WHEEL_ACTIVE,
2589 EL_ACID_POOL_TOPLEFT,
2590 EL_ACID_POOL_TOPRIGHT,
2600 EL_STEELWALL_SLIPPERY,
2603 EL_EMC_WALL_SLIPPERY_1,
2604 EL_EMC_WALL_SLIPPERY_2,
2605 EL_EMC_WALL_SLIPPERY_3,
2606 EL_EMC_WALL_SLIPPERY_4,
2608 EL_EMC_MAGIC_BALL_ACTIVE,
2613 static int ep_can_change[] =
2618 static int ep_can_move[] =
2620 /* same elements as in 'pb_can_move_into_acid' */
2643 static int ep_can_fall[] =
2657 EL_QUICKSAND_FAST_FULL,
2659 EL_BD_MAGIC_WALL_FULL,
2660 EL_DC_MAGIC_WALL_FULL,
2674 static int ep_can_smash_player[] =
2700 static int ep_can_smash_enemies[] =
2709 static int ep_can_smash_everything[] =
2718 static int ep_explodes_by_fire[] =
2720 /* same elements as in 'ep_explodes_impact' */
2725 /* same elements as in 'ep_explodes_smashed' */
2735 EL_EM_DYNAMITE_ACTIVE,
2736 EL_DYNABOMB_PLAYER_1_ACTIVE,
2737 EL_DYNABOMB_PLAYER_2_ACTIVE,
2738 EL_DYNABOMB_PLAYER_3_ACTIVE,
2739 EL_DYNABOMB_PLAYER_4_ACTIVE,
2740 EL_DYNABOMB_INCREASE_NUMBER,
2741 EL_DYNABOMB_INCREASE_SIZE,
2742 EL_DYNABOMB_INCREASE_POWER,
2743 EL_SP_DISK_RED_ACTIVE,
2757 static int ep_explodes_smashed[] =
2759 /* same elements as in 'ep_explodes_impact' */
2773 static int ep_explodes_impact[] =
2782 static int ep_walkable_over[] =
2786 EL_SOKOBAN_FIELD_EMPTY,
2793 EL_EM_STEEL_EXIT_OPEN,
2794 EL_EM_STEEL_EXIT_OPENING,
2803 EL_GATE_1_GRAY_ACTIVE,
2804 EL_GATE_2_GRAY_ACTIVE,
2805 EL_GATE_3_GRAY_ACTIVE,
2806 EL_GATE_4_GRAY_ACTIVE,
2814 static int ep_walkable_inside[] =
2819 EL_TUBE_VERTICAL_LEFT,
2820 EL_TUBE_VERTICAL_RIGHT,
2821 EL_TUBE_HORIZONTAL_UP,
2822 EL_TUBE_HORIZONTAL_DOWN,
2831 static int ep_walkable_under[] =
2836 static int ep_passable_over[] =
2846 EL_EM_GATE_1_GRAY_ACTIVE,
2847 EL_EM_GATE_2_GRAY_ACTIVE,
2848 EL_EM_GATE_3_GRAY_ACTIVE,
2849 EL_EM_GATE_4_GRAY_ACTIVE,
2858 EL_EMC_GATE_5_GRAY_ACTIVE,
2859 EL_EMC_GATE_6_GRAY_ACTIVE,
2860 EL_EMC_GATE_7_GRAY_ACTIVE,
2861 EL_EMC_GATE_8_GRAY_ACTIVE,
2863 EL_DC_GATE_WHITE_GRAY,
2864 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2871 static int ep_passable_inside[] =
2877 EL_SP_PORT_HORIZONTAL,
2878 EL_SP_PORT_VERTICAL,
2880 EL_SP_GRAVITY_PORT_LEFT,
2881 EL_SP_GRAVITY_PORT_RIGHT,
2882 EL_SP_GRAVITY_PORT_UP,
2883 EL_SP_GRAVITY_PORT_DOWN,
2884 EL_SP_GRAVITY_ON_PORT_LEFT,
2885 EL_SP_GRAVITY_ON_PORT_RIGHT,
2886 EL_SP_GRAVITY_ON_PORT_UP,
2887 EL_SP_GRAVITY_ON_PORT_DOWN,
2888 EL_SP_GRAVITY_OFF_PORT_LEFT,
2889 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2890 EL_SP_GRAVITY_OFF_PORT_UP,
2891 EL_SP_GRAVITY_OFF_PORT_DOWN,
2896 static int ep_passable_under[] =
2901 static int ep_droppable[] =
2906 static int ep_explodes_1x1_old[] =
2911 static int ep_pushable[] =
2923 EL_SOKOBAN_FIELD_FULL,
2932 static int ep_explodes_cross_old[] =
2937 static int ep_protected[] =
2939 /* same elements as in 'ep_walkable_inside' */
2943 EL_TUBE_VERTICAL_LEFT,
2944 EL_TUBE_VERTICAL_RIGHT,
2945 EL_TUBE_HORIZONTAL_UP,
2946 EL_TUBE_HORIZONTAL_DOWN,
2952 /* same elements as in 'ep_passable_over' */
2961 EL_EM_GATE_1_GRAY_ACTIVE,
2962 EL_EM_GATE_2_GRAY_ACTIVE,
2963 EL_EM_GATE_3_GRAY_ACTIVE,
2964 EL_EM_GATE_4_GRAY_ACTIVE,
2973 EL_EMC_GATE_5_GRAY_ACTIVE,
2974 EL_EMC_GATE_6_GRAY_ACTIVE,
2975 EL_EMC_GATE_7_GRAY_ACTIVE,
2976 EL_EMC_GATE_8_GRAY_ACTIVE,
2978 EL_DC_GATE_WHITE_GRAY,
2979 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2983 /* same elements as in 'ep_passable_inside' */
2988 EL_SP_PORT_HORIZONTAL,
2989 EL_SP_PORT_VERTICAL,
2991 EL_SP_GRAVITY_PORT_LEFT,
2992 EL_SP_GRAVITY_PORT_RIGHT,
2993 EL_SP_GRAVITY_PORT_UP,
2994 EL_SP_GRAVITY_PORT_DOWN,
2995 EL_SP_GRAVITY_ON_PORT_LEFT,
2996 EL_SP_GRAVITY_ON_PORT_RIGHT,
2997 EL_SP_GRAVITY_ON_PORT_UP,
2998 EL_SP_GRAVITY_ON_PORT_DOWN,
2999 EL_SP_GRAVITY_OFF_PORT_LEFT,
3000 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3001 EL_SP_GRAVITY_OFF_PORT_UP,
3002 EL_SP_GRAVITY_OFF_PORT_DOWN,
3007 static int ep_throwable[] =
3012 static int ep_can_explode[] =
3014 /* same elements as in 'ep_explodes_impact' */
3019 /* same elements as in 'ep_explodes_smashed' */
3025 /* elements that can explode by explosion or by dragonfire */
3029 EL_EM_DYNAMITE_ACTIVE,
3030 EL_DYNABOMB_PLAYER_1_ACTIVE,
3031 EL_DYNABOMB_PLAYER_2_ACTIVE,
3032 EL_DYNABOMB_PLAYER_3_ACTIVE,
3033 EL_DYNABOMB_PLAYER_4_ACTIVE,
3034 EL_DYNABOMB_INCREASE_NUMBER,
3035 EL_DYNABOMB_INCREASE_SIZE,
3036 EL_DYNABOMB_INCREASE_POWER,
3037 EL_SP_DISK_RED_ACTIVE,
3045 /* elements that can explode only by explosion */
3051 static int ep_gravity_reachable[] =
3057 EL_INVISIBLE_SAND_ACTIVE,
3062 EL_SP_PORT_HORIZONTAL,
3063 EL_SP_PORT_VERTICAL,
3065 EL_SP_GRAVITY_PORT_LEFT,
3066 EL_SP_GRAVITY_PORT_RIGHT,
3067 EL_SP_GRAVITY_PORT_UP,
3068 EL_SP_GRAVITY_PORT_DOWN,
3069 EL_SP_GRAVITY_ON_PORT_LEFT,
3070 EL_SP_GRAVITY_ON_PORT_RIGHT,
3071 EL_SP_GRAVITY_ON_PORT_UP,
3072 EL_SP_GRAVITY_ON_PORT_DOWN,
3073 EL_SP_GRAVITY_OFF_PORT_LEFT,
3074 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3075 EL_SP_GRAVITY_OFF_PORT_UP,
3076 EL_SP_GRAVITY_OFF_PORT_DOWN,
3082 static int ep_player[] =
3089 EL_SOKOBAN_FIELD_PLAYER,
3095 static int ep_can_pass_magic_wall[] =
3109 static int ep_can_pass_dc_magic_wall[] =
3125 static int ep_switchable[] =
3129 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3130 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3131 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3132 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3133 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3134 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3135 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3136 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3137 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3138 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3139 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3140 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3141 EL_SWITCHGATE_SWITCH_UP,
3142 EL_SWITCHGATE_SWITCH_DOWN,
3143 EL_DC_SWITCHGATE_SWITCH_UP,
3144 EL_DC_SWITCHGATE_SWITCH_DOWN,
3146 EL_LIGHT_SWITCH_ACTIVE,
3148 EL_DC_TIMEGATE_SWITCH,
3149 EL_BALLOON_SWITCH_LEFT,
3150 EL_BALLOON_SWITCH_RIGHT,
3151 EL_BALLOON_SWITCH_UP,
3152 EL_BALLOON_SWITCH_DOWN,
3153 EL_BALLOON_SWITCH_ANY,
3154 EL_BALLOON_SWITCH_NONE,
3157 EL_EMC_MAGIC_BALL_SWITCH,
3158 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3163 static int ep_bd_element[] =
3197 static int ep_sp_element[] =
3199 /* should always be valid */
3202 /* standard classic Supaplex elements */
3209 EL_SP_HARDWARE_GRAY,
3217 EL_SP_GRAVITY_PORT_RIGHT,
3218 EL_SP_GRAVITY_PORT_DOWN,
3219 EL_SP_GRAVITY_PORT_LEFT,
3220 EL_SP_GRAVITY_PORT_UP,
3225 EL_SP_PORT_VERTICAL,
3226 EL_SP_PORT_HORIZONTAL,
3232 EL_SP_HARDWARE_BASE_1,
3233 EL_SP_HARDWARE_GREEN,
3234 EL_SP_HARDWARE_BLUE,
3236 EL_SP_HARDWARE_YELLOW,
3237 EL_SP_HARDWARE_BASE_2,
3238 EL_SP_HARDWARE_BASE_3,
3239 EL_SP_HARDWARE_BASE_4,
3240 EL_SP_HARDWARE_BASE_5,
3241 EL_SP_HARDWARE_BASE_6,
3245 /* additional elements that appeared in newer Supaplex levels */
3248 /* additional gravity port elements (not switching, but setting gravity) */
3249 EL_SP_GRAVITY_ON_PORT_LEFT,
3250 EL_SP_GRAVITY_ON_PORT_RIGHT,
3251 EL_SP_GRAVITY_ON_PORT_UP,
3252 EL_SP_GRAVITY_ON_PORT_DOWN,
3253 EL_SP_GRAVITY_OFF_PORT_LEFT,
3254 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3255 EL_SP_GRAVITY_OFF_PORT_UP,
3256 EL_SP_GRAVITY_OFF_PORT_DOWN,
3258 /* more than one Murphy in a level results in an inactive clone */
3261 /* runtime Supaplex elements */
3262 EL_SP_DISK_RED_ACTIVE,
3263 EL_SP_TERMINAL_ACTIVE,
3264 EL_SP_BUGGY_BASE_ACTIVATING,
3265 EL_SP_BUGGY_BASE_ACTIVE,
3272 static int ep_sb_element[] =
3277 EL_SOKOBAN_FIELD_EMPTY,
3278 EL_SOKOBAN_FIELD_FULL,
3279 EL_SOKOBAN_FIELD_PLAYER,
3284 EL_INVISIBLE_STEELWALL,
3289 static int ep_gem[] =
3301 static int ep_food_dark_yamyam[] =
3329 static int ep_food_penguin[] =
3343 static int ep_food_pig[] =
3355 static int ep_historic_wall[] =
3366 EL_GATE_1_GRAY_ACTIVE,
3367 EL_GATE_2_GRAY_ACTIVE,
3368 EL_GATE_3_GRAY_ACTIVE,
3369 EL_GATE_4_GRAY_ACTIVE,
3378 EL_EM_GATE_1_GRAY_ACTIVE,
3379 EL_EM_GATE_2_GRAY_ACTIVE,
3380 EL_EM_GATE_3_GRAY_ACTIVE,
3381 EL_EM_GATE_4_GRAY_ACTIVE,
3388 EL_EXPANDABLE_WALL_HORIZONTAL,
3389 EL_EXPANDABLE_WALL_VERTICAL,
3390 EL_EXPANDABLE_WALL_ANY,
3391 EL_EXPANDABLE_WALL_GROWING,
3392 EL_BD_EXPANDABLE_WALL,
3399 EL_SP_HARDWARE_GRAY,
3400 EL_SP_HARDWARE_GREEN,
3401 EL_SP_HARDWARE_BLUE,
3403 EL_SP_HARDWARE_YELLOW,
3404 EL_SP_HARDWARE_BASE_1,
3405 EL_SP_HARDWARE_BASE_2,
3406 EL_SP_HARDWARE_BASE_3,
3407 EL_SP_HARDWARE_BASE_4,
3408 EL_SP_HARDWARE_BASE_5,
3409 EL_SP_HARDWARE_BASE_6,
3411 EL_SP_TERMINAL_ACTIVE,
3414 EL_INVISIBLE_STEELWALL,
3415 EL_INVISIBLE_STEELWALL_ACTIVE,
3417 EL_INVISIBLE_WALL_ACTIVE,
3418 EL_STEELWALL_SLIPPERY,
3435 static int ep_historic_solid[] =
3439 EL_EXPANDABLE_WALL_HORIZONTAL,
3440 EL_EXPANDABLE_WALL_VERTICAL,
3441 EL_EXPANDABLE_WALL_ANY,
3442 EL_BD_EXPANDABLE_WALL,
3455 EL_QUICKSAND_FILLING,
3456 EL_QUICKSAND_EMPTYING,
3458 EL_MAGIC_WALL_ACTIVE,
3459 EL_MAGIC_WALL_EMPTYING,
3460 EL_MAGIC_WALL_FILLING,
3464 EL_BD_MAGIC_WALL_ACTIVE,
3465 EL_BD_MAGIC_WALL_EMPTYING,
3466 EL_BD_MAGIC_WALL_FULL,
3467 EL_BD_MAGIC_WALL_FILLING,
3468 EL_BD_MAGIC_WALL_DEAD,
3477 EL_SP_TERMINAL_ACTIVE,
3481 EL_INVISIBLE_WALL_ACTIVE,
3482 EL_SWITCHGATE_SWITCH_UP,
3483 EL_SWITCHGATE_SWITCH_DOWN,
3484 EL_DC_SWITCHGATE_SWITCH_UP,
3485 EL_DC_SWITCHGATE_SWITCH_DOWN,
3487 EL_TIMEGATE_SWITCH_ACTIVE,
3488 EL_DC_TIMEGATE_SWITCH,
3489 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3501 /* the following elements are a direct copy of "indestructible" elements,
3502 except "EL_ACID", which is "indestructible", but not "solid"! */
3507 EL_ACID_POOL_TOPLEFT,
3508 EL_ACID_POOL_TOPRIGHT,
3509 EL_ACID_POOL_BOTTOMLEFT,
3510 EL_ACID_POOL_BOTTOM,
3511 EL_ACID_POOL_BOTTOMRIGHT,
3512 EL_SP_HARDWARE_GRAY,
3513 EL_SP_HARDWARE_GREEN,
3514 EL_SP_HARDWARE_BLUE,
3516 EL_SP_HARDWARE_YELLOW,
3517 EL_SP_HARDWARE_BASE_1,
3518 EL_SP_HARDWARE_BASE_2,
3519 EL_SP_HARDWARE_BASE_3,
3520 EL_SP_HARDWARE_BASE_4,
3521 EL_SP_HARDWARE_BASE_5,
3522 EL_SP_HARDWARE_BASE_6,
3523 EL_INVISIBLE_STEELWALL,
3524 EL_INVISIBLE_STEELWALL_ACTIVE,
3525 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3526 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3527 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3528 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3529 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3530 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3531 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3532 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3533 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3534 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3535 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3536 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3538 EL_LIGHT_SWITCH_ACTIVE,
3539 EL_SIGN_EXCLAMATION,
3540 EL_SIGN_RADIOACTIVITY,
3547 EL_SIGN_ENTRY_FORBIDDEN,
3548 EL_SIGN_EMERGENCY_EXIT,
3556 EL_STEEL_EXIT_CLOSED,
3558 EL_DC_STEELWALL_1_LEFT,
3559 EL_DC_STEELWALL_1_RIGHT,
3560 EL_DC_STEELWALL_1_TOP,
3561 EL_DC_STEELWALL_1_BOTTOM,
3562 EL_DC_STEELWALL_1_HORIZONTAL,
3563 EL_DC_STEELWALL_1_VERTICAL,
3564 EL_DC_STEELWALL_1_TOPLEFT,
3565 EL_DC_STEELWALL_1_TOPRIGHT,
3566 EL_DC_STEELWALL_1_BOTTOMLEFT,
3567 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3568 EL_DC_STEELWALL_1_TOPLEFT_2,
3569 EL_DC_STEELWALL_1_TOPRIGHT_2,
3570 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3571 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3572 EL_DC_STEELWALL_2_LEFT,
3573 EL_DC_STEELWALL_2_RIGHT,
3574 EL_DC_STEELWALL_2_TOP,
3575 EL_DC_STEELWALL_2_BOTTOM,
3576 EL_DC_STEELWALL_2_HORIZONTAL,
3577 EL_DC_STEELWALL_2_VERTICAL,
3578 EL_DC_STEELWALL_2_MIDDLE,
3579 EL_DC_STEELWALL_2_SINGLE,
3580 EL_STEELWALL_SLIPPERY,
3594 EL_GATE_1_GRAY_ACTIVE,
3595 EL_GATE_2_GRAY_ACTIVE,
3596 EL_GATE_3_GRAY_ACTIVE,
3597 EL_GATE_4_GRAY_ACTIVE,
3606 EL_EM_GATE_1_GRAY_ACTIVE,
3607 EL_EM_GATE_2_GRAY_ACTIVE,
3608 EL_EM_GATE_3_GRAY_ACTIVE,
3609 EL_EM_GATE_4_GRAY_ACTIVE,
3611 EL_SWITCHGATE_OPENING,
3612 EL_SWITCHGATE_CLOSED,
3613 EL_SWITCHGATE_CLOSING,
3615 EL_TIMEGATE_OPENING,
3617 EL_TIMEGATE_CLOSING,
3621 EL_TUBE_VERTICAL_LEFT,
3622 EL_TUBE_VERTICAL_RIGHT,
3623 EL_TUBE_HORIZONTAL_UP,
3624 EL_TUBE_HORIZONTAL_DOWN,
3633 static int ep_classic_enemy[] =
3650 static int ep_belt[] =
3652 EL_CONVEYOR_BELT_1_LEFT,
3653 EL_CONVEYOR_BELT_1_MIDDLE,
3654 EL_CONVEYOR_BELT_1_RIGHT,
3655 EL_CONVEYOR_BELT_2_LEFT,
3656 EL_CONVEYOR_BELT_2_MIDDLE,
3657 EL_CONVEYOR_BELT_2_RIGHT,
3658 EL_CONVEYOR_BELT_3_LEFT,
3659 EL_CONVEYOR_BELT_3_MIDDLE,
3660 EL_CONVEYOR_BELT_3_RIGHT,
3661 EL_CONVEYOR_BELT_4_LEFT,
3662 EL_CONVEYOR_BELT_4_MIDDLE,
3663 EL_CONVEYOR_BELT_4_RIGHT,
3668 static int ep_belt_active[] =
3670 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3671 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3672 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3673 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3674 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3675 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3676 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3677 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3678 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3679 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3680 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3681 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3686 static int ep_belt_switch[] =
3688 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3689 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3690 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3691 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3692 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3693 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3694 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3695 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3696 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3697 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3698 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3699 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3704 static int ep_tube[] =
3711 EL_TUBE_HORIZONTAL_UP,
3712 EL_TUBE_HORIZONTAL_DOWN,
3714 EL_TUBE_VERTICAL_LEFT,
3715 EL_TUBE_VERTICAL_RIGHT,
3721 static int ep_acid_pool[] =
3723 EL_ACID_POOL_TOPLEFT,
3724 EL_ACID_POOL_TOPRIGHT,
3725 EL_ACID_POOL_BOTTOMLEFT,
3726 EL_ACID_POOL_BOTTOM,
3727 EL_ACID_POOL_BOTTOMRIGHT,
3732 static int ep_keygate[] =
3742 EL_GATE_1_GRAY_ACTIVE,
3743 EL_GATE_2_GRAY_ACTIVE,
3744 EL_GATE_3_GRAY_ACTIVE,
3745 EL_GATE_4_GRAY_ACTIVE,
3754 EL_EM_GATE_1_GRAY_ACTIVE,
3755 EL_EM_GATE_2_GRAY_ACTIVE,
3756 EL_EM_GATE_3_GRAY_ACTIVE,
3757 EL_EM_GATE_4_GRAY_ACTIVE,
3766 EL_EMC_GATE_5_GRAY_ACTIVE,
3767 EL_EMC_GATE_6_GRAY_ACTIVE,
3768 EL_EMC_GATE_7_GRAY_ACTIVE,
3769 EL_EMC_GATE_8_GRAY_ACTIVE,
3771 EL_DC_GATE_WHITE_GRAY,
3772 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3777 static int ep_amoeboid[] =
3789 static int ep_amoebalive[] =
3800 static int ep_has_editor_content[] =
3806 EL_SOKOBAN_FIELD_PLAYER,
3823 static int ep_can_turn_each_move[] =
3825 /* !!! do something with this one !!! */
3829 static int ep_can_grow[] =
3843 static int ep_active_bomb[] =
3846 EL_EM_DYNAMITE_ACTIVE,
3847 EL_DYNABOMB_PLAYER_1_ACTIVE,
3848 EL_DYNABOMB_PLAYER_2_ACTIVE,
3849 EL_DYNABOMB_PLAYER_3_ACTIVE,
3850 EL_DYNABOMB_PLAYER_4_ACTIVE,
3851 EL_SP_DISK_RED_ACTIVE,
3856 static int ep_inactive[] =
3866 EL_QUICKSAND_FAST_EMPTY,
3889 EL_GATE_1_GRAY_ACTIVE,
3890 EL_GATE_2_GRAY_ACTIVE,
3891 EL_GATE_3_GRAY_ACTIVE,
3892 EL_GATE_4_GRAY_ACTIVE,
3901 EL_EM_GATE_1_GRAY_ACTIVE,
3902 EL_EM_GATE_2_GRAY_ACTIVE,
3903 EL_EM_GATE_3_GRAY_ACTIVE,
3904 EL_EM_GATE_4_GRAY_ACTIVE,
3913 EL_EMC_GATE_5_GRAY_ACTIVE,
3914 EL_EMC_GATE_6_GRAY_ACTIVE,
3915 EL_EMC_GATE_7_GRAY_ACTIVE,
3916 EL_EMC_GATE_8_GRAY_ACTIVE,
3918 EL_DC_GATE_WHITE_GRAY,
3919 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3920 EL_DC_GATE_FAKE_GRAY,
3923 EL_INVISIBLE_STEELWALL,
3931 EL_WALL_EMERALD_YELLOW,
3932 EL_DYNABOMB_INCREASE_NUMBER,
3933 EL_DYNABOMB_INCREASE_SIZE,
3934 EL_DYNABOMB_INCREASE_POWER,
3938 EL_SOKOBAN_FIELD_EMPTY,
3939 EL_SOKOBAN_FIELD_FULL,
3940 EL_WALL_EMERALD_RED,
3941 EL_WALL_EMERALD_PURPLE,
3942 EL_ACID_POOL_TOPLEFT,
3943 EL_ACID_POOL_TOPRIGHT,
3944 EL_ACID_POOL_BOTTOMLEFT,
3945 EL_ACID_POOL_BOTTOM,
3946 EL_ACID_POOL_BOTTOMRIGHT,
3950 EL_BD_MAGIC_WALL_DEAD,
3952 EL_DC_MAGIC_WALL_DEAD,
3953 EL_AMOEBA_TO_DIAMOND,
3961 EL_SP_GRAVITY_PORT_RIGHT,
3962 EL_SP_GRAVITY_PORT_DOWN,
3963 EL_SP_GRAVITY_PORT_LEFT,
3964 EL_SP_GRAVITY_PORT_UP,
3965 EL_SP_PORT_HORIZONTAL,
3966 EL_SP_PORT_VERTICAL,
3977 EL_SP_HARDWARE_GRAY,
3978 EL_SP_HARDWARE_GREEN,
3979 EL_SP_HARDWARE_BLUE,
3981 EL_SP_HARDWARE_YELLOW,
3982 EL_SP_HARDWARE_BASE_1,
3983 EL_SP_HARDWARE_BASE_2,
3984 EL_SP_HARDWARE_BASE_3,
3985 EL_SP_HARDWARE_BASE_4,
3986 EL_SP_HARDWARE_BASE_5,
3987 EL_SP_HARDWARE_BASE_6,
3988 EL_SP_GRAVITY_ON_PORT_LEFT,
3989 EL_SP_GRAVITY_ON_PORT_RIGHT,
3990 EL_SP_GRAVITY_ON_PORT_UP,
3991 EL_SP_GRAVITY_ON_PORT_DOWN,
3992 EL_SP_GRAVITY_OFF_PORT_LEFT,
3993 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3994 EL_SP_GRAVITY_OFF_PORT_UP,
3995 EL_SP_GRAVITY_OFF_PORT_DOWN,
3996 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3997 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3998 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3999 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4000 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4001 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4002 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4003 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4004 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4005 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4006 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4007 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4008 EL_SIGN_EXCLAMATION,
4009 EL_SIGN_RADIOACTIVITY,
4016 EL_SIGN_ENTRY_FORBIDDEN,
4017 EL_SIGN_EMERGENCY_EXIT,
4025 EL_DC_STEELWALL_1_LEFT,
4026 EL_DC_STEELWALL_1_RIGHT,
4027 EL_DC_STEELWALL_1_TOP,
4028 EL_DC_STEELWALL_1_BOTTOM,
4029 EL_DC_STEELWALL_1_HORIZONTAL,
4030 EL_DC_STEELWALL_1_VERTICAL,
4031 EL_DC_STEELWALL_1_TOPLEFT,
4032 EL_DC_STEELWALL_1_TOPRIGHT,
4033 EL_DC_STEELWALL_1_BOTTOMLEFT,
4034 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4035 EL_DC_STEELWALL_1_TOPLEFT_2,
4036 EL_DC_STEELWALL_1_TOPRIGHT_2,
4037 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4038 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4039 EL_DC_STEELWALL_2_LEFT,
4040 EL_DC_STEELWALL_2_RIGHT,
4041 EL_DC_STEELWALL_2_TOP,
4042 EL_DC_STEELWALL_2_BOTTOM,
4043 EL_DC_STEELWALL_2_HORIZONTAL,
4044 EL_DC_STEELWALL_2_VERTICAL,
4045 EL_DC_STEELWALL_2_MIDDLE,
4046 EL_DC_STEELWALL_2_SINGLE,
4047 EL_STEELWALL_SLIPPERY,
4052 EL_EMC_WALL_SLIPPERY_1,
4053 EL_EMC_WALL_SLIPPERY_2,
4054 EL_EMC_WALL_SLIPPERY_3,
4055 EL_EMC_WALL_SLIPPERY_4,
4076 static int ep_em_slippery_wall[] =
4081 static int ep_gfx_crumbled[] =
4092 static int ep_editor_cascade_active[] =
4094 EL_INTERNAL_CASCADE_BD_ACTIVE,
4095 EL_INTERNAL_CASCADE_EM_ACTIVE,
4096 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4097 EL_INTERNAL_CASCADE_RND_ACTIVE,
4098 EL_INTERNAL_CASCADE_SB_ACTIVE,
4099 EL_INTERNAL_CASCADE_SP_ACTIVE,
4100 EL_INTERNAL_CASCADE_DC_ACTIVE,
4101 EL_INTERNAL_CASCADE_DX_ACTIVE,
4102 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4103 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4104 EL_INTERNAL_CASCADE_CE_ACTIVE,
4105 EL_INTERNAL_CASCADE_GE_ACTIVE,
4106 EL_INTERNAL_CASCADE_REF_ACTIVE,
4107 EL_INTERNAL_CASCADE_USER_ACTIVE,
4108 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4113 static int ep_editor_cascade_inactive[] =
4115 EL_INTERNAL_CASCADE_BD,
4116 EL_INTERNAL_CASCADE_EM,
4117 EL_INTERNAL_CASCADE_EMC,
4118 EL_INTERNAL_CASCADE_RND,
4119 EL_INTERNAL_CASCADE_SB,
4120 EL_INTERNAL_CASCADE_SP,
4121 EL_INTERNAL_CASCADE_DC,
4122 EL_INTERNAL_CASCADE_DX,
4123 EL_INTERNAL_CASCADE_CHARS,
4124 EL_INTERNAL_CASCADE_STEEL_CHARS,
4125 EL_INTERNAL_CASCADE_CE,
4126 EL_INTERNAL_CASCADE_GE,
4127 EL_INTERNAL_CASCADE_REF,
4128 EL_INTERNAL_CASCADE_USER,
4129 EL_INTERNAL_CASCADE_DYNAMIC,
4134 static int ep_obsolete[] =
4138 EL_EM_KEY_1_FILE_OBSOLETE,
4139 EL_EM_KEY_2_FILE_OBSOLETE,
4140 EL_EM_KEY_3_FILE_OBSOLETE,
4141 EL_EM_KEY_4_FILE_OBSOLETE,
4142 EL_ENVELOPE_OBSOLETE,
4151 } element_properties[] =
4153 { ep_diggable, EP_DIGGABLE },
4154 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4155 { ep_dont_run_into, EP_DONT_RUN_INTO },
4156 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4157 { ep_dont_touch, EP_DONT_TOUCH },
4158 { ep_indestructible, EP_INDESTRUCTIBLE },
4159 { ep_slippery, EP_SLIPPERY },
4160 { ep_can_change, EP_CAN_CHANGE },
4161 { ep_can_move, EP_CAN_MOVE },
4162 { ep_can_fall, EP_CAN_FALL },
4163 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4164 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4165 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4166 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4167 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4168 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4169 { ep_walkable_over, EP_WALKABLE_OVER },
4170 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4171 { ep_walkable_under, EP_WALKABLE_UNDER },
4172 { ep_passable_over, EP_PASSABLE_OVER },
4173 { ep_passable_inside, EP_PASSABLE_INSIDE },
4174 { ep_passable_under, EP_PASSABLE_UNDER },
4175 { ep_droppable, EP_DROPPABLE },
4176 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4177 { ep_pushable, EP_PUSHABLE },
4178 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4179 { ep_protected, EP_PROTECTED },
4180 { ep_throwable, EP_THROWABLE },
4181 { ep_can_explode, EP_CAN_EXPLODE },
4182 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4184 { ep_player, EP_PLAYER },
4185 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4186 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4187 { ep_switchable, EP_SWITCHABLE },
4188 { ep_bd_element, EP_BD_ELEMENT },
4189 { ep_sp_element, EP_SP_ELEMENT },
4190 { ep_sb_element, EP_SB_ELEMENT },
4192 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4193 { ep_food_penguin, EP_FOOD_PENGUIN },
4194 { ep_food_pig, EP_FOOD_PIG },
4195 { ep_historic_wall, EP_HISTORIC_WALL },
4196 { ep_historic_solid, EP_HISTORIC_SOLID },
4197 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4198 { ep_belt, EP_BELT },
4199 { ep_belt_active, EP_BELT_ACTIVE },
4200 { ep_belt_switch, EP_BELT_SWITCH },
4201 { ep_tube, EP_TUBE },
4202 { ep_acid_pool, EP_ACID_POOL },
4203 { ep_keygate, EP_KEYGATE },
4204 { ep_amoeboid, EP_AMOEBOID },
4205 { ep_amoebalive, EP_AMOEBALIVE },
4206 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4207 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4208 { ep_can_grow, EP_CAN_GROW },
4209 { ep_active_bomb, EP_ACTIVE_BOMB },
4210 { ep_inactive, EP_INACTIVE },
4212 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4214 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4216 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4217 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4219 { ep_obsolete, EP_OBSOLETE },
4226 /* always start with reliable default values (element has no properties) */
4227 /* (but never initialize clipboard elements after the very first time) */
4228 /* (to be able to use clipboard elements between several levels) */
4229 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4230 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4231 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4232 SET_PROPERTY(i, j, FALSE);
4234 /* set all base element properties from above array definitions */
4235 for (i = 0; element_properties[i].elements != NULL; i++)
4236 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4237 SET_PROPERTY((element_properties[i].elements)[j],
4238 element_properties[i].property, TRUE);
4240 /* copy properties to some elements that are only stored in level file */
4241 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4242 for (j = 0; copy_properties[j][0] != -1; j++)
4243 if (HAS_PROPERTY(copy_properties[j][0], i))
4244 for (k = 1; k <= 4; k++)
4245 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4247 /* set static element properties that are not listed in array definitions */
4248 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4249 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4251 clipboard_elements_initialized = TRUE;
4254 void InitElementPropertiesEngine(int engine_version)
4256 static int no_wall_properties[] =
4259 EP_COLLECTIBLE_ONLY,
4261 EP_DONT_COLLIDE_WITH,
4264 EP_CAN_SMASH_PLAYER,
4265 EP_CAN_SMASH_ENEMIES,
4266 EP_CAN_SMASH_EVERYTHING,
4271 EP_FOOD_DARK_YAMYAM,
4287 /* important: after initialization in InitElementPropertiesStatic(), the
4288 elements are not again initialized to a default value; therefore all
4289 changes have to make sure that they leave the element with a defined
4290 property (which means that conditional property changes must be set to
4291 a reliable default value before) */
4293 /* resolve group elements */
4294 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4295 ResolveGroupElement(EL_GROUP_START + i);
4297 /* set all special, combined or engine dependent element properties */
4298 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4300 /* do not change (already initialized) clipboard elements here */
4301 if (IS_CLIPBOARD_ELEMENT(i))
4304 /* ---------- INACTIVE ------------------------------------------------- */
4305 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4306 i <= EL_CHAR_END) ||
4307 (i >= EL_STEEL_CHAR_START &&
4308 i <= EL_STEEL_CHAR_END)));
4310 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4311 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4312 IS_WALKABLE_INSIDE(i) ||
4313 IS_WALKABLE_UNDER(i)));
4315 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4316 IS_PASSABLE_INSIDE(i) ||
4317 IS_PASSABLE_UNDER(i)));
4319 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4320 IS_PASSABLE_OVER(i)));
4322 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4323 IS_PASSABLE_INSIDE(i)));
4325 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4326 IS_PASSABLE_UNDER(i)));
4328 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4331 /* ---------- COLLECTIBLE ---------------------------------------------- */
4332 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4336 /* ---------- SNAPPABLE ------------------------------------------------ */
4337 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4338 IS_COLLECTIBLE(i) ||
4342 /* ---------- WALL ----------------------------------------------------- */
4343 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4345 for (j = 0; no_wall_properties[j] != -1; j++)
4346 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4347 i >= EL_FIRST_RUNTIME_UNREAL)
4348 SET_PROPERTY(i, EP_WALL, FALSE);
4350 if (IS_HISTORIC_WALL(i))
4351 SET_PROPERTY(i, EP_WALL, TRUE);
4353 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4354 if (engine_version < VERSION_IDENT(2,2,0,0))
4355 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4357 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4359 !IS_COLLECTIBLE(i)));
4361 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4362 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4363 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4365 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4366 IS_INDESTRUCTIBLE(i)));
4368 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4370 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4371 else if (engine_version < VERSION_IDENT(2,2,0,0))
4372 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4374 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4378 if (IS_CUSTOM_ELEMENT(i))
4380 /* these are additional properties which are initially false when set */
4382 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4384 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4385 if (DONT_COLLIDE_WITH(i))
4386 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4388 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4389 if (CAN_SMASH_EVERYTHING(i))
4390 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4391 if (CAN_SMASH_ENEMIES(i))
4392 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4395 /* ---------- CAN_SMASH ------------------------------------------------ */
4396 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4397 CAN_SMASH_ENEMIES(i) ||
4398 CAN_SMASH_EVERYTHING(i)));
4400 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4401 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4402 EXPLODES_BY_FIRE(i)));
4404 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4405 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4406 EXPLODES_SMASHED(i)));
4408 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4409 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4410 EXPLODES_IMPACT(i)));
4412 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4413 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4415 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4416 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4417 i == EL_BLACK_ORB));
4419 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4420 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4422 IS_CUSTOM_ELEMENT(i)));
4424 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4425 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4426 i == EL_SP_ELECTRON));
4428 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4429 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4430 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4431 getMoveIntoAcidProperty(&level, i));
4433 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4434 if (MAYBE_DONT_COLLIDE_WITH(i))
4435 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4436 getDontCollideWithProperty(&level, i));
4438 /* ---------- SP_PORT -------------------------------------------------- */
4439 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4440 IS_PASSABLE_INSIDE(i)));
4442 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4443 for (j = 0; j < level.num_android_clone_elements; j++)
4444 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4446 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4448 /* ---------- CAN_CHANGE ----------------------------------------------- */
4449 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4450 for (j = 0; j < element_info[i].num_change_pages; j++)
4451 if (element_info[i].change_page[j].can_change)
4452 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4454 /* ---------- HAS_ACTION ----------------------------------------------- */
4455 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4456 for (j = 0; j < element_info[i].num_change_pages; j++)
4457 if (element_info[i].change_page[j].has_action)
4458 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4460 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4461 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4464 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4465 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4466 element_info[i].crumbled[ACTION_DEFAULT] !=
4467 element_info[i].graphic[ACTION_DEFAULT]);
4469 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4470 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4471 IS_EDITOR_CASCADE_INACTIVE(i)));
4474 /* dynamically adjust element properties according to game engine version */
4476 static int ep_em_slippery_wall[] =
4481 EL_EXPANDABLE_WALL_HORIZONTAL,
4482 EL_EXPANDABLE_WALL_VERTICAL,
4483 EL_EXPANDABLE_WALL_ANY,
4484 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4485 EL_EXPANDABLE_STEELWALL_VERTICAL,
4486 EL_EXPANDABLE_STEELWALL_ANY,
4487 EL_EXPANDABLE_STEELWALL_GROWING,
4491 static int ep_em_explodes_by_fire[] =
4494 EL_EM_DYNAMITE_ACTIVE,
4499 /* special EM style gems behaviour */
4500 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4501 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4502 level.em_slippery_gems);
4504 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4505 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4506 (level.em_slippery_gems &&
4507 engine_version > VERSION_IDENT(2,0,1,0)));
4509 /* special EM style explosion behaviour regarding chain reactions */
4510 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4511 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4512 level.em_explodes_by_fire);
4515 /* this is needed because some graphics depend on element properties */
4516 if (game_status == GAME_MODE_PLAYING)
4517 InitElementGraphicInfo();
4520 void InitElementPropertiesAfterLoading(int engine_version)
4524 /* set some other uninitialized values of custom elements in older levels */
4525 if (engine_version < VERSION_IDENT(3,1,0,0))
4527 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4529 int element = EL_CUSTOM_START + i;
4531 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4533 element_info[element].explosion_delay = 17;
4534 element_info[element].ignition_delay = 8;
4539 void InitElementPropertiesGfxElement()
4543 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4545 struct ElementInfo *ei = &element_info[i];
4547 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4551 static void InitGlobal()
4556 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4558 /* check if element_name_info entry defined for each element in "main.h" */
4559 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4560 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4562 element_info[i].token_name = element_name_info[i].token_name;
4563 element_info[i].class_name = element_name_info[i].class_name;
4564 element_info[i].editor_description= element_name_info[i].editor_description;
4567 /* create hash from image config list */
4568 image_config_hash = newSetupFileHash();
4569 for (i = 0; image_config[i].token != NULL; i++)
4570 setHashEntry(image_config_hash,
4571 image_config[i].token,
4572 image_config[i].value);
4574 /* create hash from element token list */
4575 element_token_hash = newSetupFileHash();
4576 for (i = 0; element_name_info[i].token_name != NULL; i++)
4577 setHashEntry(element_token_hash,
4578 element_name_info[i].token_name,
4581 /* create hash from graphic token list */
4582 graphic_token_hash = newSetupFileHash();
4583 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4584 if (strSuffix(image_config[i].value, ".png") ||
4585 strSuffix(image_config[i].value, ".pcx") ||
4586 strSuffix(image_config[i].value, ".wav") ||
4587 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4588 setHashEntry(graphic_token_hash,
4589 image_config[i].token,
4590 int2str(graphic++, 0));
4592 /* create hash from font token list */
4593 font_token_hash = newSetupFileHash();
4594 for (i = 0; font_info[i].token_name != NULL; i++)
4595 setHashEntry(font_token_hash,
4596 font_info[i].token_name,
4599 /* set default filenames for all cloned graphics in static configuration */
4600 for (i = 0; image_config[i].token != NULL; i++)
4602 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4604 char *token = image_config[i].token;
4605 char *token_clone_from = getStringCat2(token, ".clone_from");
4606 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4608 if (token_cloned != NULL)
4610 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4612 if (value_cloned != NULL)
4614 /* set default filename in static configuration */
4615 image_config[i].value = value_cloned;
4617 /* set default filename in image config hash */
4618 setHashEntry(image_config_hash, token, value_cloned);
4622 free(token_clone_from);
4626 /* always start with reliable default values (all elements) */
4627 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4628 ActiveElement[i] = i;
4630 /* now add all entries that have an active state (active elements) */
4631 for (i = 0; element_with_active_state[i].element != -1; i++)
4633 int element = element_with_active_state[i].element;
4634 int element_active = element_with_active_state[i].element_active;
4636 ActiveElement[element] = element_active;
4639 /* always start with reliable default values (all buttons) */
4640 for (i = 0; i < NUM_IMAGE_FILES; i++)
4641 ActiveButton[i] = i;
4643 /* now add all entries that have an active state (active buttons) */
4644 for (i = 0; button_with_active_state[i].button != -1; i++)
4646 int button = button_with_active_state[i].button;
4647 int button_active = button_with_active_state[i].button_active;
4649 ActiveButton[button] = button_active;
4652 /* always start with reliable default values (all fonts) */
4653 for (i = 0; i < NUM_FONTS; i++)
4656 /* now add all entries that have an active state (active fonts) */
4657 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4659 int font = font_with_active_state[i].font_nr;
4660 int font_active = font_with_active_state[i].font_nr_active;
4662 ActiveFont[font] = font_active;
4665 global.autoplay_leveldir = NULL;
4666 global.convert_leveldir = NULL;
4667 global.create_images_dir = NULL;
4669 global.frames_per_second = 0;
4671 global.border_status = GAME_MODE_LOADING;
4672 global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4674 global.use_envelope_request = FALSE;
4677 void Execute_Command(char *command)
4681 if (strEqual(command, "print graphicsinfo.conf"))
4683 Print("# You can configure additional/alternative image files here.\n");
4684 Print("# (The entries below are default and therefore commented out.)\n");
4686 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4688 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4691 for (i = 0; image_config[i].token != NULL; i++)
4692 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4693 image_config[i].value));
4697 else if (strEqual(command, "print soundsinfo.conf"))
4699 Print("# You can configure additional/alternative sound files here.\n");
4700 Print("# (The entries below are default and therefore commented out.)\n");
4702 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4704 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4707 for (i = 0; sound_config[i].token != NULL; i++)
4708 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4709 sound_config[i].value));
4713 else if (strEqual(command, "print musicinfo.conf"))
4715 Print("# You can configure additional/alternative music files here.\n");
4716 Print("# (The entries below are default and therefore commented out.)\n");
4718 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4720 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4723 for (i = 0; music_config[i].token != NULL; i++)
4724 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4725 music_config[i].value));
4729 else if (strEqual(command, "print editorsetup.conf"))
4731 Print("# You can configure your personal editor element list here.\n");
4732 Print("# (The entries below are default and therefore commented out.)\n");
4735 /* this is needed to be able to check element list for cascade elements */
4736 InitElementPropertiesStatic();
4737 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4739 PrintEditorElementList();
4743 else if (strEqual(command, "print helpanim.conf"))
4745 Print("# You can configure different element help animations here.\n");
4746 Print("# (The entries below are default and therefore commented out.)\n");
4749 for (i = 0; helpanim_config[i].token != NULL; i++)
4751 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4752 helpanim_config[i].value));
4754 if (strEqual(helpanim_config[i].token, "end"))
4760 else if (strEqual(command, "print helptext.conf"))
4762 Print("# You can configure different element help text here.\n");
4763 Print("# (The entries below are default and therefore commented out.)\n");
4766 for (i = 0; helptext_config[i].token != NULL; i++)
4767 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4768 helptext_config[i].value));
4772 else if (strPrefix(command, "dump level "))
4774 char *filename = &command[11];
4776 if (!fileExists(filename))
4777 Error(ERR_EXIT, "cannot open file '%s'", filename);
4779 LoadLevelFromFilename(&level, filename);
4784 else if (strPrefix(command, "dump tape "))
4786 char *filename = &command[10];
4788 if (!fileExists(filename))
4789 Error(ERR_EXIT, "cannot open file '%s'", filename);
4791 LoadTapeFromFilename(filename);
4796 else if (strPrefix(command, "autotest ") ||
4797 strPrefix(command, "autoplay ") ||
4798 strPrefix(command, "autoffwd "))
4800 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4802 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4803 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4804 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4806 while (*str_ptr != '\0') /* continue parsing string */
4808 /* cut leading whitespace from string, replace it by string terminator */
4809 while (*str_ptr == ' ' || *str_ptr == '\t')
4812 if (*str_ptr == '\0') /* end of string reached */
4815 if (global.autoplay_leveldir == NULL) /* read level set string */
4817 global.autoplay_leveldir = str_ptr;
4818 global.autoplay_all = TRUE; /* default: play all tapes */
4820 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4821 global.autoplay_level[i] = FALSE;
4823 else /* read level number string */
4825 int level_nr = atoi(str_ptr); /* get level_nr value */
4827 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4828 global.autoplay_level[level_nr] = TRUE;
4830 global.autoplay_all = FALSE;
4833 /* advance string pointer to the next whitespace (or end of string) */
4834 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4838 else if (strPrefix(command, "convert "))
4840 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4841 char *str_ptr = strchr(str_copy, ' ');
4843 global.convert_leveldir = str_copy;
4844 global.convert_level_nr = -1;
4846 if (str_ptr != NULL) /* level number follows */
4848 *str_ptr++ = '\0'; /* terminate leveldir string */
4849 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4852 else if (strPrefix(command, "create images "))
4854 global.create_images_dir = getStringCopy(&command[14]);
4856 if (access(global.create_images_dir, W_OK) != 0)
4857 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4858 global.create_images_dir);
4860 else if (strPrefix(command, "create CE image "))
4862 CreateCustomElementImages(&command[16]);
4868 #if defined(TARGET_SDL2)
4869 else if (strEqual(command, "SDL_ListModes"))
4871 SDL_Init(SDL_INIT_VIDEO);
4873 int num_displays = SDL_GetNumVideoDisplays();
4875 // check if there are any displays available
4876 if (num_displays < 0)
4878 Print("No displays available: %s\n", SDL_GetError());
4883 for (i = 0; i < num_displays; i++)
4885 int num_modes = SDL_GetNumDisplayModes(i);
4888 Print("Available display modes for display %d:\n", i);
4890 // check if there are any display modes available for this display
4893 Print("No display modes available for display %d: %s\n",
4899 for (j = 0; j < num_modes; j++)
4901 SDL_DisplayMode mode;
4903 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4905 Print("Cannot get display mode %d for display %d: %s\n",
4906 j, i, SDL_GetError());
4911 Print("- %d x %d\n", mode.w, mode.h);
4917 #elif defined(TARGET_SDL)
4918 else if (strEqual(command, "SDL_ListModes"))
4923 SDL_Init(SDL_INIT_VIDEO);
4925 /* get available fullscreen/hardware modes */
4926 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4928 /* check if there are any modes available */
4931 Print("No modes available!\n");
4936 /* check if our resolution is restricted */
4937 if (modes == (SDL_Rect **)-1)
4939 Print("All resolutions available.\n");
4943 Print("Available display modes:\n");
4945 for (i = 0; modes[i]; i++)
4946 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4956 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4960 static void InitSetup()
4962 LoadSetup(); /* global setup info */
4964 /* set some options from setup file */
4966 if (setup.options.verbose)
4967 options.verbose = TRUE;
4970 static void InitGameInfo()
4972 game.restart_level = FALSE;
4975 static void InitPlayerInfo()
4979 /* choose default local player */
4980 local_player = &stored_player[0];
4982 for (i = 0; i < MAX_PLAYERS; i++)
4983 stored_player[i].connected = FALSE;
4985 local_player->connected = TRUE;
4988 static void InitArtworkInfo()
4993 static char *get_string_in_brackets(char *string)
4995 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4997 sprintf(string_in_brackets, "[%s]", string);
4999 return string_in_brackets;
5002 static char *get_level_id_suffix(int id_nr)
5004 char *id_suffix = checked_malloc(1 + 3 + 1);
5006 if (id_nr < 0 || id_nr > 999)
5009 sprintf(id_suffix, ".%03d", id_nr);
5014 static void InitArtworkConfig()
5016 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5018 NUM_GLOBAL_ANIM_TOKENS + 1];
5019 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5020 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5021 static char *action_id_suffix[NUM_ACTIONS + 1];
5022 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5023 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5024 static char *level_id_suffix[MAX_LEVELS + 1];
5025 static char *dummy[1] = { NULL };
5026 static char *ignore_generic_tokens[] =
5032 static char **ignore_image_tokens;
5033 static char **ignore_sound_tokens;
5034 static char **ignore_music_tokens;
5035 int num_ignore_generic_tokens;
5036 int num_ignore_image_tokens;
5037 int num_ignore_sound_tokens;
5038 int num_ignore_music_tokens;
5041 /* dynamically determine list of generic tokens to be ignored */
5042 num_ignore_generic_tokens = 0;
5043 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5044 num_ignore_generic_tokens++;
5046 /* dynamically determine list of image tokens to be ignored */
5047 num_ignore_image_tokens = num_ignore_generic_tokens;
5048 for (i = 0; image_config_vars[i].token != NULL; i++)
5049 num_ignore_image_tokens++;
5050 ignore_image_tokens =
5051 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5052 for (i = 0; i < num_ignore_generic_tokens; i++)
5053 ignore_image_tokens[i] = ignore_generic_tokens[i];
5054 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5055 ignore_image_tokens[num_ignore_generic_tokens + i] =
5056 image_config_vars[i].token;
5057 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5059 /* dynamically determine list of sound tokens to be ignored */
5060 num_ignore_sound_tokens = num_ignore_generic_tokens;
5061 ignore_sound_tokens =
5062 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5063 for (i = 0; i < num_ignore_generic_tokens; i++)
5064 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5065 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5067 /* dynamically determine list of music tokens to be ignored */
5068 num_ignore_music_tokens = num_ignore_generic_tokens;
5069 ignore_music_tokens =
5070 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5071 for (i = 0; i < num_ignore_generic_tokens; i++)
5072 ignore_music_tokens[i] = ignore_generic_tokens[i];
5073 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5075 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5076 image_id_prefix[i] = element_info[i].token_name;
5077 for (i = 0; i < NUM_FONTS; i++)
5078 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5079 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5080 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5081 global_anim_info[i].token_name;
5082 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5084 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5085 sound_id_prefix[i] = element_info[i].token_name;
5086 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5087 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5088 get_string_in_brackets(element_info[i].class_name);
5089 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5091 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5092 music_id_prefix[i] = music_prefix_info[i].prefix;
5093 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5095 for (i = 0; i < NUM_ACTIONS; i++)
5096 action_id_suffix[i] = element_action_info[i].suffix;
5097 action_id_suffix[NUM_ACTIONS] = NULL;
5099 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5100 direction_id_suffix[i] = element_direction_info[i].suffix;
5101 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5103 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5104 special_id_suffix[i] = special_suffix_info[i].suffix;
5105 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5107 for (i = 0; i < MAX_LEVELS; i++)
5108 level_id_suffix[i] = get_level_id_suffix(i);
5109 level_id_suffix[MAX_LEVELS] = NULL;
5111 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5112 image_id_prefix, action_id_suffix, direction_id_suffix,
5113 special_id_suffix, ignore_image_tokens);
5114 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5115 sound_id_prefix, action_id_suffix, dummy,
5116 special_id_suffix, ignore_sound_tokens);
5117 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5118 music_id_prefix, special_id_suffix, level_id_suffix,
5119 dummy, ignore_music_tokens);
5122 static void InitMixer()
5129 void InitGfxBuffers()
5131 static int win_xsize_last = -1;
5132 static int win_ysize_last = -1;
5134 /* create additional image buffers for double-buffering and cross-fading */
5136 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5138 /* may contain content for cross-fading -- only re-create if changed */
5139 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5140 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5142 win_xsize_last = WIN_XSIZE;
5143 win_ysize_last = WIN_YSIZE;
5146 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5147 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5148 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5149 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5150 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5152 /* initialize screen properties */
5153 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5154 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5156 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5157 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5158 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5159 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5160 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5161 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5163 /* required if door size definitions have changed */
5164 InitGraphicCompatibilityInfo_Doors();
5166 InitGfxBuffers_EM();
5167 InitGfxBuffers_SP();
5172 struct GraphicInfo *graphic_info_last = graphic_info;
5173 char *filename_font_initial = NULL;
5174 char *filename_anim_initial = NULL;
5175 Bitmap *bitmap_font_initial = NULL;
5179 /* determine settings for initial font (for displaying startup messages) */
5180 for (i = 0; image_config[i].token != NULL; i++)
5182 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5184 char font_token[128];
5187 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5188 len_font_token = strlen(font_token);
5190 if (strEqual(image_config[i].token, font_token))
5191 filename_font_initial = image_config[i].value;
5192 else if (strlen(image_config[i].token) > len_font_token &&
5193 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5195 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5196 font_initial[j].src_x = atoi(image_config[i].value);
5197 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5198 font_initial[j].src_y = atoi(image_config[i].value);
5199 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5200 font_initial[j].width = atoi(image_config[i].value);
5201 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5202 font_initial[j].height = atoi(image_config[i].value);
5207 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5209 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5210 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5213 if (filename_font_initial == NULL) /* should not happen */
5214 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5217 InitGfxCustomArtworkInfo();
5218 InitGfxOtherSettings();
5220 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5222 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5223 font_initial[j].bitmap = bitmap_font_initial;
5225 InitFontGraphicInfo();
5227 font_height = getFontHeight(FC_RED);
5229 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5230 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5231 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5234 DrawInitText("Loading graphics", 120, FC_GREEN);
5236 /* initialize settings for busy animation with default values */
5237 int parameter[NUM_GFX_ARGS];
5238 for (i = 0; i < NUM_GFX_ARGS; i++)
5239 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5240 image_config_suffix[i].token,
5241 image_config_suffix[i].type);
5243 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5244 int len_anim_token = strlen(anim_token);
5246 /* read settings for busy animation from default custom artwork config */
5247 char *gfx_config_filename = getPath3(options.graphics_directory,
5249 GRAPHICSINFO_FILENAME);
5251 if (fileExists(gfx_config_filename))
5253 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5255 if (setup_file_hash)
5257 char *filename = getHashEntry(setup_file_hash, anim_token);
5261 filename_anim_initial = getStringCopy(filename);
5263 for (j = 0; image_config_suffix[j].token != NULL; j++)
5265 int type = image_config_suffix[j].type;
5266 char *suffix = image_config_suffix[j].token;
5267 char *token = getStringCat2(anim_token, suffix);
5268 char *value = getHashEntry(setup_file_hash, token);
5270 checked_free(token);
5273 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5277 freeSetupFileHash(setup_file_hash);
5281 if (filename_anim_initial == NULL)
5283 /* read settings for busy animation from static default artwork config */
5284 for (i = 0; image_config[i].token != NULL; i++)
5286 if (strEqual(image_config[i].token, anim_token))
5287 filename_anim_initial = getStringCopy(image_config[i].value);
5288 else if (strlen(image_config[i].token) > len_anim_token &&
5289 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5291 for (j = 0; image_config_suffix[j].token != NULL; j++)
5293 if (strEqual(&image_config[i].token[len_anim_token],
5294 image_config_suffix[j].token))
5296 get_graphic_parameter_value(image_config[i].value,
5297 image_config_suffix[j].token,
5298 image_config_suffix[j].type);
5304 if (filename_anim_initial == NULL) /* should not happen */
5305 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5307 anim_initial.bitmaps =
5308 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5310 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5311 LoadCustomImage(filename_anim_initial);
5313 checked_free(filename_anim_initial);
5315 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5317 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5319 graphic_info = graphic_info_last;
5321 init.busy.width = anim_initial.width;
5322 init.busy.height = anim_initial.height;
5324 InitMenuDesignSettings_Static();
5326 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5327 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5328 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5330 gfx.fade_border_source_status = global.border_status;
5331 gfx.fade_border_target_status = global.border_status;
5332 gfx.masked_border_bitmap_ptr = backbuffer;
5334 /* use copy of busy animation to prevent change while reloading artwork */
5338 void InitGfxBackground()
5340 fieldbuffer = bitmap_db_field;
5341 SetDrawtoField(DRAW_BACKBUFFER);
5343 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5345 redraw_mask = REDRAW_ALL;
5348 static void InitLevelInfo()
5350 LoadLevelInfo(); /* global level info */
5351 LoadLevelSetup_LastSeries(); /* last played series info */
5352 LoadLevelSetup_SeriesInfo(); /* last played level info */
5354 if (global.autoplay_leveldir &&
5355 global.autoplay_mode != AUTOPLAY_TEST)
5357 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5358 global.autoplay_leveldir);
5359 if (leveldir_current == NULL)
5360 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5364 static void InitLevelArtworkInfo()
5366 LoadLevelArtworkInfo();
5369 static void InitImages()
5371 print_timestamp_init("InitImages");
5374 printf("::: leveldir_current->identifier == '%s'\n",
5375 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5376 printf("::: leveldir_current->graphics_path == '%s'\n",
5377 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5378 printf("::: leveldir_current->graphics_set == '%s'\n",
5379 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5380 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5381 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5384 setLevelArtworkDir(artwork.gfx_first);
5387 printf("::: leveldir_current->identifier == '%s'\n",
5388 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5389 printf("::: leveldir_current->graphics_path == '%s'\n",
5390 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5391 printf("::: leveldir_current->graphics_set == '%s'\n",
5392 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5393 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5394 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5398 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5399 leveldir_current->identifier,
5400 artwork.gfx_current_identifier,
5401 artwork.gfx_current->identifier,
5402 leveldir_current->graphics_set,
5403 leveldir_current->graphics_path);
5406 UPDATE_BUSY_STATE();
5408 ReloadCustomImages();
5409 print_timestamp_time("ReloadCustomImages");
5411 UPDATE_BUSY_STATE();
5413 LoadCustomElementDescriptions();
5414 print_timestamp_time("LoadCustomElementDescriptions");
5416 UPDATE_BUSY_STATE();
5418 LoadMenuDesignSettings();
5419 print_timestamp_time("LoadMenuDesignSettings");
5421 UPDATE_BUSY_STATE();
5423 ReinitializeGraphics();
5424 print_timestamp_time("ReinitializeGraphics");
5426 UPDATE_BUSY_STATE();
5428 print_timestamp_done("InitImages");
5431 static void InitSound(char *identifier)
5433 print_timestamp_init("InitSound");
5435 if (identifier == NULL)
5436 identifier = artwork.snd_current->identifier;
5438 /* set artwork path to send it to the sound server process */
5439 setLevelArtworkDir(artwork.snd_first);
5441 InitReloadCustomSounds(identifier);
5442 print_timestamp_time("InitReloadCustomSounds");
5444 ReinitializeSounds();
5445 print_timestamp_time("ReinitializeSounds");
5447 print_timestamp_done("InitSound");
5450 static void InitMusic(char *identifier)
5452 print_timestamp_init("InitMusic");
5454 if (identifier == NULL)
5455 identifier = artwork.mus_current->identifier;
5457 /* set artwork path to send it to the sound server process */
5458 setLevelArtworkDir(artwork.mus_first);
5460 InitReloadCustomMusic(identifier);
5461 print_timestamp_time("InitReloadCustomMusic");
5463 ReinitializeMusic();
5464 print_timestamp_time("ReinitializeMusic");
5466 print_timestamp_done("InitMusic");
5469 void InitNetworkServer()
5471 #if defined(NETWORK_AVALIABLE)
5475 if (!options.network)
5478 #if defined(NETWORK_AVALIABLE)
5479 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5481 if (!ConnectToServer(options.server_host, options.server_port))
5482 Error(ERR_EXIT, "cannot connect to network game server");
5484 SendToServer_PlayerName(setup.player_name);
5485 SendToServer_ProtocolVersion();
5488 SendToServer_NrWanted(nr_wanted);
5492 static boolean CheckArtworkConfigForCustomElements(char *filename)
5494 SetupFileHash *setup_file_hash;
5495 boolean redefined_ce_found = FALSE;
5497 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5499 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5501 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5503 char *token = HASH_ITERATION_TOKEN(itr);
5505 if (strPrefix(token, "custom_"))
5507 redefined_ce_found = TRUE;
5512 END_HASH_ITERATION(setup_file_hash, itr)
5514 freeSetupFileHash(setup_file_hash);
5517 return redefined_ce_found;
5520 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5522 char *filename_base, *filename_local;
5523 boolean redefined_ce_found = FALSE;
5525 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5528 printf("::: leveldir_current->identifier == '%s'\n",
5529 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5530 printf("::: leveldir_current->graphics_path == '%s'\n",
5531 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5532 printf("::: leveldir_current->graphics_set == '%s'\n",
5533 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5534 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5535 leveldir_current == NULL ? "[NULL]" :
5536 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5539 /* first look for special artwork configured in level series config */
5540 filename_base = getCustomArtworkLevelConfigFilename(type);
5543 printf("::: filename_base == '%s'\n", filename_base);
5546 if (fileExists(filename_base))
5547 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5549 filename_local = getCustomArtworkConfigFilename(type);
5552 printf("::: filename_local == '%s'\n", filename_local);
5555 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5556 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5559 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5562 return redefined_ce_found;
5565 static void InitOverrideArtwork()
5567 boolean redefined_ce_found = FALSE;
5569 /* to check if this level set redefines any CEs, do not use overriding */
5570 gfx.override_level_graphics = FALSE;
5571 gfx.override_level_sounds = FALSE;
5572 gfx.override_level_music = FALSE;
5574 /* now check if this level set has definitions for custom elements */
5575 if (setup.override_level_graphics == AUTO ||
5576 setup.override_level_sounds == AUTO ||
5577 setup.override_level_music == AUTO)
5578 redefined_ce_found =
5579 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5580 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5581 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5584 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5587 if (redefined_ce_found)
5589 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5590 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5591 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5592 gfx.override_level_music = (setup.override_level_music == TRUE);
5596 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5597 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5598 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5599 gfx.override_level_music = (setup.override_level_music != FALSE);
5603 printf("::: => %d, %d, %d\n",
5604 gfx.override_level_graphics,
5605 gfx.override_level_sounds,
5606 gfx.override_level_music);
5610 static char *getNewArtworkIdentifier(int type)
5612 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5613 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5614 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5615 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5616 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5617 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5618 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5619 char *leveldir_identifier = leveldir_current->identifier;
5620 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5621 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5622 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5623 char *artwork_current_identifier;
5624 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5626 /* leveldir_current may be invalid (level group, parent link) */
5627 if (!validLevelSeries(leveldir_current))
5630 /* 1st step: determine artwork set to be activated in descending order:
5631 --------------------------------------------------------------------
5632 1. setup artwork (when configured to override everything else)
5633 2. artwork set configured in "levelinfo.conf" of current level set
5634 (artwork in level directory will have priority when loading later)
5635 3. artwork in level directory (stored in artwork sub-directory)
5636 4. setup artwork (currently configured in setup menu) */
5638 if (setup_override_artwork)
5639 artwork_current_identifier = setup_artwork_set;
5640 else if (leveldir_artwork_set != NULL)
5641 artwork_current_identifier = leveldir_artwork_set;
5642 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5643 artwork_current_identifier = leveldir_identifier;
5645 artwork_current_identifier = setup_artwork_set;
5648 /* 2nd step: check if it is really needed to reload artwork set
5649 ------------------------------------------------------------ */
5651 /* ---------- reload if level set and also artwork set has changed ------- */
5652 if (leveldir_current_identifier[type] != leveldir_identifier &&
5653 (last_has_level_artwork_set[type] || has_level_artwork_set))
5654 artwork_new_identifier = artwork_current_identifier;
5656 leveldir_current_identifier[type] = leveldir_identifier;
5657 last_has_level_artwork_set[type] = has_level_artwork_set;
5659 /* ---------- reload if "override artwork" setting has changed ----------- */
5660 if (last_override_level_artwork[type] != setup_override_artwork)
5661 artwork_new_identifier = artwork_current_identifier;
5663 last_override_level_artwork[type] = setup_override_artwork;
5665 /* ---------- reload if current artwork identifier has changed ----------- */
5666 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5667 artwork_current_identifier))
5668 artwork_new_identifier = artwork_current_identifier;
5670 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5672 /* ---------- do not reload directly after starting ---------------------- */
5673 if (!initialized[type])
5674 artwork_new_identifier = NULL;
5676 initialized[type] = TRUE;
5678 return artwork_new_identifier;
5681 void ReloadCustomArtwork(int force_reload)
5683 int last_game_status = game_status; /* save current game status */
5684 char *gfx_new_identifier;
5685 char *snd_new_identifier;
5686 char *mus_new_identifier;
5687 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5688 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5689 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5690 boolean reload_needed;
5692 InitOverrideArtwork();
5694 force_reload_gfx |= AdjustGraphicsForEMC();
5696 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5697 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5698 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5700 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5701 snd_new_identifier != NULL || force_reload_snd ||
5702 mus_new_identifier != NULL || force_reload_mus);
5707 print_timestamp_init("ReloadCustomArtwork");
5709 SetGameStatus(GAME_MODE_LOADING);
5711 FadeOut(REDRAW_ALL);
5713 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5714 print_timestamp_time("ClearRectangle");
5718 if (gfx_new_identifier != NULL || force_reload_gfx)
5721 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5722 artwork.gfx_current_identifier,
5724 artwork.gfx_current->identifier,
5725 leveldir_current->graphics_set);
5729 print_timestamp_time("InitImages");
5732 if (snd_new_identifier != NULL || force_reload_snd)
5734 InitSound(snd_new_identifier);
5735 print_timestamp_time("InitSound");
5738 if (mus_new_identifier != NULL || force_reload_mus)
5740 InitMusic(mus_new_identifier);
5741 print_timestamp_time("InitMusic");
5744 SetGameStatus(last_game_status); /* restore current game status */
5746 init_last = init; /* switch to new busy animation */
5748 FadeOut(REDRAW_ALL);
5750 RedrawGlobalBorder();
5752 /* force redraw of (open or closed) door graphics */
5753 SetDoorState(DOOR_OPEN_ALL);
5754 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5756 FadeSetEnterScreen();
5757 FadeSkipNextFadeOut();
5759 print_timestamp_done("ReloadCustomArtwork");
5761 LimitScreenUpdates(FALSE);
5764 void KeyboardAutoRepeatOffUnlessAutoplay()
5766 if (global.autoplay_leveldir == NULL)
5767 KeyboardAutoRepeatOff();
5770 void DisplayExitMessage(char *format, va_list ap)
5772 // check if draw buffer and fonts for exit message are already available
5773 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5776 int font_1 = FC_RED;
5777 int font_2 = FC_YELLOW;
5778 int font_3 = FC_BLUE;
5779 int font_width = getFontWidth(font_2);
5780 int font_height = getFontHeight(font_2);
5783 int sxsize = WIN_XSIZE - 2 * sx;
5784 int sysize = WIN_YSIZE - 2 * sy;
5785 int line_length = sxsize / font_width;
5786 int max_lines = sysize / font_height;
5787 int num_lines_printed;
5791 gfx.sxsize = sxsize;
5792 gfx.sysize = sysize;
5796 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5798 DrawTextSCentered(sy, font_1, "Fatal error:");
5799 sy += 3 * font_height;;
5802 DrawTextBufferVA(sx, sy, format, ap, font_2,
5803 line_length, line_length, max_lines,
5804 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5805 sy += (num_lines_printed + 3) * font_height;
5807 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5808 sy += 3 * font_height;
5811 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5812 line_length, line_length, max_lines,
5813 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5815 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5817 redraw_mask = REDRAW_ALL;
5819 /* force drawing exit message even if screen updates are currently limited */
5820 LimitScreenUpdates(FALSE);
5824 /* deactivate toons on error message screen */
5825 setup.toons = FALSE;
5827 WaitForEventToContinue();
5831 /* ========================================================================= */
5833 /* ========================================================================= */
5837 print_timestamp_init("OpenAll");
5839 SetGameStatus(GAME_MODE_LOADING);
5843 InitGlobal(); /* initialize some global variables */
5845 print_timestamp_time("[init global stuff]");
5849 print_timestamp_time("[init setup/config stuff (1)]");
5851 if (options.execute_command)
5852 Execute_Command(options.execute_command);
5854 if (options.serveronly)
5856 #if defined(PLATFORM_UNIX)
5857 NetworkServer(options.server_port, options.serveronly);
5859 Error(ERR_WARN, "networking only supported in Unix version");
5862 exit(0); /* never reached, server loops forever */
5866 print_timestamp_time("[init setup/config stuff (2)]");
5868 print_timestamp_time("[init setup/config stuff (3)]");
5869 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5870 print_timestamp_time("[init setup/config stuff (4)]");
5871 InitArtworkConfig(); /* needed before forking sound child process */
5872 print_timestamp_time("[init setup/config stuff (5)]");
5874 print_timestamp_time("[init setup/config stuff (6)]");
5876 InitRND(NEW_RANDOMIZE);
5877 InitSimpleRandom(NEW_RANDOMIZE);
5881 print_timestamp_time("[init setup/config stuff]");
5884 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5886 InitEventFilter(FilterEvents);
5888 print_timestamp_time("[init video stuff]");
5890 InitElementPropertiesStatic();
5891 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5892 InitElementPropertiesGfxElement();
5894 print_timestamp_time("[init element properties stuff]");
5898 print_timestamp_time("InitGfx");
5901 print_timestamp_time("InitLevelInfo");
5903 InitLevelArtworkInfo();
5904 print_timestamp_time("InitLevelArtworkInfo");
5906 InitOverrideArtwork(); /* needs to know current level directory */
5907 print_timestamp_time("InitOverrideArtwork");
5909 InitImages(); /* needs to know current level directory */
5910 print_timestamp_time("InitImages");
5912 InitSound(NULL); /* needs to know current level directory */
5913 print_timestamp_time("InitSound");
5915 InitMusic(NULL); /* needs to know current level directory */
5916 print_timestamp_time("InitMusic");
5918 InitGfxBackground();
5923 if (global.autoplay_leveldir)
5928 else if (global.convert_leveldir)
5933 else if (global.create_images_dir)
5935 CreateLevelSketchImages();
5939 SetGameStatus(GAME_MODE_MAIN);
5941 FadeSetEnterScreen();
5942 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5943 FadeSkipNextFadeOut();
5945 print_timestamp_time("[post-artwork]");
5947 print_timestamp_done("OpenAll");
5951 InitNetworkServer();
5954 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5956 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5957 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5958 #if defined(PLATFORM_ANDROID)
5959 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5960 SDL_AndroidGetInternalStoragePath());
5961 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5962 SDL_AndroidGetExternalStoragePath());
5963 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5964 (SDL_AndroidGetExternalStorageState() ==
5965 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5966 SDL_AndroidGetExternalStorageState() ==
5967 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5972 void CloseAllAndExit(int exit_value)
5977 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5984 #if defined(TARGET_SDL)
5985 #if defined(TARGET_SDL2)
5987 // set a flag to tell the network server thread to quit and wait for it
5988 // using SDL_WaitThread()
5990 if (network_server) /* terminate network server */
5991 SDL_KillThread(server_thread);
5995 CloseVideoDisplay();
5996 ClosePlatformDependentStuff();
5998 if (exit_value != 0)
6000 /* fall back to default level set (current set may have caused an error) */
6001 SaveLevelSetup_LastSeries_Deactivate();
6003 /* tell user where to find error log file which may contain more details */
6004 // (error notification now directly displayed on screen inside R'n'D
6005 // NotifyUserAboutErrorFile(); /* currently only works for Windows */