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 InitGlobalAnimations();
2063 print_timestamp_time("InitToons");
2065 print_timestamp_time("InitDoors");
2067 print_timestamp_done("ReinitializeGraphics");
2070 static void ReinitializeSounds()
2072 InitSoundInfo(); /* sound properties mapping */
2073 InitElementSoundInfo(); /* element game sound mapping */
2074 InitGameModeSoundInfo(); /* game mode sound mapping */
2076 InitPlayLevelSound(); /* internal game sound settings */
2079 static void ReinitializeMusic()
2081 InitMusicInfo(); /* music properties mapping */
2082 InitGameModeMusicInfo(); /* game mode music mapping */
2085 static int get_special_property_bit(int element, int property_bit_nr)
2087 struct PropertyBitInfo
2093 static struct PropertyBitInfo pb_can_move_into_acid[] =
2095 /* the player may be able fall into acid when gravity is activated */
2100 { EL_SP_MURPHY, 0 },
2101 { EL_SOKOBAN_FIELD_PLAYER, 0 },
2103 /* all elements that can move may be able to also move into acid */
2106 { EL_BUG_RIGHT, 1 },
2109 { EL_SPACESHIP, 2 },
2110 { EL_SPACESHIP_LEFT, 2 },
2111 { EL_SPACESHIP_RIGHT, 2 },
2112 { EL_SPACESHIP_UP, 2 },
2113 { EL_SPACESHIP_DOWN, 2 },
2114 { EL_BD_BUTTERFLY, 3 },
2115 { EL_BD_BUTTERFLY_LEFT, 3 },
2116 { EL_BD_BUTTERFLY_RIGHT, 3 },
2117 { EL_BD_BUTTERFLY_UP, 3 },
2118 { EL_BD_BUTTERFLY_DOWN, 3 },
2119 { EL_BD_FIREFLY, 4 },
2120 { EL_BD_FIREFLY_LEFT, 4 },
2121 { EL_BD_FIREFLY_RIGHT, 4 },
2122 { EL_BD_FIREFLY_UP, 4 },
2123 { EL_BD_FIREFLY_DOWN, 4 },
2125 { EL_YAMYAM_LEFT, 5 },
2126 { EL_YAMYAM_RIGHT, 5 },
2127 { EL_YAMYAM_UP, 5 },
2128 { EL_YAMYAM_DOWN, 5 },
2129 { EL_DARK_YAMYAM, 6 },
2132 { EL_PACMAN_LEFT, 8 },
2133 { EL_PACMAN_RIGHT, 8 },
2134 { EL_PACMAN_UP, 8 },
2135 { EL_PACMAN_DOWN, 8 },
2137 { EL_MOLE_LEFT, 9 },
2138 { EL_MOLE_RIGHT, 9 },
2140 { EL_MOLE_DOWN, 9 },
2144 { EL_SATELLITE, 13 },
2145 { EL_SP_SNIKSNAK, 14 },
2146 { EL_SP_ELECTRON, 15 },
2149 { EL_EMC_ANDROID, 18 },
2154 static struct PropertyBitInfo pb_dont_collide_with[] =
2156 { EL_SP_SNIKSNAK, 0 },
2157 { EL_SP_ELECTRON, 1 },
2165 struct PropertyBitInfo *pb_info;
2168 { EP_CAN_MOVE_INTO_ACID, pb_can_move_into_acid },
2169 { EP_DONT_COLLIDE_WITH, pb_dont_collide_with },
2174 struct PropertyBitInfo *pb_info = NULL;
2177 for (i = 0; pb_definition[i].bit_nr != -1; i++)
2178 if (pb_definition[i].bit_nr == property_bit_nr)
2179 pb_info = pb_definition[i].pb_info;
2181 if (pb_info == NULL)
2184 for (i = 0; pb_info[i].element != -1; i++)
2185 if (pb_info[i].element == element)
2186 return pb_info[i].bit_nr;
2191 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2192 boolean property_value)
2194 int bit_nr = get_special_property_bit(element, property_bit_nr);
2199 *bitfield |= (1 << bit_nr);
2201 *bitfield &= ~(1 << bit_nr);
2205 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2207 int bit_nr = get_special_property_bit(element, property_bit_nr);
2210 return ((*bitfield & (1 << bit_nr)) != 0);
2215 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2217 static int group_nr;
2218 static struct ElementGroupInfo *group;
2219 struct ElementGroupInfo *actual_group = element_info[group_element].group;
2222 if (actual_group == NULL) /* not yet initialized */
2225 if (recursion_depth > NUM_GROUP_ELEMENTS) /* recursion too deep */
2227 Error(ERR_WARN, "recursion too deep when resolving group element %d",
2228 group_element - EL_GROUP_START + 1);
2230 /* replace element which caused too deep recursion by question mark */
2231 group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2236 if (recursion_depth == 0) /* initialization */
2238 group = actual_group;
2239 group_nr = GROUP_NR(group_element);
2241 group->num_elements_resolved = 0;
2242 group->choice_pos = 0;
2244 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2245 element_info[i].in_group[group_nr] = FALSE;
2248 for (i = 0; i < actual_group->num_elements; i++)
2250 int element = actual_group->element[i];
2252 if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2255 if (IS_GROUP_ELEMENT(element))
2256 ResolveGroupElementExt(element, recursion_depth + 1);
2259 group->element_resolved[group->num_elements_resolved++] = element;
2260 element_info[element].in_group[group_nr] = TRUE;
2265 void ResolveGroupElement(int group_element)
2267 ResolveGroupElementExt(group_element, 0);
2270 void InitElementPropertiesStatic()
2272 static boolean clipboard_elements_initialized = FALSE;
2274 static int ep_diggable[] =
2279 EL_SP_BUGGY_BASE_ACTIVATING,
2282 EL_INVISIBLE_SAND_ACTIVE,
2285 /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2286 /* (if amoeba can grow into anything diggable, maybe keep these out) */
2291 EL_SP_BUGGY_BASE_ACTIVE,
2298 static int ep_collectible_only[] =
2320 EL_DYNABOMB_INCREASE_NUMBER,
2321 EL_DYNABOMB_INCREASE_SIZE,
2322 EL_DYNABOMB_INCREASE_POWER,
2340 /* !!! handle separately !!! */
2341 EL_DC_LANDMINE, /* deadly when running into, but can be snapped */
2347 static int ep_dont_run_into[] =
2349 /* same elements as in 'ep_dont_touch' */
2355 /* same elements as in 'ep_dont_collide_with' */
2367 /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2372 EL_SP_BUGGY_BASE_ACTIVE,
2379 static int ep_dont_collide_with[] =
2381 /* same elements as in 'ep_dont_touch' */
2398 static int ep_dont_touch[] =
2408 static int ep_indestructible[] =
2412 EL_ACID_POOL_TOPLEFT,
2413 EL_ACID_POOL_TOPRIGHT,
2414 EL_ACID_POOL_BOTTOMLEFT,
2415 EL_ACID_POOL_BOTTOM,
2416 EL_ACID_POOL_BOTTOMRIGHT,
2417 EL_SP_HARDWARE_GRAY,
2418 EL_SP_HARDWARE_GREEN,
2419 EL_SP_HARDWARE_BLUE,
2421 EL_SP_HARDWARE_YELLOW,
2422 EL_SP_HARDWARE_BASE_1,
2423 EL_SP_HARDWARE_BASE_2,
2424 EL_SP_HARDWARE_BASE_3,
2425 EL_SP_HARDWARE_BASE_4,
2426 EL_SP_HARDWARE_BASE_5,
2427 EL_SP_HARDWARE_BASE_6,
2428 EL_INVISIBLE_STEELWALL,
2429 EL_INVISIBLE_STEELWALL_ACTIVE,
2430 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2431 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2432 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2433 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2434 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2435 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2436 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2437 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2438 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2439 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2440 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2441 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2443 EL_LIGHT_SWITCH_ACTIVE,
2444 EL_SIGN_EXCLAMATION,
2445 EL_SIGN_RADIOACTIVITY,
2452 EL_SIGN_ENTRY_FORBIDDEN,
2453 EL_SIGN_EMERGENCY_EXIT,
2461 EL_STEEL_EXIT_CLOSED,
2463 EL_STEEL_EXIT_OPENING,
2464 EL_STEEL_EXIT_CLOSING,
2465 EL_EM_STEEL_EXIT_CLOSED,
2466 EL_EM_STEEL_EXIT_OPEN,
2467 EL_EM_STEEL_EXIT_OPENING,
2468 EL_EM_STEEL_EXIT_CLOSING,
2469 EL_DC_STEELWALL_1_LEFT,
2470 EL_DC_STEELWALL_1_RIGHT,
2471 EL_DC_STEELWALL_1_TOP,
2472 EL_DC_STEELWALL_1_BOTTOM,
2473 EL_DC_STEELWALL_1_HORIZONTAL,
2474 EL_DC_STEELWALL_1_VERTICAL,
2475 EL_DC_STEELWALL_1_TOPLEFT,
2476 EL_DC_STEELWALL_1_TOPRIGHT,
2477 EL_DC_STEELWALL_1_BOTTOMLEFT,
2478 EL_DC_STEELWALL_1_BOTTOMRIGHT,
2479 EL_DC_STEELWALL_1_TOPLEFT_2,
2480 EL_DC_STEELWALL_1_TOPRIGHT_2,
2481 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2482 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2483 EL_DC_STEELWALL_2_LEFT,
2484 EL_DC_STEELWALL_2_RIGHT,
2485 EL_DC_STEELWALL_2_TOP,
2486 EL_DC_STEELWALL_2_BOTTOM,
2487 EL_DC_STEELWALL_2_HORIZONTAL,
2488 EL_DC_STEELWALL_2_VERTICAL,
2489 EL_DC_STEELWALL_2_MIDDLE,
2490 EL_DC_STEELWALL_2_SINGLE,
2491 EL_STEELWALL_SLIPPERY,
2505 EL_GATE_1_GRAY_ACTIVE,
2506 EL_GATE_2_GRAY_ACTIVE,
2507 EL_GATE_3_GRAY_ACTIVE,
2508 EL_GATE_4_GRAY_ACTIVE,
2517 EL_EM_GATE_1_GRAY_ACTIVE,
2518 EL_EM_GATE_2_GRAY_ACTIVE,
2519 EL_EM_GATE_3_GRAY_ACTIVE,
2520 EL_EM_GATE_4_GRAY_ACTIVE,
2529 EL_EMC_GATE_5_GRAY_ACTIVE,
2530 EL_EMC_GATE_6_GRAY_ACTIVE,
2531 EL_EMC_GATE_7_GRAY_ACTIVE,
2532 EL_EMC_GATE_8_GRAY_ACTIVE,
2534 EL_DC_GATE_WHITE_GRAY,
2535 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2536 EL_DC_GATE_FAKE_GRAY,
2538 EL_SWITCHGATE_OPENING,
2539 EL_SWITCHGATE_CLOSED,
2540 EL_SWITCHGATE_CLOSING,
2541 EL_DC_SWITCHGATE_SWITCH_UP,
2542 EL_DC_SWITCHGATE_SWITCH_DOWN,
2544 EL_TIMEGATE_OPENING,
2546 EL_TIMEGATE_CLOSING,
2547 EL_DC_TIMEGATE_SWITCH,
2548 EL_DC_TIMEGATE_SWITCH_ACTIVE,
2552 EL_TUBE_VERTICAL_LEFT,
2553 EL_TUBE_VERTICAL_RIGHT,
2554 EL_TUBE_HORIZONTAL_UP,
2555 EL_TUBE_HORIZONTAL_DOWN,
2560 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2561 EL_EXPANDABLE_STEELWALL_VERTICAL,
2562 EL_EXPANDABLE_STEELWALL_ANY,
2567 static int ep_slippery[] =
2581 EL_ROBOT_WHEEL_ACTIVE,
2587 EL_ACID_POOL_TOPLEFT,
2588 EL_ACID_POOL_TOPRIGHT,
2598 EL_STEELWALL_SLIPPERY,
2601 EL_EMC_WALL_SLIPPERY_1,
2602 EL_EMC_WALL_SLIPPERY_2,
2603 EL_EMC_WALL_SLIPPERY_3,
2604 EL_EMC_WALL_SLIPPERY_4,
2606 EL_EMC_MAGIC_BALL_ACTIVE,
2611 static int ep_can_change[] =
2616 static int ep_can_move[] =
2618 /* same elements as in 'pb_can_move_into_acid' */
2641 static int ep_can_fall[] =
2655 EL_QUICKSAND_FAST_FULL,
2657 EL_BD_MAGIC_WALL_FULL,
2658 EL_DC_MAGIC_WALL_FULL,
2672 static int ep_can_smash_player[] =
2698 static int ep_can_smash_enemies[] =
2707 static int ep_can_smash_everything[] =
2716 static int ep_explodes_by_fire[] =
2718 /* same elements as in 'ep_explodes_impact' */
2723 /* same elements as in 'ep_explodes_smashed' */
2733 EL_EM_DYNAMITE_ACTIVE,
2734 EL_DYNABOMB_PLAYER_1_ACTIVE,
2735 EL_DYNABOMB_PLAYER_2_ACTIVE,
2736 EL_DYNABOMB_PLAYER_3_ACTIVE,
2737 EL_DYNABOMB_PLAYER_4_ACTIVE,
2738 EL_DYNABOMB_INCREASE_NUMBER,
2739 EL_DYNABOMB_INCREASE_SIZE,
2740 EL_DYNABOMB_INCREASE_POWER,
2741 EL_SP_DISK_RED_ACTIVE,
2755 static int ep_explodes_smashed[] =
2757 /* same elements as in 'ep_explodes_impact' */
2771 static int ep_explodes_impact[] =
2780 static int ep_walkable_over[] =
2784 EL_SOKOBAN_FIELD_EMPTY,
2791 EL_EM_STEEL_EXIT_OPEN,
2792 EL_EM_STEEL_EXIT_OPENING,
2801 EL_GATE_1_GRAY_ACTIVE,
2802 EL_GATE_2_GRAY_ACTIVE,
2803 EL_GATE_3_GRAY_ACTIVE,
2804 EL_GATE_4_GRAY_ACTIVE,
2812 static int ep_walkable_inside[] =
2817 EL_TUBE_VERTICAL_LEFT,
2818 EL_TUBE_VERTICAL_RIGHT,
2819 EL_TUBE_HORIZONTAL_UP,
2820 EL_TUBE_HORIZONTAL_DOWN,
2829 static int ep_walkable_under[] =
2834 static int ep_passable_over[] =
2844 EL_EM_GATE_1_GRAY_ACTIVE,
2845 EL_EM_GATE_2_GRAY_ACTIVE,
2846 EL_EM_GATE_3_GRAY_ACTIVE,
2847 EL_EM_GATE_4_GRAY_ACTIVE,
2856 EL_EMC_GATE_5_GRAY_ACTIVE,
2857 EL_EMC_GATE_6_GRAY_ACTIVE,
2858 EL_EMC_GATE_7_GRAY_ACTIVE,
2859 EL_EMC_GATE_8_GRAY_ACTIVE,
2861 EL_DC_GATE_WHITE_GRAY,
2862 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2869 static int ep_passable_inside[] =
2875 EL_SP_PORT_HORIZONTAL,
2876 EL_SP_PORT_VERTICAL,
2878 EL_SP_GRAVITY_PORT_LEFT,
2879 EL_SP_GRAVITY_PORT_RIGHT,
2880 EL_SP_GRAVITY_PORT_UP,
2881 EL_SP_GRAVITY_PORT_DOWN,
2882 EL_SP_GRAVITY_ON_PORT_LEFT,
2883 EL_SP_GRAVITY_ON_PORT_RIGHT,
2884 EL_SP_GRAVITY_ON_PORT_UP,
2885 EL_SP_GRAVITY_ON_PORT_DOWN,
2886 EL_SP_GRAVITY_OFF_PORT_LEFT,
2887 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2888 EL_SP_GRAVITY_OFF_PORT_UP,
2889 EL_SP_GRAVITY_OFF_PORT_DOWN,
2894 static int ep_passable_under[] =
2899 static int ep_droppable[] =
2904 static int ep_explodes_1x1_old[] =
2909 static int ep_pushable[] =
2921 EL_SOKOBAN_FIELD_FULL,
2930 static int ep_explodes_cross_old[] =
2935 static int ep_protected[] =
2937 /* same elements as in 'ep_walkable_inside' */
2941 EL_TUBE_VERTICAL_LEFT,
2942 EL_TUBE_VERTICAL_RIGHT,
2943 EL_TUBE_HORIZONTAL_UP,
2944 EL_TUBE_HORIZONTAL_DOWN,
2950 /* same elements as in 'ep_passable_over' */
2959 EL_EM_GATE_1_GRAY_ACTIVE,
2960 EL_EM_GATE_2_GRAY_ACTIVE,
2961 EL_EM_GATE_3_GRAY_ACTIVE,
2962 EL_EM_GATE_4_GRAY_ACTIVE,
2971 EL_EMC_GATE_5_GRAY_ACTIVE,
2972 EL_EMC_GATE_6_GRAY_ACTIVE,
2973 EL_EMC_GATE_7_GRAY_ACTIVE,
2974 EL_EMC_GATE_8_GRAY_ACTIVE,
2976 EL_DC_GATE_WHITE_GRAY,
2977 EL_DC_GATE_WHITE_GRAY_ACTIVE,
2981 /* same elements as in 'ep_passable_inside' */
2986 EL_SP_PORT_HORIZONTAL,
2987 EL_SP_PORT_VERTICAL,
2989 EL_SP_GRAVITY_PORT_LEFT,
2990 EL_SP_GRAVITY_PORT_RIGHT,
2991 EL_SP_GRAVITY_PORT_UP,
2992 EL_SP_GRAVITY_PORT_DOWN,
2993 EL_SP_GRAVITY_ON_PORT_LEFT,
2994 EL_SP_GRAVITY_ON_PORT_RIGHT,
2995 EL_SP_GRAVITY_ON_PORT_UP,
2996 EL_SP_GRAVITY_ON_PORT_DOWN,
2997 EL_SP_GRAVITY_OFF_PORT_LEFT,
2998 EL_SP_GRAVITY_OFF_PORT_RIGHT,
2999 EL_SP_GRAVITY_OFF_PORT_UP,
3000 EL_SP_GRAVITY_OFF_PORT_DOWN,
3005 static int ep_throwable[] =
3010 static int ep_can_explode[] =
3012 /* same elements as in 'ep_explodes_impact' */
3017 /* same elements as in 'ep_explodes_smashed' */
3023 /* elements that can explode by explosion or by dragonfire */
3027 EL_EM_DYNAMITE_ACTIVE,
3028 EL_DYNABOMB_PLAYER_1_ACTIVE,
3029 EL_DYNABOMB_PLAYER_2_ACTIVE,
3030 EL_DYNABOMB_PLAYER_3_ACTIVE,
3031 EL_DYNABOMB_PLAYER_4_ACTIVE,
3032 EL_DYNABOMB_INCREASE_NUMBER,
3033 EL_DYNABOMB_INCREASE_SIZE,
3034 EL_DYNABOMB_INCREASE_POWER,
3035 EL_SP_DISK_RED_ACTIVE,
3043 /* elements that can explode only by explosion */
3049 static int ep_gravity_reachable[] =
3055 EL_INVISIBLE_SAND_ACTIVE,
3060 EL_SP_PORT_HORIZONTAL,
3061 EL_SP_PORT_VERTICAL,
3063 EL_SP_GRAVITY_PORT_LEFT,
3064 EL_SP_GRAVITY_PORT_RIGHT,
3065 EL_SP_GRAVITY_PORT_UP,
3066 EL_SP_GRAVITY_PORT_DOWN,
3067 EL_SP_GRAVITY_ON_PORT_LEFT,
3068 EL_SP_GRAVITY_ON_PORT_RIGHT,
3069 EL_SP_GRAVITY_ON_PORT_UP,
3070 EL_SP_GRAVITY_ON_PORT_DOWN,
3071 EL_SP_GRAVITY_OFF_PORT_LEFT,
3072 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3073 EL_SP_GRAVITY_OFF_PORT_UP,
3074 EL_SP_GRAVITY_OFF_PORT_DOWN,
3080 static int ep_player[] =
3087 EL_SOKOBAN_FIELD_PLAYER,
3093 static int ep_can_pass_magic_wall[] =
3107 static int ep_can_pass_dc_magic_wall[] =
3123 static int ep_switchable[] =
3127 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3128 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3129 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3130 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3131 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3132 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3133 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3134 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3135 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3136 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3137 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3138 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3139 EL_SWITCHGATE_SWITCH_UP,
3140 EL_SWITCHGATE_SWITCH_DOWN,
3141 EL_DC_SWITCHGATE_SWITCH_UP,
3142 EL_DC_SWITCHGATE_SWITCH_DOWN,
3144 EL_LIGHT_SWITCH_ACTIVE,
3146 EL_DC_TIMEGATE_SWITCH,
3147 EL_BALLOON_SWITCH_LEFT,
3148 EL_BALLOON_SWITCH_RIGHT,
3149 EL_BALLOON_SWITCH_UP,
3150 EL_BALLOON_SWITCH_DOWN,
3151 EL_BALLOON_SWITCH_ANY,
3152 EL_BALLOON_SWITCH_NONE,
3155 EL_EMC_MAGIC_BALL_SWITCH,
3156 EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3161 static int ep_bd_element[] =
3195 static int ep_sp_element[] =
3197 /* should always be valid */
3200 /* standard classic Supaplex elements */
3207 EL_SP_HARDWARE_GRAY,
3215 EL_SP_GRAVITY_PORT_RIGHT,
3216 EL_SP_GRAVITY_PORT_DOWN,
3217 EL_SP_GRAVITY_PORT_LEFT,
3218 EL_SP_GRAVITY_PORT_UP,
3223 EL_SP_PORT_VERTICAL,
3224 EL_SP_PORT_HORIZONTAL,
3230 EL_SP_HARDWARE_BASE_1,
3231 EL_SP_HARDWARE_GREEN,
3232 EL_SP_HARDWARE_BLUE,
3234 EL_SP_HARDWARE_YELLOW,
3235 EL_SP_HARDWARE_BASE_2,
3236 EL_SP_HARDWARE_BASE_3,
3237 EL_SP_HARDWARE_BASE_4,
3238 EL_SP_HARDWARE_BASE_5,
3239 EL_SP_HARDWARE_BASE_6,
3243 /* additional elements that appeared in newer Supaplex levels */
3246 /* additional gravity port elements (not switching, but setting gravity) */
3247 EL_SP_GRAVITY_ON_PORT_LEFT,
3248 EL_SP_GRAVITY_ON_PORT_RIGHT,
3249 EL_SP_GRAVITY_ON_PORT_UP,
3250 EL_SP_GRAVITY_ON_PORT_DOWN,
3251 EL_SP_GRAVITY_OFF_PORT_LEFT,
3252 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3253 EL_SP_GRAVITY_OFF_PORT_UP,
3254 EL_SP_GRAVITY_OFF_PORT_DOWN,
3256 /* more than one Murphy in a level results in an inactive clone */
3259 /* runtime Supaplex elements */
3260 EL_SP_DISK_RED_ACTIVE,
3261 EL_SP_TERMINAL_ACTIVE,
3262 EL_SP_BUGGY_BASE_ACTIVATING,
3263 EL_SP_BUGGY_BASE_ACTIVE,
3270 static int ep_sb_element[] =
3275 EL_SOKOBAN_FIELD_EMPTY,
3276 EL_SOKOBAN_FIELD_FULL,
3277 EL_SOKOBAN_FIELD_PLAYER,
3282 EL_INVISIBLE_STEELWALL,
3287 static int ep_gem[] =
3299 static int ep_food_dark_yamyam[] =
3327 static int ep_food_penguin[] =
3341 static int ep_food_pig[] =
3353 static int ep_historic_wall[] =
3364 EL_GATE_1_GRAY_ACTIVE,
3365 EL_GATE_2_GRAY_ACTIVE,
3366 EL_GATE_3_GRAY_ACTIVE,
3367 EL_GATE_4_GRAY_ACTIVE,
3376 EL_EM_GATE_1_GRAY_ACTIVE,
3377 EL_EM_GATE_2_GRAY_ACTIVE,
3378 EL_EM_GATE_3_GRAY_ACTIVE,
3379 EL_EM_GATE_4_GRAY_ACTIVE,
3386 EL_EXPANDABLE_WALL_HORIZONTAL,
3387 EL_EXPANDABLE_WALL_VERTICAL,
3388 EL_EXPANDABLE_WALL_ANY,
3389 EL_EXPANDABLE_WALL_GROWING,
3390 EL_BD_EXPANDABLE_WALL,
3397 EL_SP_HARDWARE_GRAY,
3398 EL_SP_HARDWARE_GREEN,
3399 EL_SP_HARDWARE_BLUE,
3401 EL_SP_HARDWARE_YELLOW,
3402 EL_SP_HARDWARE_BASE_1,
3403 EL_SP_HARDWARE_BASE_2,
3404 EL_SP_HARDWARE_BASE_3,
3405 EL_SP_HARDWARE_BASE_4,
3406 EL_SP_HARDWARE_BASE_5,
3407 EL_SP_HARDWARE_BASE_6,
3409 EL_SP_TERMINAL_ACTIVE,
3412 EL_INVISIBLE_STEELWALL,
3413 EL_INVISIBLE_STEELWALL_ACTIVE,
3415 EL_INVISIBLE_WALL_ACTIVE,
3416 EL_STEELWALL_SLIPPERY,
3433 static int ep_historic_solid[] =
3437 EL_EXPANDABLE_WALL_HORIZONTAL,
3438 EL_EXPANDABLE_WALL_VERTICAL,
3439 EL_EXPANDABLE_WALL_ANY,
3440 EL_BD_EXPANDABLE_WALL,
3453 EL_QUICKSAND_FILLING,
3454 EL_QUICKSAND_EMPTYING,
3456 EL_MAGIC_WALL_ACTIVE,
3457 EL_MAGIC_WALL_EMPTYING,
3458 EL_MAGIC_WALL_FILLING,
3462 EL_BD_MAGIC_WALL_ACTIVE,
3463 EL_BD_MAGIC_WALL_EMPTYING,
3464 EL_BD_MAGIC_WALL_FULL,
3465 EL_BD_MAGIC_WALL_FILLING,
3466 EL_BD_MAGIC_WALL_DEAD,
3475 EL_SP_TERMINAL_ACTIVE,
3479 EL_INVISIBLE_WALL_ACTIVE,
3480 EL_SWITCHGATE_SWITCH_UP,
3481 EL_SWITCHGATE_SWITCH_DOWN,
3482 EL_DC_SWITCHGATE_SWITCH_UP,
3483 EL_DC_SWITCHGATE_SWITCH_DOWN,
3485 EL_TIMEGATE_SWITCH_ACTIVE,
3486 EL_DC_TIMEGATE_SWITCH,
3487 EL_DC_TIMEGATE_SWITCH_ACTIVE,
3499 /* the following elements are a direct copy of "indestructible" elements,
3500 except "EL_ACID", which is "indestructible", but not "solid"! */
3505 EL_ACID_POOL_TOPLEFT,
3506 EL_ACID_POOL_TOPRIGHT,
3507 EL_ACID_POOL_BOTTOMLEFT,
3508 EL_ACID_POOL_BOTTOM,
3509 EL_ACID_POOL_BOTTOMRIGHT,
3510 EL_SP_HARDWARE_GRAY,
3511 EL_SP_HARDWARE_GREEN,
3512 EL_SP_HARDWARE_BLUE,
3514 EL_SP_HARDWARE_YELLOW,
3515 EL_SP_HARDWARE_BASE_1,
3516 EL_SP_HARDWARE_BASE_2,
3517 EL_SP_HARDWARE_BASE_3,
3518 EL_SP_HARDWARE_BASE_4,
3519 EL_SP_HARDWARE_BASE_5,
3520 EL_SP_HARDWARE_BASE_6,
3521 EL_INVISIBLE_STEELWALL,
3522 EL_INVISIBLE_STEELWALL_ACTIVE,
3523 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3524 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3525 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3526 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3527 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3528 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3529 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3530 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3531 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3532 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3533 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3534 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3536 EL_LIGHT_SWITCH_ACTIVE,
3537 EL_SIGN_EXCLAMATION,
3538 EL_SIGN_RADIOACTIVITY,
3545 EL_SIGN_ENTRY_FORBIDDEN,
3546 EL_SIGN_EMERGENCY_EXIT,
3554 EL_STEEL_EXIT_CLOSED,
3556 EL_DC_STEELWALL_1_LEFT,
3557 EL_DC_STEELWALL_1_RIGHT,
3558 EL_DC_STEELWALL_1_TOP,
3559 EL_DC_STEELWALL_1_BOTTOM,
3560 EL_DC_STEELWALL_1_HORIZONTAL,
3561 EL_DC_STEELWALL_1_VERTICAL,
3562 EL_DC_STEELWALL_1_TOPLEFT,
3563 EL_DC_STEELWALL_1_TOPRIGHT,
3564 EL_DC_STEELWALL_1_BOTTOMLEFT,
3565 EL_DC_STEELWALL_1_BOTTOMRIGHT,
3566 EL_DC_STEELWALL_1_TOPLEFT_2,
3567 EL_DC_STEELWALL_1_TOPRIGHT_2,
3568 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3569 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3570 EL_DC_STEELWALL_2_LEFT,
3571 EL_DC_STEELWALL_2_RIGHT,
3572 EL_DC_STEELWALL_2_TOP,
3573 EL_DC_STEELWALL_2_BOTTOM,
3574 EL_DC_STEELWALL_2_HORIZONTAL,
3575 EL_DC_STEELWALL_2_VERTICAL,
3576 EL_DC_STEELWALL_2_MIDDLE,
3577 EL_DC_STEELWALL_2_SINGLE,
3578 EL_STEELWALL_SLIPPERY,
3592 EL_GATE_1_GRAY_ACTIVE,
3593 EL_GATE_2_GRAY_ACTIVE,
3594 EL_GATE_3_GRAY_ACTIVE,
3595 EL_GATE_4_GRAY_ACTIVE,
3604 EL_EM_GATE_1_GRAY_ACTIVE,
3605 EL_EM_GATE_2_GRAY_ACTIVE,
3606 EL_EM_GATE_3_GRAY_ACTIVE,
3607 EL_EM_GATE_4_GRAY_ACTIVE,
3609 EL_SWITCHGATE_OPENING,
3610 EL_SWITCHGATE_CLOSED,
3611 EL_SWITCHGATE_CLOSING,
3613 EL_TIMEGATE_OPENING,
3615 EL_TIMEGATE_CLOSING,
3619 EL_TUBE_VERTICAL_LEFT,
3620 EL_TUBE_VERTICAL_RIGHT,
3621 EL_TUBE_HORIZONTAL_UP,
3622 EL_TUBE_HORIZONTAL_DOWN,
3631 static int ep_classic_enemy[] =
3648 static int ep_belt[] =
3650 EL_CONVEYOR_BELT_1_LEFT,
3651 EL_CONVEYOR_BELT_1_MIDDLE,
3652 EL_CONVEYOR_BELT_1_RIGHT,
3653 EL_CONVEYOR_BELT_2_LEFT,
3654 EL_CONVEYOR_BELT_2_MIDDLE,
3655 EL_CONVEYOR_BELT_2_RIGHT,
3656 EL_CONVEYOR_BELT_3_LEFT,
3657 EL_CONVEYOR_BELT_3_MIDDLE,
3658 EL_CONVEYOR_BELT_3_RIGHT,
3659 EL_CONVEYOR_BELT_4_LEFT,
3660 EL_CONVEYOR_BELT_4_MIDDLE,
3661 EL_CONVEYOR_BELT_4_RIGHT,
3666 static int ep_belt_active[] =
3668 EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3669 EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3670 EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3671 EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3672 EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3673 EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3674 EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3675 EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3676 EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3677 EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3678 EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3679 EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3684 static int ep_belt_switch[] =
3686 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3687 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3688 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3689 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3690 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3691 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3692 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3693 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3694 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3695 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3696 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3697 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3702 static int ep_tube[] =
3709 EL_TUBE_HORIZONTAL_UP,
3710 EL_TUBE_HORIZONTAL_DOWN,
3712 EL_TUBE_VERTICAL_LEFT,
3713 EL_TUBE_VERTICAL_RIGHT,
3719 static int ep_acid_pool[] =
3721 EL_ACID_POOL_TOPLEFT,
3722 EL_ACID_POOL_TOPRIGHT,
3723 EL_ACID_POOL_BOTTOMLEFT,
3724 EL_ACID_POOL_BOTTOM,
3725 EL_ACID_POOL_BOTTOMRIGHT,
3730 static int ep_keygate[] =
3740 EL_GATE_1_GRAY_ACTIVE,
3741 EL_GATE_2_GRAY_ACTIVE,
3742 EL_GATE_3_GRAY_ACTIVE,
3743 EL_GATE_4_GRAY_ACTIVE,
3752 EL_EM_GATE_1_GRAY_ACTIVE,
3753 EL_EM_GATE_2_GRAY_ACTIVE,
3754 EL_EM_GATE_3_GRAY_ACTIVE,
3755 EL_EM_GATE_4_GRAY_ACTIVE,
3764 EL_EMC_GATE_5_GRAY_ACTIVE,
3765 EL_EMC_GATE_6_GRAY_ACTIVE,
3766 EL_EMC_GATE_7_GRAY_ACTIVE,
3767 EL_EMC_GATE_8_GRAY_ACTIVE,
3769 EL_DC_GATE_WHITE_GRAY,
3770 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3775 static int ep_amoeboid[] =
3787 static int ep_amoebalive[] =
3798 static int ep_has_editor_content[] =
3804 EL_SOKOBAN_FIELD_PLAYER,
3821 static int ep_can_turn_each_move[] =
3823 /* !!! do something with this one !!! */
3827 static int ep_can_grow[] =
3841 static int ep_active_bomb[] =
3844 EL_EM_DYNAMITE_ACTIVE,
3845 EL_DYNABOMB_PLAYER_1_ACTIVE,
3846 EL_DYNABOMB_PLAYER_2_ACTIVE,
3847 EL_DYNABOMB_PLAYER_3_ACTIVE,
3848 EL_DYNABOMB_PLAYER_4_ACTIVE,
3849 EL_SP_DISK_RED_ACTIVE,
3854 static int ep_inactive[] =
3864 EL_QUICKSAND_FAST_EMPTY,
3887 EL_GATE_1_GRAY_ACTIVE,
3888 EL_GATE_2_GRAY_ACTIVE,
3889 EL_GATE_3_GRAY_ACTIVE,
3890 EL_GATE_4_GRAY_ACTIVE,
3899 EL_EM_GATE_1_GRAY_ACTIVE,
3900 EL_EM_GATE_2_GRAY_ACTIVE,
3901 EL_EM_GATE_3_GRAY_ACTIVE,
3902 EL_EM_GATE_4_GRAY_ACTIVE,
3911 EL_EMC_GATE_5_GRAY_ACTIVE,
3912 EL_EMC_GATE_6_GRAY_ACTIVE,
3913 EL_EMC_GATE_7_GRAY_ACTIVE,
3914 EL_EMC_GATE_8_GRAY_ACTIVE,
3916 EL_DC_GATE_WHITE_GRAY,
3917 EL_DC_GATE_WHITE_GRAY_ACTIVE,
3918 EL_DC_GATE_FAKE_GRAY,
3921 EL_INVISIBLE_STEELWALL,
3929 EL_WALL_EMERALD_YELLOW,
3930 EL_DYNABOMB_INCREASE_NUMBER,
3931 EL_DYNABOMB_INCREASE_SIZE,
3932 EL_DYNABOMB_INCREASE_POWER,
3936 EL_SOKOBAN_FIELD_EMPTY,
3937 EL_SOKOBAN_FIELD_FULL,
3938 EL_WALL_EMERALD_RED,
3939 EL_WALL_EMERALD_PURPLE,
3940 EL_ACID_POOL_TOPLEFT,
3941 EL_ACID_POOL_TOPRIGHT,
3942 EL_ACID_POOL_BOTTOMLEFT,
3943 EL_ACID_POOL_BOTTOM,
3944 EL_ACID_POOL_BOTTOMRIGHT,
3948 EL_BD_MAGIC_WALL_DEAD,
3950 EL_DC_MAGIC_WALL_DEAD,
3951 EL_AMOEBA_TO_DIAMOND,
3959 EL_SP_GRAVITY_PORT_RIGHT,
3960 EL_SP_GRAVITY_PORT_DOWN,
3961 EL_SP_GRAVITY_PORT_LEFT,
3962 EL_SP_GRAVITY_PORT_UP,
3963 EL_SP_PORT_HORIZONTAL,
3964 EL_SP_PORT_VERTICAL,
3975 EL_SP_HARDWARE_GRAY,
3976 EL_SP_HARDWARE_GREEN,
3977 EL_SP_HARDWARE_BLUE,
3979 EL_SP_HARDWARE_YELLOW,
3980 EL_SP_HARDWARE_BASE_1,
3981 EL_SP_HARDWARE_BASE_2,
3982 EL_SP_HARDWARE_BASE_3,
3983 EL_SP_HARDWARE_BASE_4,
3984 EL_SP_HARDWARE_BASE_5,
3985 EL_SP_HARDWARE_BASE_6,
3986 EL_SP_GRAVITY_ON_PORT_LEFT,
3987 EL_SP_GRAVITY_ON_PORT_RIGHT,
3988 EL_SP_GRAVITY_ON_PORT_UP,
3989 EL_SP_GRAVITY_ON_PORT_DOWN,
3990 EL_SP_GRAVITY_OFF_PORT_LEFT,
3991 EL_SP_GRAVITY_OFF_PORT_RIGHT,
3992 EL_SP_GRAVITY_OFF_PORT_UP,
3993 EL_SP_GRAVITY_OFF_PORT_DOWN,
3994 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3995 EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3996 EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3997 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3998 EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3999 EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4000 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4001 EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4002 EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4003 EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4004 EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4005 EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4006 EL_SIGN_EXCLAMATION,
4007 EL_SIGN_RADIOACTIVITY,
4014 EL_SIGN_ENTRY_FORBIDDEN,
4015 EL_SIGN_EMERGENCY_EXIT,
4023 EL_DC_STEELWALL_1_LEFT,
4024 EL_DC_STEELWALL_1_RIGHT,
4025 EL_DC_STEELWALL_1_TOP,
4026 EL_DC_STEELWALL_1_BOTTOM,
4027 EL_DC_STEELWALL_1_HORIZONTAL,
4028 EL_DC_STEELWALL_1_VERTICAL,
4029 EL_DC_STEELWALL_1_TOPLEFT,
4030 EL_DC_STEELWALL_1_TOPRIGHT,
4031 EL_DC_STEELWALL_1_BOTTOMLEFT,
4032 EL_DC_STEELWALL_1_BOTTOMRIGHT,
4033 EL_DC_STEELWALL_1_TOPLEFT_2,
4034 EL_DC_STEELWALL_1_TOPRIGHT_2,
4035 EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4036 EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4037 EL_DC_STEELWALL_2_LEFT,
4038 EL_DC_STEELWALL_2_RIGHT,
4039 EL_DC_STEELWALL_2_TOP,
4040 EL_DC_STEELWALL_2_BOTTOM,
4041 EL_DC_STEELWALL_2_HORIZONTAL,
4042 EL_DC_STEELWALL_2_VERTICAL,
4043 EL_DC_STEELWALL_2_MIDDLE,
4044 EL_DC_STEELWALL_2_SINGLE,
4045 EL_STEELWALL_SLIPPERY,
4050 EL_EMC_WALL_SLIPPERY_1,
4051 EL_EMC_WALL_SLIPPERY_2,
4052 EL_EMC_WALL_SLIPPERY_3,
4053 EL_EMC_WALL_SLIPPERY_4,
4074 static int ep_em_slippery_wall[] =
4079 static int ep_gfx_crumbled[] =
4090 static int ep_editor_cascade_active[] =
4092 EL_INTERNAL_CASCADE_BD_ACTIVE,
4093 EL_INTERNAL_CASCADE_EM_ACTIVE,
4094 EL_INTERNAL_CASCADE_EMC_ACTIVE,
4095 EL_INTERNAL_CASCADE_RND_ACTIVE,
4096 EL_INTERNAL_CASCADE_SB_ACTIVE,
4097 EL_INTERNAL_CASCADE_SP_ACTIVE,
4098 EL_INTERNAL_CASCADE_DC_ACTIVE,
4099 EL_INTERNAL_CASCADE_DX_ACTIVE,
4100 EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4101 EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4102 EL_INTERNAL_CASCADE_CE_ACTIVE,
4103 EL_INTERNAL_CASCADE_GE_ACTIVE,
4104 EL_INTERNAL_CASCADE_REF_ACTIVE,
4105 EL_INTERNAL_CASCADE_USER_ACTIVE,
4106 EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4111 static int ep_editor_cascade_inactive[] =
4113 EL_INTERNAL_CASCADE_BD,
4114 EL_INTERNAL_CASCADE_EM,
4115 EL_INTERNAL_CASCADE_EMC,
4116 EL_INTERNAL_CASCADE_RND,
4117 EL_INTERNAL_CASCADE_SB,
4118 EL_INTERNAL_CASCADE_SP,
4119 EL_INTERNAL_CASCADE_DC,
4120 EL_INTERNAL_CASCADE_DX,
4121 EL_INTERNAL_CASCADE_CHARS,
4122 EL_INTERNAL_CASCADE_STEEL_CHARS,
4123 EL_INTERNAL_CASCADE_CE,
4124 EL_INTERNAL_CASCADE_GE,
4125 EL_INTERNAL_CASCADE_REF,
4126 EL_INTERNAL_CASCADE_USER,
4127 EL_INTERNAL_CASCADE_DYNAMIC,
4132 static int ep_obsolete[] =
4136 EL_EM_KEY_1_FILE_OBSOLETE,
4137 EL_EM_KEY_2_FILE_OBSOLETE,
4138 EL_EM_KEY_3_FILE_OBSOLETE,
4139 EL_EM_KEY_4_FILE_OBSOLETE,
4140 EL_ENVELOPE_OBSOLETE,
4149 } element_properties[] =
4151 { ep_diggable, EP_DIGGABLE },
4152 { ep_collectible_only, EP_COLLECTIBLE_ONLY },
4153 { ep_dont_run_into, EP_DONT_RUN_INTO },
4154 { ep_dont_collide_with, EP_DONT_COLLIDE_WITH },
4155 { ep_dont_touch, EP_DONT_TOUCH },
4156 { ep_indestructible, EP_INDESTRUCTIBLE },
4157 { ep_slippery, EP_SLIPPERY },
4158 { ep_can_change, EP_CAN_CHANGE },
4159 { ep_can_move, EP_CAN_MOVE },
4160 { ep_can_fall, EP_CAN_FALL },
4161 { ep_can_smash_player, EP_CAN_SMASH_PLAYER },
4162 { ep_can_smash_enemies, EP_CAN_SMASH_ENEMIES },
4163 { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
4164 { ep_explodes_by_fire, EP_EXPLODES_BY_FIRE },
4165 { ep_explodes_smashed, EP_EXPLODES_SMASHED },
4166 { ep_explodes_impact, EP_EXPLODES_IMPACT },
4167 { ep_walkable_over, EP_WALKABLE_OVER },
4168 { ep_walkable_inside, EP_WALKABLE_INSIDE },
4169 { ep_walkable_under, EP_WALKABLE_UNDER },
4170 { ep_passable_over, EP_PASSABLE_OVER },
4171 { ep_passable_inside, EP_PASSABLE_INSIDE },
4172 { ep_passable_under, EP_PASSABLE_UNDER },
4173 { ep_droppable, EP_DROPPABLE },
4174 { ep_explodes_1x1_old, EP_EXPLODES_1X1_OLD },
4175 { ep_pushable, EP_PUSHABLE },
4176 { ep_explodes_cross_old, EP_EXPLODES_CROSS_OLD },
4177 { ep_protected, EP_PROTECTED },
4178 { ep_throwable, EP_THROWABLE },
4179 { ep_can_explode, EP_CAN_EXPLODE },
4180 { ep_gravity_reachable, EP_GRAVITY_REACHABLE },
4182 { ep_player, EP_PLAYER },
4183 { ep_can_pass_magic_wall, EP_CAN_PASS_MAGIC_WALL },
4184 { ep_can_pass_dc_magic_wall, EP_CAN_PASS_DC_MAGIC_WALL },
4185 { ep_switchable, EP_SWITCHABLE },
4186 { ep_bd_element, EP_BD_ELEMENT },
4187 { ep_sp_element, EP_SP_ELEMENT },
4188 { ep_sb_element, EP_SB_ELEMENT },
4190 { ep_food_dark_yamyam, EP_FOOD_DARK_YAMYAM },
4191 { ep_food_penguin, EP_FOOD_PENGUIN },
4192 { ep_food_pig, EP_FOOD_PIG },
4193 { ep_historic_wall, EP_HISTORIC_WALL },
4194 { ep_historic_solid, EP_HISTORIC_SOLID },
4195 { ep_classic_enemy, EP_CLASSIC_ENEMY },
4196 { ep_belt, EP_BELT },
4197 { ep_belt_active, EP_BELT_ACTIVE },
4198 { ep_belt_switch, EP_BELT_SWITCH },
4199 { ep_tube, EP_TUBE },
4200 { ep_acid_pool, EP_ACID_POOL },
4201 { ep_keygate, EP_KEYGATE },
4202 { ep_amoeboid, EP_AMOEBOID },
4203 { ep_amoebalive, EP_AMOEBALIVE },
4204 { ep_has_editor_content, EP_HAS_EDITOR_CONTENT },
4205 { ep_can_turn_each_move, EP_CAN_TURN_EACH_MOVE },
4206 { ep_can_grow, EP_CAN_GROW },
4207 { ep_active_bomb, EP_ACTIVE_BOMB },
4208 { ep_inactive, EP_INACTIVE },
4210 { ep_em_slippery_wall, EP_EM_SLIPPERY_WALL },
4212 { ep_gfx_crumbled, EP_GFX_CRUMBLED },
4214 { ep_editor_cascade_active, EP_EDITOR_CASCADE_ACTIVE },
4215 { ep_editor_cascade_inactive, EP_EDITOR_CASCADE_INACTIVE },
4217 { ep_obsolete, EP_OBSOLETE },
4224 /* always start with reliable default values (element has no properties) */
4225 /* (but never initialize clipboard elements after the very first time) */
4226 /* (to be able to use clipboard elements between several levels) */
4227 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4228 if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4229 for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4230 SET_PROPERTY(i, j, FALSE);
4232 /* set all base element properties from above array definitions */
4233 for (i = 0; element_properties[i].elements != NULL; i++)
4234 for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4235 SET_PROPERTY((element_properties[i].elements)[j],
4236 element_properties[i].property, TRUE);
4238 /* copy properties to some elements that are only stored in level file */
4239 for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4240 for (j = 0; copy_properties[j][0] != -1; j++)
4241 if (HAS_PROPERTY(copy_properties[j][0], i))
4242 for (k = 1; k <= 4; k++)
4243 SET_PROPERTY(copy_properties[j][k], i, TRUE);
4245 /* set static element properties that are not listed in array definitions */
4246 for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4247 SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4249 clipboard_elements_initialized = TRUE;
4252 void InitElementPropertiesEngine(int engine_version)
4254 static int no_wall_properties[] =
4257 EP_COLLECTIBLE_ONLY,
4259 EP_DONT_COLLIDE_WITH,
4262 EP_CAN_SMASH_PLAYER,
4263 EP_CAN_SMASH_ENEMIES,
4264 EP_CAN_SMASH_EVERYTHING,
4269 EP_FOOD_DARK_YAMYAM,
4285 /* important: after initialization in InitElementPropertiesStatic(), the
4286 elements are not again initialized to a default value; therefore all
4287 changes have to make sure that they leave the element with a defined
4288 property (which means that conditional property changes must be set to
4289 a reliable default value before) */
4291 /* resolve group elements */
4292 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4293 ResolveGroupElement(EL_GROUP_START + i);
4295 /* set all special, combined or engine dependent element properties */
4296 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4298 /* do not change (already initialized) clipboard elements here */
4299 if (IS_CLIPBOARD_ELEMENT(i))
4302 /* ---------- INACTIVE ------------------------------------------------- */
4303 SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4304 i <= EL_CHAR_END) ||
4305 (i >= EL_STEEL_CHAR_START &&
4306 i <= EL_STEEL_CHAR_END)));
4308 /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4309 SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4310 IS_WALKABLE_INSIDE(i) ||
4311 IS_WALKABLE_UNDER(i)));
4313 SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4314 IS_PASSABLE_INSIDE(i) ||
4315 IS_PASSABLE_UNDER(i)));
4317 SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4318 IS_PASSABLE_OVER(i)));
4320 SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4321 IS_PASSABLE_INSIDE(i)));
4323 SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4324 IS_PASSABLE_UNDER(i)));
4326 SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4329 /* ---------- COLLECTIBLE ---------------------------------------------- */
4330 SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4334 /* ---------- SNAPPABLE ------------------------------------------------ */
4335 SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4336 IS_COLLECTIBLE(i) ||
4340 /* ---------- WALL ----------------------------------------------------- */
4341 SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */
4343 for (j = 0; no_wall_properties[j] != -1; j++)
4344 if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4345 i >= EL_FIRST_RUNTIME_UNREAL)
4346 SET_PROPERTY(i, EP_WALL, FALSE);
4348 if (IS_HISTORIC_WALL(i))
4349 SET_PROPERTY(i, EP_WALL, TRUE);
4351 /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4352 if (engine_version < VERSION_IDENT(2,2,0,0))
4353 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4355 SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4357 !IS_COLLECTIBLE(i)));
4359 /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4360 if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4361 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4363 SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4364 IS_INDESTRUCTIBLE(i)));
4366 /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4368 SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4369 else if (engine_version < VERSION_IDENT(2,2,0,0))
4370 SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4372 SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4376 if (IS_CUSTOM_ELEMENT(i))
4378 /* these are additional properties which are initially false when set */
4380 /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4382 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4383 if (DONT_COLLIDE_WITH(i))
4384 SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4386 /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4387 if (CAN_SMASH_EVERYTHING(i))
4388 SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4389 if (CAN_SMASH_ENEMIES(i))
4390 SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4393 /* ---------- CAN_SMASH ------------------------------------------------ */
4394 SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4395 CAN_SMASH_ENEMIES(i) ||
4396 CAN_SMASH_EVERYTHING(i)));
4398 /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4399 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4400 EXPLODES_BY_FIRE(i)));
4402 /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4403 SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4404 EXPLODES_SMASHED(i)));
4406 /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4407 SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4408 EXPLODES_IMPACT(i)));
4410 /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4411 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4413 /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4414 SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4415 i == EL_BLACK_ORB));
4417 /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4418 SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4420 IS_CUSTOM_ELEMENT(i)));
4422 /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4423 SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4424 i == EL_SP_ELECTRON));
4426 /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4427 if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4428 SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4429 getMoveIntoAcidProperty(&level, i));
4431 /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4432 if (MAYBE_DONT_COLLIDE_WITH(i))
4433 SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4434 getDontCollideWithProperty(&level, i));
4436 /* ---------- SP_PORT -------------------------------------------------- */
4437 SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4438 IS_PASSABLE_INSIDE(i)));
4440 /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4441 for (j = 0; j < level.num_android_clone_elements; j++)
4442 SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4444 IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4446 /* ---------- CAN_CHANGE ----------------------------------------------- */
4447 SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */
4448 for (j = 0; j < element_info[i].num_change_pages; j++)
4449 if (element_info[i].change_page[j].can_change)
4450 SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4452 /* ---------- HAS_ACTION ----------------------------------------------- */
4453 SET_PROPERTY(i, EP_HAS_ACTION, FALSE); /* default: has no action */
4454 for (j = 0; j < element_info[i].num_change_pages; j++)
4455 if (element_info[i].change_page[j].has_action)
4456 SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4458 /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4459 SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4462 /* ---------- GFX_CRUMBLED --------------------------------------------- */
4463 SET_PROPERTY(i, EP_GFX_CRUMBLED,
4464 element_info[i].crumbled[ACTION_DEFAULT] !=
4465 element_info[i].graphic[ACTION_DEFAULT]);
4467 /* ---------- EDITOR_CASCADE ------------------------------------------- */
4468 SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4469 IS_EDITOR_CASCADE_INACTIVE(i)));
4472 /* dynamically adjust element properties according to game engine version */
4474 static int ep_em_slippery_wall[] =
4479 EL_EXPANDABLE_WALL_HORIZONTAL,
4480 EL_EXPANDABLE_WALL_VERTICAL,
4481 EL_EXPANDABLE_WALL_ANY,
4482 EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4483 EL_EXPANDABLE_STEELWALL_VERTICAL,
4484 EL_EXPANDABLE_STEELWALL_ANY,
4485 EL_EXPANDABLE_STEELWALL_GROWING,
4489 static int ep_em_explodes_by_fire[] =
4492 EL_EM_DYNAMITE_ACTIVE,
4497 /* special EM style gems behaviour */
4498 for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4499 SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4500 level.em_slippery_gems);
4502 /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4503 SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4504 (level.em_slippery_gems &&
4505 engine_version > VERSION_IDENT(2,0,1,0)));
4507 /* special EM style explosion behaviour regarding chain reactions */
4508 for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4509 SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4510 level.em_explodes_by_fire);
4513 /* this is needed because some graphics depend on element properties */
4514 if (game_status == GAME_MODE_PLAYING)
4515 InitElementGraphicInfo();
4518 void InitElementPropertiesAfterLoading(int engine_version)
4522 /* set some other uninitialized values of custom elements in older levels */
4523 if (engine_version < VERSION_IDENT(3,1,0,0))
4525 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4527 int element = EL_CUSTOM_START + i;
4529 element_info[element].access_direction = MV_ALL_DIRECTIONS;
4531 element_info[element].explosion_delay = 17;
4532 element_info[element].ignition_delay = 8;
4537 void InitElementPropertiesGfxElement()
4541 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4543 struct ElementInfo *ei = &element_info[i];
4545 ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4549 static void InitGlobal()
4554 for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4556 /* check if element_name_info entry defined for each element in "main.h" */
4557 if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4558 Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4560 element_info[i].token_name = element_name_info[i].token_name;
4561 element_info[i].class_name = element_name_info[i].class_name;
4562 element_info[i].editor_description= element_name_info[i].editor_description;
4565 /* create hash from image config list */
4566 image_config_hash = newSetupFileHash();
4567 for (i = 0; image_config[i].token != NULL; i++)
4568 setHashEntry(image_config_hash,
4569 image_config[i].token,
4570 image_config[i].value);
4572 /* create hash from element token list */
4573 element_token_hash = newSetupFileHash();
4574 for (i = 0; element_name_info[i].token_name != NULL; i++)
4575 setHashEntry(element_token_hash,
4576 element_name_info[i].token_name,
4579 /* create hash from graphic token list */
4580 graphic_token_hash = newSetupFileHash();
4581 for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4582 if (strSuffix(image_config[i].value, ".png") ||
4583 strSuffix(image_config[i].value, ".pcx") ||
4584 strSuffix(image_config[i].value, ".wav") ||
4585 strEqual(image_config[i].value, UNDEFINED_FILENAME))
4586 setHashEntry(graphic_token_hash,
4587 image_config[i].token,
4588 int2str(graphic++, 0));
4590 /* create hash from font token list */
4591 font_token_hash = newSetupFileHash();
4592 for (i = 0; font_info[i].token_name != NULL; i++)
4593 setHashEntry(font_token_hash,
4594 font_info[i].token_name,
4597 /* set default filenames for all cloned graphics in static configuration */
4598 for (i = 0; image_config[i].token != NULL; i++)
4600 if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4602 char *token = image_config[i].token;
4603 char *token_clone_from = getStringCat2(token, ".clone_from");
4604 char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4606 if (token_cloned != NULL)
4608 char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4610 if (value_cloned != NULL)
4612 /* set default filename in static configuration */
4613 image_config[i].value = value_cloned;
4615 /* set default filename in image config hash */
4616 setHashEntry(image_config_hash, token, value_cloned);
4620 free(token_clone_from);
4624 /* always start with reliable default values (all elements) */
4625 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4626 ActiveElement[i] = i;
4628 /* now add all entries that have an active state (active elements) */
4629 for (i = 0; element_with_active_state[i].element != -1; i++)
4631 int element = element_with_active_state[i].element;
4632 int element_active = element_with_active_state[i].element_active;
4634 ActiveElement[element] = element_active;
4637 /* always start with reliable default values (all buttons) */
4638 for (i = 0; i < NUM_IMAGE_FILES; i++)
4639 ActiveButton[i] = i;
4641 /* now add all entries that have an active state (active buttons) */
4642 for (i = 0; button_with_active_state[i].button != -1; i++)
4644 int button = button_with_active_state[i].button;
4645 int button_active = button_with_active_state[i].button_active;
4647 ActiveButton[button] = button_active;
4650 /* always start with reliable default values (all fonts) */
4651 for (i = 0; i < NUM_FONTS; i++)
4654 /* now add all entries that have an active state (active fonts) */
4655 for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4657 int font = font_with_active_state[i].font_nr;
4658 int font_active = font_with_active_state[i].font_nr_active;
4660 ActiveFont[font] = font_active;
4663 global.autoplay_leveldir = NULL;
4664 global.convert_leveldir = NULL;
4665 global.create_images_dir = NULL;
4667 global.frames_per_second = 0;
4669 global.border_status = GAME_MODE_MAIN;
4671 global.use_envelope_request = FALSE;
4674 void Execute_Command(char *command)
4678 if (strEqual(command, "print graphicsinfo.conf"))
4680 Print("# You can configure additional/alternative image files here.\n");
4681 Print("# (The entries below are default and therefore commented out.)\n");
4683 Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4685 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4688 for (i = 0; image_config[i].token != NULL; i++)
4689 Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4690 image_config[i].value));
4694 else if (strEqual(command, "print soundsinfo.conf"))
4696 Print("# You can configure additional/alternative sound files here.\n");
4697 Print("# (The entries below are default and therefore commented out.)\n");
4699 Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4701 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4704 for (i = 0; sound_config[i].token != NULL; i++)
4705 Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4706 sound_config[i].value));
4710 else if (strEqual(command, "print musicinfo.conf"))
4712 Print("# You can configure additional/alternative music files here.\n");
4713 Print("# (The entries below are default and therefore commented out.)\n");
4715 Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4717 Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4720 for (i = 0; music_config[i].token != NULL; i++)
4721 Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4722 music_config[i].value));
4726 else if (strEqual(command, "print editorsetup.conf"))
4728 Print("# You can configure your personal editor element list here.\n");
4729 Print("# (The entries below are default and therefore commented out.)\n");
4732 /* this is needed to be able to check element list for cascade elements */
4733 InitElementPropertiesStatic();
4734 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4736 PrintEditorElementList();
4740 else if (strEqual(command, "print helpanim.conf"))
4742 Print("# You can configure different element help animations here.\n");
4743 Print("# (The entries below are default and therefore commented out.)\n");
4746 for (i = 0; helpanim_config[i].token != NULL; i++)
4748 Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4749 helpanim_config[i].value));
4751 if (strEqual(helpanim_config[i].token, "end"))
4757 else if (strEqual(command, "print helptext.conf"))
4759 Print("# You can configure different element help text here.\n");
4760 Print("# (The entries below are default and therefore commented out.)\n");
4763 for (i = 0; helptext_config[i].token != NULL; i++)
4764 Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4765 helptext_config[i].value));
4769 else if (strPrefix(command, "dump level "))
4771 char *filename = &command[11];
4773 if (!fileExists(filename))
4774 Error(ERR_EXIT, "cannot open file '%s'", filename);
4776 LoadLevelFromFilename(&level, filename);
4781 else if (strPrefix(command, "dump tape "))
4783 char *filename = &command[10];
4785 if (!fileExists(filename))
4786 Error(ERR_EXIT, "cannot open file '%s'", filename);
4788 LoadTapeFromFilename(filename);
4793 else if (strPrefix(command, "autotest ") ||
4794 strPrefix(command, "autoplay ") ||
4795 strPrefix(command, "autoffwd "))
4797 char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4799 global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4800 strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4801 strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4803 while (*str_ptr != '\0') /* continue parsing string */
4805 /* cut leading whitespace from string, replace it by string terminator */
4806 while (*str_ptr == ' ' || *str_ptr == '\t')
4809 if (*str_ptr == '\0') /* end of string reached */
4812 if (global.autoplay_leveldir == NULL) /* read level set string */
4814 global.autoplay_leveldir = str_ptr;
4815 global.autoplay_all = TRUE; /* default: play all tapes */
4817 for (i = 0; i < MAX_TAPES_PER_SET; i++)
4818 global.autoplay_level[i] = FALSE;
4820 else /* read level number string */
4822 int level_nr = atoi(str_ptr); /* get level_nr value */
4824 if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4825 global.autoplay_level[level_nr] = TRUE;
4827 global.autoplay_all = FALSE;
4830 /* advance string pointer to the next whitespace (or end of string) */
4831 while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4835 else if (strPrefix(command, "convert "))
4837 char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4838 char *str_ptr = strchr(str_copy, ' ');
4840 global.convert_leveldir = str_copy;
4841 global.convert_level_nr = -1;
4843 if (str_ptr != NULL) /* level number follows */
4845 *str_ptr++ = '\0'; /* terminate leveldir string */
4846 global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
4849 else if (strPrefix(command, "create images "))
4851 global.create_images_dir = getStringCopy(&command[14]);
4853 if (access(global.create_images_dir, W_OK) != 0)
4854 Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4855 global.create_images_dir);
4857 else if (strPrefix(command, "create CE image "))
4859 CreateCustomElementImages(&command[16]);
4865 #if defined(TARGET_SDL2)
4866 else if (strEqual(command, "SDL_ListModes"))
4868 SDL_Init(SDL_INIT_VIDEO);
4870 int num_displays = SDL_GetNumVideoDisplays();
4872 // check if there are any displays available
4873 if (num_displays < 0)
4875 Print("No displays available: %s\n", SDL_GetError());
4880 for (i = 0; i < num_displays; i++)
4882 int num_modes = SDL_GetNumDisplayModes(i);
4885 Print("Available display modes for display %d:\n", i);
4887 // check if there are any display modes available for this display
4890 Print("No display modes available for display %d: %s\n",
4896 for (j = 0; j < num_modes; j++)
4898 SDL_DisplayMode mode;
4900 if (SDL_GetDisplayMode(i, j, &mode) < 0)
4902 Print("Cannot get display mode %d for display %d: %s\n",
4903 j, i, SDL_GetError());
4908 Print("- %d x %d\n", mode.w, mode.h);
4914 #elif defined(TARGET_SDL)
4915 else if (strEqual(command, "SDL_ListModes"))
4920 SDL_Init(SDL_INIT_VIDEO);
4922 /* get available fullscreen/hardware modes */
4923 modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4925 /* check if there are any modes available */
4928 Print("No modes available!\n");
4933 /* check if our resolution is restricted */
4934 if (modes == (SDL_Rect **)-1)
4936 Print("All resolutions available.\n");
4940 Print("Available display modes:\n");
4942 for (i = 0; modes[i]; i++)
4943 Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4953 Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4957 static void InitSetup()
4959 LoadSetup(); /* global setup info */
4961 /* set some options from setup file */
4963 if (setup.options.verbose)
4964 options.verbose = TRUE;
4967 static void InitGameInfo()
4969 game.restart_level = FALSE;
4972 static void InitPlayerInfo()
4976 /* choose default local player */
4977 local_player = &stored_player[0];
4979 for (i = 0; i < MAX_PLAYERS; i++)
4980 stored_player[i].connected = FALSE;
4982 local_player->connected = TRUE;
4985 static void InitArtworkInfo()
4990 static char *get_string_in_brackets(char *string)
4992 char *string_in_brackets = checked_malloc(strlen(string) + 3);
4994 sprintf(string_in_brackets, "[%s]", string);
4996 return string_in_brackets;
4999 static char *get_level_id_suffix(int id_nr)
5001 char *id_suffix = checked_malloc(1 + 3 + 1);
5003 if (id_nr < 0 || id_nr > 999)
5006 sprintf(id_suffix, ".%03d", id_nr);
5011 static void InitArtworkConfig()
5013 static char *image_id_prefix[MAX_NUM_ELEMENTS +
5015 NUM_GLOBAL_ANIM_TOKENS + 1];
5016 static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5017 static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5018 static char *action_id_suffix[NUM_ACTIONS + 1];
5019 static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5020 static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5021 static char *level_id_suffix[MAX_LEVELS + 1];
5022 static char *dummy[1] = { NULL };
5023 static char *ignore_generic_tokens[] =
5029 static char **ignore_image_tokens;
5030 static char **ignore_sound_tokens;
5031 static char **ignore_music_tokens;
5032 int num_ignore_generic_tokens;
5033 int num_ignore_image_tokens;
5034 int num_ignore_sound_tokens;
5035 int num_ignore_music_tokens;
5038 /* dynamically determine list of generic tokens to be ignored */
5039 num_ignore_generic_tokens = 0;
5040 for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5041 num_ignore_generic_tokens++;
5043 /* dynamically determine list of image tokens to be ignored */
5044 num_ignore_image_tokens = num_ignore_generic_tokens;
5045 for (i = 0; image_config_vars[i].token != NULL; i++)
5046 num_ignore_image_tokens++;
5047 ignore_image_tokens =
5048 checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5049 for (i = 0; i < num_ignore_generic_tokens; i++)
5050 ignore_image_tokens[i] = ignore_generic_tokens[i];
5051 for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5052 ignore_image_tokens[num_ignore_generic_tokens + i] =
5053 image_config_vars[i].token;
5054 ignore_image_tokens[num_ignore_image_tokens] = NULL;
5056 /* dynamically determine list of sound tokens to be ignored */
5057 num_ignore_sound_tokens = num_ignore_generic_tokens;
5058 ignore_sound_tokens =
5059 checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5060 for (i = 0; i < num_ignore_generic_tokens; i++)
5061 ignore_sound_tokens[i] = ignore_generic_tokens[i];
5062 ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5064 /* dynamically determine list of music tokens to be ignored */
5065 num_ignore_music_tokens = num_ignore_generic_tokens;
5066 ignore_music_tokens =
5067 checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5068 for (i = 0; i < num_ignore_generic_tokens; i++)
5069 ignore_music_tokens[i] = ignore_generic_tokens[i];
5070 ignore_music_tokens[num_ignore_music_tokens] = NULL;
5072 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5073 image_id_prefix[i] = element_info[i].token_name;
5074 for (i = 0; i < NUM_FONTS; i++)
5075 image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5076 for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5077 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5078 global_anim_info[i].token_name;
5079 image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5081 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5082 sound_id_prefix[i] = element_info[i].token_name;
5083 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5084 sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5085 get_string_in_brackets(element_info[i].class_name);
5086 sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5088 for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5089 music_id_prefix[i] = music_prefix_info[i].prefix;
5090 music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5092 for (i = 0; i < NUM_ACTIONS; i++)
5093 action_id_suffix[i] = element_action_info[i].suffix;
5094 action_id_suffix[NUM_ACTIONS] = NULL;
5096 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5097 direction_id_suffix[i] = element_direction_info[i].suffix;
5098 direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5100 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5101 special_id_suffix[i] = special_suffix_info[i].suffix;
5102 special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5104 for (i = 0; i < MAX_LEVELS; i++)
5105 level_id_suffix[i] = get_level_id_suffix(i);
5106 level_id_suffix[MAX_LEVELS] = NULL;
5108 InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5109 image_id_prefix, action_id_suffix, direction_id_suffix,
5110 special_id_suffix, ignore_image_tokens);
5111 InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5112 sound_id_prefix, action_id_suffix, dummy,
5113 special_id_suffix, ignore_sound_tokens);
5114 InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5115 music_id_prefix, special_id_suffix, level_id_suffix,
5116 dummy, ignore_music_tokens);
5119 static void InitMixer()
5126 void InitGfxBuffers()
5128 static int win_xsize_last = -1;
5129 static int win_ysize_last = -1;
5131 /* create additional image buffers for double-buffering and cross-fading */
5133 if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5135 /* may contain content for cross-fading -- only re-create if changed */
5136 ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5137 ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5139 win_xsize_last = WIN_XSIZE;
5140 win_ysize_last = WIN_YSIZE;
5143 ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5144 ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5145 ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5146 ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5147 ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5149 /* initialize screen properties */
5150 InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5151 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5153 InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5154 InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5155 InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5156 InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5157 InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5158 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5160 /* required if door size definitions have changed */
5161 InitGraphicCompatibilityInfo_Doors();
5163 InitGfxBuffers_EM();
5164 InitGfxBuffers_SP();
5169 struct GraphicInfo *graphic_info_last = graphic_info;
5170 char *filename_font_initial = NULL;
5171 char *filename_anim_initial = NULL;
5172 Bitmap *bitmap_font_initial = NULL;
5176 /* determine settings for initial font (for displaying startup messages) */
5177 for (i = 0; image_config[i].token != NULL; i++)
5179 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5181 char font_token[128];
5184 sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5185 len_font_token = strlen(font_token);
5187 if (strEqual(image_config[i].token, font_token))
5188 filename_font_initial = image_config[i].value;
5189 else if (strlen(image_config[i].token) > len_font_token &&
5190 strncmp(image_config[i].token, font_token, len_font_token) == 0)
5192 if (strEqual(&image_config[i].token[len_font_token], ".x"))
5193 font_initial[j].src_x = atoi(image_config[i].value);
5194 else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5195 font_initial[j].src_y = atoi(image_config[i].value);
5196 else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5197 font_initial[j].width = atoi(image_config[i].value);
5198 else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5199 font_initial[j].height = atoi(image_config[i].value);
5204 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5206 font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5207 font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5210 if (filename_font_initial == NULL) /* should not happen */
5211 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5214 InitGfxCustomArtworkInfo();
5215 InitGfxOtherSettings();
5217 bitmap_font_initial = LoadCustomImage(filename_font_initial);
5219 for (j = 0; j < NUM_INITIAL_FONTS; j++)
5220 font_initial[j].bitmap = bitmap_font_initial;
5222 InitFontGraphicInfo();
5224 font_height = getFontHeight(FC_RED);
5226 DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5227 DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5228 DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5231 DrawInitText("Loading graphics", 120, FC_GREEN);
5233 /* initialize settings for busy animation with default values */
5234 int parameter[NUM_GFX_ARGS];
5235 for (i = 0; i < NUM_GFX_ARGS; i++)
5236 parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5237 image_config_suffix[i].token,
5238 image_config_suffix[i].type);
5240 char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5241 int len_anim_token = strlen(anim_token);
5243 /* read settings for busy animation from default custom artwork config */
5244 char *gfx_config_filename = getPath3(options.graphics_directory,
5246 GRAPHICSINFO_FILENAME);
5248 if (fileExists(gfx_config_filename))
5250 SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5252 if (setup_file_hash)
5254 char *filename = getHashEntry(setup_file_hash, anim_token);
5258 filename_anim_initial = getStringCopy(filename);
5260 for (j = 0; image_config_suffix[j].token != NULL; j++)
5262 int type = image_config_suffix[j].type;
5263 char *suffix = image_config_suffix[j].token;
5264 char *token = getStringCat2(anim_token, suffix);
5265 char *value = getHashEntry(setup_file_hash, token);
5267 checked_free(token);
5270 parameter[j] = get_graphic_parameter_value(value, suffix, type);
5274 freeSetupFileHash(setup_file_hash);
5278 if (filename_anim_initial == NULL)
5280 /* read settings for busy animation from static default artwork config */
5281 for (i = 0; image_config[i].token != NULL; i++)
5283 if (strEqual(image_config[i].token, anim_token))
5284 filename_anim_initial = getStringCopy(image_config[i].value);
5285 else if (strlen(image_config[i].token) > len_anim_token &&
5286 strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5288 for (j = 0; image_config_suffix[j].token != NULL; j++)
5290 if (strEqual(&image_config[i].token[len_anim_token],
5291 image_config_suffix[j].token))
5293 get_graphic_parameter_value(image_config[i].value,
5294 image_config_suffix[j].token,
5295 image_config_suffix[j].type);
5301 if (filename_anim_initial == NULL) /* should not happen */
5302 Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5304 anim_initial.bitmaps =
5305 checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5307 anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5308 LoadCustomImage(filename_anim_initial);
5310 checked_free(filename_anim_initial);
5312 graphic_info = &anim_initial; /* graphic == 0 => anim_initial */
5314 set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5316 graphic_info = graphic_info_last;
5318 init.busy.width = anim_initial.width;
5319 init.busy.height = anim_initial.height;
5321 InitMenuDesignSettings_Static();
5323 InitGfxDrawBusyAnimFunction(DrawInitAnim);
5324 InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5325 InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToScreen);
5327 /* use copy of busy animation to prevent change while reloading artwork */
5331 void InitGfxBackground()
5333 fieldbuffer = bitmap_db_field;
5334 SetDrawtoField(DRAW_BACKBUFFER);
5336 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5338 redraw_mask = REDRAW_ALL;
5341 static void InitLevelInfo()
5343 LoadLevelInfo(); /* global level info */
5344 LoadLevelSetup_LastSeries(); /* last played series info */
5345 LoadLevelSetup_SeriesInfo(); /* last played level info */
5347 if (global.autoplay_leveldir &&
5348 global.autoplay_mode != AUTOPLAY_TEST)
5350 leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5351 global.autoplay_leveldir);
5352 if (leveldir_current == NULL)
5353 leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5357 static void InitLevelArtworkInfo()
5359 LoadLevelArtworkInfo();
5362 static void InitImages()
5364 print_timestamp_init("InitImages");
5367 printf("::: leveldir_current->identifier == '%s'\n",
5368 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5369 printf("::: leveldir_current->graphics_path == '%s'\n",
5370 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5371 printf("::: leveldir_current->graphics_set == '%s'\n",
5372 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5373 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5374 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5377 setLevelArtworkDir(artwork.gfx_first);
5380 printf("::: leveldir_current->identifier == '%s'\n",
5381 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5382 printf("::: leveldir_current->graphics_path == '%s'\n",
5383 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5384 printf("::: leveldir_current->graphics_set == '%s'\n",
5385 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5386 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5387 leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5391 printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5392 leveldir_current->identifier,
5393 artwork.gfx_current_identifier,
5394 artwork.gfx_current->identifier,
5395 leveldir_current->graphics_set,
5396 leveldir_current->graphics_path);
5399 UPDATE_BUSY_STATE();
5401 ReloadCustomImages();
5402 print_timestamp_time("ReloadCustomImages");
5404 UPDATE_BUSY_STATE();
5406 LoadCustomElementDescriptions();
5407 print_timestamp_time("LoadCustomElementDescriptions");
5409 UPDATE_BUSY_STATE();
5411 LoadMenuDesignSettings();
5412 print_timestamp_time("LoadMenuDesignSettings");
5414 UPDATE_BUSY_STATE();
5416 ReinitializeGraphics();
5417 print_timestamp_time("ReinitializeGraphics");
5419 UPDATE_BUSY_STATE();
5421 print_timestamp_done("InitImages");
5424 static void InitSound(char *identifier)
5426 print_timestamp_init("InitSound");
5428 if (identifier == NULL)
5429 identifier = artwork.snd_current->identifier;
5431 /* set artwork path to send it to the sound server process */
5432 setLevelArtworkDir(artwork.snd_first);
5434 InitReloadCustomSounds(identifier);
5435 print_timestamp_time("InitReloadCustomSounds");
5437 ReinitializeSounds();
5438 print_timestamp_time("ReinitializeSounds");
5440 print_timestamp_done("InitSound");
5443 static void InitMusic(char *identifier)
5445 print_timestamp_init("InitMusic");
5447 if (identifier == NULL)
5448 identifier = artwork.mus_current->identifier;
5450 /* set artwork path to send it to the sound server process */
5451 setLevelArtworkDir(artwork.mus_first);
5453 InitReloadCustomMusic(identifier);
5454 print_timestamp_time("InitReloadCustomMusic");
5456 ReinitializeMusic();
5457 print_timestamp_time("ReinitializeMusic");
5459 print_timestamp_done("InitMusic");
5462 void InitNetworkServer()
5464 #if defined(NETWORK_AVALIABLE)
5468 if (!options.network)
5471 #if defined(NETWORK_AVALIABLE)
5472 nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5474 if (!ConnectToServer(options.server_host, options.server_port))
5475 Error(ERR_EXIT, "cannot connect to network game server");
5477 SendToServer_PlayerName(setup.player_name);
5478 SendToServer_ProtocolVersion();
5481 SendToServer_NrWanted(nr_wanted);
5485 static boolean CheckArtworkConfigForCustomElements(char *filename)
5487 SetupFileHash *setup_file_hash;
5488 boolean redefined_ce_found = FALSE;
5490 /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5492 if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5494 BEGIN_HASH_ITERATION(setup_file_hash, itr)
5496 char *token = HASH_ITERATION_TOKEN(itr);
5498 if (strPrefix(token, "custom_"))
5500 redefined_ce_found = TRUE;
5505 END_HASH_ITERATION(setup_file_hash, itr)
5507 freeSetupFileHash(setup_file_hash);
5510 return redefined_ce_found;
5513 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5515 char *filename_base, *filename_local;
5516 boolean redefined_ce_found = FALSE;
5518 setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5521 printf("::: leveldir_current->identifier == '%s'\n",
5522 leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5523 printf("::: leveldir_current->graphics_path == '%s'\n",
5524 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5525 printf("::: leveldir_current->graphics_set == '%s'\n",
5526 leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5527 printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5528 leveldir_current == NULL ? "[NULL]" :
5529 LEVELDIR_ARTWORK_SET(leveldir_current, type));
5532 /* first look for special artwork configured in level series config */
5533 filename_base = getCustomArtworkLevelConfigFilename(type);
5536 printf("::: filename_base == '%s'\n", filename_base);
5539 if (fileExists(filename_base))
5540 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5542 filename_local = getCustomArtworkConfigFilename(type);
5545 printf("::: filename_local == '%s'\n", filename_local);
5548 if (filename_local != NULL && !strEqual(filename_base, filename_local))
5549 redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5552 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5555 return redefined_ce_found;
5558 static void InitOverrideArtwork()
5560 boolean redefined_ce_found = FALSE;
5562 /* to check if this level set redefines any CEs, do not use overriding */
5563 gfx.override_level_graphics = FALSE;
5564 gfx.override_level_sounds = FALSE;
5565 gfx.override_level_music = FALSE;
5567 /* now check if this level set has definitions for custom elements */
5568 if (setup.override_level_graphics == AUTO ||
5569 setup.override_level_sounds == AUTO ||
5570 setup.override_level_music == AUTO)
5571 redefined_ce_found =
5572 (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5573 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5574 CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5577 printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5580 if (redefined_ce_found)
5582 /* this level set has CE definitions: change "AUTO" to "FALSE" */
5583 gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5584 gfx.override_level_sounds = (setup.override_level_sounds == TRUE);
5585 gfx.override_level_music = (setup.override_level_music == TRUE);
5589 /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5590 gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5591 gfx.override_level_sounds = (setup.override_level_sounds != FALSE);
5592 gfx.override_level_music = (setup.override_level_music != FALSE);
5596 printf("::: => %d, %d, %d\n",
5597 gfx.override_level_graphics,
5598 gfx.override_level_sounds,
5599 gfx.override_level_music);
5603 static char *getNewArtworkIdentifier(int type)
5605 static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5606 static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5607 static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5608 static boolean initialized[3] = { FALSE, FALSE, FALSE };
5609 TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5610 boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5611 char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5612 char *leveldir_identifier = leveldir_current->identifier;
5613 /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5614 char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5615 boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5616 char *artwork_current_identifier;
5617 char *artwork_new_identifier = NULL; /* default: nothing has changed */
5619 /* leveldir_current may be invalid (level group, parent link) */
5620 if (!validLevelSeries(leveldir_current))
5623 /* 1st step: determine artwork set to be activated in descending order:
5624 --------------------------------------------------------------------
5625 1. setup artwork (when configured to override everything else)
5626 2. artwork set configured in "levelinfo.conf" of current level set
5627 (artwork in level directory will have priority when loading later)
5628 3. artwork in level directory (stored in artwork sub-directory)
5629 4. setup artwork (currently configured in setup menu) */
5631 if (setup_override_artwork)
5632 artwork_current_identifier = setup_artwork_set;
5633 else if (leveldir_artwork_set != NULL)
5634 artwork_current_identifier = leveldir_artwork_set;
5635 else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5636 artwork_current_identifier = leveldir_identifier;
5638 artwork_current_identifier = setup_artwork_set;
5641 /* 2nd step: check if it is really needed to reload artwork set
5642 ------------------------------------------------------------ */
5644 /* ---------- reload if level set and also artwork set has changed ------- */
5645 if (leveldir_current_identifier[type] != leveldir_identifier &&
5646 (last_has_level_artwork_set[type] || has_level_artwork_set))
5647 artwork_new_identifier = artwork_current_identifier;
5649 leveldir_current_identifier[type] = leveldir_identifier;
5650 last_has_level_artwork_set[type] = has_level_artwork_set;
5652 /* ---------- reload if "override artwork" setting has changed ----------- */
5653 if (last_override_level_artwork[type] != setup_override_artwork)
5654 artwork_new_identifier = artwork_current_identifier;
5656 last_override_level_artwork[type] = setup_override_artwork;
5658 /* ---------- reload if current artwork identifier has changed ----------- */
5659 if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5660 artwork_current_identifier))
5661 artwork_new_identifier = artwork_current_identifier;
5663 *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5665 /* ---------- do not reload directly after starting ---------------------- */
5666 if (!initialized[type])
5667 artwork_new_identifier = NULL;
5669 initialized[type] = TRUE;
5671 return artwork_new_identifier;
5674 void ReloadCustomArtwork(int force_reload)
5676 int last_game_status = game_status; /* save current game status */
5677 char *gfx_new_identifier;
5678 char *snd_new_identifier;
5679 char *mus_new_identifier;
5680 boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5681 boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5682 boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5683 boolean reload_needed;
5685 InitOverrideArtwork();
5687 force_reload_gfx |= AdjustGraphicsForEMC();
5689 gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5690 snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5691 mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5693 reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5694 snd_new_identifier != NULL || force_reload_snd ||
5695 mus_new_identifier != NULL || force_reload_mus);
5700 print_timestamp_init("ReloadCustomArtwork");
5702 game_status = GAME_MODE_LOADING;
5704 FadeOut(REDRAW_ALL);
5706 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5707 print_timestamp_time("ClearRectangle");
5711 if (gfx_new_identifier != NULL || force_reload_gfx)
5714 printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5715 artwork.gfx_current_identifier,
5717 artwork.gfx_current->identifier,
5718 leveldir_current->graphics_set);
5722 print_timestamp_time("InitImages");
5725 if (snd_new_identifier != NULL || force_reload_snd)
5727 InitSound(snd_new_identifier);
5728 print_timestamp_time("InitSound");
5731 if (mus_new_identifier != NULL || force_reload_mus)
5733 InitMusic(mus_new_identifier);
5734 print_timestamp_time("InitMusic");
5737 game_status = last_game_status; /* restore current game status */
5739 init_last = init; /* switch to new busy animation */
5741 FadeOut(REDRAW_ALL);
5743 RedrawGlobalBorder();
5745 /* force redraw of (open or closed) door graphics */
5746 SetDoorState(DOOR_OPEN_ALL);
5747 CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5749 FadeSetEnterScreen();
5750 FadeSkipNextFadeOut();
5752 print_timestamp_done("ReloadCustomArtwork");
5754 LimitScreenUpdates(FALSE);
5757 void KeyboardAutoRepeatOffUnlessAutoplay()
5759 if (global.autoplay_leveldir == NULL)
5760 KeyboardAutoRepeatOff();
5763 void DisplayExitMessage(char *format, va_list ap)
5765 // check if draw buffer and fonts for exit message are already available
5766 if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5769 int font_1 = FC_RED;
5770 int font_2 = FC_YELLOW;
5771 int font_3 = FC_BLUE;
5772 int font_width = getFontWidth(font_2);
5773 int font_height = getFontHeight(font_2);
5776 int sxsize = WIN_XSIZE - 2 * sx;
5777 int sysize = WIN_YSIZE - 2 * sy;
5778 int line_length = sxsize / font_width;
5779 int max_lines = sysize / font_height;
5780 int num_lines_printed;
5784 gfx.sxsize = sxsize;
5785 gfx.sysize = sysize;
5789 ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5791 DrawTextSCentered(sy, font_1, "Fatal error:");
5792 sy += 3 * font_height;;
5795 DrawTextBufferVA(sx, sy, format, ap, font_2,
5796 line_length, line_length, max_lines,
5797 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5798 sy += (num_lines_printed + 3) * font_height;
5800 DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5801 sy += 3 * font_height;
5804 DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5805 line_length, line_length, max_lines,
5806 0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5808 DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5810 redraw_mask = REDRAW_ALL;
5812 /* force drawing exit message even if screen updates are currently limited */
5813 LimitScreenUpdates(FALSE);
5817 /* deactivate toons on error message screen */
5818 setup.toons = FALSE;
5820 WaitForEventToContinue();
5824 /* ========================================================================= */
5826 /* ========================================================================= */
5830 print_timestamp_init("OpenAll");
5832 game_status = GAME_MODE_LOADING;
5836 InitGlobal(); /* initialize some global variables */
5838 print_timestamp_time("[init global stuff]");
5842 print_timestamp_time("[init setup/config stuff (1)]");
5844 if (options.execute_command)
5845 Execute_Command(options.execute_command);
5847 if (options.serveronly)
5849 #if defined(PLATFORM_UNIX)
5850 NetworkServer(options.server_port, options.serveronly);
5852 Error(ERR_WARN, "networking only supported in Unix version");
5855 exit(0); /* never reached, server loops forever */
5859 print_timestamp_time("[init setup/config stuff (2)]");
5861 print_timestamp_time("[init setup/config stuff (3)]");
5862 InitArtworkInfo(); /* needed before loading gfx, sound & music */
5863 print_timestamp_time("[init setup/config stuff (4)]");
5864 InitArtworkConfig(); /* needed before forking sound child process */
5865 print_timestamp_time("[init setup/config stuff (5)]");
5867 print_timestamp_time("[init setup/config stuff (6)]");
5869 InitRND(NEW_RANDOMIZE);
5870 InitSimpleRandom(NEW_RANDOMIZE);
5874 print_timestamp_time("[init setup/config stuff]");
5877 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5879 InitEventFilter(FilterEvents);
5881 print_timestamp_time("[init video stuff]");
5883 InitElementPropertiesStatic();
5884 InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5885 InitElementPropertiesGfxElement();
5887 print_timestamp_time("[init element properties stuff]");
5891 print_timestamp_time("InitGfx");
5894 print_timestamp_time("InitLevelInfo");
5896 InitLevelArtworkInfo();
5897 print_timestamp_time("InitLevelArtworkInfo");
5899 InitOverrideArtwork(); /* needs to know current level directory */
5900 print_timestamp_time("InitOverrideArtwork");
5902 InitImages(); /* needs to know current level directory */
5903 print_timestamp_time("InitImages");
5905 InitSound(NULL); /* needs to know current level directory */
5906 print_timestamp_time("InitSound");
5908 InitMusic(NULL); /* needs to know current level directory */
5909 print_timestamp_time("InitMusic");
5911 InitGfxBackground();
5916 if (global.autoplay_leveldir)
5921 else if (global.convert_leveldir)
5926 else if (global.create_images_dir)
5928 CreateLevelSketchImages();
5932 game_status = GAME_MODE_MAIN;
5934 FadeSetEnterScreen();
5935 if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5936 FadeSkipNextFadeOut();
5938 print_timestamp_time("[post-artwork]");
5940 print_timestamp_done("OpenAll");
5944 InitNetworkServer();
5947 Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5949 Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5950 SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5951 #if defined(PLATFORM_ANDROID)
5952 Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5953 SDL_AndroidGetInternalStoragePath());
5954 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5955 SDL_AndroidGetExternalStoragePath());
5956 Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5957 (SDL_AndroidGetExternalStorageState() ==
5958 SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5959 SDL_AndroidGetExternalStorageState() ==
5960 SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5965 void CloseAllAndExit(int exit_value)
5970 CloseAudio(); /* called after freeing sounds (needed for SDL) */
5977 #if defined(TARGET_SDL)
5978 #if defined(TARGET_SDL2)
5980 // set a flag to tell the network server thread to quit and wait for it
5981 // using SDL_WaitThread()
5983 if (network_server) /* terminate network server */
5984 SDL_KillThread(server_thread);
5988 CloseVideoDisplay();
5989 ClosePlatformDependentStuff();
5991 if (exit_value != 0)
5993 /* fall back to default level set (current set may have caused an error) */
5994 SaveLevelSetup_LastSeries_Deactivate();
5996 /* tell user where to find error log file which may contain more details */
5997 // (error notification now directly displayed on screen inside R'n'D
5998 // NotifyUserAboutErrorFile(); /* currently only works for Windows */