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;
1139 g->fade_mode = FADE_MODE_DEFAULT;
1143 g->align = ALIGN_CENTER; /* default for title screens */
1144 g->valign = VALIGN_MIDDLE; /* default for title screens */
1145 g->sort_priority = 0; /* default for title screens */
1147 g->style = STYLE_DEFAULT;
1149 g->bitmaps = src_bitmaps;
1150 g->bitmap = src_bitmap;
1152 /* optional zoom factor for scaling up the image to a larger size */
1153 if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1154 g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1155 if (g->scale_up_factor < 1)
1156 g->scale_up_factor = 1; /* no scaling */
1158 /* optional tile size for using non-standard image size */
1159 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1161 g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1164 // CHECK: should tile sizes less than standard tile size be allowed?
1165 if (g->tile_size < TILESIZE)
1166 g->tile_size = TILESIZE; /* standard tile size */
1169 // when setting tile size, also set width and height accordingly
1170 g->width = g->tile_size;
1171 g->height = g->tile_size;
1174 if (g->use_image_size)
1176 /* set new default bitmap size (with scaling, but without small images) */
1177 g->width = get_scaled_graphic_width(graphic);
1178 g->height = get_scaled_graphic_height(graphic);
1181 /* optional width and height of each animation frame */
1182 if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1183 g->width = parameter[GFX_ARG_WIDTH];
1184 if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1185 g->height = parameter[GFX_ARG_HEIGHT];
1187 /* optional x and y tile position of animation frame sequence */
1188 if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1189 g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1190 if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1191 g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1193 /* optional x and y pixel position of animation frame sequence */
1194 if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1195 g->src_x = parameter[GFX_ARG_X];
1196 if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1197 g->src_y = parameter[GFX_ARG_Y];
1203 Error(ERR_INFO_LINE, "-");
1204 Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1205 g->width, getTokenFromImageID(graphic), TILEX);
1206 Error(ERR_INFO_LINE, "-");
1208 g->width = TILEX; /* will be checked to be inside bitmap later */
1213 Error(ERR_INFO_LINE, "-");
1214 Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1215 g->height, getTokenFromImageID(graphic), TILEY);
1216 Error(ERR_INFO_LINE, "-");
1218 g->height = TILEY; /* will be checked to be inside bitmap later */
1224 /* get final bitmap size (with scaling, but without small images) */
1225 int src_image_width = get_scaled_graphic_width(graphic);
1226 int src_image_height = get_scaled_graphic_height(graphic);
1228 if (src_image_width == 0 || src_image_height == 0)
1230 /* only happens when loaded outside artwork system (like "global.busy") */
1231 src_image_width = src_bitmap->width;
1232 src_image_height = src_bitmap->height;
1235 if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1237 anim_frames_per_row = src_image_width / g->tile_size;
1238 anim_frames_per_col = src_image_height / g->tile_size;
1242 anim_frames_per_row = src_image_width / g->width;
1243 anim_frames_per_col = src_image_height / g->height;
1246 g->src_image_width = src_image_width;
1247 g->src_image_height = src_image_height;
1250 /* correct x or y offset dependent of vertical or horizontal frame order */
1251 if (parameter[GFX_ARG_VERTICAL]) /* frames are ordered vertically */
1253 g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1254 parameter[GFX_ARG_OFFSET] : g->height);
1255 anim_frames_per_line = anim_frames_per_col;
1257 else /* frames are ordered horizontally */
1259 g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1260 parameter[GFX_ARG_OFFSET] : g->width);
1261 anim_frames_per_line = anim_frames_per_row;
1264 /* optionally, the x and y offset of frames can be specified directly */
1265 if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1266 g->offset_x = parameter[GFX_ARG_XOFFSET];
1267 if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1268 g->offset_y = parameter[GFX_ARG_YOFFSET];
1270 /* optionally, moving animations may have separate start and end graphics */
1271 g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1273 if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1274 parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1276 /* correct x or y offset2 dependent of vertical or horizontal frame order */
1277 if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
1278 g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1279 parameter[GFX_ARG_2ND_OFFSET] : g->height);
1280 else /* frames are ordered horizontally */
1281 g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1282 parameter[GFX_ARG_2ND_OFFSET] : g->width);
1284 /* optionally, the x and y offset of 2nd graphic can be specified directly */
1285 if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1286 g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1287 if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1288 g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1290 /* optionally, the second movement tile can be specified as start tile */
1291 if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1292 g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1294 /* automatically determine correct number of frames, if not defined */
1295 if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1296 g->anim_frames = parameter[GFX_ARG_FRAMES];
1297 else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1298 g->anim_frames = anim_frames_per_row;
1299 else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1300 g->anim_frames = anim_frames_per_col;
1304 if (g->anim_frames == 0) /* frames must be at least 1 */
1307 g->anim_frames_per_line =
1308 (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1309 parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1311 g->anim_delay = parameter[GFX_ARG_DELAY];
1312 if (g->anim_delay == 0) /* delay must be at least 1 */
1315 g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1317 /* automatically determine correct start frame, if not defined */
1318 if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1319 g->anim_start_frame = 0;
1320 else if (g->anim_mode & ANIM_REVERSE)
1321 g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1323 g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1325 /* animation synchronized with global frame counter, not move position */
1326 g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1328 /* optional element for cloning crumble graphics */
1329 if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1330 g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1332 /* optional element for cloning digging graphics */
1333 if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1334 g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1336 /* optional border size for "crumbling" diggable graphics */
1337 if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1338 g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1340 /* used for global animations and player "boring" and "sleeping" actions */
1341 if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1342 g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1343 if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1344 g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1345 if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1346 g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1347 if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1348 g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1349 if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1350 g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1351 if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1352 g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1354 /* used for toon animations and global animations */
1355 g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1356 g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1357 g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1358 g->step_delay = parameter[GFX_ARG_STEP_DELAY];
1359 g->direction = parameter[GFX_ARG_DIRECTION];
1360 g->position = parameter[GFX_ARG_POSITION];
1361 g->x = parameter[GFX_ARG_X]; // (may be uninitialized,
1362 g->y = parameter[GFX_ARG_Y]; // unlike src_x and src_y)
1364 /* this is only used for drawing font characters */
1365 g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1366 g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1368 /* this is only used for drawing envelope graphics */
1369 g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1371 /* used for toon animations and global animations */
1372 g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1374 /* optional graphic for cloning all graphics settings */
1375 if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1376 g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1378 /* optional settings for drawing title screens and title messages */
1379 if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1380 g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1381 if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1382 g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1383 if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1384 g->post_delay = parameter[GFX_ARG_POST_DELAY];
1385 if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1386 g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1387 if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1388 g->align = parameter[GFX_ARG_ALIGN];
1389 if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1390 g->valign = parameter[GFX_ARG_VALIGN];
1391 if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1392 g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1394 if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1395 g->class = parameter[GFX_ARG_CLASS];
1396 if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1397 g->style = parameter[GFX_ARG_STYLE];
1399 /* this is only used for drawing menu buttons and text */
1400 g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1401 g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1402 g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1403 g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1406 static void set_graphic_parameters(int graphic)
1408 struct FileInfo *image = getImageListEntryFromImageID(graphic);
1409 char **parameter_raw = image->parameter;
1410 Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1411 int parameter[NUM_GFX_ARGS];
1414 /* if fallback to default artwork is done, also use the default parameters */
1415 if (image->fallback_to_default)
1416 parameter_raw = image->default_parameter;
1418 /* get integer values from string parameters */
1419 for (i = 0; i < NUM_GFX_ARGS; i++)
1420 parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1421 image_config_suffix[i].token,
1422 image_config_suffix[i].type);
1424 set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1426 UPDATE_BUSY_STATE();
1429 static void set_cloned_graphic_parameters(int graphic)
1431 int fallback_graphic = IMG_CHAR_EXCLAM;
1432 int max_num_images = getImageListSize();
1433 int clone_graphic = graphic_info[graphic].clone_from;
1434 int num_references_followed = 1;
1436 while (graphic_info[clone_graphic].clone_from != -1 &&
1437 num_references_followed < max_num_images)
1439 clone_graphic = graphic_info[clone_graphic].clone_from;
1441 num_references_followed++;
1444 if (num_references_followed >= max_num_images)
1446 Error(ERR_INFO_LINE, "-");
1447 Error(ERR_INFO, "warning: error found in config file:");
1448 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1449 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1450 Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1451 Error(ERR_INFO, "custom graphic rejected for this element/action");
1453 if (graphic == fallback_graphic)
1454 Error(ERR_EXIT, "no fallback graphic available");
1456 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1457 Error(ERR_INFO_LINE, "-");
1459 graphic_info[graphic] = graphic_info[fallback_graphic];
1463 graphic_info[graphic] = graphic_info[clone_graphic];
1464 graphic_info[graphic].clone_from = clone_graphic;
1468 static void InitGraphicInfo()
1470 int fallback_graphic = IMG_CHAR_EXCLAM;
1471 int num_images = getImageListSize();
1474 /* use image size as default values for width and height for these images */
1475 static int full_size_graphics[] =
1478 IMG_GLOBAL_BORDER_MAIN,
1479 IMG_GLOBAL_BORDER_SCORES,
1480 IMG_GLOBAL_BORDER_EDITOR,
1481 IMG_GLOBAL_BORDER_PLAYING,
1484 IMG_BACKGROUND_ENVELOPE_1,
1485 IMG_BACKGROUND_ENVELOPE_2,
1486 IMG_BACKGROUND_ENVELOPE_3,
1487 IMG_BACKGROUND_ENVELOPE_4,
1488 IMG_BACKGROUND_REQUEST,
1491 IMG_BACKGROUND_TITLE_INITIAL,
1492 IMG_BACKGROUND_TITLE,
1493 IMG_BACKGROUND_MAIN,
1494 IMG_BACKGROUND_LEVELS,
1495 IMG_BACKGROUND_LEVELNR,
1496 IMG_BACKGROUND_SCORES,
1497 IMG_BACKGROUND_EDITOR,
1498 IMG_BACKGROUND_INFO,
1499 IMG_BACKGROUND_INFO_ELEMENTS,
1500 IMG_BACKGROUND_INFO_MUSIC,
1501 IMG_BACKGROUND_INFO_CREDITS,
1502 IMG_BACKGROUND_INFO_PROGRAM,
1503 IMG_BACKGROUND_INFO_VERSION,
1504 IMG_BACKGROUND_INFO_LEVELSET,
1505 IMG_BACKGROUND_SETUP,
1506 IMG_BACKGROUND_PLAYING,
1507 IMG_BACKGROUND_DOOR,
1508 IMG_BACKGROUND_TAPE,
1509 IMG_BACKGROUND_PANEL,
1510 IMG_BACKGROUND_PALETTE,
1511 IMG_BACKGROUND_TOOLBOX,
1513 IMG_TITLESCREEN_INITIAL_1,
1514 IMG_TITLESCREEN_INITIAL_2,
1515 IMG_TITLESCREEN_INITIAL_3,
1516 IMG_TITLESCREEN_INITIAL_4,
1517 IMG_TITLESCREEN_INITIAL_5,
1524 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1525 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1526 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1527 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1528 IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1529 IMG_BACKGROUND_TITLEMESSAGE_1,
1530 IMG_BACKGROUND_TITLEMESSAGE_2,
1531 IMG_BACKGROUND_TITLEMESSAGE_3,
1532 IMG_BACKGROUND_TITLEMESSAGE_4,
1533 IMG_BACKGROUND_TITLEMESSAGE_5,
1538 checked_free(graphic_info);
1540 graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1542 /* initialize "use_image_size" flag with default value */
1543 for (i = 0; i < num_images; i++)
1544 graphic_info[i].use_image_size = FALSE;
1546 /* initialize "use_image_size" flag from static configuration above */
1547 for (i = 0; full_size_graphics[i] != -1; i++)
1548 graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1550 /* first set all graphic paramaters ... */
1551 for (i = 0; i < num_images; i++)
1552 set_graphic_parameters(i);
1554 /* ... then copy these parameters for cloned graphics */
1555 for (i = 0; i < num_images; i++)
1556 if (graphic_info[i].clone_from != -1)
1557 set_cloned_graphic_parameters(i);
1559 for (i = 0; i < num_images; i++)
1564 int first_frame, last_frame;
1565 int src_bitmap_width, src_bitmap_height;
1567 /* now check if no animation frames are outside of the loaded image */
1569 if (graphic_info[i].bitmap == NULL)
1570 continue; /* skip check for optional images that are undefined */
1572 /* get image size (this can differ from the standard element tile size!) */
1573 width = graphic_info[i].width;
1574 height = graphic_info[i].height;
1576 /* get final bitmap size (with scaling, but without small images) */
1577 src_bitmap_width = graphic_info[i].src_image_width;
1578 src_bitmap_height = graphic_info[i].src_image_height;
1580 /* check if first animation frame is inside specified bitmap */
1583 getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1585 /* this avoids calculating wrong start position for out-of-bounds frame */
1586 src_x = graphic_info[i].src_x;
1587 src_y = graphic_info[i].src_y;
1589 if (src_x < 0 || src_y < 0 ||
1590 src_x + width > src_bitmap_width ||
1591 src_y + height > src_bitmap_height)
1593 Error(ERR_INFO_LINE, "-");
1594 Error(ERR_INFO, "warning: error found in config file:");
1595 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1596 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1597 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1599 "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1600 src_x, src_y, src_bitmap_width, src_bitmap_height);
1601 Error(ERR_INFO, "custom graphic rejected for this element/action");
1603 if (i == fallback_graphic)
1604 Error(ERR_EXIT, "no fallback graphic available");
1606 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1607 Error(ERR_INFO_LINE, "-");
1609 graphic_info[i] = graphic_info[fallback_graphic];
1612 /* check if last animation frame is inside specified bitmap */
1614 last_frame = graphic_info[i].anim_frames - 1;
1615 getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1617 if (src_x < 0 || src_y < 0 ||
1618 src_x + width > src_bitmap_width ||
1619 src_y + height > src_bitmap_height)
1621 Error(ERR_INFO_LINE, "-");
1622 Error(ERR_INFO, "warning: error found in config file:");
1623 Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1624 Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1625 Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1627 "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1628 last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1629 Error(ERR_INFO, "::: %d, %d", width, height);
1630 Error(ERR_INFO, "custom graphic rejected for this element/action");
1632 if (i == fallback_graphic)
1633 Error(ERR_EXIT, "no fallback graphic available");
1635 Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1636 Error(ERR_INFO_LINE, "-");
1638 graphic_info[i] = graphic_info[fallback_graphic];
1643 static void InitGraphicCompatibilityInfo()
1645 struct FileInfo *fi_global_door =
1646 getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1647 int num_images = getImageListSize();
1650 /* the following compatibility handling is needed for the following case:
1651 versions up to 3.3.0.0 used one large bitmap "global.door" for various
1652 graphics mainly used for door and panel graphics, like editor, tape and
1653 in-game buttons with hard-coded bitmap positions and button sizes; as
1654 these graphics now have individual definitions, redefining "global.door"
1655 to change all these graphics at once like before does not work anymore
1656 (because all those individual definitions still have their default values);
1657 to solve this, remap all those individual definitions that are not
1658 redefined to the new bitmap of "global.door" if it was redefined */
1660 /* special compatibility handling if image "global.door" was redefined */
1661 if (fi_global_door->redefined)
1663 for (i = 0; i < num_images; i++)
1665 struct FileInfo *fi = getImageListEntryFromImageID(i);
1667 /* process only those images that still use the default settings */
1670 /* process all images which default to same image as "global.door" */
1671 if (strEqual(fi->default_filename, fi_global_door->default_filename))
1673 // printf("::: special treatment needed for token '%s'\n", fi->token);
1675 graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1681 InitGraphicCompatibilityInfo_Doors();
1684 static void InitElementSoundInfo()
1686 struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1687 int num_property_mappings = getSoundListPropertyMappingSize();
1690 /* set values to -1 to identify later as "uninitialized" values */
1691 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1692 for (act = 0; act < NUM_ACTIONS; act++)
1693 element_info[i].sound[act] = -1;
1695 /* initialize element/sound mapping from static configuration */
1696 for (i = 0; element_to_sound[i].element > -1; i++)
1698 int element = element_to_sound[i].element;
1699 int action = element_to_sound[i].action;
1700 int sound = element_to_sound[i].sound;
1701 boolean is_class = element_to_sound[i].is_class;
1704 action = ACTION_DEFAULT;
1707 element_info[element].sound[action] = sound;
1709 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1710 if (strEqual(element_info[j].class_name,
1711 element_info[element].class_name))
1712 element_info[j].sound[action] = sound;
1715 /* initialize element class/sound mapping from dynamic configuration */
1716 for (i = 0; i < num_property_mappings; i++)
1718 int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1719 int action = property_mapping[i].ext1_index;
1720 int sound = property_mapping[i].artwork_index;
1722 if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1726 action = ACTION_DEFAULT;
1728 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1729 if (strEqual(element_info[j].class_name,
1730 element_info[element_class].class_name))
1731 element_info[j].sound[action] = sound;
1734 /* initialize element/sound mapping from dynamic configuration */
1735 for (i = 0; i < num_property_mappings; i++)
1737 int element = property_mapping[i].base_index;
1738 int action = property_mapping[i].ext1_index;
1739 int sound = property_mapping[i].artwork_index;
1741 if (element >= MAX_NUM_ELEMENTS)
1745 action = ACTION_DEFAULT;
1747 element_info[element].sound[action] = sound;
1750 /* now set all '-1' values to element specific default values */
1751 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1753 for (act = 0; act < NUM_ACTIONS; act++)
1755 /* generic default action sound (defined by "[default]" directive) */
1756 int default_action_sound = element_info[EL_DEFAULT].sound[act];
1758 /* look for special default action sound (classic game specific) */
1759 if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1760 default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1761 if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1762 default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1763 if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1764 default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1766 /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1767 /* !!! make this better !!! */
1768 if (i == EL_EMPTY_SPACE)
1769 default_action_sound = element_info[EL_DEFAULT].sound[act];
1771 /* no sound for this specific action -- use default action sound */
1772 if (element_info[i].sound[act] == -1)
1773 element_info[i].sound[act] = default_action_sound;
1777 /* copy sound settings to some elements that are only stored in level file
1778 in native R'n'D levels, but are used by game engine in native EM levels */
1779 for (i = 0; copy_properties[i][0] != -1; i++)
1780 for (j = 1; j <= 4; j++)
1781 for (act = 0; act < NUM_ACTIONS; act++)
1782 element_info[copy_properties[i][j]].sound[act] =
1783 element_info[copy_properties[i][0]].sound[act];
1786 static void InitGameModeSoundInfo()
1790 /* set values to -1 to identify later as "uninitialized" values */
1791 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1794 /* initialize gamemode/sound mapping from static configuration */
1795 for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1797 int gamemode = gamemode_to_sound[i].gamemode;
1798 int sound = gamemode_to_sound[i].sound;
1801 gamemode = GAME_MODE_DEFAULT;
1803 menu.sound[gamemode] = sound;
1806 /* now set all '-1' values to levelset specific default values */
1807 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1808 if (menu.sound[i] == -1)
1809 menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1812 static void set_sound_parameters(int sound, char **parameter_raw)
1814 int parameter[NUM_SND_ARGS];
1817 /* get integer values from string parameters */
1818 for (i = 0; i < NUM_SND_ARGS; i++)
1820 get_parameter_value(parameter_raw[i],
1821 sound_config_suffix[i].token,
1822 sound_config_suffix[i].type);
1824 /* explicit loop mode setting in configuration overrides default value */
1825 if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1826 sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1828 /* sound volume to change the original volume when loading the sound file */
1829 sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1831 /* sound priority to give certain sounds a higher or lower priority */
1832 sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1835 static void InitSoundInfo()
1837 int *sound_effect_properties;
1838 int num_sounds = getSoundListSize();
1841 checked_free(sound_info);
1843 sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1844 sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1846 /* initialize sound effect for all elements to "no sound" */
1847 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1848 for (j = 0; j < NUM_ACTIONS; j++)
1849 element_info[i].sound[j] = SND_UNDEFINED;
1851 for (i = 0; i < num_sounds; i++)
1853 struct FileInfo *sound = getSoundListEntry(i);
1854 int len_effect_text = strlen(sound->token);
1856 sound_effect_properties[i] = ACTION_OTHER;
1857 sound_info[i].loop = FALSE; /* default: play sound only once */
1859 /* determine all loop sounds and identify certain sound classes */
1861 for (j = 0; element_action_info[j].suffix; j++)
1863 int len_action_text = strlen(element_action_info[j].suffix);
1865 if (len_action_text < len_effect_text &&
1866 strEqual(&sound->token[len_effect_text - len_action_text],
1867 element_action_info[j].suffix))
1869 sound_effect_properties[i] = element_action_info[j].value;
1870 sound_info[i].loop = element_action_info[j].is_loop_sound;
1876 /* associate elements and some selected sound actions */
1878 for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1880 if (element_info[j].class_name)
1882 int len_class_text = strlen(element_info[j].class_name);
1884 if (len_class_text + 1 < len_effect_text &&
1885 strncmp(sound->token,
1886 element_info[j].class_name, len_class_text) == 0 &&
1887 sound->token[len_class_text] == '.')
1889 int sound_action_value = sound_effect_properties[i];
1891 element_info[j].sound[sound_action_value] = i;
1896 set_sound_parameters(i, sound->parameter);
1899 free(sound_effect_properties);
1902 static void InitGameModeMusicInfo()
1904 struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1905 int num_property_mappings = getMusicListPropertyMappingSize();
1906 int default_levelset_music = -1;
1909 /* set values to -1 to identify later as "uninitialized" values */
1910 for (i = 0; i < MAX_LEVELS; i++)
1911 levelset.music[i] = -1;
1912 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1915 /* initialize gamemode/music mapping from static configuration */
1916 for (i = 0; gamemode_to_music[i].music > -1; i++)
1918 int gamemode = gamemode_to_music[i].gamemode;
1919 int music = gamemode_to_music[i].music;
1922 gamemode = GAME_MODE_DEFAULT;
1924 menu.music[gamemode] = music;
1927 /* initialize gamemode/music mapping from dynamic configuration */
1928 for (i = 0; i < num_property_mappings; i++)
1930 int prefix = property_mapping[i].base_index;
1931 int gamemode = property_mapping[i].ext1_index;
1932 int level = property_mapping[i].ext2_index;
1933 int music = property_mapping[i].artwork_index;
1935 if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1939 gamemode = GAME_MODE_DEFAULT;
1941 /* level specific music only allowed for in-game music */
1942 if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1943 gamemode = GAME_MODE_PLAYING;
1948 default_levelset_music = music;
1951 if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1952 levelset.music[level] = music;
1953 if (gamemode != GAME_MODE_PLAYING)
1954 menu.music[gamemode] = music;
1957 /* now set all '-1' values to menu specific default values */
1958 /* (undefined values of "levelset.music[]" might stay at "-1" to
1959 allow dynamic selection of music files from music directory!) */
1960 for (i = 0; i < MAX_LEVELS; i++)
1961 if (levelset.music[i] == -1)
1962 levelset.music[i] = default_levelset_music;
1963 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1964 if (menu.music[i] == -1)
1965 menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1968 static void set_music_parameters(int music, char **parameter_raw)
1970 int parameter[NUM_MUS_ARGS];
1973 /* get integer values from string parameters */
1974 for (i = 0; i < NUM_MUS_ARGS; i++)
1976 get_parameter_value(parameter_raw[i],
1977 music_config_suffix[i].token,
1978 music_config_suffix[i].type);
1980 /* explicit loop mode setting in configuration overrides default value */
1981 if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1982 music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1985 static void InitMusicInfo()
1987 int num_music = getMusicListSize();
1990 checked_free(music_info);
1992 music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1994 for (i = 0; i < num_music; i++)
1996 struct FileInfo *music = getMusicListEntry(i);
1997 int len_music_text = strlen(music->token);
1999 music_info[i].loop = TRUE; /* default: play music in loop mode */
2001 /* determine all loop music */
2003 for (j = 0; music_prefix_info[j].prefix; j++)
2005 int len_prefix_text = strlen(music_prefix_info[j].prefix);
2007 if (len_prefix_text < len_music_text &&
2008 strncmp(music->token,
2009 music_prefix_info[j].prefix, len_prefix_text) == 0)
2011 music_info[i].loop = music_prefix_info[j].is_loop_music;
2017 set_music_parameters(i, music->parameter);
2021 static void ReinitializeGraphics()
2023 print_timestamp_init("ReinitializeGraphics");
2025 InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2027 InitGraphicInfo(); /* graphic properties mapping */
2028 print_timestamp_time("InitGraphicInfo");
2029 InitElementGraphicInfo(); /* element game graphic mapping */
2030 print_timestamp_time("InitElementGraphicInfo");
2031 InitElementSpecialGraphicInfo(); /* element special graphic mapping */
2032 print_timestamp_time("InitElementSpecialGraphicInfo");
2034 InitElementSmallImages(); /* scale elements to all needed sizes */
2035 print_timestamp_time("InitElementSmallImages");
2036 InitScaledImages(); /* scale all other images, if needed */
2037 print_timestamp_time("InitScaledImages");
2038 InitBitmapPointers(); /* set standard size bitmap pointers */
2039 print_timestamp_time("InitBitmapPointers");
2040 InitFontGraphicInfo(); /* initialize text drawing functions */
2041 print_timestamp_time("InitFontGraphicInfo");
2042 InitGlobalAnimGraphicInfo(); /* initialize global animation config */
2043 print_timestamp_time("InitGlobalAnimGraphicInfo");
2045 InitImageTextures(); /* create textures for certain images */
2046 print_timestamp_time("InitImageTextures");
2048 InitGraphicInfo_EM(); /* graphic mapping for EM engine */
2049 print_timestamp_time("InitGraphicInfo_EM");
2051 InitGraphicCompatibilityInfo();
2052 print_timestamp_time("InitGraphicCompatibilityInfo");
2054 SetMainBackgroundImage(IMG_BACKGROUND);
2055 print_timestamp_time("SetMainBackgroundImage");
2056 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2057 print_timestamp_time("SetDoorBackgroundImage");
2060 print_timestamp_time("InitGadgets");
2062 print_timestamp_time("InitToons");
2064 print_timestamp_time("InitDoors");
2066 print_timestamp_done("ReinitializeGraphics");
2069 static void ReinitializeSounds()
2071 InitSoundInfo(); /* sound properties mapping */
2072 InitElementSoundInfo(); /* element game sound mapping */
2073 InitGameModeSoundInfo(); /* game mode sound mapping */
2075 InitPlayLevelSound(); /* internal game sound settings */
2078 static void ReinitializeMusic()
2080 InitMusicInfo(); /* music properties mapping */
2081 InitGameModeMusicInfo(); /* game mode music mapping */
2084 static int get_special_property_bit(int element, int property_bit_nr)
2086 struct PropertyBitInfo
2092 static struct PropertyBitInfo pb_can_move_into_acid[] =
2094 /* the player may be able fall into acid when gravity is activated */
2099 { EL_SP_MURPHY, 0 },
2100 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2102 /* all elements that can move may be able to also move into acid */
2105 { EL_BUG_RIGHT, 1 },
2108 { EL_SPACESHIP, 2 },
2109 { EL_SPACESHIP_LEFT, 2 },
2110 { EL_SPACESHIP_RIGHT, 2 },
2111 { EL_SPACESHIP_UP, 2 },
2112 { EL_SPACESHIP_DOWN, 2 },
2113 { EL_BD_BUTTERFLY, 3 },
2114 { EL_BD_BUTTERFLY_LEFT, 3 },
2115 { EL_BD_BUTTERFLY_RIGHT, 3 },
2116 { EL_BD_BUTTERFLY_UP, 3 },
2117 { EL_BD_BUTTERFLY_DOWN, 3 },
2118 { EL_BD_FIREFLY, 4 },
2119 { EL_BD_FIREFLY_LEFT, 4 },
2120 { EL_BD_FIREFLY_RIGHT, 4 },
2121 { EL_BD_FIREFLY_UP, 4 },
2122 { EL_BD_FIREFLY_DOWN, 4 },
2124 { EL_YAMYAM_LEFT, 5 },
2125 { EL_YAMYAM_RIGHT, 5 },
2126 { EL_YAMYAM_UP, 5 },
2127 { EL_YAMYAM_DOWN, 5 },
2128 { EL_DARK_YAMYAM, 6 },
2131 { EL_PACMAN_LEFT, 8 },
2132 { EL_PACMAN_RIGHT, 8 },
2133 { EL_PACMAN_UP, 8 },
2134 { EL_PACMAN_DOWN, 8 },
2136 { EL_MOLE_LEFT, 9 },
2137 { EL_MOLE_RIGHT, 9 },
2139 { EL_MOLE_DOWN, 9 },
2143 { EL_SATELLITE, 13 },
2144 { EL_SP_SNIKSNAK, 14 },
2145 { EL_SP_ELECTRON, 15 },
2148 { EL_EMC_ANDROID, 18 },
2153 static struct PropertyBitInfo pb_dont_collide_with[] =
2155 { EL_SP_SNIKSNAK, 0 },
2156 { EL_SP_ELECTRON, 1 },
2164 struct PropertyBitInfo *pb_info;
2167 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2168 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2173 struct PropertyBitInfo *pb_info = NULL;
2176 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2177 if (pb_definition[i].bit_nr == property_bit_nr)
2178 pb_info = pb_definition[i].pb_info;
2180 if (pb_info == NULL)
2183 for (i = 0; pb_info[i].element != -1; i++)
2184 if (pb_info[i].element == element)
2185 return pb_info[i].bit_nr;
2190 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2191 boolean property_value)
2193 int bit_nr = get_special_property_bit(element, property_bit_nr);
2198 *bitfield |= (1 << bit_nr);
2200 *bitfield &= ~(1 << bit_nr);
2204 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2206 int bit_nr = get_special_property_bit(element, property_bit_nr);
2209 return ((*bitfield & (1 << bit_nr)) != 0);
2214 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2216 static int group_nr;
2217 static struct ElementGroupInfo *group;
2218 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2221 if (actual_group == NULL) /* not yet initialized */
2224 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2226 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2227 group_element - EL_GROUP_START + 1);
2229 /* replace element which caused too deep recursion by question mark */
2230 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2235 if (recursion_depth == 0) /* initialization */
2237 group = actual_group;
2238 group_nr = GROUP_NR(group_element);
2240 group->num_elements_resolved = 0;
2241 group->choice_pos = 0;
2243 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2244 element_info[i].in_group[group_nr] = FALSE;
2247 for (i = 0; i < actual_group->num_elements; i++)
2249 int element = actual_group->element[i];
2251 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2254 if (IS_GROUP_ELEMENT(element))
2255 ResolveGroupElementExt(element, recursion_depth + 1);
2258 group->element_resolved[group->num_elements_resolved++] = element;
2259 element_info[element].in_group[group_nr] = TRUE;
2264 void ResolveGroupElement(int group_element)
2266 ResolveGroupElementExt(group_element, 0);
2269 void InitElementPropertiesStatic()
2271 static boolean clipboard_elements_initialized = FALSE;
2273 static int ep_diggable[] =
2278 EL_SP_BUGGY_BASE_ACTIVATING,
2281 EL_INVISIBLE_SAND_ACTIVE,
2284 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2285 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2290 EL_SP_BUGGY_BASE_ACTIVE,
2297 static int ep_collectible_only[] =
2319 EL_DYNABOMB_INCREASE_NUMBER,
2320 EL_DYNABOMB_INCREASE_SIZE,
2321 EL_DYNABOMB_INCREASE_POWER,
2339 /* !!! handle separately !!! */
2340 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2346 static int ep_dont_run_into[] =
2348 /* same elements as in 'ep_dont_touch' */
2354 /* same elements as in 'ep_dont_collide_with' */
2366 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2371 EL_SP_BUGGY_BASE_ACTIVE,
2378 static int ep_dont_collide_with[] =
2380 /* same elements as in 'ep_dont_touch' */
2397 static int ep_dont_touch[] =
2407 static int ep_indestructible[] =
2411 EL_ACID_POOL_TOPLEFT,
2412 EL_ACID_POOL_TOPRIGHT,
2413 EL_ACID_POOL_BOTTOMLEFT,
2414 EL_ACID_POOL_BOTTOM,
2415 EL_ACID_POOL_BOTTOMRIGHT,
2416 EL_SP_HARDWARE_GRAY,
2417 EL_SP_HARDWARE_GREEN,
2418 EL_SP_HARDWARE_BLUE,
2420 EL_SP_HARDWARE_YELLOW,
2421 EL_SP_HARDWARE_BASE_1,
2422 EL_SP_HARDWARE_BASE_2,
2423 EL_SP_HARDWARE_BASE_3,
2424 EL_SP_HARDWARE_BASE_4,
2425 EL_SP_HARDWARE_BASE_5,
2426 EL_SP_HARDWARE_BASE_6,
2427 EL_INVISIBLE_STEELWALL,
2428 EL_INVISIBLE_STEELWALL_ACTIVE,
2429 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2430 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2431 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2432 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2433 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2434 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2435 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2436 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2437 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2438 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2439 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2440 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2442 EL_LIGHT_SWITCH_ACTIVE,
2443 EL_SIGN_EXCLAMATION,
2444 EL_SIGN_RADIOACTIVITY,
2451 EL_SIGN_ENTRY_FORBIDDEN,
2452 EL_SIGN_EMERGENCY_EXIT,
2460 EL_STEEL_EXIT_CLOSED,
2462 EL_STEEL_EXIT_OPENING,
2463 EL_STEEL_EXIT_CLOSING,
2464 EL_EM_STEEL_EXIT_CLOSED,
2465 EL_EM_STEEL_EXIT_OPEN,
2466 EL_EM_STEEL_EXIT_OPENING,
2467 EL_EM_STEEL_EXIT_CLOSING,
2468 EL_DC_STEELWALL_1_LEFT,
2469 EL_DC_STEELWALL_1_RIGHT,
2470 EL_DC_STEELWALL_1_TOP,
2471 EL_DC_STEELWALL_1_BOTTOM,
2472 EL_DC_STEELWALL_1_HORIZONTAL,
2473 EL_DC_STEELWALL_1_VERTICAL,
2474 EL_DC_STEELWALL_1_TOPLEFT,
2475 EL_DC_STEELWALL_1_TOPRIGHT,
2476 EL_DC_STEELWALL_1_BOTTOMLEFT,
2477 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2478 EL_DC_STEELWALL_1_TOPLEFT_2,
2479 EL_DC_STEELWALL_1_TOPRIGHT_2,
2480 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2481 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2482 EL_DC_STEELWALL_2_LEFT,
2483 EL_DC_STEELWALL_2_RIGHT,
2484 EL_DC_STEELWALL_2_TOP,
2485 EL_DC_STEELWALL_2_BOTTOM,
2486 EL_DC_STEELWALL_2_HORIZONTAL,
2487 EL_DC_STEELWALL_2_VERTICAL,
2488 EL_DC_STEELWALL_2_MIDDLE,
2489 EL_DC_STEELWALL_2_SINGLE,
2490 EL_STEELWALL_SLIPPERY,
2504 EL_GATE_1_GRAY_ACTIVE,
2505 EL_GATE_2_GRAY_ACTIVE,
2506 EL_GATE_3_GRAY_ACTIVE,
2507 EL_GATE_4_GRAY_ACTIVE,
2516 EL_EM_GATE_1_GRAY_ACTIVE,
2517 EL_EM_GATE_2_GRAY_ACTIVE,
2518 EL_EM_GATE_3_GRAY_ACTIVE,
2519 EL_EM_GATE_4_GRAY_ACTIVE,
2528 EL_EMC_GATE_5_GRAY_ACTIVE,
2529 EL_EMC_GATE_6_GRAY_ACTIVE,
2530 EL_EMC_GATE_7_GRAY_ACTIVE,
2531 EL_EMC_GATE_8_GRAY_ACTIVE,
2533 EL_DC_GATE_WHITE_GRAY,
2534 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2535 EL_DC_GATE_FAKE_GRAY,
2537 EL_SWITCHGATE_OPENING,
2538 EL_SWITCHGATE_CLOSED,
2539 EL_SWITCHGATE_CLOSING,
2540 EL_DC_SWITCHGATE_SWITCH_UP,
2541 EL_DC_SWITCHGATE_SWITCH_DOWN,
2543 EL_TIMEGATE_OPENING,
2545 EL_TIMEGATE_CLOSING,
2546 EL_DC_TIMEGATE_SWITCH,
2547 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2551 EL_TUBE_VERTICAL_LEFT,
2552 EL_TUBE_VERTICAL_RIGHT,
2553 EL_TUBE_HORIZONTAL_UP,
2554 EL_TUBE_HORIZONTAL_DOWN,
2559 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2560 EL_EXPANDABLE_STEELWALL_VERTICAL,
2561 EL_EXPANDABLE_STEELWALL_ANY,
2566 static int ep_slippery[] =
2580 EL_ROBOT_WHEEL_ACTIVE,
2586 EL_ACID_POOL_TOPLEFT,
2587 EL_ACID_POOL_TOPRIGHT,
2597 EL_STEELWALL_SLIPPERY,
2600 EL_EMC_WALL_SLIPPERY_1,
2601 EL_EMC_WALL_SLIPPERY_2,
2602 EL_EMC_WALL_SLIPPERY_3,
2603 EL_EMC_WALL_SLIPPERY_4,
2605 EL_EMC_MAGIC_BALL_ACTIVE,
2610 static int ep_can_change[] =
2615 static int ep_can_move[] =
2617 /* same elements as in 'pb_can_move_into_acid' */
2640 static int ep_can_fall[] =
2654 EL_QUICKSAND_FAST_FULL,
2656 EL_BD_MAGIC_WALL_FULL,
2657 EL_DC_MAGIC_WALL_FULL,
2671 static int ep_can_smash_player[] =
2697 static int ep_can_smash_enemies[] =
2706 static int ep_can_smash_everything[] =
2715 static int ep_explodes_by_fire[] =
2717 /* same elements as in 'ep_explodes_impact' */
2722 /* same elements as in 'ep_explodes_smashed' */
2732 EL_EM_DYNAMITE_ACTIVE,
2733 EL_DYNABOMB_PLAYER_1_ACTIVE,
2734 EL_DYNABOMB_PLAYER_2_ACTIVE,
2735 EL_DYNABOMB_PLAYER_3_ACTIVE,
2736 EL_DYNABOMB_PLAYER_4_ACTIVE,
2737 EL_DYNABOMB_INCREASE_NUMBER,
2738 EL_DYNABOMB_INCREASE_SIZE,
2739 EL_DYNABOMB_INCREASE_POWER,
2740 EL_SP_DISK_RED_ACTIVE,
2754 static int ep_explodes_smashed[] =
2756 /* same elements as in 'ep_explodes_impact' */
2770 static int ep_explodes_impact[] =
2779 static int ep_walkable_over[] =
2783 EL_SOKOBAN_FIELD_EMPTY,
2790 EL_EM_STEEL_EXIT_OPEN,
2791 EL_EM_STEEL_EXIT_OPENING,
2800 EL_GATE_1_GRAY_ACTIVE,
2801 EL_GATE_2_GRAY_ACTIVE,
2802 EL_GATE_3_GRAY_ACTIVE,
2803 EL_GATE_4_GRAY_ACTIVE,
2811 static int ep_walkable_inside[] =
2816 EL_TUBE_VERTICAL_LEFT,
2817 EL_TUBE_VERTICAL_RIGHT,
2818 EL_TUBE_HORIZONTAL_UP,
2819 EL_TUBE_HORIZONTAL_DOWN,
2828 static int ep_walkable_under[] =
2833 static int ep_passable_over[] =
2843 EL_EM_GATE_1_GRAY_ACTIVE,
2844 EL_EM_GATE_2_GRAY_ACTIVE,
2845 EL_EM_GATE_3_GRAY_ACTIVE,
2846 EL_EM_GATE_4_GRAY_ACTIVE,
2855 EL_EMC_GATE_5_GRAY_ACTIVE,
2856 EL_EMC_GATE_6_GRAY_ACTIVE,
2857 EL_EMC_GATE_7_GRAY_ACTIVE,
2858 EL_EMC_GATE_8_GRAY_ACTIVE,
2860 EL_DC_GATE_WHITE_GRAY,
2861 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2868 static int ep_passable_inside[] =
2874 EL_SP_PORT_HORIZONTAL,
2875 EL_SP_PORT_VERTICAL,
2877 EL_SP_GRAVITY_PORT_LEFT,
2878 EL_SP_GRAVITY_PORT_RIGHT,
2879 EL_SP_GRAVITY_PORT_UP,
2880 EL_SP_GRAVITY_PORT_DOWN,
2881 EL_SP_GRAVITY_ON_PORT_LEFT,
2882 EL_SP_GRAVITY_ON_PORT_RIGHT,
2883 EL_SP_GRAVITY_ON_PORT_UP,
2884 EL_SP_GRAVITY_ON_PORT_DOWN,
2885 EL_SP_GRAVITY_OFF_PORT_LEFT,
2886 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2887 EL_SP_GRAVITY_OFF_PORT_UP,
2888 EL_SP_GRAVITY_OFF_PORT_DOWN,
2893 static int ep_passable_under[] =
2898 static int ep_droppable[] =
2903 static int ep_explodes_1x1_old[] =
2908 static int ep_pushable[] =
2920 EL_SOKOBAN_FIELD_FULL,
2929 static int ep_explodes_cross_old[] =
2934 static int ep_protected[] =
2936 /* same elements as in 'ep_walkable_inside' */
2940 EL_TUBE_VERTICAL_LEFT,
2941 EL_TUBE_VERTICAL_RIGHT,
2942 EL_TUBE_HORIZONTAL_UP,
2943 EL_TUBE_HORIZONTAL_DOWN,
2949 /* same elements as in 'ep_passable_over' */
2958 EL_EM_GATE_1_GRAY_ACTIVE,
2959 EL_EM_GATE_2_GRAY_ACTIVE,
2960 EL_EM_GATE_3_GRAY_ACTIVE,
2961 EL_EM_GATE_4_GRAY_ACTIVE,
2970 EL_EMC_GATE_5_GRAY_ACTIVE,
2971 EL_EMC_GATE_6_GRAY_ACTIVE,
2972 EL_EMC_GATE_7_GRAY_ACTIVE,
2973 EL_EMC_GATE_8_GRAY_ACTIVE,
2975 EL_DC_GATE_WHITE_GRAY,
2976 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2980 /* same elements as in 'ep_passable_inside' */
2985 EL_SP_PORT_HORIZONTAL,
2986 EL_SP_PORT_VERTICAL,
2988 EL_SP_GRAVITY_PORT_LEFT,
2989 EL_SP_GRAVITY_PORT_RIGHT,
2990 EL_SP_GRAVITY_PORT_UP,
2991 EL_SP_GRAVITY_PORT_DOWN,
2992 EL_SP_GRAVITY_ON_PORT_LEFT,
2993 EL_SP_GRAVITY_ON_PORT_RIGHT,
2994 EL_SP_GRAVITY_ON_PORT_UP,
2995 EL_SP_GRAVITY_ON_PORT_DOWN,
2996 EL_SP_GRAVITY_OFF_PORT_LEFT,
2997 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2998 EL_SP_GRAVITY_OFF_PORT_UP,
2999 EL_SP_GRAVITY_OFF_PORT_DOWN,
3004 static int ep_throwable[] =
3009 static int ep_can_explode[] =
3011 /* same elements as in 'ep_explodes_impact' */
3016 /* same elements as in 'ep_explodes_smashed' */
3022 /* elements that can explode by explosion or by dragonfire */
3026 EL_EM_DYNAMITE_ACTIVE,
3027 EL_DYNABOMB_PLAYER_1_ACTIVE,
3028 EL_DYNABOMB_PLAYER_2_ACTIVE,
3029 EL_DYNABOMB_PLAYER_3_ACTIVE,
3030 EL_DYNABOMB_PLAYER_4_ACTIVE,
3031 EL_DYNABOMB_INCREASE_NUMBER,
3032 EL_DYNABOMB_INCREASE_SIZE,
3033 EL_DYNABOMB_INCREASE_POWER,
3034 EL_SP_DISK_RED_ACTIVE,
3042 /* elements that can explode only by explosion */
3048 static int ep_gravity_reachable[] =
3054 EL_INVISIBLE_SAND_ACTIVE,
3059 EL_SP_PORT_HORIZONTAL,
3060 EL_SP_PORT_VERTICAL,
3062 EL_SP_GRAVITY_PORT_LEFT,
3063 EL_SP_GRAVITY_PORT_RIGHT,
3064 EL_SP_GRAVITY_PORT_UP,
3065 EL_SP_GRAVITY_PORT_DOWN,
3066 EL_SP_GRAVITY_ON_PORT_LEFT,
3067 EL_SP_GRAVITY_ON_PORT_RIGHT,
3068 EL_SP_GRAVITY_ON_PORT_UP,
3069 EL_SP_GRAVITY_ON_PORT_DOWN,
3070 EL_SP_GRAVITY_OFF_PORT_LEFT,
3071 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3072 EL_SP_GRAVITY_OFF_PORT_UP,
3073 EL_SP_GRAVITY_OFF_PORT_DOWN,
3079 static int ep_player[] =
3086 EL_SOKOBAN_FIELD_PLAYER,
3092 static int ep_can_pass_magic_wall[] =
3106 static int ep_can_pass_dc_magic_wall[] =
3122 static int ep_switchable[] =
3126 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3127 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3128 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3129 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3130 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3131 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3132 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3133 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3134 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3135 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3136 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3137 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3138 EL_SWITCHGATE_SWITCH_UP,
3139 EL_SWITCHGATE_SWITCH_DOWN,
3140 EL_DC_SWITCHGATE_SWITCH_UP,
3141 EL_DC_SWITCHGATE_SWITCH_DOWN,
3143 EL_LIGHT_SWITCH_ACTIVE,
3145 EL_DC_TIMEGATE_SWITCH,
3146 EL_BALLOON_SWITCH_LEFT,
3147 EL_BALLOON_SWITCH_RIGHT,
3148 EL_BALLOON_SWITCH_UP,
3149 EL_BALLOON_SWITCH_DOWN,
3150 EL_BALLOON_SWITCH_ANY,
3151 EL_BALLOON_SWITCH_NONE,
3154 EL_EMC_MAGIC_BALL_SWITCH,
3155 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3160 static int ep_bd_element[] =
3194 static int ep_sp_element[] =
3196 /* should always be valid */
3199 /* standard classic Supaplex elements */
3206 EL_SP_HARDWARE_GRAY,
3214 EL_SP_GRAVITY_PORT_RIGHT,
3215 EL_SP_GRAVITY_PORT_DOWN,
3216 EL_SP_GRAVITY_PORT_LEFT,
3217 EL_SP_GRAVITY_PORT_UP,
3222 EL_SP_PORT_VERTICAL,
3223 EL_SP_PORT_HORIZONTAL,
3229 EL_SP_HARDWARE_BASE_1,
3230 EL_SP_HARDWARE_GREEN,
3231 EL_SP_HARDWARE_BLUE,
3233 EL_SP_HARDWARE_YELLOW,
3234 EL_SP_HARDWARE_BASE_2,
3235 EL_SP_HARDWARE_BASE_3,
3236 EL_SP_HARDWARE_BASE_4,
3237 EL_SP_HARDWARE_BASE_5,
3238 EL_SP_HARDWARE_BASE_6,
3242 /* additional elements that appeared in newer Supaplex levels */
3245 /* additional gravity port elements (not switching, but setting gravity) */
3246 EL_SP_GRAVITY_ON_PORT_LEFT,
3247 EL_SP_GRAVITY_ON_PORT_RIGHT,
3248 EL_SP_GRAVITY_ON_PORT_UP,
3249 EL_SP_GRAVITY_ON_PORT_DOWN,
3250 EL_SP_GRAVITY_OFF_PORT_LEFT,
3251 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3252 EL_SP_GRAVITY_OFF_PORT_UP,
3253 EL_SP_GRAVITY_OFF_PORT_DOWN,
3255 /* more than one Murphy in a level results in an inactive clone */
3258 /* runtime Supaplex elements */
3259 EL_SP_DISK_RED_ACTIVE,
3260 EL_SP_TERMINAL_ACTIVE,
3261 EL_SP_BUGGY_BASE_ACTIVATING,
3262 EL_SP_BUGGY_BASE_ACTIVE,
3269 static int ep_sb_element[] =
3274 EL_SOKOBAN_FIELD_EMPTY,
3275 EL_SOKOBAN_FIELD_FULL,
3276 EL_SOKOBAN_FIELD_PLAYER,
3281 EL_INVISIBLE_STEELWALL,
3286 static int ep_gem[] =
3298 static int ep_food_dark_yamyam[] =
3326 static int ep_food_penguin[] =
3340 static int ep_food_pig[] =
3352 static int ep_historic_wall[] =
3363 EL_GATE_1_GRAY_ACTIVE,
3364 EL_GATE_2_GRAY_ACTIVE,
3365 EL_GATE_3_GRAY_ACTIVE,
3366 EL_GATE_4_GRAY_ACTIVE,
3375 EL_EM_GATE_1_GRAY_ACTIVE,
3376 EL_EM_GATE_2_GRAY_ACTIVE,
3377 EL_EM_GATE_3_GRAY_ACTIVE,
3378 EL_EM_GATE_4_GRAY_ACTIVE,
3385 EL_EXPANDABLE_WALL_HORIZONTAL,
3386 EL_EXPANDABLE_WALL_VERTICAL,
3387 EL_EXPANDABLE_WALL_ANY,
3388 EL_EXPANDABLE_WALL_GROWING,
3389 EL_BD_EXPANDABLE_WALL,
3396 EL_SP_HARDWARE_GRAY,
3397 EL_SP_HARDWARE_GREEN,
3398 EL_SP_HARDWARE_BLUE,
3400 EL_SP_HARDWARE_YELLOW,
3401 EL_SP_HARDWARE_BASE_1,
3402 EL_SP_HARDWARE_BASE_2,
3403 EL_SP_HARDWARE_BASE_3,
3404 EL_SP_HARDWARE_BASE_4,
3405 EL_SP_HARDWARE_BASE_5,
3406 EL_SP_HARDWARE_BASE_6,
3408 EL_SP_TERMINAL_ACTIVE,
3411 EL_INVISIBLE_STEELWALL,
3412 EL_INVISIBLE_STEELWALL_ACTIVE,
3414 EL_INVISIBLE_WALL_ACTIVE,
3415 EL_STEELWALL_SLIPPERY,
3432 static int ep_historic_solid[] =
3436 EL_EXPANDABLE_WALL_HORIZONTAL,
3437 EL_EXPANDABLE_WALL_VERTICAL,
3438 EL_EXPANDABLE_WALL_ANY,
3439 EL_BD_EXPANDABLE_WALL,
3452 EL_QUICKSAND_FILLING,
3453 EL_QUICKSAND_EMPTYING,
3455 EL_MAGIC_WALL_ACTIVE,
3456 EL_MAGIC_WALL_EMPTYING,
3457 EL_MAGIC_WALL_FILLING,
3461 EL_BD_MAGIC_WALL_ACTIVE,
3462 EL_BD_MAGIC_WALL_EMPTYING,
3463 EL_BD_MAGIC_WALL_FULL,
3464 EL_BD_MAGIC_WALL_FILLING,
3465 EL_BD_MAGIC_WALL_DEAD,
3474 EL_SP_TERMINAL_ACTIVE,
3478 EL_INVISIBLE_WALL_ACTIVE,
3479 EL_SWITCHGATE_SWITCH_UP,
3480 EL_SWITCHGATE_SWITCH_DOWN,
3481 EL_DC_SWITCHGATE_SWITCH_UP,
3482 EL_DC_SWITCHGATE_SWITCH_DOWN,
3484 EL_TIMEGATE_SWITCH_ACTIVE,
3485 EL_DC_TIMEGATE_SWITCH,
3486 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3498 /* the following elements are a direct copy of "indestructible" elements,
3499 except "EL_ACID", which is "indestructible", but not "solid"! */
3504 EL_ACID_POOL_TOPLEFT,
3505 EL_ACID_POOL_TOPRIGHT,
3506 EL_ACID_POOL_BOTTOMLEFT,
3507 EL_ACID_POOL_BOTTOM,
3508 EL_ACID_POOL_BOTTOMRIGHT,
3509 EL_SP_HARDWARE_GRAY,
3510 EL_SP_HARDWARE_GREEN,
3511 EL_SP_HARDWARE_BLUE,
3513 EL_SP_HARDWARE_YELLOW,
3514 EL_SP_HARDWARE_BASE_1,
3515 EL_SP_HARDWARE_BASE_2,
3516 EL_SP_HARDWARE_BASE_3,
3517 EL_SP_HARDWARE_BASE_4,
3518 EL_SP_HARDWARE_BASE_5,
3519 EL_SP_HARDWARE_BASE_6,
3520 EL_INVISIBLE_STEELWALL,
3521 EL_INVISIBLE_STEELWALL_ACTIVE,
3522 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3523 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3524 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3525 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3526 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3527 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3528 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3529 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3530 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3531 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3532 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3533 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3535 EL_LIGHT_SWITCH_ACTIVE,
3536 EL_SIGN_EXCLAMATION,
3537 EL_SIGN_RADIOACTIVITY,
3544 EL_SIGN_ENTRY_FORBIDDEN,
3545 EL_SIGN_EMERGENCY_EXIT,
3553 EL_STEEL_EXIT_CLOSED,
3555 EL_DC_STEELWALL_1_LEFT,
3556 EL_DC_STEELWALL_1_RIGHT,
3557 EL_DC_STEELWALL_1_TOP,
3558 EL_DC_STEELWALL_1_BOTTOM,
3559 EL_DC_STEELWALL_1_HORIZONTAL,
3560 EL_DC_STEELWALL_1_VERTICAL,
3561 EL_DC_STEELWALL_1_TOPLEFT,
3562 EL_DC_STEELWALL_1_TOPRIGHT,
3563 EL_DC_STEELWALL_1_BOTTOMLEFT,
3564 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3565 EL_DC_STEELWALL_1_TOPLEFT_2,
3566 EL_DC_STEELWALL_1_TOPRIGHT_2,
3567 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3568 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3569 EL_DC_STEELWALL_2_LEFT,
3570 EL_DC_STEELWALL_2_RIGHT,
3571 EL_DC_STEELWALL_2_TOP,
3572 EL_DC_STEELWALL_2_BOTTOM,
3573 EL_DC_STEELWALL_2_HORIZONTAL,
3574 EL_DC_STEELWALL_2_VERTICAL,
3575 EL_DC_STEELWALL_2_MIDDLE,
3576 EL_DC_STEELWALL_2_SINGLE,
3577 EL_STEELWALL_SLIPPERY,
3591 EL_GATE_1_GRAY_ACTIVE,
3592 EL_GATE_2_GRAY_ACTIVE,
3593 EL_GATE_3_GRAY_ACTIVE,
3594 EL_GATE_4_GRAY_ACTIVE,
3603 EL_EM_GATE_1_GRAY_ACTIVE,
3604 EL_EM_GATE_2_GRAY_ACTIVE,
3605 EL_EM_GATE_3_GRAY_ACTIVE,
3606 EL_EM_GATE_4_GRAY_ACTIVE,
3608 EL_SWITCHGATE_OPENING,
3609 EL_SWITCHGATE_CLOSED,
3610 EL_SWITCHGATE_CLOSING,
3612 EL_TIMEGATE_OPENING,
3614 EL_TIMEGATE_CLOSING,
3618 EL_TUBE_VERTICAL_LEFT,
3619 EL_TUBE_VERTICAL_RIGHT,
3620 EL_TUBE_HORIZONTAL_UP,
3621 EL_TUBE_HORIZONTAL_DOWN,
3630 static int ep_classic_enemy[] =
3647 static int ep_belt[] =
3649 EL_CONVEYOR_BELT_1_LEFT,
3650 EL_CONVEYOR_BELT_1_MIDDLE,
3651 EL_CONVEYOR_BELT_1_RIGHT,
3652 EL_CONVEYOR_BELT_2_LEFT,
3653 EL_CONVEYOR_BELT_2_MIDDLE,
3654 EL_CONVEYOR_BELT_2_RIGHT,
3655 EL_CONVEYOR_BELT_3_LEFT,
3656 EL_CONVEYOR_BELT_3_MIDDLE,
3657 EL_CONVEYOR_BELT_3_RIGHT,
3658 EL_CONVEYOR_BELT_4_LEFT,
3659 EL_CONVEYOR_BELT_4_MIDDLE,
3660 EL_CONVEYOR_BELT_4_RIGHT,
3665 static int ep_belt_active[] =
3667 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3668 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3669 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3670 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3671 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3672 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3673 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3674 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3675 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3676 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3677 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3678 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3683 static int ep_belt_switch[] =
3685 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3686 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3687 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3688 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3689 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3690 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3691 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3692 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3693 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3694 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3695 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3696 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3701 static int ep_tube[] =
3708 EL_TUBE_HORIZONTAL_UP,
3709 EL_TUBE_HORIZONTAL_DOWN,
3711 EL_TUBE_VERTICAL_LEFT,
3712 EL_TUBE_VERTICAL_RIGHT,
3718 static int ep_acid_pool[] =
3720 EL_ACID_POOL_TOPLEFT,
3721 EL_ACID_POOL_TOPRIGHT,
3722 EL_ACID_POOL_BOTTOMLEFT,
3723 EL_ACID_POOL_BOTTOM,
3724 EL_ACID_POOL_BOTTOMRIGHT,
3729 static int ep_keygate[] =
3739 EL_GATE_1_GRAY_ACTIVE,
3740 EL_GATE_2_GRAY_ACTIVE,
3741 EL_GATE_3_GRAY_ACTIVE,
3742 EL_GATE_4_GRAY_ACTIVE,
3751 EL_EM_GATE_1_GRAY_ACTIVE,
3752 EL_EM_GATE_2_GRAY_ACTIVE,
3753 EL_EM_GATE_3_GRAY_ACTIVE,
3754 EL_EM_GATE_4_GRAY_ACTIVE,
3763 EL_EMC_GATE_5_GRAY_ACTIVE,
3764 EL_EMC_GATE_6_GRAY_ACTIVE,
3765 EL_EMC_GATE_7_GRAY_ACTIVE,
3766 EL_EMC_GATE_8_GRAY_ACTIVE,
3768 EL_DC_GATE_WHITE_GRAY,
3769 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3774 static int ep_amoeboid[] =
3786 static int ep_amoebalive[] =
3797 static int ep_has_editor_content[] =
3803 EL_SOKOBAN_FIELD_PLAYER,
3820 static int ep_can_turn_each_move[] =
3822 /* !!! do something with this one !!! */
3826 static int ep_can_grow[] =
3840 static int ep_active_bomb[] =
3843 EL_EM_DYNAMITE_ACTIVE,
3844 EL_DYNABOMB_PLAYER_1_ACTIVE,
3845 EL_DYNABOMB_PLAYER_2_ACTIVE,
3846 EL_DYNABOMB_PLAYER_3_ACTIVE,
3847 EL_DYNABOMB_PLAYER_4_ACTIVE,
3848 EL_SP_DISK_RED_ACTIVE,
3853 static int ep_inactive[] =
3863 EL_QUICKSAND_FAST_EMPTY,
3886 EL_GATE_1_GRAY_ACTIVE,
3887 EL_GATE_2_GRAY_ACTIVE,
3888 EL_GATE_3_GRAY_ACTIVE,
3889 EL_GATE_4_GRAY_ACTIVE,
3898 EL_EM_GATE_1_GRAY_ACTIVE,
3899 EL_EM_GATE_2_GRAY_ACTIVE,
3900 EL_EM_GATE_3_GRAY_ACTIVE,
3901 EL_EM_GATE_4_GRAY_ACTIVE,
3910 EL_EMC_GATE_5_GRAY_ACTIVE,
3911 EL_EMC_GATE_6_GRAY_ACTIVE,
3912 EL_EMC_GATE_7_GRAY_ACTIVE,
3913 EL_EMC_GATE_8_GRAY_ACTIVE,
3915 EL_DC_GATE_WHITE_GRAY,
3916 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3917 EL_DC_GATE_FAKE_GRAY,
3920 EL_INVISIBLE_STEELWALL,
3928 EL_WALL_EMERALD_YELLOW,
3929 EL_DYNABOMB_INCREASE_NUMBER,
3930 EL_DYNABOMB_INCREASE_SIZE,
3931 EL_DYNABOMB_INCREASE_POWER,
3935 EL_SOKOBAN_FIELD_EMPTY,
3936 EL_SOKOBAN_FIELD_FULL,
3937 EL_WALL_EMERALD_RED,
3938 EL_WALL_EMERALD_PURPLE,
3939 EL_ACID_POOL_TOPLEFT,
3940 EL_ACID_POOL_TOPRIGHT,
3941 EL_ACID_POOL_BOTTOMLEFT,
3942 EL_ACID_POOL_BOTTOM,
3943 EL_ACID_POOL_BOTTOMRIGHT,
3947 EL_BD_MAGIC_WALL_DEAD,
3949 EL_DC_MAGIC_WALL_DEAD,
3950 EL_AMOEBA_TO_DIAMOND,
3958 EL_SP_GRAVITY_PORT_RIGHT,
3959 EL_SP_GRAVITY_PORT_DOWN,
3960 EL_SP_GRAVITY_PORT_LEFT,
3961 EL_SP_GRAVITY_PORT_UP,
3962 EL_SP_PORT_HORIZONTAL,
3963 EL_SP_PORT_VERTICAL,
3974 EL_SP_HARDWARE_GRAY,
3975 EL_SP_HARDWARE_GREEN,
3976 EL_SP_HARDWARE_BLUE,
3978 EL_SP_HARDWARE_YELLOW,
3979 EL_SP_HARDWARE_BASE_1,
3980 EL_SP_HARDWARE_BASE_2,
3981 EL_SP_HARDWARE_BASE_3,
3982 EL_SP_HARDWARE_BASE_4,
3983 EL_SP_HARDWARE_BASE_5,
3984 EL_SP_HARDWARE_BASE_6,
3985 EL_SP_GRAVITY_ON_PORT_LEFT,
3986 EL_SP_GRAVITY_ON_PORT_RIGHT,
3987 EL_SP_GRAVITY_ON_PORT_UP,
3988 EL_SP_GRAVITY_ON_PORT_DOWN,
3989 EL_SP_GRAVITY_OFF_PORT_LEFT,
3990 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3991 EL_SP_GRAVITY_OFF_PORT_UP,
3992 EL_SP_GRAVITY_OFF_PORT_DOWN,
3993 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3994 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3995 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3996 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3997 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3998 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3999 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4000 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4001 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4002 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4003 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4004 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4005 EL_SIGN_EXCLAMATION,
4006 EL_SIGN_RADIOACTIVITY,
4013 EL_SIGN_ENTRY_FORBIDDEN,
4014 EL_SIGN_EMERGENCY_EXIT,
4022 EL_DC_STEELWALL_1_LEFT,
4023 EL_DC_STEELWALL_1_RIGHT,
4024 EL_DC_STEELWALL_1_TOP,
4025 EL_DC_STEELWALL_1_BOTTOM,
4026 EL_DC_STEELWALL_1_HORIZONTAL,
4027 EL_DC_STEELWALL_1_VERTICAL,
4028 EL_DC_STEELWALL_1_TOPLEFT,
4029 EL_DC_STEELWALL_1_TOPRIGHT,
4030 EL_DC_STEELWALL_1_BOTTOMLEFT,
4031 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4032 EL_DC_STEELWALL_1_TOPLEFT_2,
4033 EL_DC_STEELWALL_1_TOPRIGHT_2,
4034 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4035 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4036 EL_DC_STEELWALL_2_LEFT,
4037 EL_DC_STEELWALL_2_RIGHT,
4038 EL_DC_STEELWALL_2_TOP,
4039 EL_DC_STEELWALL_2_BOTTOM,
4040 EL_DC_STEELWALL_2_HORIZONTAL,
4041 EL_DC_STEELWALL_2_VERTICAL,
4042 EL_DC_STEELWALL_2_MIDDLE,
4043 EL_DC_STEELWALL_2_SINGLE,
4044 EL_STEELWALL_SLIPPERY,
4049 EL_EMC_WALL_SLIPPERY_1,
4050 EL_EMC_WALL_SLIPPERY_2,
4051 EL_EMC_WALL_SLIPPERY_3,
4052 EL_EMC_WALL_SLIPPERY_4,
4073 static int ep_em_slippery_wall[] =
4078 static int ep_gfx_crumbled[] =
4089 static int ep_editor_cascade_active[] =
4091 EL_INTERNAL_CASCADE_BD_ACTIVE,
4092 EL_INTERNAL_CASCADE_EM_ACTIVE,
4093 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4094 EL_INTERNAL_CASCADE_RND_ACTIVE,
4095 EL_INTERNAL_CASCADE_SB_ACTIVE,
4096 EL_INTERNAL_CASCADE_SP_ACTIVE,
4097 EL_INTERNAL_CASCADE_DC_ACTIVE,
4098 EL_INTERNAL_CASCADE_DX_ACTIVE,
4099 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4100 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4101 EL_INTERNAL_CASCADE_CE_ACTIVE,
4102 EL_INTERNAL_CASCADE_GE_ACTIVE,
4103 EL_INTERNAL_CASCADE_REF_ACTIVE,
4104 EL_INTERNAL_CASCADE_USER_ACTIVE,
4105 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4110 static int ep_editor_cascade_inactive[] =
4112 EL_INTERNAL_CASCADE_BD,
4113 EL_INTERNAL_CASCADE_EM,
4114 EL_INTERNAL_CASCADE_EMC,
4115 EL_INTERNAL_CASCADE_RND,
4116 EL_INTERNAL_CASCADE_SB,
4117 EL_INTERNAL_CASCADE_SP,
4118 EL_INTERNAL_CASCADE_DC,
4119 EL_INTERNAL_CASCADE_DX,
4120 EL_INTERNAL_CASCADE_CHARS,
4121 EL_INTERNAL_CASCADE_STEEL_CHARS,
4122 EL_INTERNAL_CASCADE_CE,
4123 EL_INTERNAL_CASCADE_GE,
4124 EL_INTERNAL_CASCADE_REF,
4125 EL_INTERNAL_CASCADE_USER,
4126 EL_INTERNAL_CASCADE_DYNAMIC,
4131 static int ep_obsolete[] =
4135 EL_EM_KEY_1_FILE_OBSOLETE,
4136 EL_EM_KEY_2_FILE_OBSOLETE,
4137 EL_EM_KEY_3_FILE_OBSOLETE,
4138 EL_EM_KEY_4_FILE_OBSOLETE,
4139 EL_ENVELOPE_OBSOLETE,
4148 } element_properties[] =
4150 { ep_diggable, EP_DIGGABLE },
4151 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4152 { ep_dont_run_into, EP_DONT_RUN_INTO },
4153 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4154 { ep_dont_touch, EP_DONT_TOUCH },
4155 { ep_indestructible, EP_INDESTRUCTIBLE },
4156 { ep_slippery, EP_SLIPPERY },
4157 { ep_can_change, EP_CAN_CHANGE },
4158 { ep_can_move, EP_CAN_MOVE },
4159 { ep_can_fall, EP_CAN_FALL },
4160 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4161 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4162 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4163 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4164 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4165 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4166 { ep_walkable_over, EP_WALKABLE_OVER },
4167 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4168 { ep_walkable_under, EP_WALKABLE_UNDER },
4169 { ep_passable_over, EP_PASSABLE_OVER },
4170 { ep_passable_inside, EP_PASSABLE_INSIDE },
4171 { ep_passable_under, EP_PASSABLE_UNDER },
4172 { ep_droppable, EP_DROPPABLE },
4173 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4174 { ep_pushable, EP_PUSHABLE },
4175 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4176 { ep_protected, EP_PROTECTED },
4177 { ep_throwable, EP_THROWABLE },
4178 { ep_can_explode, EP_CAN_EXPLODE },
4179 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4181 { ep_player, EP_PLAYER },
4182 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4183 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4184 { ep_switchable, EP_SWITCHABLE },
4185 { ep_bd_element, EP_BD_ELEMENT },
4186 { ep_sp_element, EP_SP_ELEMENT },
4187 { ep_sb_element, EP_SB_ELEMENT },
4189 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4190 { ep_food_penguin, EP_FOOD_PENGUIN },
4191 { ep_food_pig, EP_FOOD_PIG },
4192 { ep_historic_wall, EP_HISTORIC_WALL },
4193 { ep_historic_solid, EP_HISTORIC_SOLID },
4194 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4195 { ep_belt, EP_BELT },
4196 { ep_belt_active, EP_BELT_ACTIVE },
4197 { ep_belt_switch, EP_BELT_SWITCH },
4198 { ep_tube, EP_TUBE },
4199 { ep_acid_pool, EP_ACID_POOL },
4200 { ep_keygate, EP_KEYGATE },
4201 { ep_amoeboid, EP_AMOEBOID },
4202 { ep_amoebalive, EP_AMOEBALIVE },
4203 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4204 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4205 { ep_can_grow, EP_CAN_GROW },
4206 { ep_active_bomb, EP_ACTIVE_BOMB },
4207 { ep_inactive, EP_INACTIVE },
4209 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4211 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4213 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4214 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4216 { ep_obsolete, EP_OBSOLETE },
4223 /* always start with reliable default values (element has no properties) */
4224 /* (but never initialize clipboard elements after the very first time) */
4225 /* (to be able to use clipboard elements between several levels) */
4226 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4227 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4228 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4229 SET_PROPERTY(i, j, FALSE);
4231 /* set all base element properties from above array definitions */
4232 for (i = 0; element_properties[i].elements != NULL; i++)
4233 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4234 SET_PROPERTY((element_properties[i].elements)[j],
4235 element_properties[i].property, TRUE);
4237 /* copy properties to some elements that are only stored in level file */
4238 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4239 for (j = 0; copy_properties[j][0] != -1; j++)
4240 if (HAS_PROPERTY(copy_properties[j][0], i))
4241 for (k = 1; k <= 4; k++)
4242 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4244 /* set static element properties that are not listed in array definitions */
4245 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4246 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4248 clipboard_elements_initialized = TRUE;
4251 void InitElementPropertiesEngine(int engine_version)
4253 static int no_wall_properties[] =
4256 EP_COLLECTIBLE_ONLY,
4258 EP_DONT_COLLIDE_WITH,
4261 EP_CAN_SMASH_PLAYER,
4262 EP_CAN_SMASH_ENEMIES,
4263 EP_CAN_SMASH_EVERYTHING,
4268 EP_FOOD_DARK_YAMYAM,
4284 /* important: after initialization in InitElementPropertiesStatic(), the
4285 elements are not again initialized to a default value; therefore all
4286 changes have to make sure that they leave the element with a defined
4287 property (which means that conditional property changes must be set to
4288 a reliable default value before) */
4290 /* resolve group elements */
4291 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4292 ResolveGroupElement(EL_GROUP_START + i);
4294 /* set all special, combined or engine dependent element properties */
4295 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4297 /* do not change (already initialized) clipboard elements here */
4298 if (IS_CLIPBOARD_ELEMENT(i))
4301 /* ---------- INACTIVE ------------------------------------------------- */
4302 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4303 i <= EL_CHAR_END) ||
4304 (i >= EL_STEEL_CHAR_START &&
4305 i <= EL_STEEL_CHAR_END)));
4307 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4308 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4309 IS_WALKABLE_INSIDE(i) ||
4310 IS_WALKABLE_UNDER(i)));
4312 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4313 IS_PASSABLE_INSIDE(i) ||
4314 IS_PASSABLE_UNDER(i)));
4316 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4317 IS_PASSABLE_OVER(i)));
4319 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4320 IS_PASSABLE_INSIDE(i)));
4322 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4323 IS_PASSABLE_UNDER(i)));
4325 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4328 /* ---------- COLLECTIBLE ---------------------------------------------- */
4329 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4333 /* ---------- SNAPPABLE ------------------------------------------------ */
4334 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4335 IS_COLLECTIBLE(i) ||
4339 /* ---------- WALL ----------------------------------------------------- */
4340 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4342 for (j = 0; no_wall_properties[j] != -1; j++)
4343 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4344 i >= EL_FIRST_RUNTIME_UNREAL)
4345 SET_PROPERTY(i, EP_WALL, FALSE);
4347 if (IS_HISTORIC_WALL(i))
4348 SET_PROPERTY(i, EP_WALL, TRUE);
4350 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4351 if (engine_version < VERSION_IDENT(2,2,0,0))
4352 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4354 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4356 !IS_COLLECTIBLE(i)));
4358 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4359 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4360 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4362 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4363 IS_INDESTRUCTIBLE(i)));
4365 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4367 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4368 else if (engine_version < VERSION_IDENT(2,2,0,0))
4369 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4371 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4375 if (IS_CUSTOM_ELEMENT(i))
4377 /* these are additional properties which are initially false when set */
4379 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4381 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4382 if (DONT_COLLIDE_WITH(i))
4383 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4385 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4386 if (CAN_SMASH_EVERYTHING(i))
4387 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4388 if (CAN_SMASH_ENEMIES(i))
4389 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4392 /* ---------- CAN_SMASH ------------------------------------------------ */
4393 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4394 CAN_SMASH_ENEMIES(i) ||
4395 CAN_SMASH_EVERYTHING(i)));
4397 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4398 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4399 EXPLODES_BY_FIRE(i)));
4401 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4402 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4403 EXPLODES_SMASHED(i)));
4405 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4406 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4407 EXPLODES_IMPACT(i)));
4409 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4410 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4412 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4413 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4414 i == EL_BLACK_ORB));
4416 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4417 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4419 IS_CUSTOM_ELEMENT(i)));
4421 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4422 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4423 i == EL_SP_ELECTRON));
4425 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4426 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4427 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4428 getMoveIntoAcidProperty(&level, i));
4430 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4431 if (MAYBE_DONT_COLLIDE_WITH(i))
4432 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4433 getDontCollideWithProperty(&level, i));
4435 /* ---------- SP_PORT -------------------------------------------------- */
4436 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4437 IS_PASSABLE_INSIDE(i)));
4439 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4440 for (j = 0; j < level.num_android_clone_elements; j++)
4441 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4443 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4445 /* ---------- CAN_CHANGE ----------------------------------------------- */
4446 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4447 for (j = 0; j < element_info[i].num_change_pages; j++)
4448 if (element_info[i].change_page[j].can_change)
4449 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4451 /* ---------- HAS_ACTION ----------------------------------------------- */
4452 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4453 for (j = 0; j < element_info[i].num_change_pages; j++)
4454 if (element_info[i].change_page[j].has_action)
4455 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4457 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4458 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4461 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4462 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4463 element_info[i].crumbled[ACTION_DEFAULT] !=
4464 element_info[i].graphic[ACTION_DEFAULT]);
4466 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4467 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4468 IS_EDITOR_CASCADE_INACTIVE(i)));
4471 /* dynamically adjust element properties according to game engine version */
4473 static int ep_em_slippery_wall[] =
4478 EL_EXPANDABLE_WALL_HORIZONTAL,
4479 EL_EXPANDABLE_WALL_VERTICAL,
4480 EL_EXPANDABLE_WALL_ANY,
4481 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4482 EL_EXPANDABLE_STEELWALL_VERTICAL,
4483 EL_EXPANDABLE_STEELWALL_ANY,
4484 EL_EXPANDABLE_STEELWALL_GROWING,
4488 static int ep_em_explodes_by_fire[] =
4491 EL_EM_DYNAMITE_ACTIVE,
4496 /* special EM style gems behaviour */
4497 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4498 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4499 level.em_slippery_gems);
4501 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4502 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4503 (level.em_slippery_gems &&
4504 engine_version > VERSION_IDENT(2,0,1,0)));
4506 /* special EM style explosion behaviour regarding chain reactions */
4507 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4508 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4509 level.em_explodes_by_fire);
4512 /* this is needed because some graphics depend on element properties */
4513 if (game_status == GAME_MODE_PLAYING)
4514 InitElementGraphicInfo();
4517 void InitElementPropertiesAfterLoading(int engine_version)
4521 /* set some other uninitialized values of custom elements in older levels */
4522 if (engine_version < VERSION_IDENT(3,1,0,0))
4524 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4526 int element = EL_CUSTOM_START + i;
4528 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4530 element_info[element].explosion_delay = 17;
4531 element_info[element].ignition_delay = 8;
4536 void InitElementPropertiesGfxElement()
4540 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4542 struct ElementInfo *ei = &element_info[i];
4544 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4548 static void InitGlobal()
4553 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4555 /* check if element_name_info entry defined for each element in "main.h" */
4556 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4557 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4559 element_info[i].token_name = element_name_info[i].token_name;
4560 element_info[i].class_name = element_name_info[i].class_name;
4561 element_info[i].editor_description= element_name_info[i].editor_description;
4564 /* create hash from image config list */
4565 image_config_hash = newSetupFileHash();
4566 for (i = 0; image_config[i].token != NULL; i++)
4567 setHashEntry(image_config_hash,
4568 image_config[i].token,
4569 image_config[i].value);
4571 /* create hash from element token list */
4572 element_token_hash = newSetupFileHash();
4573 for (i = 0; element_name_info[i].token_name != NULL; i++)
4574 setHashEntry(element_token_hash,
4575 element_name_info[i].token_name,
4578 /* create hash from graphic token list */
4579 graphic_token_hash = newSetupFileHash();
4580 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4581 if (strSuffix(image_config[i].value, ".png") ||
4582 strSuffix(image_config[i].value, ".pcx") ||
4583 strSuffix(image_config[i].value, ".wav") ||
4584 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4585 setHashEntry(graphic_token_hash,
4586 image_config[i].token,
4587 int2str(graphic++, 0));
4589 /* create hash from font token list */
4590 font_token_hash = newSetupFileHash();
4591 for (i = 0; font_info[i].token_name != NULL; i++)
4592 setHashEntry(font_token_hash,
4593 font_info[i].token_name,
4596 /* set default filenames for all cloned graphics in static configuration */
4597 for (i = 0; image_config[i].token != NULL; i++)
4599 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4601 char *token = image_config[i].token;
4602 char *token_clone_from = getStringCat2(token, ".clone_from");
4603 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4605 if (token_cloned != NULL)
4607 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4609 if (value_cloned != NULL)
4611 /* set default filename in static configuration */
4612 image_config[i].value = value_cloned;
4614 /* set default filename in image config hash */
4615 setHashEntry(image_config_hash, token, value_cloned);
4619 free(token_clone_from);
4623 /* always start with reliable default values (all elements) */
4624 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4625 ActiveElement[i] = i;
4627 /* now add all entries that have an active state (active elements) */
4628 for (i = 0; element_with_active_state[i].element != -1; i++)
4630 int element = element_with_active_state[i].element;
4631 int element_active = element_with_active_state[i].element_active;
4633 ActiveElement[element] = element_active;
4636 /* always start with reliable default values (all buttons) */
4637 for (i = 0; i < NUM_IMAGE_FILES; i++)
4638 ActiveButton[i] = i;
4640 /* now add all entries that have an active state (active buttons) */
4641 for (i = 0; button_with_active_state[i].button != -1; i++)
4643 int button = button_with_active_state[i].button;
4644 int button_active = button_with_active_state[i].button_active;
4646 ActiveButton[button] = button_active;
4649 /* always start with reliable default values (all fonts) */
4650 for (i = 0; i < NUM_FONTS; i++)
4653 /* now add all entries that have an active state (active fonts) */
4654 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4656 int font = font_with_active_state[i].font_nr;
4657 int font_active = font_with_active_state[i].font_nr_active;
4659 ActiveFont[font] = font_active;
4662 global.autoplay_leveldir = NULL;
4663 global.convert_leveldir = NULL;
4664 global.create_images_dir = NULL;
4666 global.frames_per_second = 0;
4668 global.border_status = GAME_MODE_MAIN;
4670 global.use_envelope_request = FALSE;
4673 void Execute_Command(char *command)
4677 if (strEqual(command, "print graphicsinfo.conf"))
4679 Print("# You can configure additional/alternative image files here.\n");
4680 Print("# (The entries below are default and therefore commented out.)\n");
4682 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4684 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4687 for (i = 0; image_config[i].token != NULL; i++)
4688 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4689 image_config[i].value));
4693 else if (strEqual(command, "print soundsinfo.conf"))
4695 Print("# You can configure additional/alternative sound files here.\n");
4696 Print("# (The entries below are default and therefore commented out.)\n");
4698 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4700 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4703 for (i = 0; sound_config[i].token != NULL; i++)
4704 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4705 sound_config[i].value));
4709 else if (strEqual(command, "print musicinfo.conf"))
4711 Print("# You can configure additional/alternative music files here.\n");
4712 Print("# (The entries below are default and therefore commented out.)\n");
4714 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4716 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4719 for (i = 0; music_config[i].token != NULL; i++)
4720 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4721 music_config[i].value));
4725 else if (strEqual(command, "print editorsetup.conf"))
4727 Print("# You can configure your personal editor element list here.\n");
4728 Print("# (The entries below are default and therefore commented out.)\n");
4731 /* this is needed to be able to check element list for cascade elements */
4732 InitElementPropertiesStatic();
4733 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4735 PrintEditorElementList();
4739 else if (strEqual(command, "print helpanim.conf"))
4741 Print("# You can configure different element help animations here.\n");
4742 Print("# (The entries below are default and therefore commented out.)\n");
4745 for (i = 0; helpanim_config[i].token != NULL; i++)
4747 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4748 helpanim_config[i].value));
4750 if (strEqual(helpanim_config[i].token, "end"))
4756 else if (strEqual(command, "print helptext.conf"))
4758 Print("# You can configure different element help text here.\n");
4759 Print("# (The entries below are default and therefore commented out.)\n");
4762 for (i = 0; helptext_config[i].token != NULL; i++)
4763 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4764 helptext_config[i].value));
4768 else if (strPrefix(command, "dump level "))
4770 char *filename = &command[11];
4772 if (!fileExists(filename))
4773 Error(ERR_EXIT, "cannot open file '%s'", filename);
4775 LoadLevelFromFilename(&level, filename);
4780 else if (strPrefix(command, "dump tape "))
4782 char *filename = &command[10];
4784 if (!fileExists(filename))
4785 Error(ERR_EXIT, "cannot open file '%s'", filename);
4787 LoadTapeFromFilename(filename);
4792 else if (strPrefix(command, "autotest ") ||
4793 strPrefix(command, "autoplay ") ||
4794 strPrefix(command, "autoffwd "))
4796 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4798 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4799 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4800 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4802 while (*str_ptr != '\0') /* continue parsing string */
4804 /* cut leading whitespace from string, replace it by string terminator */
4805 while (*str_ptr == ' ' || *str_ptr == '\t')
4808 if (*str_ptr == '\0') /* end of string reached */
4811 if (global.autoplay_leveldir == NULL) /* read level set string */
4813 global.autoplay_leveldir = str_ptr;
4814 global.autoplay_all = TRUE; /* default: play all tapes */
4816 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4817 global.autoplay_level[i] = FALSE;
4819 else /* read level number string */
4821 int level_nr = atoi(str_ptr); /* get level_nr value */
4823 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4824 global.autoplay_level[level_nr] = TRUE;
4826 global.autoplay_all = FALSE;
4829 /* advance string pointer to the next whitespace (or end of string) */
4830 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4834 else if (strPrefix(command, "convert "))
4836 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4837 char *str_ptr = strchr(str_copy, ' ');
4839 global.convert_leveldir = str_copy;
4840 global.convert_level_nr = -1;
4842 if (str_ptr != NULL) /* level number follows */
4844 *str_ptr++ = '\0'; /* terminate leveldir string */
4845 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4848 else if (strPrefix(command, "create images "))
4850 global.create_images_dir = getStringCopy(&command[14]);
4852 if (access(global.create_images_dir, W_OK) != 0)
4853 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4854 global.create_images_dir);
4856 else if (strPrefix(command, "create CE image "))
4858 CreateCustomElementImages(&command[16]);
4864 #if defined(TARGET_SDL2)
4865 else if (strEqual(command, "SDL_ListModes"))
4867 SDL_Init(SDL_INIT_VIDEO);
4869 int num_displays = SDL_GetNumVideoDisplays();
4871 // check if there are any displays available
4872 if (num_displays < 0)
4874 Print("No displays available: %s\n", SDL_GetError());
4879 for (i = 0; i < num_displays; i++)
4881 int num_modes = SDL_GetNumDisplayModes(i);
4884 Print("Available display modes for display %d:\n", i);
4886 // check if there are any display modes available for this display
4889 Print("No display modes available for display %d: %s\n",
4895 for (j = 0; j < num_modes; j++)
4897 SDL_DisplayMode mode;
4899 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4901 Print("Cannot get display mode %d for display %d: %s\n",
4902 j, i, SDL_GetError());
4907 Print("- %d x %d\n", mode.w, mode.h);
4913 #elif defined(TARGET_SDL)
4914 else if (strEqual(command, "SDL_ListModes"))
4919 SDL_Init(SDL_INIT_VIDEO);
4921 /* get available fullscreen/hardware modes */
4922 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4924 /* check if there are any modes available */
4927 Print("No modes available!\n");
4932 /* check if our resolution is restricted */
4933 if (modes == (SDL_Rect **)-1)
4935 Print("All resolutions available.\n");
4939 Print("Available display modes:\n");
4941 for (i = 0; modes[i]; i++)
4942 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4952 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4956 static void InitSetup()
4958 LoadSetup(); /* global setup info */
4960 /* set some options from setup file */
4962 if (setup.options.verbose)
4963 options.verbose = TRUE;
4966 static void InitGameInfo()
4968 game.restart_level = FALSE;
4971 static void InitPlayerInfo()
4975 /* choose default local player */
4976 local_player = &stored_player[0];
4978 for (i = 0; i < MAX_PLAYERS; i++)
4979 stored_player[i].connected = FALSE;
4981 local_player->connected = TRUE;
4984 static void InitArtworkInfo()
4989 static char *get_string_in_brackets(char *string)
4991 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4993 sprintf(string_in_brackets, "[%s]", string);
4995 return string_in_brackets;
4998 static char *get_level_id_suffix(int id_nr)
5000 char *id_suffix = checked_malloc(1 + 3 + 1);
5002 if (id_nr < 0 || id_nr > 999)
5005 sprintf(id_suffix, ".%03d", id_nr);
5010 static void InitArtworkConfig()
5012 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5014 NUM_GLOBAL_ANIM_TOKENS + 1];
5015 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5016 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5017 static char *action_id_suffix[NUM_ACTIONS + 1];
5018 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5019 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5020 static char *level_id_suffix[MAX_LEVELS + 1];
5021 static char *dummy[1] = { NULL };
5022 static char *ignore_generic_tokens[] =
5028 static char **ignore_image_tokens;
5029 static char **ignore_sound_tokens;
5030 static char **ignore_music_tokens;
5031 int num_ignore_generic_tokens;
5032 int num_ignore_image_tokens;
5033 int num_ignore_sound_tokens;
5034 int num_ignore_music_tokens;
5037 /* dynamically determine list of generic tokens to be ignored */
5038 num_ignore_generic_tokens = 0;
5039 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5040 num_ignore_generic_tokens++;
5042 /* dynamically determine list of image tokens to be ignored */
5043 num_ignore_image_tokens = num_ignore_generic_tokens;
5044 for (i = 0; image_config_vars[i].token != NULL; i++)
5045 num_ignore_image_tokens++;
5046 ignore_image_tokens =
5047 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5048 for (i = 0; i < num_ignore_generic_tokens; i++)
5049 ignore_image_tokens[i] = ignore_generic_tokens[i];
5050 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5051 ignore_image_tokens[num_ignore_generic_tokens + i] =
5052 image_config_vars[i].token;
5053 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5055 /* dynamically determine list of sound tokens to be ignored */
5056 num_ignore_sound_tokens = num_ignore_generic_tokens;
5057 ignore_sound_tokens =
5058 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5059 for (i = 0; i < num_ignore_generic_tokens; i++)
5060 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5061 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5063 /* dynamically determine list of music tokens to be ignored */
5064 num_ignore_music_tokens = num_ignore_generic_tokens;
5065 ignore_music_tokens =
5066 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5067 for (i = 0; i < num_ignore_generic_tokens; i++)
5068 ignore_music_tokens[i] = ignore_generic_tokens[i];
5069 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5071 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5072 image_id_prefix[i] = element_info[i].token_name;
5073 for (i = 0; i < NUM_FONTS; i++)
5074 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5075 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5076 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5077 global_anim_info[i].token_name;
5078 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5080 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5081 sound_id_prefix[i] = element_info[i].token_name;
5082 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5083 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5084 get_string_in_brackets(element_info[i].class_name);
5085 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5087 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5088 music_id_prefix[i] = music_prefix_info[i].prefix;
5089 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5091 for (i = 0; i < NUM_ACTIONS; i++)
5092 action_id_suffix[i] = element_action_info[i].suffix;
5093 action_id_suffix[NUM_ACTIONS] = NULL;
5095 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5096 direction_id_suffix[i] = element_direction_info[i].suffix;
5097 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5099 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5100 special_id_suffix[i] = special_suffix_info[i].suffix;
5101 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5103 for (i = 0; i < MAX_LEVELS; i++)
5104 level_id_suffix[i] = get_level_id_suffix(i);
5105 level_id_suffix[MAX_LEVELS] = NULL;
5107 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5108 image_id_prefix, action_id_suffix, direction_id_suffix,
5109 special_id_suffix, ignore_image_tokens);
5110 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5111 sound_id_prefix, action_id_suffix, dummy,
5112 special_id_suffix, ignore_sound_tokens);
5113 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5114 music_id_prefix, special_id_suffix, level_id_suffix,
5115 dummy, ignore_music_tokens);
5118 static void InitMixer()
5125 void InitGfxBuffers()
5127 static int win_xsize_last = -1;
5128 static int win_ysize_last = -1;
5130 /* create additional image buffers for double-buffering and cross-fading */
5132 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5134 /* may contain content for cross-fading -- only re-create if changed */
5135 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5136 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5138 win_xsize_last = WIN_XSIZE;
5139 win_ysize_last = WIN_YSIZE;
5142 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5143 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5144 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5145 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5146 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5148 /* initialize screen properties */
5149 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5150 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5152 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5153 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5154 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5155 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5156 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5157 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5159 /* required if door size definitions have changed */
5160 InitGraphicCompatibilityInfo_Doors();
5162 InitGfxBuffers_EM();
5163 InitGfxBuffers_SP();
5168 struct GraphicInfo *graphic_info_last = graphic_info;
5169 char *filename_font_initial = NULL;
5170 char *filename_anim_initial = NULL;
5171 Bitmap *bitmap_font_initial = NULL;
5175 /* determine settings for initial font (for displaying startup messages) */
5176 for (i = 0; image_config[i].token != NULL; i++)
5178 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5180 char font_token[128];
5183 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5184 len_font_token = strlen(font_token);
5186 if (strEqual(image_config[i].token, font_token))
5187 filename_font_initial = image_config[i].value;
5188 else if (strlen(image_config[i].token) > len_font_token &&
5189 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5191 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5192 font_initial[j].src_x = atoi(image_config[i].value);
5193 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5194 font_initial[j].src_y = atoi(image_config[i].value);
5195 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5196 font_initial[j].width = atoi(image_config[i].value);
5197 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5198 font_initial[j].height = atoi(image_config[i].value);
5203 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5205 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5206 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5209 if (filename_font_initial == NULL) /* should not happen */
5210 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5213 InitGfxCustomArtworkInfo();
5214 InitGfxOtherSettings();
5216 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5218 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5219 font_initial[j].bitmap = bitmap_font_initial;
5221 InitFontGraphicInfo();
5223 font_height = getFontHeight(FC_RED);
5225 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5226 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5227 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5230 DrawInitText("Loading graphics", 120, FC_GREEN);
5232 /* initialize settings for busy animation with default values */
5233 int parameter[NUM_GFX_ARGS];
5234 for (i = 0; i < NUM_GFX_ARGS; i++)
5235 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5236 image_config_suffix[i].token,
5237 image_config_suffix[i].type);
5239 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5240 int len_anim_token = strlen(anim_token);
5242 /* read settings for busy animation from default custom artwork config */
5243 char *gfx_config_filename = getPath3(options.graphics_directory,
5245 GRAPHICSINFO_FILENAME);
5247 if (fileExists(gfx_config_filename))
5249 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5251 if (setup_file_hash)
5253 char *filename = getHashEntry(setup_file_hash, anim_token);
5257 filename_anim_initial = getStringCopy(filename);
5259 for (j = 0; image_config_suffix[j].token != NULL; j++)
5261 int type = image_config_suffix[j].type;
5262 char *suffix = image_config_suffix[j].token;
5263 char *token = getStringCat2(anim_token, suffix);
5264 char *value = getHashEntry(setup_file_hash, token);
5266 checked_free(token);
5269 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5273 freeSetupFileHash(setup_file_hash);
5277 if (filename_anim_initial == NULL)
5279 /* read settings for busy animation from static default artwork config */
5280 for (i = 0; image_config[i].token != NULL; i++)
5282 if (strEqual(image_config[i].token, anim_token))
5283 filename_anim_initial = getStringCopy(image_config[i].value);
5284 else if (strlen(image_config[i].token) > len_anim_token &&
5285 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5287 for (j = 0; image_config_suffix[j].token != NULL; j++)
5289 if (strEqual(&image_config[i].token[len_anim_token],
5290 image_config_suffix[j].token))
5292 get_graphic_parameter_value(image_config[i].value,
5293 image_config_suffix[j].token,
5294 image_config_suffix[j].type);
5300 if (filename_anim_initial == NULL) /* should not happen */
5301 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5303 anim_initial.bitmaps =
5304 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5306 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5307 LoadCustomImage(filename_anim_initial);
5309 checked_free(filename_anim_initial);
5311 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5313 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5315 graphic_info = graphic_info_last;
5317 init.busy.width = anim_initial.width;
5318 init.busy.height = anim_initial.height;
5320 InitMenuDesignSettings_Static();
5322 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5323 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5324 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToScreen);
5326 /* use copy of busy animation to prevent change while reloading artwork */
5330 void InitGfxBackground()
5332 fieldbuffer = bitmap_db_field;
5333 SetDrawtoField(DRAW_BACKBUFFER);
5335 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5337 redraw_mask = REDRAW_ALL;
5340 static void InitLevelInfo()
5342 LoadLevelInfo(); /* global level info */
5343 LoadLevelSetup_LastSeries(); /* last played series info */
5344 LoadLevelSetup_SeriesInfo(); /* last played level info */
5346 if (global.autoplay_leveldir &&
5347 global.autoplay_mode != AUTOPLAY_TEST)
5349 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5350 global.autoplay_leveldir);
5351 if (leveldir_current == NULL)
5352 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5356 static void InitLevelArtworkInfo()
5358 LoadLevelArtworkInfo();
5361 static void InitImages()
5363 print_timestamp_init("InitImages");
5366 printf("::: leveldir_current->identifier == '%s'\n",
5367 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5368 printf("::: leveldir_current->graphics_path == '%s'\n",
5369 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5370 printf("::: leveldir_current->graphics_set == '%s'\n",
5371 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5372 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5373 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5376 setLevelArtworkDir(artwork.gfx_first);
5379 printf("::: leveldir_current->identifier == '%s'\n",
5380 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5381 printf("::: leveldir_current->graphics_path == '%s'\n",
5382 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5383 printf("::: leveldir_current->graphics_set == '%s'\n",
5384 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5385 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5386 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5390 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5391 leveldir_current->identifier,
5392 artwork.gfx_current_identifier,
5393 artwork.gfx_current->identifier,
5394 leveldir_current->graphics_set,
5395 leveldir_current->graphics_path);
5398 UPDATE_BUSY_STATE();
5400 ReloadCustomImages();
5401 print_timestamp_time("ReloadCustomImages");
5403 UPDATE_BUSY_STATE();
5405 LoadCustomElementDescriptions();
5406 print_timestamp_time("LoadCustomElementDescriptions");
5408 UPDATE_BUSY_STATE();
5410 LoadMenuDesignSettings();
5411 print_timestamp_time("LoadMenuDesignSettings");
5413 UPDATE_BUSY_STATE();
5415 ReinitializeGraphics();
5416 print_timestamp_time("ReinitializeGraphics");
5418 UPDATE_BUSY_STATE();
5420 print_timestamp_done("InitImages");
5423 static void InitSound(char *identifier)
5425 print_timestamp_init("InitSound");
5427 if (identifier == NULL)
5428 identifier = artwork.snd_current->identifier;
5430 /* set artwork path to send it to the sound server process */
5431 setLevelArtworkDir(artwork.snd_first);
5433 InitReloadCustomSounds(identifier);
5434 print_timestamp_time("InitReloadCustomSounds");
5436 ReinitializeSounds();
5437 print_timestamp_time("ReinitializeSounds");
5439 print_timestamp_done("InitSound");
5442 static void InitMusic(char *identifier)
5444 print_timestamp_init("InitMusic");
5446 if (identifier == NULL)
5447 identifier = artwork.mus_current->identifier;
5449 /* set artwork path to send it to the sound server process */
5450 setLevelArtworkDir(artwork.mus_first);
5452 InitReloadCustomMusic(identifier);
5453 print_timestamp_time("InitReloadCustomMusic");
5455 ReinitializeMusic();
5456 print_timestamp_time("ReinitializeMusic");
5458 print_timestamp_done("InitMusic");
5461 void InitNetworkServer()
5463 #if defined(NETWORK_AVALIABLE)
5467 if (!options.network)
5470 #if defined(NETWORK_AVALIABLE)
5471 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5473 if (!ConnectToServer(options.server_host, options.server_port))
5474 Error(ERR_EXIT, "cannot connect to network game server");
5476 SendToServer_PlayerName(setup.player_name);
5477 SendToServer_ProtocolVersion();
5480 SendToServer_NrWanted(nr_wanted);
5484 static boolean CheckArtworkConfigForCustomElements(char *filename)
5486 SetupFileHash *setup_file_hash;
5487 boolean redefined_ce_found = FALSE;
5489 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5491 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5493 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5495 char *token = HASH_ITERATION_TOKEN(itr);
5497 if (strPrefix(token, "custom_"))
5499 redefined_ce_found = TRUE;
5504 END_HASH_ITERATION(setup_file_hash, itr)
5506 freeSetupFileHash(setup_file_hash);
5509 return redefined_ce_found;
5512 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5514 char *filename_base, *filename_local;
5515 boolean redefined_ce_found = FALSE;
5517 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5520 printf("::: leveldir_current->identifier == '%s'\n",
5521 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5522 printf("::: leveldir_current->graphics_path == '%s'\n",
5523 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5524 printf("::: leveldir_current->graphics_set == '%s'\n",
5525 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5526 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5527 leveldir_current == NULL ? "[NULL]" :
5528 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5531 /* first look for special artwork configured in level series config */
5532 filename_base = getCustomArtworkLevelConfigFilename(type);
5535 printf("::: filename_base == '%s'\n", filename_base);
5538 if (fileExists(filename_base))
5539 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5541 filename_local = getCustomArtworkConfigFilename(type);
5544 printf("::: filename_local == '%s'\n", filename_local);
5547 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5548 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5551 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5554 return redefined_ce_found;
5557 static void InitOverrideArtwork()
5559 boolean redefined_ce_found = FALSE;
5561 /* to check if this level set redefines any CEs, do not use overriding */
5562 gfx.override_level_graphics = FALSE;
5563 gfx.override_level_sounds = FALSE;
5564 gfx.override_level_music = FALSE;
5566 /* now check if this level set has definitions for custom elements */
5567 if (setup.override_level_graphics == AUTO ||
5568 setup.override_level_sounds == AUTO ||
5569 setup.override_level_music == AUTO)
5570 redefined_ce_found =
5571 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5572 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5573 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5576 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5579 if (redefined_ce_found)
5581 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5582 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5583 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5584 gfx.override_level_music = (setup.override_level_music == TRUE);
5588 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5589 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5590 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5591 gfx.override_level_music = (setup.override_level_music != FALSE);
5595 printf("::: => %d, %d, %d\n",
5596 gfx.override_level_graphics,
5597 gfx.override_level_sounds,
5598 gfx.override_level_music);
5602 static char *getNewArtworkIdentifier(int type)
5604 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5605 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5606 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5607 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5608 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5609 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5610 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5611 char *leveldir_identifier = leveldir_current->identifier;
5612 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5613 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5614 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5615 char *artwork_current_identifier;
5616 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5618 /* leveldir_current may be invalid (level group, parent link) */
5619 if (!validLevelSeries(leveldir_current))
5622 /* 1st step: determine artwork set to be activated in descending order:
5623 --------------------------------------------------------------------
5624 1. setup artwork (when configured to override everything else)
5625 2. artwork set configured in "levelinfo.conf" of current level set
5626 (artwork in level directory will have priority when loading later)
5627 3. artwork in level directory (stored in artwork sub-directory)
5628 4. setup artwork (currently configured in setup menu) */
5630 if (setup_override_artwork)
5631 artwork_current_identifier = setup_artwork_set;
5632 else if (leveldir_artwork_set != NULL)
5633 artwork_current_identifier = leveldir_artwork_set;
5634 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5635 artwork_current_identifier = leveldir_identifier;
5637 artwork_current_identifier = setup_artwork_set;
5640 /* 2nd step: check if it is really needed to reload artwork set
5641 ------------------------------------------------------------ */
5643 /* ---------- reload if level set and also artwork set has changed ------- */
5644 if (leveldir_current_identifier[type] != leveldir_identifier &&
5645 (last_has_level_artwork_set[type] || has_level_artwork_set))
5646 artwork_new_identifier = artwork_current_identifier;
5648 leveldir_current_identifier[type] = leveldir_identifier;
5649 last_has_level_artwork_set[type] = has_level_artwork_set;
5651 /* ---------- reload if "override artwork" setting has changed ----------- */
5652 if (last_override_level_artwork[type] != setup_override_artwork)
5653 artwork_new_identifier = artwork_current_identifier;
5655 last_override_level_artwork[type] = setup_override_artwork;
5657 /* ---------- reload if current artwork identifier has changed ----------- */
5658 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5659 artwork_current_identifier))
5660 artwork_new_identifier = artwork_current_identifier;
5662 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5664 /* ---------- do not reload directly after starting ---------------------- */
5665 if (!initialized[type])
5666 artwork_new_identifier = NULL;
5668 initialized[type] = TRUE;
5670 return artwork_new_identifier;
5673 void ReloadCustomArtwork(int force_reload)
5675 int last_game_status = game_status; /* save current game status */
5676 char *gfx_new_identifier;
5677 char *snd_new_identifier;
5678 char *mus_new_identifier;
5679 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5680 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5681 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5682 boolean reload_needed;
5684 InitOverrideArtwork();
5686 force_reload_gfx |= AdjustGraphicsForEMC();
5688 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5689 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5690 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5692 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5693 snd_new_identifier != NULL || force_reload_snd ||
5694 mus_new_identifier != NULL || force_reload_mus);
5699 print_timestamp_init("ReloadCustomArtwork");
5701 game_status = GAME_MODE_LOADING;
5703 FadeOut(REDRAW_ALL);
5705 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5706 print_timestamp_time("ClearRectangle");
5710 if (gfx_new_identifier != NULL || force_reload_gfx)
5713 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5714 artwork.gfx_current_identifier,
5716 artwork.gfx_current->identifier,
5717 leveldir_current->graphics_set);
5721 print_timestamp_time("InitImages");
5724 if (snd_new_identifier != NULL || force_reload_snd)
5726 InitSound(snd_new_identifier);
5727 print_timestamp_time("InitSound");
5730 if (mus_new_identifier != NULL || force_reload_mus)
5732 InitMusic(mus_new_identifier);
5733 print_timestamp_time("InitMusic");
5736 game_status = last_game_status; /* restore current game status */
5738 init_last = init; /* switch to new busy animation */
5740 FadeOut(REDRAW_ALL);
5742 RedrawGlobalBorder();
5744 /* force redraw of (open or closed) door graphics */
5745 SetDoorState(DOOR_OPEN_ALL);
5746 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5748 FadeSetEnterScreen();
5749 FadeSkipNextFadeOut();
5751 print_timestamp_done("ReloadCustomArtwork");
5753 LimitScreenUpdates(FALSE);
5756 void KeyboardAutoRepeatOffUnlessAutoplay()
5758 if (global.autoplay_leveldir == NULL)
5759 KeyboardAutoRepeatOff();
5762 void DisplayExitMessage(char *format, va_list ap)
5764 // check if draw buffer and fonts for exit message are already available
5765 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5768 int font_1 = FC_RED;
5769 int font_2 = FC_YELLOW;
5770 int font_3 = FC_BLUE;
5771 int font_width = getFontWidth(font_2);
5772 int font_height = getFontHeight(font_2);
5775 int sxsize = WIN_XSIZE - 2 * sx;
5776 int sysize = WIN_YSIZE - 2 * sy;
5777 int line_length = sxsize / font_width;
5778 int max_lines = sysize / font_height;
5779 int num_lines_printed;
5783 gfx.sxsize = sxsize;
5784 gfx.sysize = sysize;
5788 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5790 DrawTextSCentered(sy, font_1, "Fatal error:");
5791 sy += 3 * font_height;;
5794 DrawTextBufferVA(sx, sy, format, ap, font_2,
5795 line_length, line_length, max_lines,
5796 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5797 sy += (num_lines_printed + 3) * font_height;
5799 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5800 sy += 3 * font_height;
5803 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5804 line_length, line_length, max_lines,
5805 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5807 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5809 redraw_mask = REDRAW_ALL;
5811 /* force drawing exit message even if screen updates are currently limited */
5812 LimitScreenUpdates(FALSE);
5816 /* deactivate toons on error message screen */
5817 setup.toons = FALSE;
5819 WaitForEventToContinue();
5823 /* ========================================================================= */
5825 /* ========================================================================= */
5829 print_timestamp_init("OpenAll");
5831 game_status = GAME_MODE_LOADING;
5835 InitGlobal(); /* initialize some global variables */
5837 print_timestamp_time("[init global stuff]");
5841 print_timestamp_time("[init setup/config stuff (1)]");
5843 if (options.execute_command)
5844 Execute_Command(options.execute_command);
5846 if (options.serveronly)
5848 #if defined(PLATFORM_UNIX)
5849 NetworkServer(options.server_port, options.serveronly);
5851 Error(ERR_WARN, "networking only supported in Unix version");
5854 exit(0); /* never reached, server loops forever */
5858 print_timestamp_time("[init setup/config stuff (2)]");
5860 print_timestamp_time("[init setup/config stuff (3)]");
5861 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5862 print_timestamp_time("[init setup/config stuff (4)]");
5863 InitArtworkConfig(); /* needed before forking sound child process */
5864 print_timestamp_time("[init setup/config stuff (5)]");
5866 print_timestamp_time("[init setup/config stuff (6)]");
5868 InitRND(NEW_RANDOMIZE);
5869 InitSimpleRandom(NEW_RANDOMIZE);
5873 print_timestamp_time("[init setup/config stuff]");
5876 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5878 InitEventFilter(FilterEvents);
5880 print_timestamp_time("[init video stuff]");
5882 InitElementPropertiesStatic();
5883 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5884 InitElementPropertiesGfxElement();
5886 print_timestamp_time("[init element properties stuff]");
5890 print_timestamp_time("InitGfx");
5893 print_timestamp_time("InitLevelInfo");
5895 InitLevelArtworkInfo();
5896 print_timestamp_time("InitLevelArtworkInfo");
5898 InitOverrideArtwork(); /* needs to know current level directory */
5899 print_timestamp_time("InitOverrideArtwork");
5901 InitImages(); /* needs to know current level directory */
5902 print_timestamp_time("InitImages");
5904 InitSound(NULL); /* needs to know current level directory */
5905 print_timestamp_time("InitSound");
5907 InitMusic(NULL); /* needs to know current level directory */
5908 print_timestamp_time("InitMusic");
5910 InitGfxBackground();
5915 if (global.autoplay_leveldir)
5920 else if (global.convert_leveldir)
5925 else if (global.create_images_dir)
5927 CreateLevelSketchImages();
5931 game_status = GAME_MODE_MAIN;
5933 FadeSetEnterScreen();
5934 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5935 FadeSkipNextFadeOut();
5937 print_timestamp_time("[post-artwork]");
5939 print_timestamp_done("OpenAll");
5943 InitNetworkServer();
5946 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5948 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5949 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5950 #if defined(PLATFORM_ANDROID)
5951 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5952 SDL_AndroidGetInternalStoragePath());
5953 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5954 SDL_AndroidGetExternalStoragePath());
5955 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5956 (SDL_AndroidGetExternalStorageState() ==
5957 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5958 SDL_AndroidGetExternalStorageState() ==
5959 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5964 void CloseAllAndExit(int exit_value)
5969 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5976 #if defined(TARGET_SDL)
5977 #if defined(TARGET_SDL2)
5979 // set a flag to tell the network server thread to quit and wait for it
5980 // using SDL_WaitThread()
5982 if (network_server) /* terminate network server */
5983 SDL_KillThread(server_thread);
5987 CloseVideoDisplay();
5988 ClosePlatformDependentStuff();
5990 if (exit_value != 0)
5992 /* fall back to default level set (current set may have caused an error) */
5993 SaveLevelSetup_LastSeries_Deactivate();
5995 /* tell user where to find error log file which may contain more details */
5996 // (error notification now directly displayed on screen inside R'n'D
5997 // NotifyUserAboutErrorFile(); /* currently only works for Windows */