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 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4872 static void InitSetup()
4874 LoadSetup(); /* global setup info */
4876 /* set some options from setup file */
4878 if (setup.options.verbose)
4879 options.verbose = TRUE;
4882 static void InitGameInfo()
4884 game.restart_level = FALSE;
4887 static void InitPlayerInfo()
4891 /* choose default local player */
4892 local_player = &stored_player[0];
4894 for (i = 0; i < MAX_PLAYERS; i++)
4895 stored_player[i].connected = FALSE;
4897 local_player->connected = TRUE;
4900 static void InitArtworkInfo()
4905 static char *get_string_in_brackets(char *string)
4907 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4909 sprintf(string_in_brackets, "[%s]", string);
4911 return string_in_brackets;
4914 static char *get_level_id_suffix(int id_nr)
4916 char *id_suffix = checked_malloc(1 + 3 + 1);
4918 if (id_nr < 0 || id_nr > 999)
4921 sprintf(id_suffix, ".%03d", id_nr);
4926 static void InitArtworkConfig()
4928 static char *image_id_prefix[MAX_NUM_ELEMENTS +
4930 NUM_GLOBAL_ANIM_TOKENS + 1];
4931 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4932 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4933 static char *action_id_suffix[NUM_ACTIONS + 1];
4934 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4935 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4936 static char *level_id_suffix[MAX_LEVELS + 1];
4937 static char *dummy[1] = { NULL };
4938 static char *ignore_generic_tokens[] =
4944 static char **ignore_image_tokens;
4945 static char **ignore_sound_tokens;
4946 static char **ignore_music_tokens;
4947 int num_ignore_generic_tokens;
4948 int num_ignore_image_tokens;
4949 int num_ignore_sound_tokens;
4950 int num_ignore_music_tokens;
4953 /* dynamically determine list of generic tokens to be ignored */
4954 num_ignore_generic_tokens = 0;
4955 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4956 num_ignore_generic_tokens++;
4958 /* dynamically determine list of image tokens to be ignored */
4959 num_ignore_image_tokens = num_ignore_generic_tokens;
4960 for (i = 0; image_config_vars[i].token != NULL; i++)
4961 num_ignore_image_tokens++;
4962 ignore_image_tokens =
4963 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4964 for (i = 0; i < num_ignore_generic_tokens; i++)
4965 ignore_image_tokens[i] = ignore_generic_tokens[i];
4966 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4967 ignore_image_tokens[num_ignore_generic_tokens + i] =
4968 image_config_vars[i].token;
4969 ignore_image_tokens[num_ignore_image_tokens] = NULL;
4971 /* dynamically determine list of sound tokens to be ignored */
4972 num_ignore_sound_tokens = num_ignore_generic_tokens;
4973 ignore_sound_tokens =
4974 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4975 for (i = 0; i < num_ignore_generic_tokens; i++)
4976 ignore_sound_tokens[i] = ignore_generic_tokens[i];
4977 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4979 /* dynamically determine list of music tokens to be ignored */
4980 num_ignore_music_tokens = num_ignore_generic_tokens;
4981 ignore_music_tokens =
4982 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4983 for (i = 0; i < num_ignore_generic_tokens; i++)
4984 ignore_music_tokens[i] = ignore_generic_tokens[i];
4985 ignore_music_tokens[num_ignore_music_tokens] = NULL;
4987 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4988 image_id_prefix[i] = element_info[i].token_name;
4989 for (i = 0; i < NUM_FONTS; i++)
4990 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4991 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
4992 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
4993 global_anim_info[i].token_name;
4994 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
4996 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4997 sound_id_prefix[i] = element_info[i].token_name;
4998 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4999 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5000 get_string_in_brackets(element_info[i].class_name);
5001 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5003 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5004 music_id_prefix[i] = music_prefix_info[i].prefix;
5005 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5007 for (i = 0; i < NUM_ACTIONS; i++)
5008 action_id_suffix[i] = element_action_info[i].suffix;
5009 action_id_suffix[NUM_ACTIONS] = NULL;
5011 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5012 direction_id_suffix[i] = element_direction_info[i].suffix;
5013 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5015 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5016 special_id_suffix[i] = special_suffix_info[i].suffix;
5017 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5019 for (i = 0; i < MAX_LEVELS; i++)
5020 level_id_suffix[i] = get_level_id_suffix(i);
5021 level_id_suffix[MAX_LEVELS] = NULL;
5023 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5024 image_id_prefix, action_id_suffix, direction_id_suffix,
5025 special_id_suffix, ignore_image_tokens);
5026 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5027 sound_id_prefix, action_id_suffix, dummy,
5028 special_id_suffix, ignore_sound_tokens);
5029 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5030 music_id_prefix, special_id_suffix, level_id_suffix,
5031 dummy, ignore_music_tokens);
5034 static void InitMixer()
5041 void InitGfxBuffers()
5043 static int win_xsize_last = -1;
5044 static int win_ysize_last = -1;
5046 /* create additional image buffers for double-buffering and cross-fading */
5048 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5050 /* may contain content for cross-fading -- only re-create if changed */
5051 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5052 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5054 win_xsize_last = WIN_XSIZE;
5055 win_ysize_last = WIN_YSIZE;
5058 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5059 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5060 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5061 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5062 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5064 /* initialize screen properties */
5065 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5066 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5068 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5069 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5070 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5071 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5072 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5073 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5075 /* required if door size definitions have changed */
5076 InitGraphicCompatibilityInfo_Doors();
5078 InitGfxBuffers_EM();
5079 InitGfxBuffers_SP();
5084 struct GraphicInfo *graphic_info_last = graphic_info;
5085 char *filename_font_initial = NULL;
5086 char *filename_anim_initial = NULL;
5087 Bitmap *bitmap_font_initial = NULL;
5091 /* determine settings for initial font (for displaying startup messages) */
5092 for (i = 0; image_config[i].token != NULL; i++)
5094 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5096 char font_token[128];
5099 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5100 len_font_token = strlen(font_token);
5102 if (strEqual(image_config[i].token, font_token))
5103 filename_font_initial = image_config[i].value;
5104 else if (strlen(image_config[i].token) > len_font_token &&
5105 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5107 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5108 font_initial[j].src_x = atoi(image_config[i].value);
5109 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5110 font_initial[j].src_y = atoi(image_config[i].value);
5111 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5112 font_initial[j].width = atoi(image_config[i].value);
5113 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5114 font_initial[j].height = atoi(image_config[i].value);
5119 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5121 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5122 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5125 if (filename_font_initial == NULL) /* should not happen */
5126 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5129 InitGfxCustomArtworkInfo();
5130 InitGfxOtherSettings();
5132 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5134 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5135 font_initial[j].bitmap = bitmap_font_initial;
5137 InitFontGraphicInfo();
5139 font_height = getFontHeight(FC_RED);
5141 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5142 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5143 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5146 DrawInitText("Loading graphics", 120, FC_GREEN);
5148 /* initialize settings for busy animation with default values */
5149 int parameter[NUM_GFX_ARGS];
5150 for (i = 0; i < NUM_GFX_ARGS; i++)
5151 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5152 image_config_suffix[i].token,
5153 image_config_suffix[i].type);
5155 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5156 int len_anim_token = strlen(anim_token);
5158 /* read settings for busy animation from default custom artwork config */
5159 char *gfx_config_filename = getPath3(options.graphics_directory,
5161 GRAPHICSINFO_FILENAME);
5163 if (fileExists(gfx_config_filename))
5165 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5167 if (setup_file_hash)
5169 char *filename = getHashEntry(setup_file_hash, anim_token);
5173 filename_anim_initial = getStringCopy(filename);
5175 for (j = 0; image_config_suffix[j].token != NULL; j++)
5177 int type = image_config_suffix[j].type;
5178 char *suffix = image_config_suffix[j].token;
5179 char *token = getStringCat2(anim_token, suffix);
5180 char *value = getHashEntry(setup_file_hash, token);
5182 checked_free(token);
5185 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5189 freeSetupFileHash(setup_file_hash);
5193 if (filename_anim_initial == NULL)
5195 /* read settings for busy animation from static default artwork config */
5196 for (i = 0; image_config[i].token != NULL; i++)
5198 if (strEqual(image_config[i].token, anim_token))
5199 filename_anim_initial = getStringCopy(image_config[i].value);
5200 else if (strlen(image_config[i].token) > len_anim_token &&
5201 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5203 for (j = 0; image_config_suffix[j].token != NULL; j++)
5205 if (strEqual(&image_config[i].token[len_anim_token],
5206 image_config_suffix[j].token))
5208 get_graphic_parameter_value(image_config[i].value,
5209 image_config_suffix[j].token,
5210 image_config_suffix[j].type);
5216 if (filename_anim_initial == NULL) /* should not happen */
5217 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5219 anim_initial.bitmaps =
5220 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5222 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5223 LoadCustomImage(filename_anim_initial);
5225 checked_free(filename_anim_initial);
5227 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5229 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5231 graphic_info = graphic_info_last;
5233 init.busy.width = anim_initial.width;
5234 init.busy.height = anim_initial.height;
5236 InitMenuDesignSettings_Static();
5238 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5239 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5240 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5242 gfx.fade_border_source_status = global.border_status;
5243 gfx.fade_border_target_status = global.border_status;
5244 gfx.masked_border_bitmap_ptr = backbuffer;
5246 /* use copy of busy animation to prevent change while reloading artwork */
5250 void InitGfxBackground()
5252 fieldbuffer = bitmap_db_field;
5253 SetDrawtoField(DRAW_BACKBUFFER);
5255 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5257 redraw_mask = REDRAW_ALL;
5260 static void InitLevelInfo()
5262 LoadLevelInfo(); /* global level info */
5263 LoadLevelSetup_LastSeries(); /* last played series info */
5264 LoadLevelSetup_SeriesInfo(); /* last played level info */
5266 if (global.autoplay_leveldir &&
5267 global.autoplay_mode != AUTOPLAY_TEST)
5269 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5270 global.autoplay_leveldir);
5271 if (leveldir_current == NULL)
5272 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5276 static void InitLevelArtworkInfo()
5278 LoadLevelArtworkInfo();
5281 static void InitImages()
5283 print_timestamp_init("InitImages");
5286 printf("::: leveldir_current->identifier == '%s'\n",
5287 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5288 printf("::: leveldir_current->graphics_path == '%s'\n",
5289 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5290 printf("::: leveldir_current->graphics_set == '%s'\n",
5291 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5292 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5293 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5296 setLevelArtworkDir(artwork.gfx_first);
5299 printf("::: leveldir_current->identifier == '%s'\n",
5300 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5301 printf("::: leveldir_current->graphics_path == '%s'\n",
5302 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5303 printf("::: leveldir_current->graphics_set == '%s'\n",
5304 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5305 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5306 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5310 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5311 leveldir_current->identifier,
5312 artwork.gfx_current_identifier,
5313 artwork.gfx_current->identifier,
5314 leveldir_current->graphics_set,
5315 leveldir_current->graphics_path);
5318 UPDATE_BUSY_STATE();
5320 ReloadCustomImages();
5321 print_timestamp_time("ReloadCustomImages");
5323 UPDATE_BUSY_STATE();
5325 LoadCustomElementDescriptions();
5326 print_timestamp_time("LoadCustomElementDescriptions");
5328 UPDATE_BUSY_STATE();
5330 LoadMenuDesignSettings();
5331 print_timestamp_time("LoadMenuDesignSettings");
5333 UPDATE_BUSY_STATE();
5335 ReinitializeGraphics();
5336 print_timestamp_time("ReinitializeGraphics");
5338 UPDATE_BUSY_STATE();
5340 print_timestamp_done("InitImages");
5343 static void InitSound(char *identifier)
5345 print_timestamp_init("InitSound");
5347 if (identifier == NULL)
5348 identifier = artwork.snd_current->identifier;
5350 /* set artwork path to send it to the sound server process */
5351 setLevelArtworkDir(artwork.snd_first);
5353 InitReloadCustomSounds(identifier);
5354 print_timestamp_time("InitReloadCustomSounds");
5356 ReinitializeSounds();
5357 print_timestamp_time("ReinitializeSounds");
5359 print_timestamp_done("InitSound");
5362 static void InitMusic(char *identifier)
5364 print_timestamp_init("InitMusic");
5366 if (identifier == NULL)
5367 identifier = artwork.mus_current->identifier;
5369 /* set artwork path to send it to the sound server process */
5370 setLevelArtworkDir(artwork.mus_first);
5372 InitReloadCustomMusic(identifier);
5373 print_timestamp_time("InitReloadCustomMusic");
5375 ReinitializeMusic();
5376 print_timestamp_time("ReinitializeMusic");
5378 print_timestamp_done("InitMusic");
5381 void InitNetworkServer()
5383 #if defined(NETWORK_AVALIABLE)
5387 if (!options.network)
5390 #if defined(NETWORK_AVALIABLE)
5391 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5393 if (!ConnectToServer(options.server_host, options.server_port))
5394 Error(ERR_EXIT, "cannot connect to network game server");
5396 SendToServer_PlayerName(setup.player_name);
5397 SendToServer_ProtocolVersion();
5400 SendToServer_NrWanted(nr_wanted);
5404 static boolean CheckArtworkConfigForCustomElements(char *filename)
5406 SetupFileHash *setup_file_hash;
5407 boolean redefined_ce_found = FALSE;
5409 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5411 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5413 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5415 char *token = HASH_ITERATION_TOKEN(itr);
5417 if (strPrefix(token, "custom_"))
5419 redefined_ce_found = TRUE;
5424 END_HASH_ITERATION(setup_file_hash, itr)
5426 freeSetupFileHash(setup_file_hash);
5429 return redefined_ce_found;
5432 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5434 char *filename_base, *filename_local;
5435 boolean redefined_ce_found = FALSE;
5437 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5440 printf("::: leveldir_current->identifier == '%s'\n",
5441 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5442 printf("::: leveldir_current->graphics_path == '%s'\n",
5443 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5444 printf("::: leveldir_current->graphics_set == '%s'\n",
5445 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5446 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5447 leveldir_current == NULL ? "[NULL]" :
5448 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5451 /* first look for special artwork configured in level series config */
5452 filename_base = getCustomArtworkLevelConfigFilename(type);
5455 printf("::: filename_base == '%s'\n", filename_base);
5458 if (fileExists(filename_base))
5459 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5461 filename_local = getCustomArtworkConfigFilename(type);
5464 printf("::: filename_local == '%s'\n", filename_local);
5467 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5468 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5471 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5474 return redefined_ce_found;
5477 static void InitOverrideArtwork()
5479 boolean redefined_ce_found = FALSE;
5481 /* to check if this level set redefines any CEs, do not use overriding */
5482 gfx.override_level_graphics = FALSE;
5483 gfx.override_level_sounds = FALSE;
5484 gfx.override_level_music = FALSE;
5486 /* now check if this level set has definitions for custom elements */
5487 if (setup.override_level_graphics == AUTO ||
5488 setup.override_level_sounds == AUTO ||
5489 setup.override_level_music == AUTO)
5490 redefined_ce_found =
5491 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5492 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5493 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5496 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5499 if (redefined_ce_found)
5501 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5502 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5503 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5504 gfx.override_level_music = (setup.override_level_music == TRUE);
5508 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5509 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5510 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5511 gfx.override_level_music = (setup.override_level_music != FALSE);
5515 printf("::: => %d, %d, %d\n",
5516 gfx.override_level_graphics,
5517 gfx.override_level_sounds,
5518 gfx.override_level_music);
5522 static char *getNewArtworkIdentifier(int type)
5524 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5525 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5526 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5527 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5528 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5529 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5530 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5531 char *leveldir_identifier = leveldir_current->identifier;
5532 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5533 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5534 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5535 char *artwork_current_identifier;
5536 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5538 /* leveldir_current may be invalid (level group, parent link) */
5539 if (!validLevelSeries(leveldir_current))
5542 /* 1st step: determine artwork set to be activated in descending order:
5543 --------------------------------------------------------------------
5544 1. setup artwork (when configured to override everything else)
5545 2. artwork set configured in "levelinfo.conf" of current level set
5546 (artwork in level directory will have priority when loading later)
5547 3. artwork in level directory (stored in artwork sub-directory)
5548 4. setup artwork (currently configured in setup menu) */
5550 if (setup_override_artwork)
5551 artwork_current_identifier = setup_artwork_set;
5552 else if (leveldir_artwork_set != NULL)
5553 artwork_current_identifier = leveldir_artwork_set;
5554 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5555 artwork_current_identifier = leveldir_identifier;
5557 artwork_current_identifier = setup_artwork_set;
5560 /* 2nd step: check if it is really needed to reload artwork set
5561 ------------------------------------------------------------ */
5563 /* ---------- reload if level set and also artwork set has changed ------- */
5564 if (leveldir_current_identifier[type] != leveldir_identifier &&
5565 (last_has_level_artwork_set[type] || has_level_artwork_set))
5566 artwork_new_identifier = artwork_current_identifier;
5568 leveldir_current_identifier[type] = leveldir_identifier;
5569 last_has_level_artwork_set[type] = has_level_artwork_set;
5571 /* ---------- reload if "override artwork" setting has changed ----------- */
5572 if (last_override_level_artwork[type] != setup_override_artwork)
5573 artwork_new_identifier = artwork_current_identifier;
5575 last_override_level_artwork[type] = setup_override_artwork;
5577 /* ---------- reload if current artwork identifier has changed ----------- */
5578 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5579 artwork_current_identifier))
5580 artwork_new_identifier = artwork_current_identifier;
5582 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5584 /* ---------- do not reload directly after starting ---------------------- */
5585 if (!initialized[type])
5586 artwork_new_identifier = NULL;
5588 initialized[type] = TRUE;
5590 return artwork_new_identifier;
5593 void ReloadCustomArtwork(int force_reload)
5595 int last_game_status = game_status; /* save current game status */
5596 char *gfx_new_identifier;
5597 char *snd_new_identifier;
5598 char *mus_new_identifier;
5599 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5600 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5601 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5602 boolean reload_needed;
5604 InitOverrideArtwork();
5606 force_reload_gfx |= AdjustGraphicsForEMC();
5608 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5609 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5610 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5612 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5613 snd_new_identifier != NULL || force_reload_snd ||
5614 mus_new_identifier != NULL || force_reload_mus);
5619 print_timestamp_init("ReloadCustomArtwork");
5621 SetGameStatus(GAME_MODE_LOADING);
5623 FadeOut(REDRAW_ALL);
5625 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5626 print_timestamp_time("ClearRectangle");
5630 if (gfx_new_identifier != NULL || force_reload_gfx)
5633 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5634 artwork.gfx_current_identifier,
5636 artwork.gfx_current->identifier,
5637 leveldir_current->graphics_set);
5641 print_timestamp_time("InitImages");
5644 if (snd_new_identifier != NULL || force_reload_snd)
5646 InitSound(snd_new_identifier);
5647 print_timestamp_time("InitSound");
5650 if (mus_new_identifier != NULL || force_reload_mus)
5652 InitMusic(mus_new_identifier);
5653 print_timestamp_time("InitMusic");
5656 SetGameStatus(last_game_status); /* restore current game status */
5658 init_last = init; /* switch to new busy animation */
5660 FadeOut(REDRAW_ALL);
5662 RedrawGlobalBorder();
5664 /* force redraw of (open or closed) door graphics */
5665 SetDoorState(DOOR_OPEN_ALL);
5666 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5668 FadeSetEnterScreen();
5669 FadeSkipNextFadeOut();
5671 print_timestamp_done("ReloadCustomArtwork");
5673 LimitScreenUpdates(FALSE);
5676 void KeyboardAutoRepeatOffUnlessAutoplay()
5678 if (global.autoplay_leveldir == NULL)
5679 KeyboardAutoRepeatOff();
5682 void DisplayExitMessage(char *format, va_list ap)
5684 // check if draw buffer and fonts for exit message are already available
5685 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5688 int font_1 = FC_RED;
5689 int font_2 = FC_YELLOW;
5690 int font_3 = FC_BLUE;
5691 int font_width = getFontWidth(font_2);
5692 int font_height = getFontHeight(font_2);
5695 int sxsize = WIN_XSIZE - 2 * sx;
5696 int sysize = WIN_YSIZE - 2 * sy;
5697 int line_length = sxsize / font_width;
5698 int max_lines = sysize / font_height;
5699 int num_lines_printed;
5703 gfx.sxsize = sxsize;
5704 gfx.sysize = sysize;
5708 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5710 DrawTextSCentered(sy, font_1, "Fatal error:");
5711 sy += 3 * font_height;;
5714 DrawTextBufferVA(sx, sy, format, ap, font_2,
5715 line_length, line_length, max_lines,
5716 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5717 sy += (num_lines_printed + 3) * font_height;
5719 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5720 sy += 3 * font_height;
5723 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5724 line_length, line_length, max_lines,
5725 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5727 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5729 redraw_mask = REDRAW_ALL;
5731 /* force drawing exit message even if screen updates are currently limited */
5732 LimitScreenUpdates(FALSE);
5736 /* deactivate toons on error message screen */
5737 setup.toons = FALSE;
5739 WaitForEventToContinue();
5743 /* ========================================================================= */
5745 /* ========================================================================= */
5749 print_timestamp_init("OpenAll");
5751 SetGameStatus(GAME_MODE_LOADING);
5755 InitGlobal(); /* initialize some global variables */
5757 print_timestamp_time("[init global stuff]");
5761 print_timestamp_time("[init setup/config stuff (1)]");
5763 if (options.execute_command)
5764 Execute_Command(options.execute_command);
5766 if (options.serveronly)
5768 #if defined(PLATFORM_UNIX)
5769 NetworkServer(options.server_port, options.serveronly);
5771 Error(ERR_WARN, "networking only supported in Unix version");
5774 exit(0); /* never reached, server loops forever */
5778 print_timestamp_time("[init setup/config stuff (2)]");
5780 print_timestamp_time("[init setup/config stuff (3)]");
5781 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5782 print_timestamp_time("[init setup/config stuff (4)]");
5783 InitArtworkConfig(); /* needed before forking sound child process */
5784 print_timestamp_time("[init setup/config stuff (5)]");
5786 print_timestamp_time("[init setup/config stuff (6)]");
5788 InitRND(NEW_RANDOMIZE);
5789 InitSimpleRandom(NEW_RANDOMIZE);
5793 print_timestamp_time("[init setup/config stuff]");
5796 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5798 InitEventFilter(FilterEvents);
5800 print_timestamp_time("[init video stuff]");
5802 InitElementPropertiesStatic();
5803 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5804 InitElementPropertiesGfxElement();
5806 print_timestamp_time("[init element properties stuff]");
5810 print_timestamp_time("InitGfx");
5813 print_timestamp_time("InitLevelInfo");
5815 InitLevelArtworkInfo();
5816 print_timestamp_time("InitLevelArtworkInfo");
5818 InitOverrideArtwork(); /* needs to know current level directory */
5819 print_timestamp_time("InitOverrideArtwork");
5821 InitImages(); /* needs to know current level directory */
5822 print_timestamp_time("InitImages");
5824 InitSound(NULL); /* needs to know current level directory */
5825 print_timestamp_time("InitSound");
5827 InitMusic(NULL); /* needs to know current level directory */
5828 print_timestamp_time("InitMusic");
5830 InitGfxBackground();
5835 if (global.autoplay_leveldir)
5840 else if (global.convert_leveldir)
5845 else if (global.create_images_dir)
5847 CreateLevelSketchImages();
5851 SetGameStatus(GAME_MODE_MAIN);
5853 FadeSetEnterScreen();
5854 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5855 FadeSkipNextFadeOut();
5857 print_timestamp_time("[post-artwork]");
5859 print_timestamp_done("OpenAll");
5863 InitNetworkServer();
5866 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5868 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5869 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5870 #if defined(PLATFORM_ANDROID)
5871 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5872 SDL_AndroidGetInternalStoragePath());
5873 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5874 SDL_AndroidGetExternalStoragePath());
5875 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5876 (SDL_AndroidGetExternalStorageState() ==
5877 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5878 SDL_AndroidGetExternalStorageState() ==
5879 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5884 void CloseAllAndExit(int exit_value)
5889 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5896 #if defined(TARGET_SDL)
5897 #if defined(TARGET_SDL2)
5899 // set a flag to tell the network server thread to quit and wait for it
5900 // using SDL_WaitThread()
5902 if (network_server) /* terminate network server */
5903 SDL_KillThread(server_thread);
5907 CloseVideoDisplay();
5908 ClosePlatformDependentStuff();
5910 if (exit_value != 0)
5912 /* fall back to default level set (current set may have caused an error) */
5913 SaveLevelSetup_LastSeries_Deactivate();
5915 /* tell user where to find error log file which may contain more details */
5916 // (error notification now directly displayed on screen inside R'n'D
5917 // NotifyUserAboutErrorFile(); /* currently only works for Windows */