93d77928411fe907bb5ee88b3822c400cb5217e2
[rocksndiamonds.git] / src / init.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // init.c
10 // ============================================================================
11
12 #include "libgame/libgame.h"
13
14 #include "init.h"
15 #include "events.h"
16 #include "screens.h"
17 #include "editor.h"
18 #include "game.h"
19 #include "tape.h"
20 #include "tools.h"
21 #include "files.h"
22 #include "network.h"
23 #include "netserv.h"
24 #include "anim.h"
25 #include "config.h"
26
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
34
35
36 #define CONFIG_TOKEN_FONT_INITIAL               "font.initial"
37 #define CONFIG_TOKEN_GLOBAL_BUSY_INITIAL        "global.busy_initial"
38 #define CONFIG_TOKEN_GLOBAL_BUSY                "global.busy"
39 #define CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD      "global.busy_playfield"
40 #define CONFIG_TOKEN_BACKGROUND                 "background"
41 #define CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL "background.LOADING_INITIAL"
42 #define CONFIG_TOKEN_BACKGROUND_LOADING         "background.LOADING"
43
44 #define INITIAL_IMG_GLOBAL_BUSY_INITIAL         0
45 #define INITIAL_IMG_GLOBAL_BUSY                 1
46 #define INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD       2
47
48 #define NUM_INITIAL_IMAGES_BUSY                 3
49
50 #define INITIAL_IMG_BACKGROUND                  3
51 #define INITIAL_IMG_BACKGROUND_LOADING_INITIAL  4
52 #define INITIAL_IMG_BACKGROUND_LOADING          5
53
54 #define NUM_INITIAL_IMAGES                      6
55
56
57 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
58 static struct GraphicInfo   image_initial[NUM_INITIAL_IMAGES];
59
60 static int copy_properties[][5] =
61 {
62   {
63     EL_BUG,
64     EL_BUG_LEFT,                EL_BUG_RIGHT,
65     EL_BUG_UP,                  EL_BUG_DOWN
66   },
67   {
68     EL_SPACESHIP,
69     EL_SPACESHIP_LEFT,          EL_SPACESHIP_RIGHT,
70     EL_SPACESHIP_UP,            EL_SPACESHIP_DOWN
71   },
72   {
73     EL_BD_BUTTERFLY,
74     EL_BD_BUTTERFLY_LEFT,       EL_BD_BUTTERFLY_RIGHT,
75     EL_BD_BUTTERFLY_UP,         EL_BD_BUTTERFLY_DOWN
76   },
77   {
78     EL_BD_FIREFLY,
79     EL_BD_FIREFLY_LEFT,         EL_BD_FIREFLY_RIGHT,
80     EL_BD_FIREFLY_UP,           EL_BD_FIREFLY_DOWN
81   },
82   {
83     EL_PACMAN,
84     EL_PACMAN_LEFT,             EL_PACMAN_RIGHT,
85     EL_PACMAN_UP,               EL_PACMAN_DOWN
86   },
87   {
88     EL_YAMYAM,
89     EL_YAMYAM_LEFT,             EL_YAMYAM_RIGHT,
90     EL_YAMYAM_UP,               EL_YAMYAM_DOWN
91   },
92   {
93     EL_MOLE,
94     EL_MOLE_LEFT,               EL_MOLE_RIGHT,
95     EL_MOLE_UP,                 EL_MOLE_DOWN
96   },
97   {
98     EL_SPRING,
99     EL_SPRING_LEFT,             EL_SPRING_RIGHT,
100     EL_SPRING_LEFT,             EL_SPRING_RIGHT,        // (to match array size)
101   },
102   {
103     -1,
104     -1, -1, -1, -1
105   }
106 };
107
108
109 // forward declaration for internal use
110 static int get_graphic_parameter_value(char *, char *, int);
111
112
113 static int getLoadingBackgroundImage(int graphic)
114 {
115   return getImageFromGraphicOrDefault(graphic, INITIAL_IMG_BACKGROUND);
116 }
117
118 static void SetLoadingWindowBackgroundImage(int graphic)
119 {
120   SetBackgroundImage(getLoadingBackgroundImage(graphic), REDRAW_ALL);
121 }
122
123 static void SetLoadingBackgroundImage(void)
124 {
125   struct GraphicInfo *graphic_info_last = graphic_info;
126   int background_image = (game_status_last_screen == -1 ?
127                           INITIAL_IMG_BACKGROUND_LOADING_INITIAL :
128                           INITIAL_IMG_BACKGROUND_LOADING);
129
130   graphic_info = image_initial;
131
132   SetDrawDeactivationMask(REDRAW_NONE);
133   SetDrawBackgroundMask(REDRAW_ALL);
134
135   SetLoadingWindowBackgroundImage(background_image);
136
137   graphic_info = graphic_info_last;
138 }
139
140 static void DrawInitAnim(boolean only_when_loading)
141 {
142   struct GraphicInfo *graphic_info_last = graphic_info;
143   int graphic = (game_status_last_screen == -1 ?
144                  INITIAL_IMG_GLOBAL_BUSY_INITIAL :
145                  game_status == GAME_MODE_LOADING ?
146                  INITIAL_IMG_GLOBAL_BUSY :
147                  INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD);
148   struct MenuPosInfo *busy = (game_status_last_screen == -1 ?
149                               &init_last.busy_initial :
150                               game_status == GAME_MODE_LOADING ?
151                               &init_last.busy :
152                               &init_last.busy_playfield);
153   static DelayCounter action_delay = { 0 };
154   int sync_frame = FrameCounter;
155   int x, y;
156
157   action_delay.value = GameFrameDelay;
158
159   // prevent OS (Windows) from complaining about program not responding
160   CheckQuitEvent();
161
162   if (game_status != GAME_MODE_LOADING && only_when_loading)
163     return;
164
165   if (image_initial[graphic].bitmap == NULL || window == NULL)
166     return;
167
168   if (!DelayReached(&action_delay))
169     return;
170
171   if (busy->x == -1)
172     busy->x = (game_status == GAME_MODE_LOADING ? WIN_XSIZE / 2 : SXSIZE / 2);
173   if (busy->y == -1)
174     busy->y = (game_status == GAME_MODE_LOADING ? WIN_YSIZE / 2 : SYSIZE / 2);
175
176   x = (game_status == GAME_MODE_LOADING ? 0 : SX) + ALIGNED_TEXT_XPOS(busy);
177   y = (game_status == GAME_MODE_LOADING ? 0 : SY) + ALIGNED_TEXT_YPOS(busy);
178
179   graphic_info = image_initial;
180
181   if (sync_frame % image_initial[graphic].anim_delay == 0)
182   {
183     Bitmap *src_bitmap;
184     int src_x, src_y;
185     int width = graphic_info[graphic].width;
186     int height = graphic_info[graphic].height;
187     int frame = getGraphicAnimationFrame(graphic, sync_frame);
188
189     ClearRectangleOnBackground(drawto, x, y, width, height);
190
191     getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
192     BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, x, y);
193
194     BlitBitmap(drawto, window, x, y, width, height, x, y);
195   }
196
197   graphic_info = graphic_info_last;
198
199   FrameCounter++;
200 }
201
202 static void DrawProgramInfo(void)
203 {
204   int font1_nr = FC_YELLOW;
205   int font2_nr = FC_RED;
206   int font2_height = getFontHeight(font2_nr);
207   int ypos1 = 20;
208   int ypos2 = 50;
209   int ypos3 = WIN_YSIZE - 20 - font2_height;
210
211   DrawInitText(getProgramInitString(),           ypos1, font1_nr);
212   DrawInitText(setup.internal.program_copyright, ypos2, font2_nr);
213   DrawInitText(setup.internal.program_website,   ypos3, font2_nr);
214 }
215
216 static void FreeGadgets(void)
217 {
218   FreeLevelEditorGadgets();
219   FreeGameButtons();
220   FreeTapeButtons();
221   FreeToolButtons();
222   FreeScreenGadgets();
223 }
224
225 void InitGadgets(void)
226 {
227   static boolean gadgets_initialized = FALSE;
228
229   if (gadgets_initialized)
230     FreeGadgets();
231
232   CreateLevelEditorGadgets();
233   CreateGameButtons();
234   CreateTapeButtons();
235   CreateToolButtons();
236   CreateScreenGadgets();
237
238   InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
239
240   gadgets_initialized = TRUE;
241 }
242
243 static void InitElementSmallImagesScaledUp(int graphic)
244 {
245   struct GraphicInfo *g = &graphic_info[graphic];
246
247   // if graphic was cloned, scale cloned graphic
248   if (graphic_info[graphic].clone_from != -1)
249     graphic = graphic_info[graphic].clone_from;
250
251   // create small and game tile sized bitmaps (and scale up, if needed)
252   CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
253 }
254
255 static void InitElementSmallImages(void)
256 {
257   print_timestamp_init("InitElementSmallImages");
258
259   static int special_graphics[] =
260   {
261     IMG_FLAMES_1_LEFT,
262     IMG_FLAMES_2_LEFT,
263     IMG_FLAMES_3_LEFT,
264     IMG_FLAMES_1_RIGHT,
265     IMG_FLAMES_2_RIGHT,
266     IMG_FLAMES_3_RIGHT,
267     IMG_FLAMES_1_UP,
268     IMG_FLAMES_2_UP,
269     IMG_FLAMES_3_UP,
270     IMG_FLAMES_1_DOWN,
271     IMG_FLAMES_2_DOWN,
272     IMG_FLAMES_3_DOWN,
273     IMG_EDITOR_ELEMENT_BORDER,
274     IMG_EDITOR_ELEMENT_BORDER_INPUT,
275     IMG_EDITOR_CASCADE_LIST,
276     IMG_EDITOR_CASCADE_LIST_ACTIVE,
277     -1
278   };
279   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
280   int num_property_mappings = getImageListPropertyMappingSize();
281   int i;
282
283   print_timestamp_time("getImageListPropertyMapping/Size");
284
285   print_timestamp_init("InitElementSmallImagesScaledUp (1)");
286   // initialize normal element images from static configuration
287   for (i = 0; element_to_graphic[i].element > -1; i++)
288     InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
289   print_timestamp_done("InitElementSmallImagesScaledUp (1)");
290
291   // initialize special element images from static configuration
292   for (i = 0; element_to_special_graphic[i].element > -1; i++)
293     InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
294   print_timestamp_time("InitElementSmallImagesScaledUp (2)");
295
296   // initialize element images from dynamic configuration
297   for (i = 0; i < num_property_mappings; i++)
298     if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
299       InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
300   print_timestamp_time("InitElementSmallImagesScaledUp (3)");
301
302   // initialize special non-element images from above list
303   for (i = 0; special_graphics[i] > -1; i++)
304     InitElementSmallImagesScaledUp(special_graphics[i]);
305   print_timestamp_time("InitElementSmallImagesScaledUp (4)");
306
307   print_timestamp_done("InitElementSmallImages");
308 }
309
310 static void InitScaledImagesScaledUp(int graphic)
311 {
312   struct GraphicInfo *g = &graphic_info[graphic];
313
314   // if graphic was cloned, scale cloned graphic
315   if (graphic_info[graphic].clone_from != -1)
316     graphic = graphic_info[graphic].clone_from;
317
318   ScaleImage(graphic, g->scale_up_factor);
319 }
320
321 static void InitScaledImages(void)
322 {
323   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
324   int num_property_mappings = getImageListPropertyMappingSize();
325   int i;
326
327   // scale normal images from static configuration, if not already scaled
328   for (i = 0; i < NUM_IMAGE_FILES; i++)
329     InitScaledImagesScaledUp(i);
330
331   // scale images from dynamic configuration, if not already scaled
332   for (i = 0; i < num_property_mappings; i++)
333     InitScaledImagesScaledUp(property_mapping[i].artwork_index);
334 }
335
336 static void InitBitmapPointers(void)
337 {
338   int num_images = getImageListSize();
339   int i;
340
341   // standard size bitmap may have changed -- update default bitmap pointer
342   for (i = 0; i < num_images; i++)
343     if (graphic_info[i].bitmaps)
344       graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
345 }
346
347 void InitImageTextures(void)
348 {
349   static int texture_graphics[] =
350   {
351     IMG_GFX_REQUEST_BUTTON_TOUCH_YES,
352     IMG_GFX_REQUEST_BUTTON_TOUCH_NO,
353     IMG_GFX_REQUEST_BUTTON_TOUCH_CONFIRM,
354     IMG_GFX_GAME_BUTTON_TOUCH_STOP,
355     IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,
356     IMG_MENU_BUTTON_TOUCH_BACK,
357     IMG_MENU_BUTTON_TOUCH_NEXT,
358     IMG_MENU_BUTTON_TOUCH_BACK2,
359     IMG_MENU_BUTTON_TOUCH_NEXT2,
360     -1
361   };
362   int i, j, k;
363
364   FreeAllImageTextures();
365
366   for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
367     CreateImageTextures(i);
368
369   for (i = 0; i < MAX_NUM_TOONS; i++)
370     CreateImageTextures(IMG_TOON_1 + i);
371
372   for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
373   {
374     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
375     {
376       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
377       {
378         int graphic = global_anim_info[i].graphic[j][k];
379
380         if (graphic == IMG_UNDEFINED)
381           continue;
382
383         CreateImageTextures(graphic);
384       }
385     }
386   }
387
388   for (i = 0; texture_graphics[i] > -1; i++)
389     CreateImageTextures(texture_graphics[i]);
390 }
391
392 static int getFontSpecialSuffix(void)
393 {
394   int special = -1;
395
396   // (special case: do not use special font for GAME_MODE_LOADING)
397   if (game_status >= GAME_MODE_TITLE_INITIAL &&
398       game_status <= GAME_MODE_PSEUDO_PREVIEW)
399     special = game_status;
400   else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
401     special = GFX_SPECIAL_ARG_MAIN;
402   else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
403     special = GFX_SPECIAL_ARG_NAMES;
404
405   return special;
406 }
407
408 static int getFontBitmapID(int font_nr)
409 {
410   int special = getFontSpecialSuffix();
411
412   if (special != -1)
413     return font_info[font_nr].special_bitmap_id[special];
414   else
415     return font_nr;
416 }
417
418 static int getFontFromToken(char *token)
419 {
420   char *value = getHashEntry(font_token_hash, token);
421
422   if (value != NULL)
423     return atoi(value);
424
425   // if font not found, use reliable default value
426   return FONT_INITIAL_1;
427 }
428
429 static char *getTokenFromFont(int font_nr)
430 {
431   static char *token = NULL;
432   int special = getFontSpecialSuffix();
433
434   checked_free(token);
435
436   if (special != -1)
437     token = getStringCat2(font_info[font_nr].token_name,
438                           special_suffix_info[special].suffix);
439   else
440     token = getStringCopy(font_info[font_nr].token_name);
441
442   return token;
443 }
444
445 static void InitFontGraphicInfo(void)
446 {
447   static struct FontBitmapInfo *font_bitmap_info = NULL;
448   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
449   int num_property_mappings = getImageListPropertyMappingSize();
450   int num_font_bitmaps = NUM_FONTS;
451   int i, j;
452
453   if (graphic_info == NULL)             // still at startup phase
454   {
455     InitFontInfo(font_initial, NUM_INITIAL_FONTS,
456                  getFontBitmapID, getFontFromToken, getTokenFromFont);
457
458     return;
459   }
460
461   // ---------- initialize font graphic definitions ----------
462
463   // always start with reliable default values (normal font graphics)
464   for (i = 0; i < NUM_FONTS; i++)
465     font_info[i].graphic = IMG_FONT_INITIAL_1;
466
467   // initialize normal font/graphic mapping from static configuration
468   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
469   {
470     int font_nr = font_to_graphic[i].font_nr;
471     int special = font_to_graphic[i].special;
472     int graphic = font_to_graphic[i].graphic;
473
474     if (special != -1)
475       continue;
476
477     font_info[font_nr].graphic = graphic;
478   }
479
480   // always start with reliable default values (special font graphics)
481   for (i = 0; i < NUM_FONTS; i++)
482   {
483     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
484     {
485       font_info[i].special_graphic[j] = font_info[i].graphic;
486       font_info[i].special_bitmap_id[j] = i;
487     }
488   }
489
490   // initialize special font/graphic mapping from static configuration
491   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
492   {
493     int font_nr      = font_to_graphic[i].font_nr;
494     int special      = font_to_graphic[i].special;
495     int graphic      = font_to_graphic[i].graphic;
496     int base_graphic = font2baseimg(font_nr);
497
498     if (IS_SPECIAL_GFX_ARG(special))
499     {
500       boolean base_redefined =
501         getImageListEntryFromImageID(base_graphic)->redefined;
502       boolean special_redefined =
503         getImageListEntryFromImageID(graphic)->redefined;
504       boolean special_cloned = (graphic_info[graphic].clone_from != -1);
505
506       /* if the base font ("font.title_1", for example) has been redefined,
507          but not the special font ("font.title_1.LEVELS", for example), do not
508          use an existing (in this case considered obsolete) special font
509          anymore, but use the automatically determined default font */
510       /* special case: cloned special fonts must be explicitly redefined,
511          but are not automatically redefined by redefining base font */
512       if (base_redefined && !special_redefined && !special_cloned)
513         continue;
514
515       font_info[font_nr].special_graphic[special] = graphic;
516       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
517       num_font_bitmaps++;
518     }
519   }
520
521   // initialize special font/graphic mapping from dynamic configuration
522   for (i = 0; i < num_property_mappings; i++)
523   {
524     int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
525     int special = property_mapping[i].ext3_index;
526     int graphic = property_mapping[i].artwork_index;
527
528     if (font_nr < 0 || font_nr >= NUM_FONTS)
529       continue;
530
531     if (IS_SPECIAL_GFX_ARG(special))
532     {
533       font_info[font_nr].special_graphic[special] = graphic;
534       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
535       num_font_bitmaps++;
536     }
537   }
538
539   /* correct special font/graphic mapping for cloned fonts for downwards
540      compatibility of PREVIEW fonts -- this is only needed for implicit
541      redefinition of special font by redefined base font, and only if other
542      fonts are cloned from this special font (like in the "Zelda" level set) */
543   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
544   {
545     int font_nr = font_to_graphic[i].font_nr;
546     int special = font_to_graphic[i].special;
547     int graphic = font_to_graphic[i].graphic;
548
549     if (IS_SPECIAL_GFX_ARG(special))
550     {
551       boolean special_redefined =
552         getImageListEntryFromImageID(graphic)->redefined;
553       boolean special_cloned = (graphic_info[graphic].clone_from != -1);
554
555       if (special_cloned && !special_redefined)
556       {
557         int j;
558
559         for (j = 0; font_to_graphic[j].font_nr > -1; j++)
560         {
561           int font_nr2 = font_to_graphic[j].font_nr;
562           int special2 = font_to_graphic[j].special;
563           int graphic2 = font_to_graphic[j].graphic;
564
565           if (IS_SPECIAL_GFX_ARG(special2) &&
566               graphic2 == graphic_info[graphic].clone_from)
567           {
568             font_info[font_nr].special_graphic[special] =
569               font_info[font_nr2].special_graphic[special2];
570             font_info[font_nr].special_bitmap_id[special] =
571               font_info[font_nr2].special_bitmap_id[special2];
572           }
573         }
574       }
575     }
576   }
577
578   // reset non-redefined ".active" font graphics if normal font is redefined
579   // (this different treatment is needed because normal and active fonts are
580   // independently defined ("active" is not a property of font definitions!)
581   for (i = 0; i < NUM_FONTS; i++)
582   {
583     int font_nr_base = i;
584     int font_nr_active = FONT_ACTIVE(font_nr_base);
585
586     // check only those fonts with exist as normal and ".active" variant
587     if (font_nr_base != font_nr_active)
588     {
589       int base_graphic = font_info[font_nr_base].graphic;
590       int active_graphic = font_info[font_nr_active].graphic;
591       boolean base_redefined =
592         getImageListEntryFromImageID(base_graphic)->redefined;
593       boolean active_redefined =
594         getImageListEntryFromImageID(active_graphic)->redefined;
595
596       /* if the base font ("font.menu_1", for example) has been redefined,
597          but not the active font ("font.menu_1.active", for example), do not
598          use an existing (in this case considered obsolete) active font
599          anymore, but use the automatically determined default font */
600       if (base_redefined && !active_redefined)
601         font_info[font_nr_active].graphic = base_graphic;
602
603       // now also check each "special" font (which may be the same as above)
604       for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
605       {
606         int base_graphic = font_info[font_nr_base].special_graphic[j];
607         int active_graphic = font_info[font_nr_active].special_graphic[j];
608         boolean base_redefined =
609           getImageListEntryFromImageID(base_graphic)->redefined;
610         boolean active_redefined =
611           getImageListEntryFromImageID(active_graphic)->redefined;
612
613         // same as above, but check special graphic definitions, for example:
614         // redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN"
615         if (base_redefined && !active_redefined)
616         {
617           font_info[font_nr_active].special_graphic[j] =
618             font_info[font_nr_base].special_graphic[j];
619           font_info[font_nr_active].special_bitmap_id[j] =
620             font_info[font_nr_base].special_bitmap_id[j];
621         }
622       }
623     }
624   }
625
626   // ---------- initialize font bitmap array ----------
627
628   if (font_bitmap_info != NULL)
629     FreeFontInfo(font_bitmap_info);
630
631   font_bitmap_info =
632     checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
633
634   // ---------- initialize font bitmap definitions ----------
635
636   for (i = 0; i < NUM_FONTS; i++)
637   {
638     if (i < NUM_INITIAL_FONTS)
639     {
640       font_bitmap_info[i] = font_initial[i];
641       continue;
642     }
643
644     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
645     {
646       int font_bitmap_id = font_info[i].special_bitmap_id[j];
647       int graphic = font_info[i].special_graphic[j];
648
649       // set 'graphic_info' for font entries, if uninitialized (guessed)
650       if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
651       {
652         graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
653         graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
654       }
655
656       // copy font relevant information from graphics information
657       font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
658       font_bitmap_info[font_bitmap_id].src_x  = graphic_info[graphic].src_x;
659       font_bitmap_info[font_bitmap_id].src_y  = graphic_info[graphic].src_y;
660       font_bitmap_info[font_bitmap_id].width  = graphic_info[graphic].width;
661       font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
662
663       font_bitmap_info[font_bitmap_id].offset_x =
664         graphic_info[graphic].offset_x;
665       font_bitmap_info[font_bitmap_id].offset_y =
666         graphic_info[graphic].offset_y;
667
668       font_bitmap_info[font_bitmap_id].draw_xoffset =
669         graphic_info[graphic].draw_xoffset;
670       font_bitmap_info[font_bitmap_id].draw_yoffset =
671         graphic_info[graphic].draw_yoffset;
672
673       font_bitmap_info[font_bitmap_id].num_chars =
674         graphic_info[graphic].anim_frames;
675       font_bitmap_info[font_bitmap_id].num_chars_per_line =
676         graphic_info[graphic].anim_frames_per_line;
677     }
678   }
679
680   InitFontInfo(font_bitmap_info, num_font_bitmaps,
681                getFontBitmapID, getFontFromToken, getTokenFromFont);
682 }
683
684 static void InitGlobalAnimGraphicInfo(void)
685 {
686   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
687   int num_property_mappings = getImageListPropertyMappingSize();
688   int i, j, k;
689
690   if (graphic_info == NULL)             // still at startup phase
691     return;
692
693   // always start with reliable default values (no global animations)
694   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
695     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
696       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
697         global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
698
699   // initialize global animation definitions from static configuration
700   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
701   {
702     int j = GLOBAL_ANIM_ID_PART_BASE;
703     int k = GFX_SPECIAL_ARG_DEFAULT;
704
705     global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
706   }
707
708   // initialize global animation definitions from dynamic configuration
709   for (i = 0; i < num_property_mappings; i++)
710   {
711     int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
712     int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
713     int special = property_mapping[i].ext3_index;
714     int graphic = property_mapping[i].artwork_index;
715
716     if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
717       continue;
718
719     // set animation part to base part, if not specified
720     if (!IS_GLOBAL_ANIM_PART(part_nr))
721       part_nr = GLOBAL_ANIM_ID_PART_BASE;
722
723     // set animation screen to default, if not specified
724     if (!IS_SPECIAL_GFX_ARG(special))
725       special = GFX_SPECIAL_ARG_DEFAULT;
726
727     global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
728
729     // fix default value for ".draw_masked" (for backward compatibility)
730     struct GraphicInfo *g = &graphic_info[graphic];
731     struct FileInfo *image = getImageListEntryFromImageID(graphic);
732     char **parameter_raw = image->parameter;
733     int p = GFX_ARG_DRAW_MASKED;
734     int draw_masked = get_graphic_parameter_value(parameter_raw[p],
735                                                   image_config_suffix[p].token,
736                                                   image_config_suffix[p].type);
737
738     // if ".draw_masked" parameter is undefined, use default value "TRUE"
739     if (draw_masked == ARG_UNDEFINED_VALUE)
740       g->draw_masked = TRUE;
741   }
742
743 #if 0
744   for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
745     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
746       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
747         if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
748             graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
749           Debug("init:InitGlobalAnimGraphicInfo",
750                 "anim %d, part %d, mode %d => %d",
751                 i, j, k, global_anim_info[i].graphic[j][k]);
752 #endif
753 }
754
755 static void InitGlobalAnimSoundInfo(void)
756 {
757   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
758   int num_property_mappings = getSoundListPropertyMappingSize();
759   int i, j, k;
760
761   // always start with reliable default values (no global animation sounds)
762   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
763     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
764       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
765         global_anim_info[i].sound[j][k] = SND_UNDEFINED;
766
767   // initialize global animation sound definitions from dynamic configuration
768   for (i = 0; i < num_property_mappings; i++)
769   {
770     int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
771     int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
772     int special = property_mapping[i].ext3_index;
773     int sound   = property_mapping[i].artwork_index;
774
775     // sound uses control definition; map it to position of graphic (artwork)
776     anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
777
778     if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
779       continue;
780
781     // set animation part to base part, if not specified
782     if (!IS_GLOBAL_ANIM_PART(part_nr))
783       part_nr = GLOBAL_ANIM_ID_PART_BASE;
784
785     // set animation screen to default, if not specified
786     if (!IS_SPECIAL_GFX_ARG(special))
787       special = GFX_SPECIAL_ARG_DEFAULT;
788
789     global_anim_info[anim_nr].sound[part_nr][special] = sound;
790   }
791
792 #if 0
793   for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
794     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
795       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
796         if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
797           Debug("init:InitGlobalAnimSoundInfo",
798                 "anim %d, part %d, mode %d => %d",
799                 i, j, k, global_anim_info[i].sound[j][k]);
800 #endif
801 }
802
803 static void InitGlobalAnimMusicInfo(void)
804 {
805   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
806   int num_property_mappings = getMusicListPropertyMappingSize();
807   int i, j, k;
808
809   // always start with reliable default values (no global animation music)
810   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
811     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
812       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
813         global_anim_info[i].music[j][k] = MUS_UNDEFINED;
814
815   // initialize global animation music definitions from dynamic configuration
816   for (i = 0; i < num_property_mappings; i++)
817   {
818     int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
819     int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
820     int special = property_mapping[i].ext2_index;
821     int music   = property_mapping[i].artwork_index;
822
823     // music uses control definition; map it to position of graphic (artwork)
824     anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
825
826     if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
827       continue;
828
829     // set animation part to base part, if not specified
830     if (!IS_GLOBAL_ANIM_PART(part_nr))
831       part_nr = GLOBAL_ANIM_ID_PART_BASE;
832
833     // set animation screen to default, if not specified
834     if (!IS_SPECIAL_GFX_ARG(special))
835       special = GFX_SPECIAL_ARG_DEFAULT;
836
837     global_anim_info[anim_nr].music[part_nr][special] = music;
838   }
839
840 #if 0
841   for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
842     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
843       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
844         if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
845           Debug("init:InitGlobalAnimMusicInfo",
846                 "anim %d, part %d, mode %d => %d",
847                 i, j, k, global_anim_info[i].music[j][k]);
848 #endif
849 }
850
851 static void InitElementGraphicInfo(void)
852 {
853   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
854   int num_property_mappings = getImageListPropertyMappingSize();
855   int i, act, dir;
856
857   if (graphic_info == NULL)             // still at startup phase
858     return;
859
860   // set values to -1 to identify later as "uninitialized" values
861   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
862   {
863     for (act = 0; act < NUM_ACTIONS; act++)
864     {
865       element_info[i].graphic[act] = -1;
866       element_info[i].crumbled[act] = -1;
867
868       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
869       {
870         element_info[i].direction_graphic[act][dir] = -1;
871         element_info[i].direction_crumbled[act][dir] = -1;
872       }
873     }
874   }
875
876   UPDATE_BUSY_STATE();
877
878   // initialize normal element/graphic mapping from static configuration
879   for (i = 0; element_to_graphic[i].element > -1; i++)
880   {
881     int element      = element_to_graphic[i].element;
882     int action       = element_to_graphic[i].action;
883     int direction    = element_to_graphic[i].direction;
884     boolean crumbled = element_to_graphic[i].crumbled;
885     int graphic      = element_to_graphic[i].graphic;
886     int base_graphic = el2baseimg(element);
887
888     if (graphic_info[graphic].bitmap == NULL)
889       continue;
890
891     if ((action > -1 || direction > -1 || crumbled == TRUE) &&
892         base_graphic != -1)
893     {
894       boolean base_redefined =
895         getImageListEntryFromImageID(base_graphic)->redefined;
896       boolean act_dir_redefined =
897         getImageListEntryFromImageID(graphic)->redefined;
898
899       /* if the base graphic ("emerald", for example) has been redefined,
900          but not the action graphic ("emerald.falling", for example), do not
901          use an existing (in this case considered obsolete) action graphic
902          anymore, but use the automatically determined default graphic */
903       if (base_redefined && !act_dir_redefined)
904         continue;
905     }
906
907     if (action < 0)
908       action = ACTION_DEFAULT;
909
910     if (crumbled)
911     {
912       if (direction > -1)
913         element_info[element].direction_crumbled[action][direction] = graphic;
914       else
915         element_info[element].crumbled[action] = graphic;
916     }
917     else
918     {
919       if (direction > -1)
920         element_info[element].direction_graphic[action][direction] = graphic;
921       else
922         element_info[element].graphic[action] = graphic;
923     }
924   }
925
926   // initialize normal element/graphic mapping from dynamic configuration
927   for (i = 0; i < num_property_mappings; i++)
928   {
929     int element   = property_mapping[i].base_index;
930     int action    = property_mapping[i].ext1_index;
931     int direction = property_mapping[i].ext2_index;
932     int special   = property_mapping[i].ext3_index;
933     int graphic   = property_mapping[i].artwork_index;
934     boolean crumbled = FALSE;
935
936     if (special == GFX_SPECIAL_ARG_CRUMBLED)
937     {
938       special = -1;
939       crumbled = TRUE;
940     }
941
942     if (graphic_info[graphic].bitmap == NULL)
943       continue;
944
945     if (element >= MAX_NUM_ELEMENTS || special != -1)
946       continue;
947
948     if (action < 0)
949       action = ACTION_DEFAULT;
950
951     if (crumbled)
952     {
953       if (direction < 0)
954         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
955           element_info[element].direction_crumbled[action][dir] = -1;
956
957       if (direction > -1)
958         element_info[element].direction_crumbled[action][direction] = graphic;
959       else
960         element_info[element].crumbled[action] = graphic;
961     }
962     else
963     {
964       if (direction < 0)
965         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
966           element_info[element].direction_graphic[action][dir] = -1;
967
968       if (direction > -1)
969         element_info[element].direction_graphic[action][direction] = graphic;
970       else
971         element_info[element].graphic[action] = graphic;
972     }
973   }
974
975   // now copy all graphics that are defined to be cloned from other graphics
976   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
977   {
978     int graphic = element_info[i].graphic[ACTION_DEFAULT];
979     int crumbled_like, diggable_like;
980
981     if (graphic == -1)
982       continue;
983
984     crumbled_like = graphic_info[graphic].crumbled_like;
985     diggable_like = graphic_info[graphic].diggable_like;
986
987     if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
988     {
989       for (act = 0; act < NUM_ACTIONS; act++)
990         element_info[i].crumbled[act] =
991           element_info[crumbled_like].crumbled[act];
992       for (act = 0; act < NUM_ACTIONS; act++)
993         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
994           element_info[i].direction_crumbled[act][dir] =
995             element_info[crumbled_like].direction_crumbled[act][dir];
996     }
997
998     if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
999     {
1000       element_info[i].graphic[ACTION_DIGGING] =
1001         element_info[diggable_like].graphic[ACTION_DIGGING];
1002       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1003         element_info[i].direction_graphic[ACTION_DIGGING][dir] =
1004           element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
1005     }
1006   }
1007
1008   // set hardcoded definitions for some runtime elements without graphic
1009   element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
1010
1011   // set hardcoded definitions for some internal elements without graphic
1012   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1013   {
1014     if (IS_EDITOR_CASCADE_INACTIVE(i))
1015       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
1016     else if (IS_EDITOR_CASCADE_ACTIVE(i))
1017       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
1018   }
1019
1020   // now set all undefined/invalid graphics to -1 to set to default after it
1021   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1022   {
1023     for (act = 0; act < NUM_ACTIONS; act++)
1024     {
1025       int graphic;
1026
1027       graphic = element_info[i].graphic[act];
1028       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1029         element_info[i].graphic[act] = -1;
1030
1031       graphic = element_info[i].crumbled[act];
1032       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1033         element_info[i].crumbled[act] = -1;
1034
1035       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1036       {
1037         graphic = element_info[i].direction_graphic[act][dir];
1038         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1039           element_info[i].direction_graphic[act][dir] = -1;
1040
1041         graphic = element_info[i].direction_crumbled[act][dir];
1042         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
1043           element_info[i].direction_crumbled[act][dir] = -1;
1044       }
1045     }
1046   }
1047
1048   UPDATE_BUSY_STATE();
1049
1050   // adjust graphics with 2nd tile for movement according to direction
1051   // (do this before correcting '-1' values to minimize calculations)
1052   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1053   {
1054     for (act = 0; act < NUM_ACTIONS; act++)
1055     {
1056       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1057       {
1058         int graphic = element_info[i].direction_graphic[act][dir];
1059         int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
1060
1061         if (act == ACTION_FALLING)      // special case
1062           graphic = element_info[i].graphic[act];
1063
1064         if (graphic != -1 &&
1065             graphic_info[graphic].double_movement &&
1066             graphic_info[graphic].swap_double_tiles != 0)
1067         {
1068           struct GraphicInfo *g = &graphic_info[graphic];
1069           int src_x_front = g->src_x;
1070           int src_y_front = g->src_y;
1071           int src_x_back = g->src_x + g->offset2_x;
1072           int src_y_back = g->src_y + g->offset2_y;
1073           boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
1074                                                    g->offset_y != 0);
1075           boolean front_is_left_or_upper = (src_x_front < src_x_back ||
1076                                             src_y_front < src_y_back);
1077           boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
1078           boolean swap_movement_tiles_autodetected =
1079             (!frames_are_ordered_diagonally &&
1080              ((move_dir == MV_BIT_LEFT  && !front_is_left_or_upper) ||
1081               (move_dir == MV_BIT_UP    && !front_is_left_or_upper) ||
1082               (move_dir == MV_BIT_RIGHT &&  front_is_left_or_upper) ||
1083               (move_dir == MV_BIT_DOWN  &&  front_is_left_or_upper)));
1084
1085           // swap frontside and backside graphic tile coordinates, if needed
1086           if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
1087           {
1088             // get current (wrong) backside tile coordinates
1089             getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
1090
1091             // set frontside tile coordinates to backside tile coordinates
1092             g->src_x = src_x_back;
1093             g->src_y = src_y_back;
1094
1095             // invert tile offset to point to new backside tile coordinates
1096             g->offset2_x *= -1;
1097             g->offset2_y *= -1;
1098
1099             // do not swap front and backside tiles again after correction
1100             g->swap_double_tiles = 0;
1101           }
1102         }
1103       }
1104     }
1105   }
1106
1107   UPDATE_BUSY_STATE();
1108
1109   // now set all '-1' values to element specific default values
1110   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1111   {
1112     int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
1113     int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
1114     int default_direction_graphic[NUM_DIRECTIONS_FULL];
1115     int default_direction_crumbled[NUM_DIRECTIONS_FULL];
1116
1117     if (default_graphic == -1)
1118       default_graphic = IMG_UNKNOWN;
1119
1120     if (default_crumbled == -1)
1121       default_crumbled = default_graphic;
1122
1123     for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1124     {
1125       default_direction_graphic[dir] =
1126         element_info[i].direction_graphic[ACTION_DEFAULT][dir];
1127       default_direction_crumbled[dir] =
1128         element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
1129
1130       if (default_direction_graphic[dir] == -1)
1131         default_direction_graphic[dir] = default_graphic;
1132
1133       if (default_direction_crumbled[dir] == -1)
1134         default_direction_crumbled[dir] = default_direction_graphic[dir];
1135     }
1136
1137     for (act = 0; act < NUM_ACTIONS; act++)
1138     {
1139       boolean act_remove = ((IS_DIGGABLE(i)    && act == ACTION_DIGGING)  ||
1140                             (IS_SNAPPABLE(i)   && act == ACTION_SNAPPING) ||
1141                             (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
1142       boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
1143                              act == ACTION_TURNING_FROM_RIGHT ||
1144                              act == ACTION_TURNING_FROM_UP ||
1145                              act == ACTION_TURNING_FROM_DOWN);
1146
1147       // generic default action graphic (defined by "[default]" directive)
1148       int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1149       int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1150       int default_remove_graphic = IMG_EMPTY;
1151
1152       if (act_remove && default_action_graphic != -1)
1153         default_remove_graphic = default_action_graphic;
1154
1155       // look for special default action graphic (classic game specific)
1156       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1157         default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1158       if (IS_BD_NATIVE_ELEMENT(i) && element_info[EL_BD_NATIVE_DEFAULT].graphic[act] != -1)
1159         default_action_graphic = element_info[EL_BD_NATIVE_DEFAULT].graphic[act];
1160       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1161         default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1162       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1163         default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1164       if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].graphic[act] != -1)
1165         default_action_graphic = element_info[EL_MM_DEFAULT].graphic[act];
1166
1167       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1168         default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1169       if (IS_BD_NATIVE_ELEMENT(i) && element_info[EL_BD_NATIVE_DEFAULT].crumbled[act] != -1)
1170         default_action_crumbled = element_info[EL_BD_NATIVE_DEFAULT].crumbled[act];
1171       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1172         default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1173       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1174         default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1175       if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].crumbled[act] != -1)
1176         default_action_crumbled = element_info[EL_MM_DEFAULT].crumbled[act];
1177
1178       // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
1179       // !!! make this better !!!
1180       if (i == EL_EMPTY_SPACE)
1181       {
1182         default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1183         default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1184       }
1185
1186       if (default_action_graphic == -1)
1187         default_action_graphic = default_graphic;
1188
1189       if (default_action_crumbled == -1)
1190         default_action_crumbled = default_action_graphic;
1191
1192       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1193       {
1194         // use action graphic as the default direction graphic, if undefined
1195         int default_action_direction_graphic = element_info[i].graphic[act];
1196         int default_action_direction_crumbled = element_info[i].crumbled[act];
1197
1198         // no graphic for current action -- use default direction graphic
1199         if (default_action_direction_graphic == -1)
1200           default_action_direction_graphic =
1201             (act_remove ? default_remove_graphic :
1202              act_turning ?
1203              element_info[i].direction_graphic[ACTION_TURNING][dir] :
1204              default_action_graphic != default_graphic ?
1205              default_action_graphic :
1206              default_direction_graphic[dir]);
1207
1208         if (element_info[i].direction_graphic[act][dir] == -1)
1209           element_info[i].direction_graphic[act][dir] =
1210             default_action_direction_graphic;
1211
1212         if (default_action_direction_crumbled == -1)
1213           default_action_direction_crumbled =
1214             element_info[i].direction_graphic[act][dir];
1215
1216         if (element_info[i].direction_crumbled[act][dir] == -1)
1217           element_info[i].direction_crumbled[act][dir] =
1218             default_action_direction_crumbled;
1219       }
1220
1221       // no graphic for this specific action -- use default action graphic
1222       if (element_info[i].graphic[act] == -1)
1223         element_info[i].graphic[act] =
1224           (act_remove ? default_remove_graphic :
1225            act_turning ? element_info[i].graphic[ACTION_TURNING] :
1226            default_action_graphic);
1227
1228       if (element_info[i].crumbled[act] == -1)
1229         element_info[i].crumbled[act] = element_info[i].graphic[act];
1230     }
1231   }
1232
1233   UPDATE_BUSY_STATE();
1234 }
1235
1236 static void InitElementSpecialGraphicInfo(void)
1237 {
1238   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1239   int num_property_mappings = getImageListPropertyMappingSize();
1240   int i, j;
1241
1242   // always start with reliable default values
1243   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1244     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1245       element_info[i].special_graphic[j] =
1246         element_info[i].graphic[ACTION_DEFAULT];
1247
1248   // initialize special element/graphic mapping from static configuration
1249   for (i = 0; element_to_special_graphic[i].element > -1; i++)
1250   {
1251     int element = element_to_special_graphic[i].element;
1252     int special = element_to_special_graphic[i].special;
1253     int graphic = element_to_special_graphic[i].graphic;
1254     int base_graphic = el2baseimg(element);
1255     boolean base_redefined =
1256       getImageListEntryFromImageID(base_graphic)->redefined;
1257     boolean special_redefined =
1258       getImageListEntryFromImageID(graphic)->redefined;
1259
1260     /* if the base graphic ("emerald", for example) has been redefined,
1261        but not the special graphic ("emerald.EDITOR", for example), do not
1262        use an existing (in this case considered obsolete) special graphic
1263        anymore, but use the automatically created (down-scaled) graphic */
1264     if (base_redefined && !special_redefined)
1265       continue;
1266
1267     element_info[element].special_graphic[special] = graphic;
1268   }
1269
1270   // initialize special element/graphic mapping from dynamic configuration
1271   for (i = 0; i < num_property_mappings; i++)
1272   {
1273     int element   = property_mapping[i].base_index;
1274     int action    = property_mapping[i].ext1_index;
1275     int direction = property_mapping[i].ext2_index;
1276     int special   = property_mapping[i].ext3_index;
1277     int graphic   = property_mapping[i].artwork_index;
1278
1279     // for action ".active", replace element with active element, if exists
1280     if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1281     {
1282       element = ELEMENT_ACTIVE(element);
1283       action = -1;
1284     }
1285
1286     // for BD effect editor graphics, replace element with effect element, if exists
1287     if (action != -1 && special == GFX_SPECIAL_ARG_EDITOR)
1288     {
1289       int element_bd = map_element_RND_to_BD_effect(element, action);
1290       int element_ef = map_element_BD_to_RND_cave(element_bd);
1291
1292       if (element_ef != EL_UNKNOWN)
1293       {
1294         element = element_ef;
1295         action = -1;
1296       }
1297     }
1298
1299     if (element >= MAX_NUM_ELEMENTS)
1300       continue;
1301
1302     // do not change special graphic if action or direction was specified
1303     if (action != -1 || direction != -1)
1304       continue;
1305
1306     if (IS_SPECIAL_GFX_ARG(special))
1307       element_info[element].special_graphic[special] = graphic;
1308   }
1309
1310   // now set all undefined/invalid graphics to default
1311   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1312     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1313       if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1314         element_info[i].special_graphic[j] =
1315           element_info[i].graphic[ACTION_DEFAULT];
1316 }
1317
1318 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1319 {
1320   if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1321     return get_parameter_value(value_raw, suffix, type);
1322
1323   if (strEqual(value_raw, ARG_UNDEFINED))
1324     return ARG_UNDEFINED_VALUE;
1325
1326   if (type == TYPE_ELEMENT)
1327   {
1328     char *value = getHashEntry(element_token_hash, value_raw);
1329
1330     if (value == NULL)
1331     {
1332       Warn("---");
1333       Warn("error found in config file:");
1334       Warn("- config file: '%s'", getImageConfigFilename());
1335       Warn("error: invalid element token '%s'", value_raw);
1336       Warn("custom graphic rejected for this element/action");
1337       Warn("fallback done to undefined element for this graphic");
1338       Warn("---");
1339     }
1340
1341     return (value != NULL ? atoi(value) : EL_UNDEFINED);
1342   }
1343   else if (type == TYPE_GRAPHIC)
1344   {
1345     char *value = getHashEntry(graphic_token_hash, value_raw);
1346     int fallback_graphic = IMG_CHAR_EXCLAM;
1347
1348     if (value == NULL)
1349     {
1350       Warn("---");
1351       Warn("error found in config file:");
1352       Warn("- config file: '%s'", getImageConfigFilename());
1353       Warn("error: invalid graphic token '%s'", value_raw);
1354       Warn("custom graphic rejected for this element/action");
1355       Warn("fallback done to 'char_exclam' for this graphic");
1356       Warn("---");
1357     }
1358
1359     return (value != NULL ? atoi(value) : fallback_graphic);
1360   }
1361
1362   return -1;
1363 }
1364
1365 static int get_scaled_graphic_width(Bitmap *src_bitmap, int graphic)
1366 {
1367   int original_width = getOriginalImageWidthFromImageID(graphic);
1368   int scale_up_factor = graphic_info[graphic].scale_up_factor;
1369
1370   // only happens when loaded outside artwork system (like "global.busy")
1371   if (graphic_info == image_initial && src_bitmap)
1372     original_width = src_bitmap->width;
1373
1374   return original_width * scale_up_factor;
1375 }
1376
1377 static int get_scaled_graphic_height(Bitmap *src_bitmap, int graphic)
1378 {
1379   int original_height = getOriginalImageHeightFromImageID(graphic);
1380   int scale_up_factor = graphic_info[graphic].scale_up_factor;
1381
1382   // only happens when loaded outside artwork system (like "global.busy")
1383   if (graphic_info == image_initial && src_bitmap)
1384     original_height = src_bitmap->height;
1385
1386   return original_height * scale_up_factor;
1387 }
1388
1389 static void set_graphic_parameters_ext(int graphic, int *parameter,
1390                                        Bitmap **src_bitmaps)
1391 {
1392   struct GraphicInfo *g = &graphic_info[graphic];
1393   Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1394   int anim_frames_per_row = 1, anim_frames_per_col = 1;
1395   int anim_frames_per_line = 1;
1396
1397   // always start with reliable default values
1398   g->src_image_width = 0;
1399   g->src_image_height = 0;
1400   g->src_x = 0;
1401   g->src_y = 0;
1402   g->width  = TILEX;                    // default for element graphics
1403   g->height = TILEY;                    // default for element graphics
1404   g->offset_x = 0;                      // one or both of these values ...
1405   g->offset_y = 0;                      // ... will be corrected later
1406   g->offset2_x = 0;                     // one or both of these values ...
1407   g->offset2_y = 0;                     // ... will be corrected later
1408   g->swap_double_tiles = -1;            // auto-detect tile swapping
1409   g->crumbled_like = -1;                // do not use clone element
1410   g->diggable_like = -1;                // do not use clone element
1411   g->border_size = TILEX / 8;           // "CRUMBLED" border size
1412   g->scale_up_factor = 1;               // default: no scaling up
1413   g->tile_size = TILESIZE;              // default: standard tile size
1414   g->clone_from = -1;                   // do not use clone graphic
1415   g->init_delay_fixed = 0;
1416   g->init_delay_random = 0;
1417   g->init_delay_action = -1;
1418   g->anim_delay_fixed = 0;
1419   g->anim_delay_random = 0;
1420   g->anim_delay_action = -1;
1421   g->post_delay_fixed = 0;
1422   g->post_delay_random = 0;
1423   g->post_delay_action = -1;
1424   g->init_event = ANIM_EVENT_UNDEFINED;
1425   g->anim_event = ANIM_EVENT_UNDEFINED;
1426   g->init_event_action = -1;
1427   g->anim_event_action = -1;
1428   g->draw_masked = FALSE;
1429   g->draw_order = 0;
1430   g->fade_mode = FADE_MODE_DEFAULT;
1431   g->fade_delay = -1;
1432   g->post_delay = -1;
1433   g->auto_delay = -1;
1434   g->auto_delay_unit = AUTO_DELAY_UNIT_DEFAULT;
1435   g->align = ALIGN_CENTER;              // default for title screens
1436   g->valign = VALIGN_MIDDLE;            // default for title screens
1437   g->sort_priority = 0;                 // default for title screens
1438   g->class = 0;
1439   g->style = STYLE_DEFAULT;
1440   g->alpha = -1;
1441
1442   g->bitmaps = src_bitmaps;
1443   g->bitmap = src_bitmap;
1444
1445   // optional zoom factor for scaling up the image to a larger size
1446   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1447     g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1448   if (g->scale_up_factor < 1)
1449     g->scale_up_factor = 1;             // no scaling
1450
1451   // optional tile size for using non-standard image size
1452   if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1453   {
1454     g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1455
1456 #if 0
1457     // CHECK: should tile sizes less than standard tile size be allowed?
1458     if (g->tile_size < TILESIZE)
1459       g->tile_size = TILESIZE;          // standard tile size
1460 #endif
1461
1462     // when setting tile size, also set width and height accordingly
1463     g->width  = g->tile_size;
1464     g->height = g->tile_size;
1465   }
1466
1467   if (g->use_image_size)
1468   {
1469     // set new default bitmap size (with scaling, but without small images)
1470     g->width  = get_scaled_graphic_width(src_bitmap, graphic);
1471     g->height = get_scaled_graphic_height(src_bitmap, graphic);
1472   }
1473
1474   // optional width and height of each animation frame
1475   if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1476     g->width = parameter[GFX_ARG_WIDTH];
1477   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1478     g->height = parameter[GFX_ARG_HEIGHT];
1479
1480   // optional x and y tile position of animation frame sequence
1481   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1482     g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1483   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1484     g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1485
1486   // optional x and y pixel position of animation frame sequence
1487   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1488     g->src_x = parameter[GFX_ARG_X];
1489   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1490     g->src_y = parameter[GFX_ARG_Y];
1491
1492   if (src_bitmap)
1493   {
1494     if (g->width <= 0)
1495     {
1496       Warn("---");
1497       Warn("invalid value %d for '%s.width' (fallback done to %d)",
1498            g->width, getTokenFromImageID(graphic), TILEX);
1499       Warn("---");
1500
1501       g->width = TILEX;         // will be checked to be inside bitmap later
1502     }
1503
1504     if (g->height <= 0)
1505     {
1506       Warn("---");
1507       Warn("invalid value %d for '%s.height' (fallback done to %d)",
1508            g->height, getTokenFromImageID(graphic), TILEY);
1509       Warn("---");
1510
1511       g->height = TILEY;        // will be checked to be inside bitmap later
1512     }
1513   }
1514
1515   if (src_bitmap)
1516   {
1517     // get final bitmap size (with scaling, but without small images)
1518     int src_image_width  = get_scaled_graphic_width(src_bitmap, graphic);
1519     int src_image_height = get_scaled_graphic_height(src_bitmap, graphic);
1520
1521     if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1522     {
1523       anim_frames_per_row = MAX(1, src_image_width  / g->tile_size);
1524       anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1525     }
1526     else
1527     {
1528       anim_frames_per_row = MAX(1, src_image_width  / g->width);
1529       anim_frames_per_col = MAX(1, src_image_height / g->height);
1530     }
1531
1532     g->src_image_width  = src_image_width;
1533     g->src_image_height = src_image_height;
1534   }
1535
1536   // correct x or y offset dependent of vertical or horizontal frame order
1537   if (parameter[GFX_ARG_VERTICAL])      // frames are ordered vertically
1538   {
1539     g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1540                    parameter[GFX_ARG_OFFSET] : g->height);
1541     anim_frames_per_line = anim_frames_per_col;
1542   }
1543   else                                  // frames are ordered horizontally
1544   {
1545     g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1546                    parameter[GFX_ARG_OFFSET] : g->width);
1547     anim_frames_per_line = anim_frames_per_row;
1548   }
1549
1550   // optionally, the x and y offset of frames can be specified directly
1551   if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1552     g->offset_x = parameter[GFX_ARG_XOFFSET];
1553   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1554     g->offset_y = parameter[GFX_ARG_YOFFSET];
1555
1556   // optionally, moving animations may have separate start and end graphics
1557   g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1558
1559   if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1560     parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1561
1562   // correct x or y offset2 dependent of vertical or horizontal frame order
1563   if (parameter[GFX_ARG_2ND_VERTICAL])  // frames are ordered vertically
1564     g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1565                     parameter[GFX_ARG_2ND_OFFSET] : g->height);
1566   else                                  // frames are ordered horizontally
1567     g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1568                     parameter[GFX_ARG_2ND_OFFSET] : g->width);
1569
1570   // optionally, the x and y offset of 2nd graphic can be specified directly
1571   if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1572     g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1573   if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1574     g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1575
1576   // optionally, the second movement tile can be specified as start tile
1577   if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1578     g->swap_double_tiles = parameter[GFX_ARG_2ND_SWAP_TILES];
1579
1580   // automatically determine correct number of frames, if not defined
1581   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1582     g->anim_frames = parameter[GFX_ARG_FRAMES];
1583   else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1584     g->anim_frames = anim_frames_per_row;
1585   else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1586     g->anim_frames = anim_frames_per_col;
1587   else
1588     g->anim_frames = 1;
1589
1590   if (g->anim_frames < 1)               // frames must be at least 1
1591     g->anim_frames = 1;
1592
1593   g->anim_frames_per_line =
1594     (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1595      parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1596
1597   g->anim_delay = parameter[GFX_ARG_DELAY];
1598   if (g->anim_delay < 1)                // delay must be at least 1
1599     g->anim_delay = 1;
1600
1601   g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1602
1603   // automatically determine correct start frame, if not defined
1604   if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1605     g->anim_start_frame = 0;
1606   else if (g->anim_mode & ANIM_REVERSE)
1607     g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1608   else
1609     g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1610
1611   // animation synchronized with global frame counter, not move position
1612   g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1613
1614   // animation synchronized with global anim frame counter, not move position
1615   g->anim_global_anim_sync = parameter[GFX_ARG_GLOBAL_ANIM_SYNC];
1616
1617   // optional element for cloning crumble graphics
1618   if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1619     g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1620
1621   // optional element for cloning digging graphics
1622   if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1623     g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1624
1625   // optional border size for "crumbling" diggable graphics
1626   if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1627     g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1628
1629   // used for global animations and player "boring" and "sleeping" actions
1630   if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1631     g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1632   if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1633     g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1634   if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1635     g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1636   if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1637     g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1638   if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1639     g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1640   if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1641     g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1642
1643   // used for global animations
1644   if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1645     g->init_event = parameter[GFX_ARG_INIT_EVENT];
1646   if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1647     g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1648   if (parameter[GFX_ARG_INIT_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1649     g->init_event_action = parameter[GFX_ARG_INIT_EVENT_ACTION];
1650   if (parameter[GFX_ARG_ANIM_EVENT_ACTION] != ARG_UNDEFINED_VALUE)
1651     g->anim_event_action = parameter[GFX_ARG_ANIM_EVENT_ACTION];
1652   if (parameter[GFX_ARG_INIT_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1653     g->init_delay_action = parameter[GFX_ARG_INIT_DELAY_ACTION];
1654   if (parameter[GFX_ARG_ANIM_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1655     g->anim_delay_action = parameter[GFX_ARG_ANIM_DELAY_ACTION];
1656   if (parameter[GFX_ARG_POST_DELAY_ACTION] != ARG_UNDEFINED_VALUE)
1657     g->post_delay_action = parameter[GFX_ARG_POST_DELAY_ACTION];
1658
1659   // used for toon animations and global animations
1660   g->step_offset  = parameter[GFX_ARG_STEP_OFFSET];
1661   g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1662   g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1663   g->step_delay   = parameter[GFX_ARG_STEP_DELAY];
1664   g->direction    = parameter[GFX_ARG_DIRECTION];
1665   g->position     = parameter[GFX_ARG_POSITION];
1666   g->x            = parameter[GFX_ARG_X];       // (may be uninitialized,
1667   g->y            = parameter[GFX_ARG_Y];       // unlike src_x and src_y)
1668
1669   if (g->step_delay < 1)                        // delay must be at least 1
1670     g->step_delay = 1;
1671
1672   // this is only used for drawing font characters
1673   g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1674   g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1675
1676   // use a different default value for global animations and toons
1677   if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_32) ||
1678       (graphic >= IMG_TOON_1            && graphic <= IMG_TOON_20))
1679     g->draw_masked = TRUE;
1680
1681   // this is used for drawing envelopes, global animations and toons
1682   if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
1683     g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1684
1685   // used for toon animations and global animations
1686   if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1687     g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1688
1689   // optional graphic for cloning all graphics settings
1690   if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1691     g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1692
1693   // optional settings for drawing title screens and title messages
1694   if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1695     g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1696   if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1697     g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1698   if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1699     g->post_delay = parameter[GFX_ARG_POST_DELAY];
1700   if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1701     g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1702   if (parameter[GFX_ARG_AUTO_DELAY_UNIT] != ARG_UNDEFINED_VALUE)
1703     g->auto_delay_unit = parameter[GFX_ARG_AUTO_DELAY_UNIT];
1704   if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1705     g->align = parameter[GFX_ARG_ALIGN];
1706   if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1707     g->valign = parameter[GFX_ARG_VALIGN];
1708   if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1709     g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1710
1711   if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1712     g->class = parameter[GFX_ARG_CLASS];
1713   if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1714     g->style = parameter[GFX_ARG_STYLE];
1715   if (parameter[GFX_ARG_ALPHA] != ARG_UNDEFINED_VALUE)
1716     g->alpha = parameter[GFX_ARG_ALPHA];
1717
1718   // this is only used for drawing menu buttons and text
1719   g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1720   g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1721   g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1722   g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1723
1724   // this is only used for drawing stacked global animations
1725   g->stacked_xfactor = parameter[GFX_ARG_STACKED_XFACTOR];
1726   g->stacked_yfactor = parameter[GFX_ARG_STACKED_YFACTOR];
1727   g->stacked_xoffset = parameter[GFX_ARG_STACKED_XOFFSET];
1728   g->stacked_yoffset = parameter[GFX_ARG_STACKED_YOFFSET];
1729 }
1730
1731 static void set_graphic_parameters(int graphic)
1732 {
1733   struct FileInfo *image = getImageListEntryFromImageID(graphic);
1734   char **parameter_raw = image->parameter;
1735   Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1736   int parameter[NUM_GFX_ARGS];
1737   int i;
1738
1739   // if fallback to default artwork is done, also use the default parameters
1740   if (image->fallback_to_default)
1741     parameter_raw = image->default_parameter;
1742
1743   // get integer values from string parameters
1744   for (i = 0; i < NUM_GFX_ARGS; i++)
1745     parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1746                                                image_config_suffix[i].token,
1747                                                image_config_suffix[i].type);
1748
1749   set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1750
1751   UPDATE_BUSY_STATE();
1752 }
1753
1754 static void set_cloned_graphic_parameters(int graphic)
1755 {
1756   int fallback_graphic = IMG_CHAR_EXCLAM;
1757   int max_num_images = getImageListSize();
1758   int clone_graphic = graphic_info[graphic].clone_from;
1759   int num_references_followed = 1;
1760
1761   while (graphic_info[clone_graphic].clone_from != -1 &&
1762          num_references_followed < max_num_images)
1763   {
1764     clone_graphic = graphic_info[clone_graphic].clone_from;
1765
1766     num_references_followed++;
1767   }
1768
1769   if (num_references_followed >= max_num_images)
1770   {
1771     Warn("---");
1772     Warn("error found in config file:");
1773     Warn("- config file: '%s'", getImageConfigFilename());
1774     Warn("- config token: '%s'", getTokenFromImageID(graphic));
1775     Warn("error: loop discovered when resolving cloned graphics");
1776     Warn("custom graphic rejected for this element/action");
1777
1778     if (graphic == fallback_graphic)
1779       Fail("no fallback graphic available");
1780
1781     Warn("fallback done to 'char_exclam' for this graphic");
1782     Warn("---");
1783
1784     graphic_info[graphic] = graphic_info[fallback_graphic];
1785   }
1786   else
1787   {
1788     graphic_info[graphic] = graphic_info[clone_graphic];
1789     graphic_info[graphic].clone_from = clone_graphic;
1790   }
1791 }
1792
1793 static void InitGraphicInfo(void)
1794 {
1795   int fallback_graphic = IMG_CHAR_EXCLAM;
1796   int num_images = getImageListSize();
1797   int i;
1798
1799   // use image size as default values for width and height for these images
1800   static int full_size_graphics[] =
1801   {
1802     IMG_GLOBAL_BORDER,
1803     IMG_GLOBAL_BORDER_MAIN,
1804     IMG_GLOBAL_BORDER_SCORES,
1805     IMG_GLOBAL_BORDER_EDITOR,
1806     IMG_GLOBAL_BORDER_PLAYING,
1807     IMG_GLOBAL_DOOR,
1808
1809     IMG_BACKGROUND_ENVELOPE_1,
1810     IMG_BACKGROUND_ENVELOPE_2,
1811     IMG_BACKGROUND_ENVELOPE_3,
1812     IMG_BACKGROUND_ENVELOPE_4,
1813     IMG_BACKGROUND_REQUEST,
1814
1815     IMG_BACKGROUND,
1816     IMG_BACKGROUND_LOADING_INITIAL,
1817     IMG_BACKGROUND_LOADING,
1818     IMG_BACKGROUND_TITLE_INITIAL,
1819     IMG_BACKGROUND_TITLE,
1820     IMG_BACKGROUND_MAIN,
1821     IMG_BACKGROUND_NAMES,
1822     IMG_BACKGROUND_LEVELS,
1823     IMG_BACKGROUND_LEVELNR,
1824     IMG_BACKGROUND_SCORES,
1825     IMG_BACKGROUND_SCOREINFO,
1826     IMG_BACKGROUND_EDITOR,
1827     IMG_BACKGROUND_INFO,
1828     IMG_BACKGROUND_INFO_ELEMENTS,
1829     IMG_BACKGROUND_INFO_MUSIC,
1830     IMG_BACKGROUND_INFO_CREDITS,
1831     IMG_BACKGROUND_INFO_PROGRAM,
1832     IMG_BACKGROUND_INFO_VERSION,
1833     IMG_BACKGROUND_INFO_LEVELSET,
1834     IMG_BACKGROUND_SETUP,
1835     IMG_BACKGROUND_PLAYING,
1836     IMG_BACKGROUND_DOOR,
1837     IMG_BACKGROUND_TAPE,
1838     IMG_BACKGROUND_PANEL,
1839     IMG_BACKGROUND_PALETTE,
1840     IMG_BACKGROUND_TOOLBOX,
1841
1842     IMG_TITLESCREEN_INITIAL_1,
1843     IMG_TITLESCREEN_INITIAL_2,
1844     IMG_TITLESCREEN_INITIAL_3,
1845     IMG_TITLESCREEN_INITIAL_4,
1846     IMG_TITLESCREEN_INITIAL_5,
1847     IMG_TITLESCREEN_1,
1848     IMG_TITLESCREEN_2,
1849     IMG_TITLESCREEN_3,
1850     IMG_TITLESCREEN_4,
1851     IMG_TITLESCREEN_5,
1852
1853     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1854     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1855     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1856     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1857     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1858     IMG_BACKGROUND_TITLEMESSAGE_1,
1859     IMG_BACKGROUND_TITLEMESSAGE_2,
1860     IMG_BACKGROUND_TITLEMESSAGE_3,
1861     IMG_BACKGROUND_TITLEMESSAGE_4,
1862     IMG_BACKGROUND_TITLEMESSAGE_5,
1863
1864     -1
1865   };
1866
1867   FreeGlobalAnimEventInfo();
1868
1869   checked_free(graphic_info);
1870
1871   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1872
1873   // initialize "use_image_size" flag with default value
1874   for (i = 0; i < num_images; i++)
1875     graphic_info[i].use_image_size = FALSE;
1876
1877   // initialize "use_image_size" flag from static configuration above
1878   for (i = 0; full_size_graphics[i] != -1; i++)
1879     graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1880
1881   // first set all graphic paramaters ...
1882   for (i = 0; i < num_images; i++)
1883     set_graphic_parameters(i);
1884
1885   // ... then copy these parameters for cloned graphics
1886   for (i = 0; i < num_images; i++)
1887     if (graphic_info[i].clone_from != -1)
1888       set_cloned_graphic_parameters(i);
1889
1890   for (i = 0; i < num_images; i++)
1891   {
1892     Bitmap *src_bitmap = graphic_info[i].bitmap;
1893     int src_x, src_y;
1894     int width, height;
1895     int last_frame;
1896     int src_bitmap_width, src_bitmap_height;
1897
1898     // now check if no animation frames are outside of the loaded image
1899
1900     if (graphic_info[i].bitmap == NULL)
1901       continue;         // skip check for optional images that are undefined
1902
1903     // get image size (this can differ from the standard element tile size!)
1904     width  = graphic_info[i].width;
1905     height = graphic_info[i].height;
1906
1907     // get final bitmap size (with scaling, but without small images)
1908     src_bitmap_width  = graphic_info[i].src_image_width;
1909     src_bitmap_height = graphic_info[i].src_image_height;
1910
1911     // check if first animation frame is inside specified bitmap
1912
1913     // do not use getGraphicSourceXY() here to get position of first frame;
1914     // this avoids calculating wrong start position for out-of-bounds frame
1915     src_x = graphic_info[i].src_x;
1916     src_y = graphic_info[i].src_y;
1917
1918     if (program.headless)
1919       continue;
1920
1921     if (src_x < 0 || src_y < 0 ||
1922         src_x + width  > src_bitmap_width ||
1923         src_y + height > src_bitmap_height)
1924     {
1925       Warn("---");
1926       Warn("error found in config file:");
1927       Warn("- config file: '%s'", getImageConfigFilename());
1928       Warn("- config token: '%s'", getTokenFromImageID(i));
1929       Warn("- image file: '%s'", src_bitmap->source_filename);
1930       Warn("- frame size: %d, %d", width, height);
1931       Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
1932            src_x, src_y, src_bitmap_width, src_bitmap_height);
1933       Warn("custom graphic rejected for this element/action");
1934
1935       if (i == fallback_graphic)
1936         Fail("no fallback graphic available");
1937
1938       Warn("fallback done to 'char_exclam' for this graphic");
1939       Warn("---");
1940
1941       graphic_info[i] = graphic_info[fallback_graphic];
1942
1943       // if first frame out of bounds, do not check last frame anymore
1944       continue;
1945     }
1946
1947     // check if last animation frame is inside specified bitmap
1948
1949     last_frame = graphic_info[i].anim_frames - 1;
1950     getGraphicSourceXY(i, last_frame, &src_x, &src_y, FALSE);
1951
1952     if (src_x < 0 || src_y < 0 ||
1953         src_x + width  > src_bitmap_width ||
1954         src_y + height > src_bitmap_height)
1955     {
1956       Warn("---");
1957       Warn("error found in config file:");
1958       Warn("- config file: '%s'", getImageConfigFilename());
1959       Warn("- config token: '%s'", getTokenFromImageID(i));
1960       Warn("- image file: '%s'", src_bitmap->source_filename);
1961       Warn("- frame size: %d, %d", width, height);
1962       Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1963            last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1964       Warn("custom graphic rejected for this element/action");
1965
1966       if (i == fallback_graphic)
1967         Fail("no fallback graphic available");
1968
1969       Warn("fallback done to 'char_exclam' for this graphic");
1970       Warn("---");
1971
1972       graphic_info[i] = graphic_info[fallback_graphic];
1973     }
1974   }
1975 }
1976
1977 static void InitGraphicCompatibilityInfo(void)
1978 {
1979   struct FileInfo *fi_global_door =
1980     getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1981   int num_images = getImageListSize();
1982   int i;
1983
1984   /* the following compatibility handling is needed for the following case:
1985      versions up to 3.3.0.0 used one large bitmap "global.door" for various
1986      graphics mainly used for door and panel graphics, like editor, tape and
1987      in-game buttons with hard-coded bitmap positions and button sizes; as
1988      these graphics now have individual definitions, redefining "global.door"
1989      to change all these graphics at once like before does not work anymore
1990      (because all those individual definitions still have their default values);
1991      to solve this, remap all those individual definitions that are not
1992      redefined to the new bitmap of "global.door" if it was redefined */
1993
1994   // special compatibility handling if image "global.door" was redefined
1995   if (fi_global_door->redefined)
1996   {
1997     for (i = 0; i < num_images; i++)
1998     {
1999       struct FileInfo *fi = getImageListEntryFromImageID(i);
2000
2001       // process only those images that still use the default settings
2002       if (!fi->redefined)
2003       {
2004         // process all images which default to same image as "global.door"
2005         if (strEqual(fi->default_filename, fi_global_door->default_filename))
2006         {
2007           // skip all images that are cloned from images that default to same
2008           // image as "global.door", but that are redefined to something else
2009           if (graphic_info[i].clone_from != -1)
2010           {
2011             int cloned_graphic = graphic_info[i].clone_from;
2012
2013             if (getImageListEntryFromImageID(cloned_graphic)->redefined)
2014               continue;
2015           }
2016
2017 #if 0
2018           Debug("init:InitGraphicCompatibilityInfo",
2019                 "special treatment needed for token '%s'", fi->token);
2020 #endif
2021
2022           graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
2023           graphic_info[i].bitmap  = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2024         }
2025       }
2026     }
2027   }
2028
2029   // special compatibility handling for "Snake Bite" graphics set
2030   if (strPrefix(leveldir_current->identifier, "snake_bite"))
2031   {
2032     Bitmap *bitmap = graphic_info[IMG_BACKGROUND_SCORES].bitmap;
2033
2034     BlitBitmap(bitmap, bitmap, 18,  66, 32, 480, 50,  66);
2035     BlitBitmap(bitmap, bitmap, 466, 66, 32, 480, 434, 66);
2036
2037     ClearRectangle(bitmap, 2,   66, 32, 480);
2038     ClearRectangle(bitmap, 514, 66, 32, 480);
2039   }
2040
2041   // special compatibility handling for "Jue" graphics sets (2007 and 2019)
2042   boolean supports_score_info = (menu.draw_xoffset[GAME_MODE_SCOREINFO] != 0);
2043   if (strPrefix(artwork.gfx_current_identifier, "jue") && !supports_score_info)
2044   {
2045     int font_title[] =
2046     {
2047       FONT_TITLE_1,
2048       FONT_TITLE_2,
2049
2050       -1
2051     };
2052     int font_text[] =
2053     {
2054       FONT_TEXT_1,
2055       FONT_TEXT_2,
2056       FONT_TEXT_3,
2057       FONT_TEXT_4,
2058
2059       -1
2060     };
2061     int mode_old = GAME_MODE_SCORES;
2062     int mode_new = GAME_MODE_SCOREINFO;
2063     int i, j;
2064
2065     // adjust title screens on score info page
2066     for (i = 0; font_title[i] != -1; i++)
2067     {
2068       struct FontInfo *fi = &font_info[font_title[i]];
2069
2070       fi->special_graphic[mode_new]   = fi->special_graphic[mode_old];
2071       fi->special_bitmap_id[mode_new] = fi->special_bitmap_id[mode_old];
2072     }
2073
2074     // adjust vertical text and button positions on scores page
2075     for (i = 0; font_text[i] != -1; i++)
2076     {
2077       for (j = 0; j < 2; j++)
2078       {
2079         boolean jue0 = strEqual(artwork.gfx_current_identifier, "jue0");
2080         int font_nr = (j == 0 ? font_text[i] : FONT_ACTIVE(font_text[i]));
2081         int font_bitmap_id = font_info[font_nr].special_bitmap_id[mode_old];
2082         int font_yoffset = (jue0 ? 10 : 5);
2083
2084         gfx.font_bitmap_info[font_bitmap_id].draw_yoffset = font_yoffset;
2085       }
2086     }
2087
2088     // adjust page offsets on score info page
2089     menu.draw_xoffset[mode_new] = menu.draw_xoffset[mode_old];
2090     menu.draw_yoffset[mode_new] = menu.draw_yoffset[mode_old];
2091   }
2092
2093   InitGraphicCompatibilityInfo_Doors();
2094 }
2095
2096 static void InitElementSoundInfo(void)
2097 {
2098   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2099   int num_property_mappings = getSoundListPropertyMappingSize();
2100   int i, j, act;
2101
2102   // set values to -1 to identify later as "uninitialized" values
2103   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2104     for (act = 0; act < NUM_ACTIONS; act++)
2105       element_info[i].sound[act] = -1;
2106
2107   // initialize element/sound mapping from static configuration
2108   for (i = 0; element_to_sound[i].element > -1; i++)
2109   {
2110     int element      = element_to_sound[i].element;
2111     int action       = element_to_sound[i].action;
2112     int sound        = element_to_sound[i].sound;
2113     boolean is_class = element_to_sound[i].is_class;
2114
2115     if (action < 0)
2116       action = ACTION_DEFAULT;
2117
2118     if (!is_class)
2119       element_info[element].sound[action] = sound;
2120     else
2121       for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2122         if (strEqual(element_info[j].class_name,
2123                      element_info[element].class_name))
2124           element_info[j].sound[action] = sound;
2125   }
2126
2127   // initialize element class/sound mapping from dynamic configuration
2128   for (i = 0; i < num_property_mappings; i++)
2129   {
2130     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2131     int action        = property_mapping[i].ext1_index;
2132     int sound         = property_mapping[i].artwork_index;
2133
2134     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2135       continue;
2136
2137     if (action < 0)
2138       action = ACTION_DEFAULT;
2139
2140     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2141       if (strEqual(element_info[j].class_name,
2142                    element_info[element_class].class_name))
2143         element_info[j].sound[action] = sound;
2144   }
2145
2146   // initialize element/sound mapping from dynamic configuration
2147   for (i = 0; i < num_property_mappings; i++)
2148   {
2149     int element = property_mapping[i].base_index;
2150     int action  = property_mapping[i].ext1_index;
2151     int sound   = property_mapping[i].artwork_index;
2152
2153     if (element >= MAX_NUM_ELEMENTS)
2154       continue;
2155
2156     if (action < 0)
2157       action = ACTION_DEFAULT;
2158
2159     element_info[element].sound[action] = sound;
2160   }
2161
2162   // now set all '-1' values to element specific default values
2163   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2164   {
2165     for (act = 0; act < NUM_ACTIONS; act++)
2166     {
2167       // generic default action sound (defined by "[default]" directive)
2168       int default_action_sound = element_info[EL_DEFAULT].sound[act];
2169
2170       // look for special default action sound (classic game specific)
2171       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2172         default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2173       if (IS_BD_NATIVE_ELEMENT(i) && element_info[EL_BD_NATIVE_DEFAULT].sound[act] != -1)
2174         default_action_sound = element_info[EL_BD_NATIVE_DEFAULT].sound[act];
2175       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2176         default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2177       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2178         default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2179       if (IS_MM_ELEMENT(i) && element_info[EL_MM_DEFAULT].sound[act] != -1)
2180         default_action_sound = element_info[EL_MM_DEFAULT].sound[act];
2181
2182       // !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!!
2183       // !!! make this better !!!
2184       if (i == EL_EMPTY_SPACE)
2185         default_action_sound = element_info[EL_DEFAULT].sound[act];
2186
2187       // no sound for this specific action -- use default action sound
2188       if (element_info[i].sound[act] == -1)
2189         element_info[i].sound[act] = default_action_sound;
2190     }
2191   }
2192
2193   // copy sound settings to some elements that are only stored in level file
2194   // in native R'n'D levels, but are used by game engine in native EM levels
2195   for (i = 0; copy_properties[i][0] != -1; i++)
2196     for (j = 1; j <= 4; j++)
2197       for (act = 0; act < NUM_ACTIONS; act++)
2198         element_info[copy_properties[i][j]].sound[act] =
2199           element_info[copy_properties[i][0]].sound[act];
2200 }
2201
2202 static void InitGameModeSoundInfo(void)
2203 {
2204   int i;
2205
2206   // set values to -1 to identify later as "uninitialized" values
2207   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2208     menu.sound[i] = -1;
2209
2210   // initialize gamemode/sound mapping from static configuration
2211   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2212   {
2213     int gamemode = gamemode_to_sound[i].gamemode;
2214     int sound    = gamemode_to_sound[i].sound;
2215
2216     if (gamemode < 0)
2217       gamemode = GAME_MODE_DEFAULT;
2218
2219     menu.sound[gamemode] = sound;
2220   }
2221
2222   // now set all '-1' values to levelset specific default values
2223   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2224     if (menu.sound[i] == -1)
2225       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2226 }
2227
2228 static void set_sound_parameters(int sound, char **parameter_raw)
2229 {
2230   int parameter[NUM_SND_ARGS];
2231   int i;
2232
2233   // get integer values from string parameters
2234   for (i = 0; i < NUM_SND_ARGS; i++)
2235     parameter[i] =
2236       get_parameter_value(parameter_raw[i],
2237                           sound_config_suffix[i].token,
2238                           sound_config_suffix[i].type);
2239
2240   // explicit loop mode setting in configuration overrides default value
2241   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2242     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2243
2244   // sound volume to change the original volume when loading the sound file
2245   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2246
2247   // sound priority to give certain sounds a higher or lower priority
2248   sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2249 }
2250
2251 static void InitSoundInfo(void)
2252 {
2253   int *sound_effect_properties;
2254   int num_sounds = getSoundListSize();
2255   int i, j;
2256
2257   checked_free(sound_info);
2258
2259   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2260   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2261
2262   // initialize sound effect for all elements to "no sound"
2263   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2264     for (j = 0; j < NUM_ACTIONS; j++)
2265       element_info[i].sound[j] = SND_UNDEFINED;
2266
2267   for (i = 0; i < num_sounds; i++)
2268   {
2269     struct FileInfo *sound = getSoundListEntry(i);
2270     int len_effect_text = strlen(sound->token);
2271
2272     sound_effect_properties[i] = ACTION_OTHER;
2273     sound_info[i].loop = FALSE;         // default: play sound only once
2274
2275     // determine all loop sounds and identify certain sound classes
2276
2277     for (j = 0; element_action_info[j].suffix; j++)
2278     {
2279       int len_action_text = strlen(element_action_info[j].suffix);
2280
2281       if (len_action_text < len_effect_text &&
2282           strEqual(&sound->token[len_effect_text - len_action_text],
2283                    element_action_info[j].suffix))
2284       {
2285         sound_effect_properties[i] = element_action_info[j].value;
2286         sound_info[i].loop = element_action_info[j].is_loop_sound;
2287
2288         break;
2289       }
2290     }
2291
2292     // associate elements and some selected sound actions
2293
2294     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2295     {
2296       if (element_info[j].class_name)
2297       {
2298         int len_class_text = strlen(element_info[j].class_name);
2299
2300         if (len_class_text + 1 < len_effect_text &&
2301             strncmp(sound->token,
2302                     element_info[j].class_name, len_class_text) == 0 &&
2303             sound->token[len_class_text] == '.')
2304         {
2305           int sound_action_value = sound_effect_properties[i];
2306
2307           element_info[j].sound[sound_action_value] = i;
2308         }
2309       }
2310     }
2311
2312     set_sound_parameters(i, sound->parameter);
2313
2314 #if 0
2315     Debug("init:InitSoundInfo", "loop mode: %d ['%s']",
2316           sound_info[i].loop, sound->token);
2317 #endif
2318   }
2319
2320   free(sound_effect_properties);
2321 }
2322
2323 static void InitGameModeMusicInfo(void)
2324 {
2325   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2326   int num_property_mappings = getMusicListPropertyMappingSize();
2327   int default_levelset_music = -1;
2328   int i;
2329
2330   // set values to -1 to identify later as "uninitialized" values
2331   for (i = 0; i < MAX_LEVELS; i++)
2332     levelset.music[i] = -1;
2333   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2334     menu.music[i] = -1;
2335
2336   // initialize gamemode/music mapping from static configuration
2337   for (i = 0; gamemode_to_music[i].music > -1; i++)
2338   {
2339     int gamemode = gamemode_to_music[i].gamemode;
2340     int music    = gamemode_to_music[i].music;
2341
2342     if (gamemode < 0)
2343       gamemode = GAME_MODE_DEFAULT;
2344
2345     menu.music[gamemode] = music;
2346   }
2347
2348   // initialize gamemode/music mapping from dynamic configuration
2349   for (i = 0; i < num_property_mappings; i++)
2350   {
2351     int prefix   = property_mapping[i].base_index;
2352     int gamemode = property_mapping[i].ext2_index;
2353     int level    = property_mapping[i].ext3_index;
2354     int music    = property_mapping[i].artwork_index;
2355
2356     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2357       continue;
2358
2359     if (gamemode < 0)
2360       gamemode = GAME_MODE_DEFAULT;
2361
2362     // level specific music only allowed for in-game music
2363     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2364       gamemode = GAME_MODE_PLAYING;
2365
2366     if (level == -1)
2367     {
2368       level = 0;
2369       default_levelset_music = music;
2370     }
2371
2372     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2373       levelset.music[level] = music;
2374     if (gamemode != GAME_MODE_PLAYING)
2375       menu.music[gamemode] = music;
2376   }
2377
2378   // now set all '-1' values to menu specific default values
2379   // (undefined values of "levelset.music[]" might stay at "-1" to
2380   // allow dynamic selection of music files from music directory!)
2381   for (i = 0; i < MAX_LEVELS; i++)
2382     if (levelset.music[i] == -1)
2383       levelset.music[i] = default_levelset_music;
2384   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2385     if (menu.music[i] == -1)
2386       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2387 }
2388
2389 static void set_music_parameters(int music, char **parameter_raw)
2390 {
2391   int parameter[NUM_MUS_ARGS];
2392   int i;
2393
2394   // get integer values from string parameters
2395   for (i = 0; i < NUM_MUS_ARGS; i++)
2396     parameter[i] =
2397       get_parameter_value(parameter_raw[i],
2398                           music_config_suffix[i].token,
2399                           music_config_suffix[i].type);
2400
2401   // explicit loop mode setting in configuration overrides default value
2402   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2403     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2404 }
2405
2406 static void InitMusicInfo(void)
2407 {
2408   int num_music = getMusicListSize();
2409   int i, j;
2410
2411   checked_free(music_info);
2412
2413   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2414
2415   for (i = 0; i < num_music; i++)
2416   {
2417     struct FileInfo *music = getMusicListEntry(i);
2418     int len_music_text = strlen(music->token);
2419
2420     music_info[i].loop = TRUE;          // default: play music in loop mode
2421
2422     // determine all loop music
2423
2424     for (j = 0; music_prefix_info[j].prefix; j++)
2425     {
2426       int len_prefix_text = strlen(music_prefix_info[j].prefix);
2427
2428       if (len_prefix_text < len_music_text &&
2429           strncmp(music->token,
2430                   music_prefix_info[j].prefix, len_prefix_text) == 0)
2431       {
2432         music_info[i].loop = music_prefix_info[j].is_loop_music;
2433
2434         break;
2435       }
2436     }
2437
2438     set_music_parameters(i, music->parameter);
2439   }
2440 }
2441
2442
2443 static void InitGameInfoFromArtworkInfo(void)
2444 {
2445   // special case: store initial value of custom artwork setting
2446   game.use_masked_elements_initial = game.use_masked_elements;
2447 }
2448
2449 static void ReinitializeGraphics(void)
2450 {
2451   print_timestamp_init("ReinitializeGraphics");
2452
2453   InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2454
2455   InitGraphicInfo();                    // graphic properties mapping
2456   print_timestamp_time("InitGraphicInfo");
2457   InitElementGraphicInfo();             // element game graphic mapping
2458   print_timestamp_time("InitElementGraphicInfo");
2459   InitElementSpecialGraphicInfo();      // element special graphic mapping
2460   print_timestamp_time("InitElementSpecialGraphicInfo");
2461
2462   InitElementSmallImages();             // scale elements to all needed sizes
2463   print_timestamp_time("InitElementSmallImages");
2464   InitScaledImages();                   // scale all other images, if needed
2465   print_timestamp_time("InitScaledImages");
2466   InitBitmapPointers();                 // set standard size bitmap pointers
2467   print_timestamp_time("InitBitmapPointers");
2468   InitFontGraphicInfo();                // initialize text drawing functions
2469   print_timestamp_time("InitFontGraphicInfo");
2470   InitGlobalAnimGraphicInfo();          // initialize global animation config
2471   print_timestamp_time("InitGlobalAnimGraphicInfo");
2472
2473   InitImageTextures();                  // create textures for certain images
2474   print_timestamp_time("InitImageTextures");
2475
2476   InitGraphicInfo_BD();                 // graphic mapping for BD engine
2477   print_timestamp_time("InitGraphicInfo_BD");
2478   InitGraphicInfo_EM();                 // graphic mapping for EM engine
2479   print_timestamp_time("InitGraphicInfo_EM");
2480
2481   InitGraphicCompatibilityInfo();
2482   print_timestamp_time("InitGraphicCompatibilityInfo");
2483
2484   InitGadgets();
2485   print_timestamp_time("InitGadgets");
2486   InitDoors();
2487   print_timestamp_time("InitDoors");
2488
2489   InitGameInfoFromArtworkInfo();
2490
2491   print_timestamp_done("ReinitializeGraphics");
2492 }
2493
2494 static void ReinitializeSounds(void)
2495 {
2496   InitSoundInfo();              // sound properties mapping
2497   InitElementSoundInfo();       // element game sound mapping
2498   InitGameModeSoundInfo();      // game mode sound mapping
2499   InitGlobalAnimSoundInfo();    // global animation sound settings
2500
2501   InitPlayLevelSound();         // internal game sound settings
2502 }
2503
2504 static void ReinitializeMusic(void)
2505 {
2506   InitMusicInfo();              // music properties mapping
2507   InitGameModeMusicInfo();      // game mode music mapping
2508   InitGlobalAnimMusicInfo();    // global animation music settings
2509 }
2510
2511 static int get_special_property_bit(int element, int property_bit_nr)
2512 {
2513   struct PropertyBitInfo
2514   {
2515     int element;
2516     int bit_nr;
2517   };
2518
2519   static struct PropertyBitInfo pb_can_move_into_acid[] =
2520   {
2521     // the player may be able fall into acid when gravity is activated
2522     { EL_PLAYER_1,              0       },
2523     { EL_PLAYER_2,              0       },
2524     { EL_PLAYER_3,              0       },
2525     { EL_PLAYER_4,              0       },
2526     { EL_SP_MURPHY,             0       },
2527     { EL_SOKOBAN_FIELD_PLAYER,  0       },
2528
2529     // all elements that can move may be able to also move into acid
2530     { EL_BUG,                   1       },
2531     { EL_BUG_LEFT,              1       },
2532     { EL_BUG_RIGHT,             1       },
2533     { EL_BUG_UP,                1       },
2534     { EL_BUG_DOWN,              1       },
2535     { EL_SPACESHIP,             2       },
2536     { EL_SPACESHIP_LEFT,        2       },
2537     { EL_SPACESHIP_RIGHT,       2       },
2538     { EL_SPACESHIP_UP,          2       },
2539     { EL_SPACESHIP_DOWN,        2       },
2540     { EL_BD_BUTTERFLY,          3       },
2541     { EL_BD_BUTTERFLY_LEFT,     3       },
2542     { EL_BD_BUTTERFLY_RIGHT,    3       },
2543     { EL_BD_BUTTERFLY_UP,       3       },
2544     { EL_BD_BUTTERFLY_DOWN,     3       },
2545     { EL_BD_FIREFLY,            4       },
2546     { EL_BD_FIREFLY_LEFT,       4       },
2547     { EL_BD_FIREFLY_RIGHT,      4       },
2548     { EL_BD_FIREFLY_UP,         4       },
2549     { EL_BD_FIREFLY_DOWN,       4       },
2550     { EL_YAMYAM,                5       },
2551     { EL_YAMYAM_LEFT,           5       },
2552     { EL_YAMYAM_RIGHT,          5       },
2553     { EL_YAMYAM_UP,             5       },
2554     { EL_YAMYAM_DOWN,           5       },
2555     { EL_DARK_YAMYAM,           6       },
2556     { EL_ROBOT,                 7       },
2557     { EL_PACMAN,                8       },
2558     { EL_PACMAN_LEFT,           8       },
2559     { EL_PACMAN_RIGHT,          8       },
2560     { EL_PACMAN_UP,             8       },
2561     { EL_PACMAN_DOWN,           8       },
2562     { EL_MOLE,                  9       },
2563     { EL_MOLE_LEFT,             9       },
2564     { EL_MOLE_RIGHT,            9       },
2565     { EL_MOLE_UP,               9       },
2566     { EL_MOLE_DOWN,             9       },
2567     { EL_PENGUIN,               10      },
2568     { EL_PIG,                   11      },
2569     { EL_DRAGON,                12      },
2570     { EL_SATELLITE,             13      },
2571     { EL_SP_SNIKSNAK,           14      },
2572     { EL_SP_ELECTRON,           15      },
2573     { EL_BALLOON,               16      },
2574     { EL_SPRING,                17      },
2575     { EL_SPRING_LEFT,           17      },
2576     { EL_SPRING_RIGHT,          17      },
2577     { EL_EMC_ANDROID,           18      },
2578
2579     { -1,                       -1      },
2580   };
2581
2582   static struct PropertyBitInfo pb_dont_collide_with[] =
2583   {
2584     { EL_SP_SNIKSNAK,           0       },
2585     { EL_SP_ELECTRON,           1       },
2586
2587     { -1,                       -1      },
2588   };
2589
2590   static struct
2591   {
2592     int bit_nr;
2593     struct PropertyBitInfo *pb_info;
2594   } pb_definition[] =
2595   {
2596     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
2597     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
2598
2599     { -1,                       NULL                    },
2600   };
2601
2602   struct PropertyBitInfo *pb_info = NULL;
2603   int i;
2604
2605   for (i = 0; pb_definition[i].bit_nr != -1; i++)
2606     if (pb_definition[i].bit_nr == property_bit_nr)
2607       pb_info = pb_definition[i].pb_info;
2608
2609   if (pb_info == NULL)
2610     return -1;
2611
2612   for (i = 0; pb_info[i].element != -1; i++)
2613     if (pb_info[i].element == element)
2614       return pb_info[i].bit_nr;
2615
2616   return -1;
2617 }
2618
2619 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2620                          boolean property_value)
2621 {
2622   int bit_nr = get_special_property_bit(element, property_bit_nr);
2623
2624   if (bit_nr > -1)
2625   {
2626     if (property_value)
2627       *bitfield |=  (1 << bit_nr);
2628     else
2629       *bitfield &= ~(1 << bit_nr);
2630   }
2631 }
2632
2633 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2634 {
2635   int bit_nr = get_special_property_bit(element, property_bit_nr);
2636
2637   if (bit_nr > -1)
2638     return ((*bitfield & (1 << bit_nr)) != 0);
2639
2640   return FALSE;
2641 }
2642
2643 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2644 {
2645   static int group_nr;
2646   static struct ElementGroupInfo *group;
2647   struct ElementGroupInfo *actual_group = element_info[group_element].group;
2648   int i;
2649
2650   if (actual_group == NULL)                     // not yet initialized
2651     return;
2652
2653   if (recursion_depth > NUM_GROUP_ELEMENTS)     // recursion too deep
2654   {
2655     Warn("recursion too deep when resolving group element %d",
2656           group_element - EL_GROUP_START + 1);
2657
2658     // replace element which caused too deep recursion by question mark
2659     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2660
2661     return;
2662   }
2663
2664   if (recursion_depth == 0)                     // initialization
2665   {
2666     group = actual_group;
2667     group_nr = GROUP_NR(group_element);
2668
2669     group->num_elements_resolved = 0;
2670     group->choice_pos = 0;
2671
2672     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2673       element_info[i].in_group[group_nr] = FALSE;
2674   }
2675
2676   for (i = 0; i < actual_group->num_elements; i++)
2677   {
2678     int element = actual_group->element[i];
2679
2680     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2681       break;
2682
2683     if (IS_GROUP_ELEMENT(element))
2684       ResolveGroupElementExt(element, recursion_depth + 1);
2685     else
2686     {
2687       group->element_resolved[group->num_elements_resolved++] = element;
2688       element_info[element].in_group[group_nr] = TRUE;
2689     }
2690   }
2691 }
2692
2693 void ResolveGroupElement(int group_element)
2694 {
2695   ResolveGroupElementExt(group_element, 0);
2696 }
2697
2698 void InitElementPropertiesStatic(void)
2699 {
2700   static boolean clipboard_elements_initialized = FALSE;
2701
2702   static int ep_diggable[] =
2703   {
2704     EL_SAND,
2705     EL_SP_BASE,
2706     EL_SP_BUGGY_BASE,
2707     EL_SP_BUGGY_BASE_ACTIVATING,
2708     EL_TRAP,
2709     EL_INVISIBLE_SAND,
2710     EL_INVISIBLE_SAND_ACTIVE,
2711     EL_EMC_GRASS,
2712
2713     // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2714     // (if amoeba can grow into anything diggable, maybe keep these out)
2715 #if 0
2716     EL_LANDMINE,
2717     EL_DC_LANDMINE,
2718     EL_TRAP_ACTIVE,
2719     EL_SP_BUGGY_BASE_ACTIVE,
2720     EL_EMC_PLANT,
2721 #endif
2722
2723     -1
2724   };
2725
2726   static int ep_collectible_only[] =
2727   {
2728     EL_BD_DIAMOND,
2729     EL_EMERALD,
2730     EL_DIAMOND,
2731     EL_EMERALD_YELLOW,
2732     EL_EMERALD_RED,
2733     EL_EMERALD_PURPLE,
2734     EL_KEY_1,
2735     EL_KEY_2,
2736     EL_KEY_3,
2737     EL_KEY_4,
2738     EL_EM_KEY_1,
2739     EL_EM_KEY_2,
2740     EL_EM_KEY_3,
2741     EL_EM_KEY_4,
2742     EL_EMC_KEY_5,
2743     EL_EMC_KEY_6,
2744     EL_EMC_KEY_7,
2745     EL_EMC_KEY_8,
2746     EL_DYNAMITE,
2747     EL_EM_DYNAMITE,
2748     EL_DYNABOMB_INCREASE_NUMBER,
2749     EL_DYNABOMB_INCREASE_SIZE,
2750     EL_DYNABOMB_INCREASE_POWER,
2751     EL_SP_INFOTRON,
2752     EL_SP_DISK_RED,
2753     EL_PEARL,
2754     EL_CRYSTAL,
2755     EL_DC_KEY_WHITE,
2756     EL_SHIELD_NORMAL,
2757     EL_SHIELD_DEADLY,
2758     EL_EXTRA_TIME,
2759     EL_ENVELOPE_1,
2760     EL_ENVELOPE_2,
2761     EL_ENVELOPE_3,
2762     EL_ENVELOPE_4,
2763     EL_SPEED_PILL,
2764     EL_EMC_LENSES,
2765     EL_EMC_MAGNIFIER,
2766
2767 #if 0
2768     // !!! handle separately !!!
2769     EL_DC_LANDMINE,     // deadly when running into, but can be snapped
2770 #endif
2771
2772     -1
2773   };
2774
2775   static int ep_dont_run_into[] =
2776   {
2777     // same elements as in 'ep_dont_touch'
2778     EL_BUG,
2779     EL_SPACESHIP,
2780     EL_BD_BUTTERFLY,
2781     EL_BD_FIREFLY,
2782
2783     // same elements as in 'ep_dont_collide_with'
2784     EL_YAMYAM,
2785     EL_DARK_YAMYAM,
2786     EL_ROBOT,
2787     EL_PACMAN,
2788     EL_SP_SNIKSNAK,
2789     EL_SP_ELECTRON,
2790
2791     // new elements
2792     EL_AMOEBA_DROP,
2793     EL_ACID,
2794
2795     // !!! maybe this should better be handled by 'ep_diggable' !!!
2796 #if 1
2797     EL_LANDMINE,
2798     EL_DC_LANDMINE,
2799     EL_TRAP_ACTIVE,
2800     EL_SP_BUGGY_BASE_ACTIVE,
2801     EL_EMC_PLANT,
2802 #endif
2803
2804     -1
2805   };
2806
2807   static int ep_dont_collide_with[] =
2808   {
2809     // same elements as in 'ep_dont_touch'
2810     EL_BUG,
2811     EL_SPACESHIP,
2812     EL_BD_BUTTERFLY,
2813     EL_BD_FIREFLY,
2814
2815     // new elements
2816     EL_YAMYAM,
2817     EL_DARK_YAMYAM,
2818     EL_ROBOT,
2819     EL_PACMAN,
2820     EL_SP_SNIKSNAK,
2821     EL_SP_ELECTRON,
2822
2823     -1
2824   };
2825
2826   static int ep_dont_touch[] =
2827   {
2828     EL_BUG,
2829     EL_SPACESHIP,
2830     EL_BD_BUTTERFLY,
2831     EL_BD_FIREFLY,
2832
2833     -1
2834   };
2835
2836   static int ep_indestructible[] =
2837   {
2838     EL_STEELWALL,
2839     EL_ACID,
2840     EL_ACID_POOL_TOPLEFT,
2841     EL_ACID_POOL_TOPRIGHT,
2842     EL_ACID_POOL_BOTTOMLEFT,
2843     EL_ACID_POOL_BOTTOM,
2844     EL_ACID_POOL_BOTTOMRIGHT,
2845     EL_SP_HARDWARE_GRAY,
2846     EL_SP_HARDWARE_GREEN,
2847     EL_SP_HARDWARE_BLUE,
2848     EL_SP_HARDWARE_RED,
2849     EL_SP_HARDWARE_YELLOW,
2850     EL_SP_HARDWARE_BASE_1,
2851     EL_SP_HARDWARE_BASE_2,
2852     EL_SP_HARDWARE_BASE_3,
2853     EL_SP_HARDWARE_BASE_4,
2854     EL_SP_HARDWARE_BASE_5,
2855     EL_SP_HARDWARE_BASE_6,
2856     EL_INVISIBLE_STEELWALL,
2857     EL_INVISIBLE_STEELWALL_ACTIVE,
2858     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2859     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2860     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2861     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2862     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2863     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2864     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2865     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2866     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2867     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2868     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2869     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2870     EL_LIGHT_SWITCH,
2871     EL_LIGHT_SWITCH_ACTIVE,
2872     EL_SIGN_EXCLAMATION,
2873     EL_SIGN_RADIOACTIVITY,
2874     EL_SIGN_STOP,
2875     EL_SIGN_WHEELCHAIR,
2876     EL_SIGN_PARKING,
2877     EL_SIGN_NO_ENTRY,
2878     EL_SIGN_UNUSED_1,
2879     EL_SIGN_GIVE_WAY,
2880     EL_SIGN_ENTRY_FORBIDDEN,
2881     EL_SIGN_EMERGENCY_EXIT,
2882     EL_SIGN_YIN_YANG,
2883     EL_SIGN_UNUSED_2,
2884     EL_SIGN_SPERMS,
2885     EL_SIGN_BULLET,
2886     EL_SIGN_HEART,
2887     EL_SIGN_CROSS,
2888     EL_SIGN_FRANKIE,
2889     EL_STEEL_EXIT_CLOSED,
2890     EL_STEEL_EXIT_OPEN,
2891     EL_STEEL_EXIT_OPENING,
2892     EL_STEEL_EXIT_CLOSING,
2893     EL_EM_STEEL_EXIT_CLOSED,
2894     EL_EM_STEEL_EXIT_OPEN,
2895     EL_EM_STEEL_EXIT_OPENING,
2896     EL_EM_STEEL_EXIT_CLOSING,
2897     EL_DC_STEELWALL_1_LEFT,
2898     EL_DC_STEELWALL_1_RIGHT,
2899     EL_DC_STEELWALL_1_TOP,
2900     EL_DC_STEELWALL_1_BOTTOM,
2901     EL_DC_STEELWALL_1_HORIZONTAL,
2902     EL_DC_STEELWALL_1_VERTICAL,
2903     EL_DC_STEELWALL_1_TOPLEFT,
2904     EL_DC_STEELWALL_1_TOPRIGHT,
2905     EL_DC_STEELWALL_1_BOTTOMLEFT,
2906     EL_DC_STEELWALL_1_BOTTOMRIGHT,
2907     EL_DC_STEELWALL_1_TOPLEFT_2,
2908     EL_DC_STEELWALL_1_TOPRIGHT_2,
2909     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2910     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2911     EL_DC_STEELWALL_2_LEFT,
2912     EL_DC_STEELWALL_2_RIGHT,
2913     EL_DC_STEELWALL_2_TOP,
2914     EL_DC_STEELWALL_2_BOTTOM,
2915     EL_DC_STEELWALL_2_HORIZONTAL,
2916     EL_DC_STEELWALL_2_VERTICAL,
2917     EL_DC_STEELWALL_2_MIDDLE,
2918     EL_DC_STEELWALL_2_SINGLE,
2919     EL_STEELWALL_SLIPPERY,
2920     EL_EMC_STEELWALL_1,
2921     EL_EMC_STEELWALL_2,
2922     EL_EMC_STEELWALL_3,
2923     EL_EMC_STEELWALL_4,
2924     EL_CRYSTAL,
2925     EL_GATE_1,
2926     EL_GATE_2,
2927     EL_GATE_3,
2928     EL_GATE_4,
2929     EL_GATE_1_GRAY,
2930     EL_GATE_2_GRAY,
2931     EL_GATE_3_GRAY,
2932     EL_GATE_4_GRAY,
2933     EL_GATE_1_GRAY_ACTIVE,
2934     EL_GATE_2_GRAY_ACTIVE,
2935     EL_GATE_3_GRAY_ACTIVE,
2936     EL_GATE_4_GRAY_ACTIVE,
2937     EL_EM_GATE_1,
2938     EL_EM_GATE_2,
2939     EL_EM_GATE_3,
2940     EL_EM_GATE_4,
2941     EL_EM_GATE_1_GRAY,
2942     EL_EM_GATE_2_GRAY,
2943     EL_EM_GATE_3_GRAY,
2944     EL_EM_GATE_4_GRAY,
2945     EL_EM_GATE_1_GRAY_ACTIVE,
2946     EL_EM_GATE_2_GRAY_ACTIVE,
2947     EL_EM_GATE_3_GRAY_ACTIVE,
2948     EL_EM_GATE_4_GRAY_ACTIVE,
2949     EL_EMC_GATE_5,
2950     EL_EMC_GATE_6,
2951     EL_EMC_GATE_7,
2952     EL_EMC_GATE_8,
2953     EL_EMC_GATE_5_GRAY,
2954     EL_EMC_GATE_6_GRAY,
2955     EL_EMC_GATE_7_GRAY,
2956     EL_EMC_GATE_8_GRAY,
2957     EL_EMC_GATE_5_GRAY_ACTIVE,
2958     EL_EMC_GATE_6_GRAY_ACTIVE,
2959     EL_EMC_GATE_7_GRAY_ACTIVE,
2960     EL_EMC_GATE_8_GRAY_ACTIVE,
2961     EL_DC_GATE_WHITE,
2962     EL_DC_GATE_WHITE_GRAY,
2963     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2964     EL_DC_GATE_FAKE_GRAY,
2965     EL_SWITCHGATE_OPEN,
2966     EL_SWITCHGATE_OPENING,
2967     EL_SWITCHGATE_CLOSED,
2968     EL_SWITCHGATE_CLOSING,
2969     EL_DC_SWITCHGATE_SWITCH_UP,
2970     EL_DC_SWITCHGATE_SWITCH_DOWN,
2971     EL_TIMEGATE_OPEN,
2972     EL_TIMEGATE_OPENING,
2973     EL_TIMEGATE_CLOSED,
2974     EL_TIMEGATE_CLOSING,
2975     EL_DC_TIMEGATE_SWITCH,
2976     EL_DC_TIMEGATE_SWITCH_ACTIVE,
2977     EL_TUBE_ANY,
2978     EL_TUBE_VERTICAL,
2979     EL_TUBE_HORIZONTAL,
2980     EL_TUBE_VERTICAL_LEFT,
2981     EL_TUBE_VERTICAL_RIGHT,
2982     EL_TUBE_HORIZONTAL_UP,
2983     EL_TUBE_HORIZONTAL_DOWN,
2984     EL_TUBE_LEFT_UP,
2985     EL_TUBE_LEFT_DOWN,
2986     EL_TUBE_RIGHT_UP,
2987     EL_TUBE_RIGHT_DOWN,
2988     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2989     EL_EXPANDABLE_STEELWALL_VERTICAL,
2990     EL_EXPANDABLE_STEELWALL_ANY,
2991
2992     -1
2993   };
2994
2995   static int ep_slippery[] =
2996   {
2997     EL_WALL_SLIPPERY,
2998     EL_BD_WALL,
2999     EL_ROCK,
3000     EL_BD_ROCK,
3001     EL_EMERALD,
3002     EL_BD_DIAMOND,
3003     EL_EMERALD_YELLOW,
3004     EL_EMERALD_RED,
3005     EL_EMERALD_PURPLE,
3006     EL_DIAMOND,
3007     EL_BOMB,
3008     EL_NUT,
3009     EL_ROBOT_WHEEL_ACTIVE,
3010     EL_ROBOT_WHEEL,
3011     EL_TIME_ORB_FULL,
3012     EL_TIME_ORB_EMPTY,
3013     EL_LAMP_ACTIVE,
3014     EL_LAMP,
3015     EL_ACID_POOL_TOPLEFT,
3016     EL_ACID_POOL_TOPRIGHT,
3017     EL_SATELLITE,
3018     EL_SP_ZONK,
3019     EL_SP_INFOTRON,
3020     EL_SP_CHIP_SINGLE,
3021     EL_SP_CHIP_LEFT,
3022     EL_SP_CHIP_RIGHT,
3023     EL_SP_CHIP_TOP,
3024     EL_SP_CHIP_BOTTOM,
3025     EL_SPEED_PILL,
3026     EL_STEELWALL_SLIPPERY,
3027     EL_PEARL,
3028     EL_CRYSTAL,
3029     EL_EMC_WALL_SLIPPERY_1,
3030     EL_EMC_WALL_SLIPPERY_2,
3031     EL_EMC_WALL_SLIPPERY_3,
3032     EL_EMC_WALL_SLIPPERY_4,
3033     EL_EMC_MAGIC_BALL,
3034     EL_EMC_MAGIC_BALL_ACTIVE,
3035
3036     -1
3037   };
3038
3039   static int ep_can_change[] =
3040   {
3041     -1
3042   };
3043
3044   static int ep_can_move[] =
3045   {
3046     // same elements as in 'pb_can_move_into_acid'
3047     EL_BUG,
3048     EL_SPACESHIP,
3049     EL_BD_BUTTERFLY,
3050     EL_BD_FIREFLY,
3051     EL_YAMYAM,
3052     EL_DARK_YAMYAM,
3053     EL_ROBOT,
3054     EL_PACMAN,
3055     EL_MOLE,
3056     EL_PENGUIN,
3057     EL_PIG,
3058     EL_DRAGON,
3059     EL_SATELLITE,
3060     EL_SP_SNIKSNAK,
3061     EL_SP_ELECTRON,
3062     EL_BALLOON,
3063     EL_SPRING,
3064     EL_EMC_ANDROID,
3065
3066     -1
3067   };
3068
3069   static int ep_can_fall[] =
3070   {
3071     EL_ROCK,
3072     EL_BD_ROCK,
3073     EL_EMERALD,
3074     EL_BD_DIAMOND,
3075     EL_EMERALD_YELLOW,
3076     EL_EMERALD_RED,
3077     EL_EMERALD_PURPLE,
3078     EL_DIAMOND,
3079     EL_BOMB,
3080     EL_NUT,
3081     EL_AMOEBA_DROP,
3082     EL_AMOEBA_DROPPING,
3083     EL_QUICKSAND_FULL,
3084     EL_QUICKSAND_FAST_FULL,
3085     EL_MAGIC_WALL_FULL,
3086     EL_BD_MAGIC_WALL_FULL,
3087     EL_DC_MAGIC_WALL_FULL,
3088     EL_TIME_ORB_FULL,
3089     EL_TIME_ORB_EMPTY,
3090     EL_SP_ZONK,
3091     EL_SP_INFOTRON,
3092     EL_SP_DISK_ORANGE,
3093     EL_PEARL,
3094     EL_CRYSTAL,
3095     EL_SPRING,
3096     EL_DX_SUPABOMB,
3097
3098     -1
3099   };
3100
3101   static int ep_can_smash_player[] =
3102   {
3103     EL_ROCK,
3104     EL_BD_ROCK,
3105     EL_EMERALD,
3106     EL_BD_DIAMOND,
3107     EL_EMERALD_YELLOW,
3108     EL_EMERALD_RED,
3109     EL_EMERALD_PURPLE,
3110     EL_DIAMOND,
3111     EL_BOMB,
3112     EL_NUT,
3113     EL_AMOEBA_DROP,
3114     EL_TIME_ORB_FULL,
3115     EL_TIME_ORB_EMPTY,
3116     EL_SP_ZONK,
3117     EL_SP_INFOTRON,
3118     EL_SP_DISK_ORANGE,
3119     EL_PEARL,
3120     EL_CRYSTAL,
3121     EL_SPRING,
3122     EL_DX_SUPABOMB,
3123
3124     -1
3125   };
3126
3127   static int ep_can_smash_enemies[] =
3128   {
3129     EL_ROCK,
3130     EL_BD_ROCK,
3131     EL_SP_ZONK,
3132
3133     -1
3134   };
3135
3136   static int ep_can_smash_everything[] =
3137   {
3138     EL_ROCK,
3139     EL_BD_ROCK,
3140     EL_SP_ZONK,
3141
3142     -1
3143   };
3144
3145   static int ep_explodes_by_fire[] =
3146   {
3147     // same elements as in 'ep_explodes_impact'
3148     EL_BOMB,
3149     EL_SP_DISK_ORANGE,
3150     EL_DX_SUPABOMB,
3151
3152     // same elements as in 'ep_explodes_smashed'
3153     EL_SATELLITE,
3154     EL_PIG,
3155     EL_DRAGON,
3156     EL_MOLE,
3157
3158     // new elements
3159     EL_DYNAMITE,
3160     EL_DYNAMITE_ACTIVE,
3161     EL_EM_DYNAMITE,
3162     EL_EM_DYNAMITE_ACTIVE,
3163     EL_DYNABOMB_PLAYER_1_ACTIVE,
3164     EL_DYNABOMB_PLAYER_2_ACTIVE,
3165     EL_DYNABOMB_PLAYER_3_ACTIVE,
3166     EL_DYNABOMB_PLAYER_4_ACTIVE,
3167     EL_DYNABOMB_INCREASE_NUMBER,
3168     EL_DYNABOMB_INCREASE_SIZE,
3169     EL_DYNABOMB_INCREASE_POWER,
3170     EL_SP_DISK_RED_ACTIVE,
3171     EL_BUG,
3172     EL_PENGUIN,
3173     EL_SP_DISK_RED,
3174     EL_SP_DISK_YELLOW,
3175     EL_SP_SNIKSNAK,
3176     EL_SP_ELECTRON,
3177 #if 0
3178     EL_BLACK_ORB,
3179 #endif
3180
3181     -1
3182   };
3183
3184   static int ep_explodes_smashed[] =
3185   {
3186     // same elements as in 'ep_explodes_impact'
3187     EL_BOMB,
3188     EL_SP_DISK_ORANGE,
3189     EL_DX_SUPABOMB,
3190
3191     // new elements
3192     EL_SATELLITE,
3193     EL_PIG,
3194     EL_DRAGON,
3195     EL_MOLE,
3196
3197     -1
3198   };
3199
3200   static int ep_explodes_impact[] =
3201   {
3202     EL_BOMB,
3203     EL_SP_DISK_ORANGE,
3204     EL_DX_SUPABOMB,
3205
3206     -1
3207   };
3208
3209   static int ep_walkable_over[] =
3210   {
3211     EL_EMPTY_SPACE,
3212     EL_EMPTY_SPACE_1,
3213     EL_EMPTY_SPACE_2,
3214     EL_EMPTY_SPACE_3,
3215     EL_EMPTY_SPACE_4,
3216     EL_EMPTY_SPACE_5,
3217     EL_EMPTY_SPACE_6,
3218     EL_EMPTY_SPACE_7,
3219     EL_EMPTY_SPACE_8,
3220     EL_EMPTY_SPACE_9,
3221     EL_EMPTY_SPACE_10,
3222     EL_EMPTY_SPACE_11,
3223     EL_EMPTY_SPACE_12,
3224     EL_EMPTY_SPACE_13,
3225     EL_EMPTY_SPACE_14,
3226     EL_EMPTY_SPACE_15,
3227     EL_EMPTY_SPACE_16,
3228     EL_SP_EMPTY_SPACE,
3229     EL_SOKOBAN_FIELD_EMPTY,
3230     EL_EXIT_OPEN,
3231     EL_EM_EXIT_OPEN,
3232     EL_EM_EXIT_OPENING,
3233     EL_SP_EXIT_OPEN,
3234     EL_SP_EXIT_OPENING,
3235     EL_STEEL_EXIT_OPEN,
3236     EL_EM_STEEL_EXIT_OPEN,
3237     EL_EM_STEEL_EXIT_OPENING,
3238     EL_GATE_1,
3239     EL_GATE_2,
3240     EL_GATE_3,
3241     EL_GATE_4,
3242     EL_GATE_1_GRAY,
3243     EL_GATE_2_GRAY,
3244     EL_GATE_3_GRAY,
3245     EL_GATE_4_GRAY,
3246     EL_GATE_1_GRAY_ACTIVE,
3247     EL_GATE_2_GRAY_ACTIVE,
3248     EL_GATE_3_GRAY_ACTIVE,
3249     EL_GATE_4_GRAY_ACTIVE,
3250     EL_PENGUIN,
3251     EL_PIG,
3252     EL_DRAGON,
3253
3254     -1
3255   };
3256
3257   static int ep_walkable_inside[] =
3258   {
3259     EL_TUBE_ANY,
3260     EL_TUBE_VERTICAL,
3261     EL_TUBE_HORIZONTAL,
3262     EL_TUBE_VERTICAL_LEFT,
3263     EL_TUBE_VERTICAL_RIGHT,
3264     EL_TUBE_HORIZONTAL_UP,
3265     EL_TUBE_HORIZONTAL_DOWN,
3266     EL_TUBE_LEFT_UP,
3267     EL_TUBE_LEFT_DOWN,
3268     EL_TUBE_RIGHT_UP,
3269     EL_TUBE_RIGHT_DOWN,
3270
3271     -1
3272   };
3273
3274   static int ep_walkable_under[] =
3275   {
3276     -1
3277   };
3278
3279   static int ep_passable_over[] =
3280   {
3281     EL_EM_GATE_1,
3282     EL_EM_GATE_2,
3283     EL_EM_GATE_3,
3284     EL_EM_GATE_4,
3285     EL_EM_GATE_1_GRAY,
3286     EL_EM_GATE_2_GRAY,
3287     EL_EM_GATE_3_GRAY,
3288     EL_EM_GATE_4_GRAY,
3289     EL_EM_GATE_1_GRAY_ACTIVE,
3290     EL_EM_GATE_2_GRAY_ACTIVE,
3291     EL_EM_GATE_3_GRAY_ACTIVE,
3292     EL_EM_GATE_4_GRAY_ACTIVE,
3293     EL_EMC_GATE_5,
3294     EL_EMC_GATE_6,
3295     EL_EMC_GATE_7,
3296     EL_EMC_GATE_8,
3297     EL_EMC_GATE_5_GRAY,
3298     EL_EMC_GATE_6_GRAY,
3299     EL_EMC_GATE_7_GRAY,
3300     EL_EMC_GATE_8_GRAY,
3301     EL_EMC_GATE_5_GRAY_ACTIVE,
3302     EL_EMC_GATE_6_GRAY_ACTIVE,
3303     EL_EMC_GATE_7_GRAY_ACTIVE,
3304     EL_EMC_GATE_8_GRAY_ACTIVE,
3305     EL_DC_GATE_WHITE,
3306     EL_DC_GATE_WHITE_GRAY,
3307     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3308     EL_SWITCHGATE_OPEN,
3309     EL_TIMEGATE_OPEN,
3310
3311     -1
3312   };
3313
3314   static int ep_passable_inside[] =
3315   {
3316     EL_SP_PORT_LEFT,
3317     EL_SP_PORT_RIGHT,
3318     EL_SP_PORT_UP,
3319     EL_SP_PORT_DOWN,
3320     EL_SP_PORT_HORIZONTAL,
3321     EL_SP_PORT_VERTICAL,
3322     EL_SP_PORT_ANY,
3323     EL_SP_GRAVITY_PORT_LEFT,
3324     EL_SP_GRAVITY_PORT_RIGHT,
3325     EL_SP_GRAVITY_PORT_UP,
3326     EL_SP_GRAVITY_PORT_DOWN,
3327     EL_SP_GRAVITY_ON_PORT_LEFT,
3328     EL_SP_GRAVITY_ON_PORT_RIGHT,
3329     EL_SP_GRAVITY_ON_PORT_UP,
3330     EL_SP_GRAVITY_ON_PORT_DOWN,
3331     EL_SP_GRAVITY_OFF_PORT_LEFT,
3332     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3333     EL_SP_GRAVITY_OFF_PORT_UP,
3334     EL_SP_GRAVITY_OFF_PORT_DOWN,
3335
3336     -1
3337   };
3338
3339   static int ep_passable_under[] =
3340   {
3341     -1
3342   };
3343
3344   static int ep_droppable[] =
3345   {
3346     -1
3347   };
3348
3349   static int ep_explodes_1x1_old[] =
3350   {
3351     -1
3352   };
3353
3354   static int ep_pushable[] =
3355   {
3356     EL_ROCK,
3357     EL_BOMB,
3358     EL_DX_SUPABOMB,
3359     EL_NUT,
3360     EL_TIME_ORB_EMPTY,
3361     EL_SP_ZONK,
3362     EL_SP_DISK_ORANGE,
3363     EL_SPRING,
3364     EL_BD_ROCK,
3365     EL_SOKOBAN_OBJECT,
3366     EL_SOKOBAN_FIELD_FULL,
3367     EL_SATELLITE,
3368     EL_SP_DISK_YELLOW,
3369     EL_BALLOON,
3370     EL_EMC_ANDROID,
3371
3372     -1
3373   };
3374
3375   static int ep_explodes_cross_old[] =
3376   {
3377     -1
3378   };
3379
3380   static int ep_protected[] =
3381   {
3382     // same elements as in 'ep_walkable_inside'
3383     EL_TUBE_ANY,
3384     EL_TUBE_VERTICAL,
3385     EL_TUBE_HORIZONTAL,
3386     EL_TUBE_VERTICAL_LEFT,
3387     EL_TUBE_VERTICAL_RIGHT,
3388     EL_TUBE_HORIZONTAL_UP,
3389     EL_TUBE_HORIZONTAL_DOWN,
3390     EL_TUBE_LEFT_UP,
3391     EL_TUBE_LEFT_DOWN,
3392     EL_TUBE_RIGHT_UP,
3393     EL_TUBE_RIGHT_DOWN,
3394
3395     // same elements as in 'ep_passable_over'
3396     EL_EM_GATE_1,
3397     EL_EM_GATE_2,
3398     EL_EM_GATE_3,
3399     EL_EM_GATE_4,
3400     EL_EM_GATE_1_GRAY,
3401     EL_EM_GATE_2_GRAY,
3402     EL_EM_GATE_3_GRAY,
3403     EL_EM_GATE_4_GRAY,
3404     EL_EM_GATE_1_GRAY_ACTIVE,
3405     EL_EM_GATE_2_GRAY_ACTIVE,
3406     EL_EM_GATE_3_GRAY_ACTIVE,
3407     EL_EM_GATE_4_GRAY_ACTIVE,
3408     EL_EMC_GATE_5,
3409     EL_EMC_GATE_6,
3410     EL_EMC_GATE_7,
3411     EL_EMC_GATE_8,
3412     EL_EMC_GATE_5_GRAY,
3413     EL_EMC_GATE_6_GRAY,
3414     EL_EMC_GATE_7_GRAY,
3415     EL_EMC_GATE_8_GRAY,
3416     EL_EMC_GATE_5_GRAY_ACTIVE,
3417     EL_EMC_GATE_6_GRAY_ACTIVE,
3418     EL_EMC_GATE_7_GRAY_ACTIVE,
3419     EL_EMC_GATE_8_GRAY_ACTIVE,
3420     EL_DC_GATE_WHITE,
3421     EL_DC_GATE_WHITE_GRAY,
3422     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3423     EL_SWITCHGATE_OPEN,
3424     EL_TIMEGATE_OPEN,
3425
3426     // same elements as in 'ep_passable_inside'
3427     EL_SP_PORT_LEFT,
3428     EL_SP_PORT_RIGHT,
3429     EL_SP_PORT_UP,
3430     EL_SP_PORT_DOWN,
3431     EL_SP_PORT_HORIZONTAL,
3432     EL_SP_PORT_VERTICAL,
3433     EL_SP_PORT_ANY,
3434     EL_SP_GRAVITY_PORT_LEFT,
3435     EL_SP_GRAVITY_PORT_RIGHT,
3436     EL_SP_GRAVITY_PORT_UP,
3437     EL_SP_GRAVITY_PORT_DOWN,
3438     EL_SP_GRAVITY_ON_PORT_LEFT,
3439     EL_SP_GRAVITY_ON_PORT_RIGHT,
3440     EL_SP_GRAVITY_ON_PORT_UP,
3441     EL_SP_GRAVITY_ON_PORT_DOWN,
3442     EL_SP_GRAVITY_OFF_PORT_LEFT,
3443     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3444     EL_SP_GRAVITY_OFF_PORT_UP,
3445     EL_SP_GRAVITY_OFF_PORT_DOWN,
3446
3447     -1
3448   };
3449
3450   static int ep_throwable[] =
3451   {
3452     -1
3453   };
3454
3455   static int ep_can_explode[] =
3456   {
3457     // same elements as in 'ep_explodes_impact'
3458     EL_BOMB,
3459     EL_SP_DISK_ORANGE,
3460     EL_DX_SUPABOMB,
3461
3462     // same elements as in 'ep_explodes_smashed'
3463     EL_SATELLITE,
3464     EL_PIG,
3465     EL_DRAGON,
3466     EL_MOLE,
3467
3468     // elements that can explode by explosion or by dragonfire
3469     EL_DYNAMITE,
3470     EL_DYNAMITE_ACTIVE,
3471     EL_EM_DYNAMITE,
3472     EL_EM_DYNAMITE_ACTIVE,
3473     EL_DYNABOMB_PLAYER_1_ACTIVE,
3474     EL_DYNABOMB_PLAYER_2_ACTIVE,
3475     EL_DYNABOMB_PLAYER_3_ACTIVE,
3476     EL_DYNABOMB_PLAYER_4_ACTIVE,
3477     EL_DYNABOMB_INCREASE_NUMBER,
3478     EL_DYNABOMB_INCREASE_SIZE,
3479     EL_DYNABOMB_INCREASE_POWER,
3480     EL_SP_DISK_RED_ACTIVE,
3481     EL_BUG,
3482     EL_PENGUIN,
3483     EL_SP_DISK_RED,
3484     EL_SP_DISK_YELLOW,
3485     EL_SP_SNIKSNAK,
3486     EL_SP_ELECTRON,
3487
3488     // elements that can explode only by explosion
3489     EL_BLACK_ORB,
3490
3491     -1
3492   };
3493
3494   static int ep_gravity_reachable[] =
3495   {
3496     EL_SAND,
3497     EL_SP_BASE,
3498     EL_TRAP,
3499     EL_INVISIBLE_SAND,
3500     EL_INVISIBLE_SAND_ACTIVE,
3501     EL_SP_PORT_LEFT,
3502     EL_SP_PORT_RIGHT,
3503     EL_SP_PORT_UP,
3504     EL_SP_PORT_DOWN,
3505     EL_SP_PORT_HORIZONTAL,
3506     EL_SP_PORT_VERTICAL,
3507     EL_SP_PORT_ANY,
3508     EL_SP_GRAVITY_PORT_LEFT,
3509     EL_SP_GRAVITY_PORT_RIGHT,
3510     EL_SP_GRAVITY_PORT_UP,
3511     EL_SP_GRAVITY_PORT_DOWN,
3512     EL_SP_GRAVITY_ON_PORT_LEFT,
3513     EL_SP_GRAVITY_ON_PORT_RIGHT,
3514     EL_SP_GRAVITY_ON_PORT_UP,
3515     EL_SP_GRAVITY_ON_PORT_DOWN,
3516     EL_SP_GRAVITY_OFF_PORT_LEFT,
3517     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3518     EL_SP_GRAVITY_OFF_PORT_UP,
3519     EL_SP_GRAVITY_OFF_PORT_DOWN,
3520     EL_EMC_GRASS,
3521
3522     -1
3523   };
3524
3525   static int ep_empty_space[] =
3526   {
3527     EL_EMPTY_SPACE,
3528     EL_EMPTY_SPACE_1,
3529     EL_EMPTY_SPACE_2,
3530     EL_EMPTY_SPACE_3,
3531     EL_EMPTY_SPACE_4,
3532     EL_EMPTY_SPACE_5,
3533     EL_EMPTY_SPACE_6,
3534     EL_EMPTY_SPACE_7,
3535     EL_EMPTY_SPACE_8,
3536     EL_EMPTY_SPACE_9,
3537     EL_EMPTY_SPACE_10,
3538     EL_EMPTY_SPACE_11,
3539     EL_EMPTY_SPACE_12,
3540     EL_EMPTY_SPACE_13,
3541     EL_EMPTY_SPACE_14,
3542     EL_EMPTY_SPACE_15,
3543     EL_EMPTY_SPACE_16,
3544
3545     -1
3546   };
3547
3548   static int ep_player[] =
3549   {
3550     EL_PLAYER_1,
3551     EL_PLAYER_2,
3552     EL_PLAYER_3,
3553     EL_PLAYER_4,
3554     EL_SP_MURPHY,
3555     EL_SOKOBAN_FIELD_PLAYER,
3556     EL_TRIGGER_PLAYER,
3557
3558     -1
3559   };
3560
3561   static int ep_can_pass_magic_wall[] =
3562   {
3563     EL_ROCK,
3564     EL_BD_ROCK,
3565     EL_EMERALD,
3566     EL_BD_DIAMOND,
3567     EL_EMERALD_YELLOW,
3568     EL_EMERALD_RED,
3569     EL_EMERALD_PURPLE,
3570     EL_DIAMOND,
3571
3572     -1
3573   };
3574
3575   static int ep_can_pass_dc_magic_wall[] =
3576   {
3577     EL_ROCK,
3578     EL_BD_ROCK,
3579     EL_EMERALD,
3580     EL_BD_DIAMOND,
3581     EL_EMERALD_YELLOW,
3582     EL_EMERALD_RED,
3583     EL_EMERALD_PURPLE,
3584     EL_DIAMOND,
3585     EL_PEARL,
3586     EL_CRYSTAL,
3587
3588     -1
3589   };
3590
3591   static int ep_switchable[] =
3592   {
3593     EL_ROBOT_WHEEL,
3594     EL_SP_TERMINAL,
3595     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3596     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3597     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3598     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3599     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3600     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3601     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3602     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3603     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3604     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3605     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3606     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3607     EL_SWITCHGATE_SWITCH_UP,
3608     EL_SWITCHGATE_SWITCH_DOWN,
3609     EL_DC_SWITCHGATE_SWITCH_UP,
3610     EL_DC_SWITCHGATE_SWITCH_DOWN,
3611     EL_LIGHT_SWITCH,
3612     EL_LIGHT_SWITCH_ACTIVE,
3613     EL_TIMEGATE_SWITCH,
3614     EL_DC_TIMEGATE_SWITCH,
3615     EL_BALLOON_SWITCH_LEFT,
3616     EL_BALLOON_SWITCH_RIGHT,
3617     EL_BALLOON_SWITCH_UP,
3618     EL_BALLOON_SWITCH_DOWN,
3619     EL_BALLOON_SWITCH_ANY,
3620     EL_BALLOON_SWITCH_NONE,
3621     EL_LAMP,
3622     EL_TIME_ORB_FULL,
3623     EL_EMC_MAGIC_BALL_SWITCH,
3624     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3625
3626     -1
3627   };
3628
3629   static int ep_bd_element[] =
3630   {
3631     EL_EMPTY,
3632     EL_SAND,
3633     EL_WALL_SLIPPERY,
3634     EL_BD_WALL,
3635     EL_ROCK,
3636     EL_BD_ROCK,
3637     EL_BD_DIAMOND,
3638     EL_BD_MAGIC_WALL,
3639     EL_EXIT_CLOSED,
3640     EL_EXIT_OPEN,
3641     EL_STEELWALL,
3642     EL_PLAYER_1,
3643     EL_PLAYER_2,
3644     EL_PLAYER_3,
3645     EL_PLAYER_4,
3646     EL_BD_FIREFLY,
3647     EL_BD_FIREFLY_LEFT,
3648     EL_BD_FIREFLY_DOWN,
3649     EL_BD_FIREFLY_RIGHT,
3650     EL_BD_FIREFLY_UP,
3651     EL_BD_BUTTERFLY,
3652     EL_BD_BUTTERFLY_DOWN,
3653     EL_BD_BUTTERFLY_LEFT,
3654     EL_BD_BUTTERFLY_UP,
3655     EL_BD_BUTTERFLY_RIGHT,
3656     EL_BD_AMOEBA,
3657     EL_CHAR_QUESTION,
3658     EL_UNKNOWN,
3659
3660     -1
3661   };
3662
3663   static int ep_sp_element[] =
3664   {
3665     // should always be valid
3666     EL_EMPTY,
3667
3668     // standard classic Supaplex elements
3669     EL_SP_EMPTY,
3670     EL_SP_ZONK,
3671     EL_SP_BASE,
3672     EL_SP_MURPHY,
3673     EL_SP_INFOTRON,
3674     EL_SP_CHIP_SINGLE,
3675     EL_SP_HARDWARE_GRAY,
3676     EL_SP_EXIT_CLOSED,
3677     EL_SP_EXIT_OPEN,
3678     EL_SP_DISK_ORANGE,
3679     EL_SP_PORT_RIGHT,
3680     EL_SP_PORT_DOWN,
3681     EL_SP_PORT_LEFT,
3682     EL_SP_PORT_UP,
3683     EL_SP_GRAVITY_PORT_RIGHT,
3684     EL_SP_GRAVITY_PORT_DOWN,
3685     EL_SP_GRAVITY_PORT_LEFT,
3686     EL_SP_GRAVITY_PORT_UP,
3687     EL_SP_SNIKSNAK,
3688     EL_SP_DISK_YELLOW,
3689     EL_SP_TERMINAL,
3690     EL_SP_DISK_RED,
3691     EL_SP_PORT_VERTICAL,
3692     EL_SP_PORT_HORIZONTAL,
3693     EL_SP_PORT_ANY,
3694     EL_SP_ELECTRON,
3695     EL_SP_BUGGY_BASE,
3696     EL_SP_CHIP_LEFT,
3697     EL_SP_CHIP_RIGHT,
3698     EL_SP_HARDWARE_BASE_1,
3699     EL_SP_HARDWARE_GREEN,
3700     EL_SP_HARDWARE_BLUE,
3701     EL_SP_HARDWARE_RED,
3702     EL_SP_HARDWARE_YELLOW,
3703     EL_SP_HARDWARE_BASE_2,
3704     EL_SP_HARDWARE_BASE_3,
3705     EL_SP_HARDWARE_BASE_4,
3706     EL_SP_HARDWARE_BASE_5,
3707     EL_SP_HARDWARE_BASE_6,
3708     EL_SP_CHIP_TOP,
3709     EL_SP_CHIP_BOTTOM,
3710
3711     // additional elements that appeared in newer Supaplex levels
3712     EL_INVISIBLE_WALL,
3713
3714     // additional gravity port elements (not switching, but setting gravity)
3715     EL_SP_GRAVITY_ON_PORT_LEFT,
3716     EL_SP_GRAVITY_ON_PORT_RIGHT,
3717     EL_SP_GRAVITY_ON_PORT_UP,
3718     EL_SP_GRAVITY_ON_PORT_DOWN,
3719     EL_SP_GRAVITY_OFF_PORT_LEFT,
3720     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3721     EL_SP_GRAVITY_OFF_PORT_UP,
3722     EL_SP_GRAVITY_OFF_PORT_DOWN,
3723
3724     // more than one Murphy in a level results in an inactive clone
3725     EL_SP_MURPHY_CLONE,
3726
3727     // runtime Supaplex elements
3728     EL_SP_DISK_RED_ACTIVE,
3729     EL_SP_TERMINAL_ACTIVE,
3730     EL_SP_BUGGY_BASE_ACTIVATING,
3731     EL_SP_BUGGY_BASE_ACTIVE,
3732     EL_SP_EXIT_OPENING,
3733     EL_SP_EXIT_CLOSING,
3734
3735     -1
3736   };
3737
3738   static int ep_sb_element[] =
3739   {
3740     EL_EMPTY,
3741     EL_STEELWALL,
3742     EL_SOKOBAN_OBJECT,
3743     EL_SOKOBAN_FIELD_EMPTY,
3744     EL_SOKOBAN_FIELD_FULL,
3745     EL_SOKOBAN_FIELD_PLAYER,
3746     EL_PLAYER_1,
3747     EL_PLAYER_2,
3748     EL_PLAYER_3,
3749     EL_PLAYER_4,
3750     EL_INVISIBLE_STEELWALL,
3751
3752     -1
3753   };
3754
3755   static int ep_gem[] =
3756   {
3757     EL_BD_DIAMOND,
3758     EL_EMERALD,
3759     EL_EMERALD_YELLOW,
3760     EL_EMERALD_RED,
3761     EL_EMERALD_PURPLE,
3762     EL_DIAMOND,
3763
3764     -1
3765   };
3766
3767   static int ep_food_dark_yamyam[] =
3768   {
3769     EL_SAND,
3770     EL_BUG,
3771     EL_SPACESHIP,
3772     EL_BD_BUTTERFLY,
3773     EL_BD_FIREFLY,
3774     EL_YAMYAM,
3775     EL_ROBOT,
3776     EL_PACMAN,
3777     EL_AMOEBA_DROP,
3778     EL_AMOEBA_DEAD,
3779     EL_AMOEBA_WET,
3780     EL_AMOEBA_DRY,
3781     EL_AMOEBA_FULL,
3782     EL_BD_AMOEBA,
3783     EL_EMERALD,
3784     EL_BD_DIAMOND,
3785     EL_EMERALD_YELLOW,
3786     EL_EMERALD_RED,
3787     EL_EMERALD_PURPLE,
3788     EL_DIAMOND,
3789     EL_PEARL,
3790     EL_CRYSTAL,
3791
3792     -1
3793   };
3794
3795   static int ep_food_penguin[] =
3796   {
3797     EL_EMERALD,
3798     EL_BD_DIAMOND,
3799     EL_EMERALD_YELLOW,
3800     EL_EMERALD_RED,
3801     EL_EMERALD_PURPLE,
3802     EL_DIAMOND,
3803     EL_PEARL,
3804     EL_CRYSTAL,
3805
3806     -1
3807   };
3808
3809   static int ep_food_pig[] =
3810   {
3811     EL_EMERALD,
3812     EL_BD_DIAMOND,
3813     EL_EMERALD_YELLOW,
3814     EL_EMERALD_RED,
3815     EL_EMERALD_PURPLE,
3816     EL_DIAMOND,
3817
3818     -1
3819   };
3820
3821   static int ep_historic_wall[] =
3822   {
3823     EL_STEELWALL,
3824     EL_GATE_1,
3825     EL_GATE_2,
3826     EL_GATE_3,
3827     EL_GATE_4,
3828     EL_GATE_1_GRAY,
3829     EL_GATE_2_GRAY,
3830     EL_GATE_3_GRAY,
3831     EL_GATE_4_GRAY,
3832     EL_GATE_1_GRAY_ACTIVE,
3833     EL_GATE_2_GRAY_ACTIVE,
3834     EL_GATE_3_GRAY_ACTIVE,
3835     EL_GATE_4_GRAY_ACTIVE,
3836     EL_EM_GATE_1,
3837     EL_EM_GATE_2,
3838     EL_EM_GATE_3,
3839     EL_EM_GATE_4,
3840     EL_EM_GATE_1_GRAY,
3841     EL_EM_GATE_2_GRAY,
3842     EL_EM_GATE_3_GRAY,
3843     EL_EM_GATE_4_GRAY,
3844     EL_EM_GATE_1_GRAY_ACTIVE,
3845     EL_EM_GATE_2_GRAY_ACTIVE,
3846     EL_EM_GATE_3_GRAY_ACTIVE,
3847     EL_EM_GATE_4_GRAY_ACTIVE,
3848     EL_EXIT_CLOSED,
3849     EL_EXIT_OPENING,
3850     EL_EXIT_OPEN,
3851     EL_WALL,
3852     EL_WALL_SLIPPERY,
3853     EL_EXPANDABLE_WALL,
3854     EL_EXPANDABLE_WALL_HORIZONTAL,
3855     EL_EXPANDABLE_WALL_VERTICAL,
3856     EL_EXPANDABLE_WALL_ANY,
3857     EL_EXPANDABLE_WALL_GROWING,
3858     EL_BD_EXPANDABLE_WALL,
3859     EL_BD_WALL,
3860     EL_SP_CHIP_SINGLE,
3861     EL_SP_CHIP_LEFT,
3862     EL_SP_CHIP_RIGHT,
3863     EL_SP_CHIP_TOP,
3864     EL_SP_CHIP_BOTTOM,
3865     EL_SP_HARDWARE_GRAY,
3866     EL_SP_HARDWARE_GREEN,
3867     EL_SP_HARDWARE_BLUE,
3868     EL_SP_HARDWARE_RED,
3869     EL_SP_HARDWARE_YELLOW,
3870     EL_SP_HARDWARE_BASE_1,
3871     EL_SP_HARDWARE_BASE_2,
3872     EL_SP_HARDWARE_BASE_3,
3873     EL_SP_HARDWARE_BASE_4,
3874     EL_SP_HARDWARE_BASE_5,
3875     EL_SP_HARDWARE_BASE_6,
3876     EL_SP_TERMINAL,
3877     EL_SP_TERMINAL_ACTIVE,
3878     EL_SP_EXIT_CLOSED,
3879     EL_SP_EXIT_OPEN,
3880     EL_INVISIBLE_STEELWALL,
3881     EL_INVISIBLE_STEELWALL_ACTIVE,
3882     EL_INVISIBLE_WALL,
3883     EL_INVISIBLE_WALL_ACTIVE,
3884     EL_STEELWALL_SLIPPERY,
3885     EL_EMC_STEELWALL_1,
3886     EL_EMC_STEELWALL_2,
3887     EL_EMC_STEELWALL_3,
3888     EL_EMC_STEELWALL_4,
3889     EL_EMC_WALL_1,
3890     EL_EMC_WALL_2,
3891     EL_EMC_WALL_3,
3892     EL_EMC_WALL_4,
3893     EL_EMC_WALL_5,
3894     EL_EMC_WALL_6,
3895     EL_EMC_WALL_7,
3896     EL_EMC_WALL_8,
3897
3898     -1
3899   };
3900
3901   static int ep_historic_solid[] =
3902   {
3903     EL_WALL,
3904     EL_EXPANDABLE_WALL,
3905     EL_EXPANDABLE_WALL_HORIZONTAL,
3906     EL_EXPANDABLE_WALL_VERTICAL,
3907     EL_EXPANDABLE_WALL_ANY,
3908     EL_BD_EXPANDABLE_WALL,
3909     EL_BD_WALL,
3910     EL_WALL_SLIPPERY,
3911     EL_EXIT_CLOSED,
3912     EL_EXIT_OPENING,
3913     EL_EXIT_OPEN,
3914     EL_AMOEBA_DEAD,
3915     EL_AMOEBA_WET,
3916     EL_AMOEBA_DRY,
3917     EL_AMOEBA_FULL,
3918     EL_BD_AMOEBA,
3919     EL_QUICKSAND_EMPTY,
3920     EL_QUICKSAND_FULL,
3921     EL_QUICKSAND_FILLING,
3922     EL_QUICKSAND_EMPTYING,
3923     EL_MAGIC_WALL,
3924     EL_MAGIC_WALL_ACTIVE,
3925     EL_MAGIC_WALL_EMPTYING,
3926     EL_MAGIC_WALL_FILLING,
3927     EL_MAGIC_WALL_FULL,
3928     EL_MAGIC_WALL_DEAD,
3929     EL_BD_MAGIC_WALL,
3930     EL_BD_MAGIC_WALL_ACTIVE,
3931     EL_BD_MAGIC_WALL_EMPTYING,
3932     EL_BD_MAGIC_WALL_FULL,
3933     EL_BD_MAGIC_WALL_FILLING,
3934     EL_BD_MAGIC_WALL_DEAD,
3935     EL_GAME_OF_LIFE,
3936     EL_BIOMAZE,
3937     EL_SP_CHIP_SINGLE,
3938     EL_SP_CHIP_LEFT,
3939     EL_SP_CHIP_RIGHT,
3940     EL_SP_CHIP_TOP,
3941     EL_SP_CHIP_BOTTOM,
3942     EL_SP_TERMINAL,
3943     EL_SP_TERMINAL_ACTIVE,
3944     EL_SP_EXIT_CLOSED,
3945     EL_SP_EXIT_OPEN,
3946     EL_INVISIBLE_WALL,
3947     EL_INVISIBLE_WALL_ACTIVE,
3948     EL_SWITCHGATE_SWITCH_UP,
3949     EL_SWITCHGATE_SWITCH_DOWN,
3950     EL_TIMEGATE_SWITCH,
3951     EL_TIMEGATE_SWITCH_ACTIVE,
3952     EL_EMC_WALL_1,
3953     EL_EMC_WALL_2,
3954     EL_EMC_WALL_3,
3955     EL_EMC_WALL_4,
3956     EL_EMC_WALL_5,
3957     EL_EMC_WALL_6,
3958     EL_EMC_WALL_7,
3959     EL_EMC_WALL_8,
3960     EL_WALL_PEARL,
3961     EL_WALL_CRYSTAL,
3962
3963     // the following elements are a direct copy of "indestructible" elements,
3964     // except "EL_ACID", which is "indestructible", but not "solid"!
3965 #if 0
3966     EL_ACID,
3967 #endif
3968     EL_STEELWALL,
3969     EL_ACID_POOL_TOPLEFT,
3970     EL_ACID_POOL_TOPRIGHT,
3971     EL_ACID_POOL_BOTTOMLEFT,
3972     EL_ACID_POOL_BOTTOM,
3973     EL_ACID_POOL_BOTTOMRIGHT,
3974     EL_SP_HARDWARE_GRAY,
3975     EL_SP_HARDWARE_GREEN,
3976     EL_SP_HARDWARE_BLUE,
3977     EL_SP_HARDWARE_RED,
3978     EL_SP_HARDWARE_YELLOW,
3979     EL_SP_HARDWARE_BASE_1,
3980     EL_SP_HARDWARE_BASE_2,
3981     EL_SP_HARDWARE_BASE_3,
3982     EL_SP_HARDWARE_BASE_4,
3983     EL_SP_HARDWARE_BASE_5,
3984     EL_SP_HARDWARE_BASE_6,
3985     EL_INVISIBLE_STEELWALL,
3986     EL_INVISIBLE_STEELWALL_ACTIVE,
3987     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3988     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3989     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3990     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3991     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3992     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3993     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3994     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3995     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3996     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3997     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3998     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3999     EL_LIGHT_SWITCH,
4000     EL_LIGHT_SWITCH_ACTIVE,
4001     EL_SIGN_EXCLAMATION,
4002     EL_SIGN_RADIOACTIVITY,
4003     EL_SIGN_STOP,
4004     EL_SIGN_WHEELCHAIR,
4005     EL_SIGN_PARKING,
4006     EL_SIGN_NO_ENTRY,
4007     EL_SIGN_UNUSED_1,
4008     EL_SIGN_GIVE_WAY,
4009     EL_SIGN_ENTRY_FORBIDDEN,
4010     EL_SIGN_EMERGENCY_EXIT,
4011     EL_SIGN_YIN_YANG,
4012     EL_SIGN_UNUSED_2,
4013     EL_SIGN_SPERMS,
4014     EL_SIGN_BULLET,
4015     EL_SIGN_HEART,
4016     EL_SIGN_CROSS,
4017     EL_SIGN_FRANKIE,
4018     EL_STEEL_EXIT_CLOSED,
4019     EL_STEEL_EXIT_OPEN,
4020     EL_STEEL_EXIT_OPENING,
4021     EL_STEEL_EXIT_CLOSING,
4022     EL_EM_STEEL_EXIT_CLOSED,
4023     EL_EM_STEEL_EXIT_OPEN,
4024     EL_EM_STEEL_EXIT_OPENING,
4025     EL_EM_STEEL_EXIT_CLOSING,
4026     EL_DC_STEELWALL_1_LEFT,
4027     EL_DC_STEELWALL_1_RIGHT,
4028     EL_DC_STEELWALL_1_TOP,
4029     EL_DC_STEELWALL_1_BOTTOM,
4030     EL_DC_STEELWALL_1_HORIZONTAL,
4031     EL_DC_STEELWALL_1_VERTICAL,
4032     EL_DC_STEELWALL_1_TOPLEFT,
4033     EL_DC_STEELWALL_1_TOPRIGHT,
4034     EL_DC_STEELWALL_1_BOTTOMLEFT,
4035     EL_DC_STEELWALL_1_BOTTOMRIGHT,
4036     EL_DC_STEELWALL_1_TOPLEFT_2,
4037     EL_DC_STEELWALL_1_TOPRIGHT_2,
4038     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4039     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4040     EL_DC_STEELWALL_2_LEFT,
4041     EL_DC_STEELWALL_2_RIGHT,
4042     EL_DC_STEELWALL_2_TOP,
4043     EL_DC_STEELWALL_2_BOTTOM,
4044     EL_DC_STEELWALL_2_HORIZONTAL,
4045     EL_DC_STEELWALL_2_VERTICAL,
4046     EL_DC_STEELWALL_2_MIDDLE,
4047     EL_DC_STEELWALL_2_SINGLE,
4048     EL_STEELWALL_SLIPPERY,
4049     EL_EMC_STEELWALL_1,
4050     EL_EMC_STEELWALL_2,
4051     EL_EMC_STEELWALL_3,
4052     EL_EMC_STEELWALL_4,
4053     EL_CRYSTAL,
4054     EL_GATE_1,
4055     EL_GATE_2,
4056     EL_GATE_3,
4057     EL_GATE_4,
4058     EL_GATE_1_GRAY,
4059     EL_GATE_2_GRAY,
4060     EL_GATE_3_GRAY,
4061     EL_GATE_4_GRAY,
4062     EL_GATE_1_GRAY_ACTIVE,
4063     EL_GATE_2_GRAY_ACTIVE,
4064     EL_GATE_3_GRAY_ACTIVE,
4065     EL_GATE_4_GRAY_ACTIVE,
4066     EL_EM_GATE_1,
4067     EL_EM_GATE_2,
4068     EL_EM_GATE_3,
4069     EL_EM_GATE_4,
4070     EL_EM_GATE_1_GRAY,
4071     EL_EM_GATE_2_GRAY,
4072     EL_EM_GATE_3_GRAY,
4073     EL_EM_GATE_4_GRAY,
4074     EL_EM_GATE_1_GRAY_ACTIVE,
4075     EL_EM_GATE_2_GRAY_ACTIVE,
4076     EL_EM_GATE_3_GRAY_ACTIVE,
4077     EL_EM_GATE_4_GRAY_ACTIVE,
4078     EL_EMC_GATE_5,
4079     EL_EMC_GATE_6,
4080     EL_EMC_GATE_7,
4081     EL_EMC_GATE_8,
4082     EL_EMC_GATE_5_GRAY,
4083     EL_EMC_GATE_6_GRAY,
4084     EL_EMC_GATE_7_GRAY,
4085     EL_EMC_GATE_8_GRAY,
4086     EL_EMC_GATE_5_GRAY_ACTIVE,
4087     EL_EMC_GATE_6_GRAY_ACTIVE,
4088     EL_EMC_GATE_7_GRAY_ACTIVE,
4089     EL_EMC_GATE_8_GRAY_ACTIVE,
4090     EL_DC_GATE_WHITE,
4091     EL_DC_GATE_WHITE_GRAY,
4092     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4093     EL_DC_GATE_FAKE_GRAY,
4094     EL_SWITCHGATE_OPEN,
4095     EL_SWITCHGATE_OPENING,
4096     EL_SWITCHGATE_CLOSED,
4097     EL_SWITCHGATE_CLOSING,
4098     EL_DC_SWITCHGATE_SWITCH_UP,
4099     EL_DC_SWITCHGATE_SWITCH_DOWN,
4100     EL_TIMEGATE_OPEN,
4101     EL_TIMEGATE_OPENING,
4102     EL_TIMEGATE_CLOSED,
4103     EL_TIMEGATE_CLOSING,
4104     EL_DC_TIMEGATE_SWITCH,
4105     EL_DC_TIMEGATE_SWITCH_ACTIVE,
4106     EL_TUBE_ANY,
4107     EL_TUBE_VERTICAL,
4108     EL_TUBE_HORIZONTAL,
4109     EL_TUBE_VERTICAL_LEFT,
4110     EL_TUBE_VERTICAL_RIGHT,
4111     EL_TUBE_HORIZONTAL_UP,
4112     EL_TUBE_HORIZONTAL_DOWN,
4113     EL_TUBE_LEFT_UP,
4114     EL_TUBE_LEFT_DOWN,
4115     EL_TUBE_RIGHT_UP,
4116     EL_TUBE_RIGHT_DOWN,
4117     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4118     EL_EXPANDABLE_STEELWALL_VERTICAL,
4119     EL_EXPANDABLE_STEELWALL_ANY,
4120
4121     -1
4122   };
4123
4124   static int ep_classic_enemy[] =
4125   {
4126     EL_BUG,
4127     EL_SPACESHIP,
4128     EL_BD_BUTTERFLY,
4129     EL_BD_FIREFLY,
4130
4131     EL_YAMYAM,
4132     EL_DARK_YAMYAM,
4133     EL_ROBOT,
4134     EL_PACMAN,
4135     EL_SP_SNIKSNAK,
4136     EL_SP_ELECTRON,
4137
4138     -1
4139   };
4140
4141   static int ep_belt[] =
4142   {
4143     EL_CONVEYOR_BELT_1_LEFT,
4144     EL_CONVEYOR_BELT_1_MIDDLE,
4145     EL_CONVEYOR_BELT_1_RIGHT,
4146     EL_CONVEYOR_BELT_2_LEFT,
4147     EL_CONVEYOR_BELT_2_MIDDLE,
4148     EL_CONVEYOR_BELT_2_RIGHT,
4149     EL_CONVEYOR_BELT_3_LEFT,
4150     EL_CONVEYOR_BELT_3_MIDDLE,
4151     EL_CONVEYOR_BELT_3_RIGHT,
4152     EL_CONVEYOR_BELT_4_LEFT,
4153     EL_CONVEYOR_BELT_4_MIDDLE,
4154     EL_CONVEYOR_BELT_4_RIGHT,
4155
4156     -1
4157   };
4158
4159   static int ep_belt_active[] =
4160   {
4161     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4162     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4163     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4164     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4165     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4166     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4167     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4168     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4169     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4170     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4171     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4172     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4173
4174     -1
4175   };
4176
4177   static int ep_belt_switch[] =
4178   {
4179     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4180     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4181     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4182     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4183     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4184     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4185     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4186     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4187     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4188     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4189     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4190     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4191
4192     -1
4193   };
4194
4195   static int ep_tube[] =
4196   {
4197     EL_TUBE_LEFT_UP,
4198     EL_TUBE_LEFT_DOWN,
4199     EL_TUBE_RIGHT_UP,
4200     EL_TUBE_RIGHT_DOWN,
4201     EL_TUBE_HORIZONTAL,
4202     EL_TUBE_HORIZONTAL_UP,
4203     EL_TUBE_HORIZONTAL_DOWN,
4204     EL_TUBE_VERTICAL,
4205     EL_TUBE_VERTICAL_LEFT,
4206     EL_TUBE_VERTICAL_RIGHT,
4207     EL_TUBE_ANY,
4208
4209     -1
4210   };
4211
4212   static int ep_acid_pool[] =
4213   {
4214     EL_ACID_POOL_TOPLEFT,
4215     EL_ACID_POOL_TOPRIGHT,
4216     EL_ACID_POOL_BOTTOMLEFT,
4217     EL_ACID_POOL_BOTTOM,
4218     EL_ACID_POOL_BOTTOMRIGHT,
4219
4220     -1
4221   };
4222
4223   static int ep_keygate[] =
4224   {
4225     EL_GATE_1,
4226     EL_GATE_2,
4227     EL_GATE_3,
4228     EL_GATE_4,
4229     EL_GATE_1_GRAY,
4230     EL_GATE_2_GRAY,
4231     EL_GATE_3_GRAY,
4232     EL_GATE_4_GRAY,
4233     EL_GATE_1_GRAY_ACTIVE,
4234     EL_GATE_2_GRAY_ACTIVE,
4235     EL_GATE_3_GRAY_ACTIVE,
4236     EL_GATE_4_GRAY_ACTIVE,
4237     EL_EM_GATE_1,
4238     EL_EM_GATE_2,
4239     EL_EM_GATE_3,
4240     EL_EM_GATE_4,
4241     EL_EM_GATE_1_GRAY,
4242     EL_EM_GATE_2_GRAY,
4243     EL_EM_GATE_3_GRAY,
4244     EL_EM_GATE_4_GRAY,
4245     EL_EM_GATE_1_GRAY_ACTIVE,
4246     EL_EM_GATE_2_GRAY_ACTIVE,
4247     EL_EM_GATE_3_GRAY_ACTIVE,
4248     EL_EM_GATE_4_GRAY_ACTIVE,
4249     EL_EMC_GATE_5,
4250     EL_EMC_GATE_6,
4251     EL_EMC_GATE_7,
4252     EL_EMC_GATE_8,
4253     EL_EMC_GATE_5_GRAY,
4254     EL_EMC_GATE_6_GRAY,
4255     EL_EMC_GATE_7_GRAY,
4256     EL_EMC_GATE_8_GRAY,
4257     EL_EMC_GATE_5_GRAY_ACTIVE,
4258     EL_EMC_GATE_6_GRAY_ACTIVE,
4259     EL_EMC_GATE_7_GRAY_ACTIVE,
4260     EL_EMC_GATE_8_GRAY_ACTIVE,
4261     EL_DC_GATE_WHITE,
4262     EL_DC_GATE_WHITE_GRAY,
4263     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4264
4265     -1
4266   };
4267
4268   static int ep_amoeboid[] =
4269   {
4270     EL_AMOEBA_DEAD,
4271     EL_AMOEBA_WET,
4272     EL_AMOEBA_DRY,
4273     EL_AMOEBA_FULL,
4274     EL_BD_AMOEBA,
4275     EL_EMC_DRIPPER,
4276
4277     -1
4278   };
4279
4280   static int ep_amoebalive[] =
4281   {
4282     EL_AMOEBA_WET,
4283     EL_AMOEBA_DRY,
4284     EL_AMOEBA_FULL,
4285     EL_BD_AMOEBA,
4286     EL_EMC_DRIPPER,
4287
4288     -1
4289   };
4290
4291   static int ep_has_editor_content[] =
4292   {
4293     EL_PLAYER_1,
4294     EL_PLAYER_2,
4295     EL_PLAYER_3,
4296     EL_PLAYER_4,
4297     EL_SOKOBAN_FIELD_PLAYER,
4298     EL_SP_MURPHY,
4299     EL_YAMYAM,
4300     EL_YAMYAM_LEFT,
4301     EL_YAMYAM_RIGHT,
4302     EL_YAMYAM_UP,
4303     EL_YAMYAM_DOWN,
4304     EL_AMOEBA_WET,
4305     EL_AMOEBA_DRY,
4306     EL_AMOEBA_FULL,
4307     EL_BD_AMOEBA,
4308     EL_BD_AMOEBA_2,
4309     EL_BD_SLIME,
4310     EL_BD_ACID,
4311     EL_BD_BITER,
4312     EL_BD_BITER_RIGHT,
4313     EL_BD_BITER_UP,
4314     EL_BD_BITER_LEFT,
4315     EL_BD_BITER_DOWN,
4316     EL_BD_BLADDER,
4317     EL_BD_NUT,
4318     EL_EMC_MAGIC_BALL,
4319     EL_EMC_ANDROID,
4320     EL_MM_GRAY_BALL,
4321
4322     -1
4323   };
4324
4325   static int ep_can_turn_each_move[] =
4326   {
4327     // !!! do something with this one !!!
4328     -1
4329   };
4330
4331   static int ep_can_grow[] =
4332   {
4333     EL_BD_AMOEBA,
4334     EL_AMOEBA_DROP,
4335     EL_AMOEBA_WET,
4336     EL_AMOEBA_DRY,
4337     EL_AMOEBA_FULL,
4338     EL_GAME_OF_LIFE,
4339     EL_BIOMAZE,
4340     EL_EMC_DRIPPER,
4341
4342     -1
4343   };
4344
4345   static int ep_active_bomb[] =
4346   {
4347     EL_DYNAMITE_ACTIVE,
4348     EL_EM_DYNAMITE_ACTIVE,
4349     EL_DYNABOMB_PLAYER_1_ACTIVE,
4350     EL_DYNABOMB_PLAYER_2_ACTIVE,
4351     EL_DYNABOMB_PLAYER_3_ACTIVE,
4352     EL_DYNABOMB_PLAYER_4_ACTIVE,
4353     EL_SP_DISK_RED_ACTIVE,
4354
4355     -1
4356   };
4357
4358   static int ep_inactive[] =
4359   {
4360     EL_EMPTY,
4361     EL_EMPTY_SPACE_1,
4362     EL_EMPTY_SPACE_2,
4363     EL_EMPTY_SPACE_3,
4364     EL_EMPTY_SPACE_4,
4365     EL_EMPTY_SPACE_5,
4366     EL_EMPTY_SPACE_6,
4367     EL_EMPTY_SPACE_7,
4368     EL_EMPTY_SPACE_8,
4369     EL_EMPTY_SPACE_9,
4370     EL_EMPTY_SPACE_10,
4371     EL_EMPTY_SPACE_11,
4372     EL_EMPTY_SPACE_12,
4373     EL_EMPTY_SPACE_13,
4374     EL_EMPTY_SPACE_14,
4375     EL_EMPTY_SPACE_15,
4376     EL_EMPTY_SPACE_16,
4377     EL_SAND,
4378     EL_WALL,
4379     EL_BD_WALL,
4380     EL_WALL_SLIPPERY,
4381     EL_STEELWALL,
4382     EL_AMOEBA_DEAD,
4383     EL_QUICKSAND_EMPTY,
4384     EL_QUICKSAND_FAST_EMPTY,
4385     EL_STONEBLOCK,
4386     EL_ROBOT_WHEEL,
4387     EL_KEY_1,
4388     EL_KEY_2,
4389     EL_KEY_3,
4390     EL_KEY_4,
4391     EL_EM_KEY_1,
4392     EL_EM_KEY_2,
4393     EL_EM_KEY_3,
4394     EL_EM_KEY_4,
4395     EL_EMC_KEY_5,
4396     EL_EMC_KEY_6,
4397     EL_EMC_KEY_7,
4398     EL_EMC_KEY_8,
4399     EL_GATE_1,
4400     EL_GATE_2,
4401     EL_GATE_3,
4402     EL_GATE_4,
4403     EL_GATE_1_GRAY,
4404     EL_GATE_2_GRAY,
4405     EL_GATE_3_GRAY,
4406     EL_GATE_4_GRAY,
4407     EL_GATE_1_GRAY_ACTIVE,
4408     EL_GATE_2_GRAY_ACTIVE,
4409     EL_GATE_3_GRAY_ACTIVE,
4410     EL_GATE_4_GRAY_ACTIVE,
4411     EL_EM_GATE_1,
4412     EL_EM_GATE_2,
4413     EL_EM_GATE_3,
4414     EL_EM_GATE_4,
4415     EL_EM_GATE_1_GRAY,
4416     EL_EM_GATE_2_GRAY,
4417     EL_EM_GATE_3_GRAY,
4418     EL_EM_GATE_4_GRAY,
4419     EL_EM_GATE_1_GRAY_ACTIVE,
4420     EL_EM_GATE_2_GRAY_ACTIVE,
4421     EL_EM_GATE_3_GRAY_ACTIVE,
4422     EL_EM_GATE_4_GRAY_ACTIVE,
4423     EL_EMC_GATE_5,
4424     EL_EMC_GATE_6,
4425     EL_EMC_GATE_7,
4426     EL_EMC_GATE_8,
4427     EL_EMC_GATE_5_GRAY,
4428     EL_EMC_GATE_6_GRAY,
4429     EL_EMC_GATE_7_GRAY,
4430     EL_EMC_GATE_8_GRAY,
4431     EL_EMC_GATE_5_GRAY_ACTIVE,
4432     EL_EMC_GATE_6_GRAY_ACTIVE,
4433     EL_EMC_GATE_7_GRAY_ACTIVE,
4434     EL_EMC_GATE_8_GRAY_ACTIVE,
4435     EL_DC_GATE_WHITE,
4436     EL_DC_GATE_WHITE_GRAY,
4437     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4438     EL_DC_GATE_FAKE_GRAY,
4439     EL_DYNAMITE,
4440     EL_EM_DYNAMITE,
4441     EL_INVISIBLE_STEELWALL,
4442     EL_INVISIBLE_WALL,
4443     EL_INVISIBLE_SAND,
4444     EL_LAMP,
4445     EL_LAMP_ACTIVE,
4446     EL_WALL_EMERALD,
4447     EL_WALL_DIAMOND,
4448     EL_WALL_BD_DIAMOND,
4449     EL_WALL_EMERALD_YELLOW,
4450     EL_DYNABOMB_INCREASE_NUMBER,
4451     EL_DYNABOMB_INCREASE_SIZE,
4452     EL_DYNABOMB_INCREASE_POWER,
4453 #if 0
4454     EL_SOKOBAN_OBJECT,
4455 #endif
4456     EL_SOKOBAN_FIELD_EMPTY,
4457     EL_SOKOBAN_FIELD_FULL,
4458     EL_WALL_EMERALD_RED,
4459     EL_WALL_EMERALD_PURPLE,
4460     EL_ACID_POOL_TOPLEFT,
4461     EL_ACID_POOL_TOPRIGHT,
4462     EL_ACID_POOL_BOTTOMLEFT,
4463     EL_ACID_POOL_BOTTOM,
4464     EL_ACID_POOL_BOTTOMRIGHT,
4465     EL_MAGIC_WALL,
4466     EL_MAGIC_WALL_DEAD,
4467     EL_BD_MAGIC_WALL,
4468     EL_BD_MAGIC_WALL_DEAD,
4469     EL_DC_MAGIC_WALL,
4470     EL_DC_MAGIC_WALL_DEAD,
4471     EL_AMOEBA_TO_DIAMOND,
4472     EL_BLOCKED,
4473     EL_SP_EMPTY,
4474     EL_SP_BASE,
4475     EL_SP_PORT_RIGHT,
4476     EL_SP_PORT_DOWN,
4477     EL_SP_PORT_LEFT,
4478     EL_SP_PORT_UP,
4479     EL_SP_GRAVITY_PORT_RIGHT,
4480     EL_SP_GRAVITY_PORT_DOWN,
4481     EL_SP_GRAVITY_PORT_LEFT,
4482     EL_SP_GRAVITY_PORT_UP,
4483     EL_SP_PORT_HORIZONTAL,
4484     EL_SP_PORT_VERTICAL,
4485     EL_SP_PORT_ANY,
4486     EL_SP_DISK_RED,
4487 #if 0
4488     EL_SP_DISK_YELLOW,
4489 #endif
4490     EL_SP_CHIP_SINGLE,
4491     EL_SP_CHIP_LEFT,
4492     EL_SP_CHIP_RIGHT,
4493     EL_SP_CHIP_TOP,
4494     EL_SP_CHIP_BOTTOM,
4495     EL_SP_HARDWARE_GRAY,
4496     EL_SP_HARDWARE_GREEN,
4497     EL_SP_HARDWARE_BLUE,
4498     EL_SP_HARDWARE_RED,
4499     EL_SP_HARDWARE_YELLOW,
4500     EL_SP_HARDWARE_BASE_1,
4501     EL_SP_HARDWARE_BASE_2,
4502     EL_SP_HARDWARE_BASE_3,
4503     EL_SP_HARDWARE_BASE_4,
4504     EL_SP_HARDWARE_BASE_5,
4505     EL_SP_HARDWARE_BASE_6,
4506     EL_SP_GRAVITY_ON_PORT_LEFT,
4507     EL_SP_GRAVITY_ON_PORT_RIGHT,
4508     EL_SP_GRAVITY_ON_PORT_UP,
4509     EL_SP_GRAVITY_ON_PORT_DOWN,
4510     EL_SP_GRAVITY_OFF_PORT_LEFT,
4511     EL_SP_GRAVITY_OFF_PORT_RIGHT,
4512     EL_SP_GRAVITY_OFF_PORT_UP,
4513     EL_SP_GRAVITY_OFF_PORT_DOWN,
4514     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4515     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4516     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4517     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4518     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4519     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4520     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4521     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4522     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4523     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4524     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4525     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4526     EL_SIGN_EXCLAMATION,
4527     EL_SIGN_RADIOACTIVITY,
4528     EL_SIGN_STOP,
4529     EL_SIGN_WHEELCHAIR,
4530     EL_SIGN_PARKING,
4531     EL_SIGN_NO_ENTRY,
4532     EL_SIGN_UNUSED_1,
4533     EL_SIGN_GIVE_WAY,
4534     EL_SIGN_ENTRY_FORBIDDEN,
4535     EL_SIGN_EMERGENCY_EXIT,
4536     EL_SIGN_YIN_YANG,
4537     EL_SIGN_UNUSED_2,
4538     EL_SIGN_SPERMS,
4539     EL_SIGN_BULLET,
4540     EL_SIGN_HEART,
4541     EL_SIGN_CROSS,
4542     EL_SIGN_FRANKIE,
4543     EL_DC_STEELWALL_1_LEFT,
4544     EL_DC_STEELWALL_1_RIGHT,
4545     EL_DC_STEELWALL_1_TOP,
4546     EL_DC_STEELWALL_1_BOTTOM,
4547     EL_DC_STEELWALL_1_HORIZONTAL,
4548     EL_DC_STEELWALL_1_VERTICAL,
4549     EL_DC_STEELWALL_1_TOPLEFT,
4550     EL_DC_STEELWALL_1_TOPRIGHT,
4551     EL_DC_STEELWALL_1_BOTTOMLEFT,
4552     EL_DC_STEELWALL_1_BOTTOMRIGHT,
4553     EL_DC_STEELWALL_1_TOPLEFT_2,
4554     EL_DC_STEELWALL_1_TOPRIGHT_2,
4555     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4556     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4557     EL_DC_STEELWALL_2_LEFT,
4558     EL_DC_STEELWALL_2_RIGHT,
4559     EL_DC_STEELWALL_2_TOP,
4560     EL_DC_STEELWALL_2_BOTTOM,
4561     EL_DC_STEELWALL_2_HORIZONTAL,
4562     EL_DC_STEELWALL_2_VERTICAL,
4563     EL_DC_STEELWALL_2_MIDDLE,
4564     EL_DC_STEELWALL_2_SINGLE,
4565     EL_STEELWALL_SLIPPERY,
4566     EL_EMC_STEELWALL_1,
4567     EL_EMC_STEELWALL_2,
4568     EL_EMC_STEELWALL_3,
4569     EL_EMC_STEELWALL_4,
4570     EL_EMC_WALL_SLIPPERY_1,
4571     EL_EMC_WALL_SLIPPERY_2,
4572     EL_EMC_WALL_SLIPPERY_3,
4573     EL_EMC_WALL_SLIPPERY_4,
4574     EL_EMC_WALL_1,
4575     EL_EMC_WALL_2,
4576     EL_EMC_WALL_3,
4577     EL_EMC_WALL_4,
4578     EL_EMC_WALL_5,
4579     EL_EMC_WALL_6,
4580     EL_EMC_WALL_7,
4581     EL_EMC_WALL_8,
4582     EL_EMC_WALL_9,
4583     EL_EMC_WALL_10,
4584     EL_EMC_WALL_11,
4585     EL_EMC_WALL_12,
4586     EL_EMC_WALL_13,
4587     EL_EMC_WALL_14,
4588     EL_EMC_WALL_15,
4589     EL_EMC_WALL_16,
4590
4591     -1
4592   };
4593
4594   static int ep_em_slippery_wall[] =
4595   {
4596     -1
4597   };
4598
4599   static int ep_gfx_crumbled[] =
4600   {
4601     EL_SAND,
4602     EL_LANDMINE,
4603     EL_DC_LANDMINE,
4604     EL_TRAP,
4605     EL_TRAP_ACTIVE,
4606
4607     -1
4608   };
4609
4610   static int ep_editor_cascade_active[] =
4611   {
4612     EL_INTERNAL_CASCADE_BD_ACTIVE,
4613     EL_INTERNAL_CASCADE_BD_NATIVE_ACTIVE,
4614     EL_INTERNAL_CASCADE_BD_EFFECTS_ACTIVE,
4615     EL_INTERNAL_CASCADE_EM_ACTIVE,
4616     EL_INTERNAL_CASCADE_EMC_ACTIVE,
4617     EL_INTERNAL_CASCADE_RND_ACTIVE,
4618     EL_INTERNAL_CASCADE_SB_ACTIVE,
4619     EL_INTERNAL_CASCADE_SP_ACTIVE,
4620     EL_INTERNAL_CASCADE_DC_ACTIVE,
4621     EL_INTERNAL_CASCADE_DX_ACTIVE,
4622     EL_INTERNAL_CASCADE_MM_ACTIVE,
4623     EL_INTERNAL_CASCADE_DF_ACTIVE,
4624     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4625     EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4626     EL_INTERNAL_CASCADE_CE_ACTIVE,
4627     EL_INTERNAL_CASCADE_GE_ACTIVE,
4628     EL_INTERNAL_CASCADE_ES_ACTIVE,
4629     EL_INTERNAL_CASCADE_REF_ACTIVE,
4630     EL_INTERNAL_CASCADE_USER_ACTIVE,
4631     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4632
4633     -1
4634   };
4635
4636   static int ep_editor_cascade_inactive[] =
4637   {
4638     EL_INTERNAL_CASCADE_BD,
4639     EL_INTERNAL_CASCADE_BD_NATIVE,
4640     EL_INTERNAL_CASCADE_BD_EFFECTS,
4641     EL_INTERNAL_CASCADE_EM,
4642     EL_INTERNAL_CASCADE_EMC,
4643     EL_INTERNAL_CASCADE_RND,
4644     EL_INTERNAL_CASCADE_SB,
4645     EL_INTERNAL_CASCADE_SP,
4646     EL_INTERNAL_CASCADE_DC,
4647     EL_INTERNAL_CASCADE_DX,
4648     EL_INTERNAL_CASCADE_MM,
4649     EL_INTERNAL_CASCADE_DF,
4650     EL_INTERNAL_CASCADE_CHARS,
4651     EL_INTERNAL_CASCADE_STEEL_CHARS,
4652     EL_INTERNAL_CASCADE_CE,
4653     EL_INTERNAL_CASCADE_GE,
4654     EL_INTERNAL_CASCADE_ES,
4655     EL_INTERNAL_CASCADE_REF,
4656     EL_INTERNAL_CASCADE_USER,
4657     EL_INTERNAL_CASCADE_DYNAMIC,
4658
4659     -1
4660   };
4661
4662   static int ep_obsolete[] =
4663   {
4664     EL_PLAYER_OBSOLETE,
4665     EL_KEY_OBSOLETE,
4666     EL_EM_KEY_1_FILE_OBSOLETE,
4667     EL_EM_KEY_2_FILE_OBSOLETE,
4668     EL_EM_KEY_3_FILE_OBSOLETE,
4669     EL_EM_KEY_4_FILE_OBSOLETE,
4670     EL_ENVELOPE_OBSOLETE,
4671
4672     -1
4673   };
4674
4675   static struct
4676   {
4677     int *elements;
4678     int property;
4679   } element_properties[] =
4680   {
4681     { ep_diggable,                      EP_DIGGABLE                     },
4682     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
4683     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
4684     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
4685     { ep_dont_touch,                    EP_DONT_TOUCH                   },
4686     { ep_indestructible,                EP_INDESTRUCTIBLE               },
4687     { ep_slippery,                      EP_SLIPPERY                     },
4688     { ep_can_change,                    EP_CAN_CHANGE                   },
4689     { ep_can_move,                      EP_CAN_MOVE                     },
4690     { ep_can_fall,                      EP_CAN_FALL                     },
4691     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
4692     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
4693     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
4694     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
4695     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
4696     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
4697     { ep_walkable_over,                 EP_WALKABLE_OVER                },
4698     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
4699     { ep_walkable_under,                EP_WALKABLE_UNDER               },
4700     { ep_passable_over,                 EP_PASSABLE_OVER                },
4701     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
4702     { ep_passable_under,                EP_PASSABLE_UNDER               },
4703     { ep_droppable,                     EP_DROPPABLE                    },
4704     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
4705     { ep_pushable,                      EP_PUSHABLE                     },
4706     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
4707     { ep_protected,                     EP_PROTECTED                    },
4708     { ep_throwable,                     EP_THROWABLE                    },
4709     { ep_can_explode,                   EP_CAN_EXPLODE                  },
4710     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
4711
4712     { ep_empty_space,                   EP_EMPTY_SPACE                  },
4713     { ep_player,                        EP_PLAYER                       },
4714     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
4715     { ep_can_pass_dc_magic_wall,        EP_CAN_PASS_DC_MAGIC_WALL       },
4716     { ep_switchable,                    EP_SWITCHABLE                   },
4717     { ep_bd_element,                    EP_BD_ELEMENT                   },
4718     { ep_sp_element,                    EP_SP_ELEMENT                   },
4719     { ep_sb_element,                    EP_SB_ELEMENT                   },
4720     { ep_gem,                           EP_GEM                          },
4721     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
4722     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
4723     { ep_food_pig,                      EP_FOOD_PIG                     },
4724     { ep_historic_wall,                 EP_HISTORIC_WALL                },
4725     { ep_historic_solid,                EP_HISTORIC_SOLID               },
4726     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
4727     { ep_belt,                          EP_BELT                         },
4728     { ep_belt_active,                   EP_BELT_ACTIVE                  },
4729     { ep_belt_switch,                   EP_BELT_SWITCH                  },
4730     { ep_tube,                          EP_TUBE                         },
4731     { ep_acid_pool,                     EP_ACID_POOL                    },
4732     { ep_keygate,                       EP_KEYGATE                      },
4733     { ep_amoeboid,                      EP_AMOEBOID                     },
4734     { ep_amoebalive,                    EP_AMOEBALIVE                   },
4735     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
4736     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
4737     { ep_can_grow,                      EP_CAN_GROW                     },
4738     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
4739     { ep_inactive,                      EP_INACTIVE                     },
4740
4741     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
4742
4743     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
4744
4745     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
4746     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
4747
4748     { ep_obsolete,                      EP_OBSOLETE                     },
4749
4750     { NULL,                             -1                              }
4751   };
4752
4753   int i, j, k;
4754
4755   // always start with reliable default values (element has no properties)
4756   // (but never initialize clipboard elements after the very first time)
4757   // (to be able to use clipboard elements between several levels)
4758   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4759     if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4760       for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4761         SET_PROPERTY(i, j, FALSE);
4762
4763   // set all base element properties from above array definitions
4764   for (i = 0; element_properties[i].elements != NULL; i++)
4765     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4766       SET_PROPERTY((element_properties[i].elements)[j],
4767                    element_properties[i].property, TRUE);
4768
4769   // copy properties to some elements that are only stored in level file
4770   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4771     for (j = 0; copy_properties[j][0] != -1; j++)
4772       if (HAS_PROPERTY(copy_properties[j][0], i))
4773         for (k = 1; k <= 4; k++)
4774           SET_PROPERTY(copy_properties[j][k], i, TRUE);
4775
4776   // set static element properties that are not listed in array definitions
4777   for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4778     SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4779
4780   clipboard_elements_initialized = TRUE;
4781 }
4782
4783 void InitElementPropertiesEngine(int engine_version)
4784 {
4785   static int no_wall_properties[] =
4786   {
4787     EP_DIGGABLE,
4788     EP_COLLECTIBLE_ONLY,
4789     EP_DONT_RUN_INTO,
4790     EP_DONT_COLLIDE_WITH,
4791     EP_CAN_MOVE,
4792     EP_CAN_FALL,
4793     EP_CAN_SMASH_PLAYER,
4794     EP_CAN_SMASH_ENEMIES,
4795     EP_CAN_SMASH_EVERYTHING,
4796     EP_PUSHABLE,
4797
4798     EP_PLAYER,
4799     EP_GEM,
4800     EP_FOOD_DARK_YAMYAM,
4801     EP_FOOD_PENGUIN,
4802     EP_BELT,
4803     EP_BELT_ACTIVE,
4804     EP_TUBE,
4805     EP_AMOEBOID,
4806     EP_AMOEBALIVE,
4807     EP_ACTIVE_BOMB,
4808
4809     EP_ACCESSIBLE,
4810
4811     -1
4812   };
4813
4814   int i, j;
4815
4816   /* important: after initialization in InitElementPropertiesStatic(), the
4817      elements are not again initialized to a default value; therefore all
4818      changes have to make sure that they leave the element with a defined
4819      property (which means that conditional property changes must be set to
4820      a reliable default value before) */
4821
4822   // resolve group elements
4823   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4824     ResolveGroupElement(EL_GROUP_START + i);
4825
4826   // set all special, combined or engine dependent element properties
4827   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4828   {
4829     // do not change (already initialized) clipboard elements here
4830     if (IS_CLIPBOARD_ELEMENT(i))
4831       continue;
4832
4833     // ---------- INACTIVE ----------------------------------------------------
4834     SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4835                                    i <= EL_CHAR_END) ||
4836                                   (i >= EL_STEEL_CHAR_START &&
4837                                    i <= EL_STEEL_CHAR_END)));
4838
4839     // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4840     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4841                                   IS_WALKABLE_INSIDE(i) ||
4842                                   IS_WALKABLE_UNDER(i)));
4843
4844     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4845                                   IS_PASSABLE_INSIDE(i) ||
4846                                   IS_PASSABLE_UNDER(i)));
4847
4848     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4849                                          IS_PASSABLE_OVER(i)));
4850
4851     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4852                                            IS_PASSABLE_INSIDE(i)));
4853
4854     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4855                                           IS_PASSABLE_UNDER(i)));
4856
4857     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4858                                     IS_PASSABLE(i)));
4859
4860     // ---------- COLLECTIBLE -------------------------------------------------
4861     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4862                                      IS_DROPPABLE(i) ||
4863                                      IS_THROWABLE(i)));
4864
4865     // ---------- SNAPPABLE ---------------------------------------------------
4866     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4867                                    IS_COLLECTIBLE(i) ||
4868                                    IS_SWITCHABLE(i) ||
4869                                    i == EL_BD_ROCK));
4870
4871     // ---------- WALL --------------------------------------------------------
4872     SET_PROPERTY(i, EP_WALL, TRUE);     // default: element is wall
4873
4874     for (j = 0; no_wall_properties[j] != -1; j++)
4875       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4876           i >= EL_FIRST_RUNTIME_UNREAL)
4877         SET_PROPERTY(i, EP_WALL, FALSE);
4878
4879     if (IS_HISTORIC_WALL(i))
4880       SET_PROPERTY(i, EP_WALL, TRUE);
4881
4882     // ---------- SOLID_FOR_PUSHING -------------------------------------------
4883     if (engine_version < VERSION_IDENT(2,2,0,0))
4884       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4885     else
4886       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4887                                              !IS_DIGGABLE(i) &&
4888                                              !IS_COLLECTIBLE(i)));
4889
4890     // ---------- DRAGONFIRE_PROOF --------------------------------------------
4891     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4892       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4893     else
4894       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4895                                             i != EL_ACID));
4896
4897     // ---------- EXPLOSION_PROOF ---------------------------------------------
4898     if (i == EL_FLAMES)
4899       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4900     else if (engine_version < VERSION_IDENT(2,2,0,0))
4901       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4902     else
4903       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4904                                            (!IS_WALKABLE(i) ||
4905                                             IS_PROTECTED(i))));
4906
4907     if (IS_CUSTOM_ELEMENT(i))
4908     {
4909       // these are additional properties which are initially false when set
4910
4911       // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4912       if (DONT_TOUCH(i))
4913         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4914       if (DONT_COLLIDE_WITH(i))
4915         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4916
4917       // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4918       if (CAN_SMASH_EVERYTHING(i))
4919         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4920       if (CAN_SMASH_ENEMIES(i))
4921         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4922     }
4923
4924     // ---------- CAN_SMASH ---------------------------------------------------
4925     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4926                                    CAN_SMASH_ENEMIES(i) ||
4927                                    CAN_SMASH_EVERYTHING(i)));
4928
4929     // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4930     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4931                                              EXPLODES_BY_FIRE(i)));
4932
4933     // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4934     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4935                                              EXPLODES_SMASHED(i)));
4936
4937     // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4938     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4939                                             EXPLODES_IMPACT(i)));
4940
4941     // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4942     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4943
4944     // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4945     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4946                                                   i == EL_BLACK_ORB));
4947
4948     // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4949     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4950                                               CAN_MOVE(i) ||
4951                                               IS_CUSTOM_ELEMENT(i)));
4952
4953     // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4954     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4955                                                  i == EL_SP_ELECTRON));
4956
4957     // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4958     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4959       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4960                    getMoveIntoAcidProperty(&level, i));
4961
4962     // ---------- DONT_COLLIDE_WITH -------------------------------------------
4963     if (MAYBE_DONT_COLLIDE_WITH(i))
4964       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4965                    getDontCollideWithProperty(&level, i));
4966
4967     // ---------- SP_PORT -----------------------------------------------------
4968     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4969                                  IS_PASSABLE_INSIDE(i)));
4970
4971     // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4972     for (j = 0; j < level.num_android_clone_elements; j++)
4973       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4974                    (!IS_EMPTY(i) &&
4975                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4976
4977     // ---------- CAN_CHANGE --------------------------------------------------
4978     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      // default: cannot change
4979     for (j = 0; j < element_info[i].num_change_pages; j++)
4980       if (element_info[i].change_page[j].can_change)
4981         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4982
4983     // ---------- HAS_ACTION --------------------------------------------------
4984     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      // default: has no action
4985     for (j = 0; j < element_info[i].num_change_pages; j++)
4986       if (element_info[i].change_page[j].has_action)
4987         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4988
4989     // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4990     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4991                                                   HAS_ACTION(i)));
4992
4993     // ---------- GFX_CRUMBLED ------------------------------------------------
4994     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4995                  element_info[i].crumbled[ACTION_DEFAULT] !=
4996                  element_info[i].graphic[ACTION_DEFAULT]);
4997
4998     // ---------- EDITOR_CASCADE ----------------------------------------------
4999     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
5000                                         IS_EDITOR_CASCADE_INACTIVE(i)));
5001   }
5002
5003   // dynamically adjust element properties according to game engine version
5004   {
5005     static int ep_em_slippery_wall[] =
5006     {
5007       EL_WALL,
5008       EL_STEELWALL,
5009       EL_EXPANDABLE_WALL,
5010       EL_EXPANDABLE_WALL_HORIZONTAL,
5011       EL_EXPANDABLE_WALL_VERTICAL,
5012       EL_EXPANDABLE_WALL_ANY,
5013       EL_EXPANDABLE_STEELWALL_HORIZONTAL,
5014       EL_EXPANDABLE_STEELWALL_VERTICAL,
5015       EL_EXPANDABLE_STEELWALL_ANY,
5016       EL_EXPANDABLE_STEELWALL_GROWING,
5017       -1
5018     };
5019
5020     static int ep_em_explodes_by_fire[] =
5021     {
5022       EL_EM_DYNAMITE,
5023       EL_EM_DYNAMITE_ACTIVE,
5024       EL_MOLE,
5025       -1
5026     };
5027
5028     // special EM style gems behaviour
5029     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
5030       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
5031                    level.em_slippery_gems);
5032
5033     // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
5034     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
5035                  (level.em_slippery_gems &&
5036                   engine_version > VERSION_IDENT(2,0,1,0)));
5037
5038     // special EM style explosion behaviour regarding chain reactions
5039     for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
5040       SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
5041                    level.em_explodes_by_fire);
5042   }
5043
5044   // this is needed because some graphics depend on element properties
5045   if (game_status == GAME_MODE_PLAYING)
5046     InitElementGraphicInfo();
5047 }
5048
5049 void InitElementPropertiesGfxElement(void)
5050 {
5051   int i;
5052
5053   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5054   {
5055     struct ElementInfo *ei = &element_info[i];
5056
5057     ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
5058   }
5059 }
5060
5061 static void InitGlobal(void)
5062 {
5063   int graphic;
5064   int i;
5065
5066   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
5067   {
5068     // check if element_name_info entry defined for each element in "main.h"
5069     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
5070       Fail("undefined 'element_name_info' entry for element %d", i);
5071
5072     element_info[i].token_name = element_name_info[i].token_name;
5073     element_info[i].class_name = element_name_info[i].class_name;
5074     element_info[i].editor_description = element_name_info[i].editor_description;
5075   }
5076
5077   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
5078   {
5079     // check if global_anim_name_info defined for each entry in "main.h"
5080     if (i < NUM_GLOBAL_ANIM_TOKENS &&
5081         global_anim_name_info[i].token_name == NULL)
5082       Fail("undefined 'global_anim_name_info' entry for anim %d", i);
5083
5084     global_anim_info[i].token_name = global_anim_name_info[i].token_name;
5085   }
5086
5087   // create hash to store URLs for global animations
5088   anim_url_hash = newSetupFileHash();
5089
5090   // create hash from image config list
5091   image_config_hash = newSetupFileHash();
5092   for (i = 0; image_config[i].token != NULL; i++)
5093     setHashEntry(image_config_hash,
5094                  image_config[i].token,
5095                  image_config[i].value);
5096
5097   // create hash from sound config list
5098   sound_config_hash = newSetupFileHash();
5099   for (i = 0; sound_config[i].token != NULL; i++)
5100     setHashEntry(sound_config_hash,
5101                  sound_config[i].token,
5102                  sound_config[i].value);
5103
5104   // create hash from element token list
5105   element_token_hash = newSetupFileHash();
5106   for (i = 0; element_name_info[i].token_name != NULL; i++)
5107     setHashEntry(element_token_hash,
5108                  element_name_info[i].token_name,
5109                  int2str(i, 0));
5110
5111   // create hash from graphic token list
5112   graphic_token_hash = newSetupFileHash();
5113   for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
5114     if (strSuffix(image_config[i].value, ".png") ||
5115         strSuffix(image_config[i].value, ".pcx") ||
5116         strSuffix(image_config[i].value, ".wav") ||
5117         strEqual(image_config[i].value, UNDEFINED_FILENAME))
5118       setHashEntry(graphic_token_hash,
5119                    image_config[i].token,
5120                    int2str(graphic++, 0));
5121
5122   // create hash from font token list
5123   font_token_hash = newSetupFileHash();
5124   for (i = 0; font_info[i].token_name != NULL; i++)
5125     setHashEntry(font_token_hash,
5126                  font_info[i].token_name,
5127                  int2str(i, 0));
5128
5129   // set default filenames for all cloned graphics in static configuration
5130   for (i = 0; image_config[i].token != NULL; i++)
5131   {
5132     if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
5133     {
5134       char *token = image_config[i].token;
5135       char *token_clone_from = getStringCat2(token, ".clone_from");
5136       char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
5137
5138       if (token_cloned != NULL)
5139       {
5140         char *value_cloned = getHashEntry(image_config_hash, token_cloned);
5141
5142         if (value_cloned != NULL)
5143         {
5144           // set default filename in static configuration
5145           image_config[i].value = value_cloned;
5146
5147           // set default filename in image config hash
5148           setHashEntry(image_config_hash, token, value_cloned);
5149         }
5150       }
5151
5152       free(token_clone_from);
5153     }
5154   }
5155
5156   // always start with reliable default values (all elements)
5157   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5158     ActiveElement[i] = i;
5159
5160   // now add all entries that have an active state (active elements)
5161   for (i = 0; element_with_active_state[i].element != -1; i++)
5162   {
5163     int element = element_with_active_state[i].element;
5164     int element_active = element_with_active_state[i].element_active;
5165
5166     ActiveElement[element] = element_active;
5167   }
5168
5169   // always start with reliable default values (all buttons)
5170   for (i = 0; i < NUM_IMAGE_FILES; i++)
5171     ActiveButton[i] = i;
5172
5173   // now add all entries that have an active state (active buttons)
5174   for (i = 0; button_with_active_state[i].button != -1; i++)
5175   {
5176     int button = button_with_active_state[i].button;
5177     int button_active = button_with_active_state[i].button_active;
5178
5179     ActiveButton[button] = button_active;
5180   }
5181
5182   // always start with reliable default values (all fonts)
5183   for (i = 0; i < NUM_FONTS; i++)
5184     ActiveFont[i] = i;
5185
5186   // now add all entries that have an active state (active fonts)
5187   for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5188   {
5189     int font = font_with_active_state[i].font_nr;
5190     int font_active = font_with_active_state[i].font_nr_active;
5191
5192     ActiveFont[font] = font_active;
5193   }
5194
5195   global.autoplay_leveldir = NULL;
5196   global.patchtapes_leveldir = NULL;
5197   global.convert_leveldir = NULL;
5198   global.dumplevel_leveldir = NULL;
5199   global.dumptape_leveldir = NULL;
5200   global.create_sketch_images_dir = NULL;
5201   global.create_collect_images_dir = NULL;
5202
5203   global.frames_per_second = 0;
5204   global.show_frames_per_second = FALSE;
5205
5206   global.border_status = GAME_MODE_LOADING;
5207   global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
5208
5209   global.use_envelope_request = FALSE;
5210
5211   global.user_names = NULL;
5212 }
5213
5214 static void Execute_Command(char *command)
5215 {
5216   int i;
5217
5218   if (strEqual(command, "print graphicsinfo.conf"))
5219   {
5220     Print("# You can configure additional/alternative image files here.\n");
5221     Print("# (The entries below are default and therefore commented out.)\n");
5222     Print("\n");
5223     Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5224     Print("\n");
5225     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5226     Print("\n");
5227
5228     for (i = 0; image_config[i].token != NULL; i++)
5229       Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5230                                              image_config[i].value));
5231
5232     exit(0);
5233   }
5234   else if (strEqual(command, "print soundsinfo.conf"))
5235   {
5236     Print("# You can configure additional/alternative sound files here.\n");
5237     Print("# (The entries below are default and therefore commented out.)\n");
5238     Print("\n");
5239     Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5240     Print("\n");
5241     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5242     Print("\n");
5243
5244     for (i = 0; sound_config[i].token != NULL; i++)
5245       Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5246                                              sound_config[i].value));
5247
5248     exit(0);
5249   }
5250   else if (strEqual(command, "print musicinfo.conf"))
5251   {
5252     Print("# You can configure additional/alternative music files here.\n");
5253     Print("# (The entries below are default and therefore commented out.)\n");
5254     Print("\n");
5255     Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5256     Print("\n");
5257     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5258     Print("\n");
5259
5260     for (i = 0; music_config[i].token != NULL; i++)
5261       Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5262                                              music_config[i].value));
5263
5264     exit(0);
5265   }
5266   else if (strEqual(command, "print editorsetup.conf"))
5267   {
5268     Print("# You can configure your personal editor element list here.\n");
5269     Print("# (The entries below are default and therefore commented out.)\n");
5270     Print("\n");
5271
5272     // this is needed to be able to check element list for cascade elements
5273     InitElementPropertiesStatic();
5274     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5275
5276     PrintEditorElementList();
5277
5278     exit(0);
5279   }
5280   else if (strEqual(command, "print helpanim.conf"))
5281   {
5282     Print("# You can configure different element help animations here.\n");
5283     Print("# (The entries below are default and therefore commented out.)\n");
5284     Print("\n");
5285
5286     for (i = 0; helpanim_config[i].token != NULL; i++)
5287     {
5288       Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5289                                              helpanim_config[i].value));
5290
5291       if (strEqual(helpanim_config[i].token, "end"))
5292         Print("#\n");
5293     }
5294
5295     exit(0);
5296   }
5297   else if (strEqual(command, "print helptext.conf"))
5298   {
5299     Print("# You can configure different element help text here.\n");
5300     Print("# (The entries below are default and therefore commented out.)\n");
5301     Print("\n");
5302
5303     for (i = 0; helptext_config[i].token != NULL; i++)
5304       Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5305                                              helptext_config[i].value));
5306
5307     exit(0);
5308   }
5309   else if (strPrefix(command, "dump level "))
5310   {
5311     char *filename = &command[11];
5312
5313     if (fileExists(filename))
5314     {
5315       LoadLevelFromFilename(&level, filename);
5316       DumpLevel(&level);
5317
5318       exit(0);
5319     }
5320
5321     char *leveldir = getStringCopy(filename);   // read command parameters
5322     char *level_nr = strchr(leveldir, ' ');
5323
5324     if (level_nr == NULL)
5325       Fail("cannot open file '%s'", filename);
5326
5327     *level_nr++ = '\0';
5328
5329     global.dumplevel_leveldir = leveldir;
5330     global.dumplevel_level_nr = atoi(level_nr);
5331
5332     program.headless = TRUE;
5333   }
5334   else if (strPrefix(command, "dump tape "))
5335   {
5336     char *filename = &command[10];
5337
5338     if (fileExists(filename))
5339     {
5340       LoadTapeFromFilename(filename);
5341       DumpTape(&tape);
5342
5343       exit(0);
5344     }
5345
5346     char *leveldir = getStringCopy(filename);   // read command parameters
5347     char *level_nr = strchr(leveldir, ' ');
5348
5349     if (level_nr == NULL)
5350       Fail("cannot open file '%s'", filename);
5351
5352     *level_nr++ = '\0';
5353
5354     global.dumptape_leveldir = leveldir;
5355     global.dumptape_level_nr = atoi(level_nr);
5356
5357     program.headless = TRUE;
5358   }
5359   else if (strPrefix(command, "autoplay ") ||
5360            strPrefix(command, "autoffwd ") ||
5361            strPrefix(command, "autowarp ") ||
5362            strPrefix(command, "autotest ") ||
5363            strPrefix(command, "autosave ") ||
5364            strPrefix(command, "autoupload ") ||
5365            strPrefix(command, "autofix "))
5366   {
5367     char *arg_ptr = strchr(command, ' ');
5368     char *str_ptr = getStringCopy(arg_ptr);     // read command parameters
5369
5370     global.autoplay_mode =
5371       (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5372        strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5373        strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5374        strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5375        strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5376        strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5377        strPrefix(command, "autofix")  ? AUTOPLAY_MODE_FIX :
5378        AUTOPLAY_MODE_NONE);
5379
5380     while (*str_ptr != '\0')                    // continue parsing string
5381     {
5382       // cut leading whitespace from string, replace it by string terminator
5383       while (*str_ptr == ' ' || *str_ptr == '\t')
5384         *str_ptr++ = '\0';
5385
5386       if (*str_ptr == '\0')                     // end of string reached
5387         break;
5388
5389       if (global.autoplay_leveldir == NULL)     // read level set string
5390       {
5391         global.autoplay_leveldir = str_ptr;
5392         global.autoplay_all = TRUE;             // default: play all tapes
5393
5394         for (i = 0; i < MAX_TAPES_PER_SET; i++)
5395           global.autoplay_level[i] = FALSE;
5396       }
5397       else                                      // read level number string
5398       {
5399         int level_nr = atoi(str_ptr);           // get level_nr value
5400
5401         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5402           global.autoplay_level[level_nr] = TRUE;
5403
5404         global.autoplay_all = FALSE;
5405       }
5406
5407       // advance string pointer to the next whitespace (or end of string)
5408       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5409         str_ptr++;
5410     }
5411
5412     if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5413       program.headless = TRUE;
5414   }
5415   else if (strPrefix(command, "patch tapes "))
5416   {
5417     char *str_ptr = getStringCopy(&command[12]); // read command parameters
5418
5419     // skip leading whitespace
5420     while (*str_ptr == ' ' || *str_ptr == '\t')
5421       str_ptr++;
5422
5423     if (*str_ptr == '\0')
5424       Fail("cannot find MODE in command '%s'", command);
5425
5426     global.patchtapes_mode = str_ptr;           // store patch mode
5427
5428     // advance to next whitespace (or end of string)
5429     while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5430       str_ptr++;
5431
5432     while (*str_ptr != '\0')                    // continue parsing string
5433     {
5434       // cut leading whitespace from string, replace it by string terminator
5435       while (*str_ptr == ' ' || *str_ptr == '\t')
5436         *str_ptr++ = '\0';
5437
5438       if (*str_ptr == '\0')                     // end of string reached
5439         break;
5440
5441       if (global.patchtapes_leveldir == NULL)   // read level set string
5442       {
5443         global.patchtapes_leveldir = str_ptr;
5444         global.patchtapes_all = TRUE;           // default: patch all tapes
5445
5446         for (i = 0; i < MAX_TAPES_PER_SET; i++)
5447           global.patchtapes_level[i] = FALSE;
5448       }
5449       else                                      // read level number string
5450       {
5451         int level_nr = atoi(str_ptr);           // get level_nr value
5452
5453         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5454           global.patchtapes_level[level_nr] = TRUE;
5455
5456         global.patchtapes_all = FALSE;
5457       }
5458
5459       // advance string pointer to the next whitespace (or end of string)
5460       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5461         str_ptr++;
5462     }
5463
5464     if (global.patchtapes_leveldir == NULL)
5465     {
5466       if (strEqual(global.patchtapes_mode, "help"))
5467         global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5468       else
5469         Fail("cannot find LEVELDIR in command '%s'", command);
5470     }
5471
5472     program.headless = TRUE;
5473   }
5474   else if (strPrefix(command, "convert "))
5475   {
5476     char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5477     char *str_ptr = strchr(str_copy, ' ');
5478
5479     global.convert_leveldir = str_copy;
5480     global.convert_level_nr = -1;
5481
5482     if (str_ptr != NULL)                        // level number follows
5483     {
5484       *str_ptr++ = '\0';                        // terminate leveldir string
5485       global.convert_level_nr = atoi(str_ptr);  // get level_nr value
5486     }
5487
5488     program.headless = TRUE;
5489   }
5490   else if (strPrefix(command, "create sketch images "))
5491   {
5492     global.create_sketch_images_dir = getStringCopy(&command[21]);
5493
5494     if (access(global.create_sketch_images_dir, W_OK) != 0)
5495       Fail("image target directory '%s' not found or not writable",
5496            global.create_sketch_images_dir);
5497   }
5498   else if (strPrefix(command, "create collect image "))
5499   {
5500     global.create_collect_images_dir = getStringCopy(&command[21]);
5501
5502     if (access(global.create_collect_images_dir, W_OK) != 0)
5503       Fail("image target directory '%s' not found or not writable",
5504            global.create_collect_images_dir);
5505   }
5506   else if (strPrefix(command, "create CE image "))
5507   {
5508     CreateCustomElementImages(&command[16]);
5509
5510     exit(0);
5511   }
5512   else
5513   {
5514     FailWithHelp("unrecognized command '%s'", command);
5515   }
5516
5517   // disable networking if any valid command was recognized
5518   options.network = setup.network_mode = FALSE;
5519 }
5520
5521 static void InitSetup(void)
5522 {
5523   LoadUserNames();                              // global user names
5524   LoadUserSetup();                              // global user number
5525
5526   LoadSetup();                                  // global setup info
5527
5528   // set some options from setup file
5529
5530   if (setup.options.verbose)
5531     options.verbose = TRUE;
5532
5533   if (setup.options.debug)
5534     options.debug = TRUE;
5535
5536   if (!strEqual(setup.options.debug_mode, ARG_UNDEFINED_STRING))
5537     options.debug_mode = getStringCopy(setup.options.debug_mode);
5538
5539   if (setup.debug.show_frames_per_second)
5540     global.show_frames_per_second = TRUE;
5541 }
5542
5543 static void InitGameInfo(void)
5544 {
5545   game.restart_level = FALSE;
5546   game.request_active = FALSE;
5547
5548   game.use_masked_elements_initial = FALSE;
5549 }
5550
5551 static void InitPlayerInfo(void)
5552 {
5553   int i;
5554
5555   // choose default local player
5556   local_player = &stored_player[0];
5557
5558   for (i = 0; i < MAX_PLAYERS; i++)
5559   {
5560     stored_player[i].connected_locally = FALSE;
5561     stored_player[i].connected_network = FALSE;
5562   }
5563
5564   local_player->connected_locally = TRUE;
5565 }
5566
5567 static void InitArtworkInfo(void)
5568 {
5569   LoadArtworkInfo();
5570 }
5571
5572 static char *get_string_in_brackets(char *string)
5573 {
5574   char *string_in_brackets = checked_malloc(strlen(string) + 3);
5575
5576   sprintf(string_in_brackets, "[%s]", string);
5577
5578   return string_in_brackets;
5579 }
5580
5581 static char *get_level_id_suffix(int id_nr)
5582 {
5583   char *id_suffix = checked_malloc(1 + 3 + 1);
5584
5585   if (id_nr < 0 || id_nr > 999)
5586     id_nr = 0;
5587
5588   sprintf(id_suffix, ".%03d", id_nr);
5589
5590   return id_suffix;
5591 }
5592
5593 static void InitArtworkConfig(void)
5594 {
5595   static char *image_id_prefix[MAX_NUM_ELEMENTS +
5596                                NUM_FONTS +
5597                                NUM_GLOBAL_ANIM_TOKENS + 1];
5598   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5599                                NUM_GLOBAL_ANIM_TOKENS + 1];
5600   static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5601                                NUM_GLOBAL_ANIM_TOKENS + 1];
5602   static char *action_id_suffix[NUM_ACTIONS + 1];
5603   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5604   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5605   static char *level_id_suffix[MAX_LEVELS + 1];
5606   static char *dummy[1] = { NULL };
5607   static char *ignore_generic_tokens[] =
5608   {
5609     "name",
5610     "sort_priority",
5611     "program_title",
5612     "program_copyright",
5613     "program_company",
5614
5615     NULL
5616   };
5617   static char **ignore_image_tokens;
5618   static char **ignore_sound_tokens;
5619   static char **ignore_music_tokens;
5620   int num_ignore_generic_tokens;
5621   int num_ignore_image_tokens;
5622   int num_ignore_sound_tokens;
5623   int num_ignore_music_tokens;
5624   int i;
5625
5626   // dynamically determine list of generic tokens to be ignored
5627   num_ignore_generic_tokens = 0;
5628   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5629     num_ignore_generic_tokens++;
5630
5631   // dynamically determine list of image tokens to be ignored
5632   num_ignore_image_tokens = num_ignore_generic_tokens;
5633   for (i = 0; image_config_vars[i].token != NULL; i++)
5634     num_ignore_image_tokens++;
5635   ignore_image_tokens =
5636     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5637   for (i = 0; i < num_ignore_generic_tokens; i++)
5638     ignore_image_tokens[i] = ignore_generic_tokens[i];
5639   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5640     ignore_image_tokens[num_ignore_generic_tokens + i] =
5641       image_config_vars[i].token;
5642   ignore_image_tokens[num_ignore_image_tokens] = NULL;
5643
5644   // dynamically determine list of sound tokens to be ignored
5645   num_ignore_sound_tokens = num_ignore_generic_tokens;
5646   for (i = 0; sound_config_vars[i].token != NULL; i++)
5647     num_ignore_sound_tokens++;
5648   ignore_sound_tokens =
5649     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5650   for (i = 0; i < num_ignore_generic_tokens; i++)
5651     ignore_sound_tokens[i] = ignore_generic_tokens[i];
5652   for (i = 0; i < num_ignore_sound_tokens - num_ignore_generic_tokens; i++)
5653     ignore_sound_tokens[num_ignore_generic_tokens + i] =
5654       sound_config_vars[i].token;
5655   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5656
5657   // dynamically determine list of music tokens to be ignored
5658   num_ignore_music_tokens = num_ignore_generic_tokens;
5659   ignore_music_tokens =
5660     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5661   for (i = 0; i < num_ignore_generic_tokens; i++)
5662     ignore_music_tokens[i] = ignore_generic_tokens[i];
5663   ignore_music_tokens[num_ignore_music_tokens] = NULL;
5664
5665   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5666     image_id_prefix[i] = element_info[i].token_name;
5667   for (i = 0; i < NUM_FONTS; i++)
5668     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5669   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5670     image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5671       global_anim_info[i].token_name;
5672   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5673
5674   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5675     sound_id_prefix[i] = element_info[i].token_name;
5676   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5677     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5678       get_string_in_brackets(element_info[i].class_name);
5679   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5680     sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5681       global_anim_info[i].token_name;
5682   sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5683
5684   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5685     music_id_prefix[i] = music_prefix_info[i].prefix;
5686   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5687     music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5688       global_anim_info[i].token_name;
5689   music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5690
5691   for (i = 0; i < NUM_ACTIONS; i++)
5692     action_id_suffix[i] = element_action_info[i].suffix;
5693   action_id_suffix[NUM_ACTIONS] = NULL;
5694
5695   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5696     direction_id_suffix[i] = element_direction_info[i].suffix;
5697   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5698
5699   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5700     special_id_suffix[i] = special_suffix_info[i].suffix;
5701   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5702
5703   for (i = 0; i < MAX_LEVELS; i++)
5704     level_id_suffix[i] = get_level_id_suffix(i);
5705   level_id_suffix[MAX_LEVELS] = NULL;
5706
5707   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5708                 image_id_prefix, action_id_suffix, direction_id_suffix,
5709                 special_id_suffix, ignore_image_tokens);
5710   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5711                 sound_id_prefix, action_id_suffix, dummy,
5712                 special_id_suffix, ignore_sound_tokens);
5713   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5714                 music_id_prefix, action_id_suffix, special_id_suffix,
5715                 level_id_suffix, ignore_music_tokens);
5716 }
5717
5718 static void InitMixer(void)
5719 {
5720   OpenAudio();
5721
5722   StartMixer();
5723 }
5724
5725 static void InitVideoOverlay(void)
5726 {
5727   // if virtual buttons are not loaded from setup file, repeat initializing
5728   // virtual buttons grid with default values now that video is initialized
5729   if (!setup.touch.grid_initialized)
5730     InitSetup();
5731
5732   InitTileCursorInfo();
5733   InitOverlayInfo();
5734 }
5735
5736 void InitGfxBuffers(void)
5737 {
5738   static int win_xsize_last = -1;
5739   static int win_ysize_last = -1;
5740
5741   // create additional image buffers for double-buffering and cross-fading
5742
5743   if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5744   {
5745     // used to temporarily store the backbuffer -- only re-create if changed
5746     ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5747     ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5748
5749     win_xsize_last = WIN_XSIZE;
5750     win_ysize_last = WIN_YSIZE;
5751   }
5752
5753   ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5754   ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5755   ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5756
5757   // initialize screen properties
5758   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5759                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5760                    bitmap_db_field);
5761   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5762   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5763   InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5764   InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5765   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5766   InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5767
5768   // required if door size definitions have changed
5769   InitGraphicCompatibilityInfo_Doors();
5770
5771   InitGfxBuffers_BD();
5772   InitGfxBuffers_EM();
5773   InitGfxBuffers_SP();
5774   InitGfxBuffers_MM();
5775 }
5776
5777 static void InitGfx(void)
5778 {
5779   struct GraphicInfo *graphic_info_last = graphic_info;
5780   char *filename_font_initial = NULL;
5781   char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
5782   char *image_token[NUM_INITIAL_IMAGES] =
5783   {
5784     CONFIG_TOKEN_GLOBAL_BUSY_INITIAL,
5785     CONFIG_TOKEN_GLOBAL_BUSY,
5786     CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD,
5787     CONFIG_TOKEN_BACKGROUND,
5788     CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL,
5789     CONFIG_TOKEN_BACKGROUND_LOADING
5790   };
5791   struct MenuPosInfo *init_busy[NUM_INITIAL_IMAGES_BUSY] =
5792   {
5793     &init.busy_initial,
5794     &init.busy,
5795     &init.busy_playfield
5796   };
5797   Bitmap *bitmap_font_initial = NULL;
5798   int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
5799   int i, j, k;
5800
5801   // determine settings for initial font (for displaying startup messages)
5802   for (i = 0; image_config[i].token != NULL; i++)
5803   {
5804     for (j = 0; j < NUM_INITIAL_FONTS; j++)
5805     {
5806       char font_token[128];
5807       int len_font_token;
5808
5809       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5810       len_font_token = strlen(font_token);
5811
5812       if (strEqual(image_config[i].token, font_token))
5813       {
5814         filename_font_initial = image_config[i].value;
5815       }
5816       else if (strlen(image_config[i].token) > len_font_token &&
5817                strncmp(image_config[i].token, font_token, len_font_token) == 0)
5818       {
5819         if (strEqual(&image_config[i].token[len_font_token], ".x"))
5820           font_initial[j].src_x = atoi(image_config[i].value);
5821         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5822           font_initial[j].src_y = atoi(image_config[i].value);
5823         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5824           font_initial[j].width = atoi(image_config[i].value);
5825         else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5826           font_initial[j].height = atoi(image_config[i].value);
5827       }
5828     }
5829   }
5830
5831   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5832   {
5833     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5834     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5835   }
5836
5837   if (filename_font_initial == NULL)    // should not happen
5838     Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5839
5840   InitGfxBuffers();
5841   InitGfxCustomArtworkInfo();
5842   InitGfxOtherSettings();
5843
5844   InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5845
5846   bitmap_font_initial = LoadCustomImage(filename_font_initial);
5847
5848   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5849     font_initial[j].bitmap = bitmap_font_initial;
5850
5851   InitFontGraphicInfo();
5852
5853   InitMenuDesignSettings_Static();
5854
5855   // initialize settings for initial images with default values
5856   for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5857     for (j = 0; j < NUM_GFX_ARGS; j++)
5858       parameter[i][j] =
5859         get_graphic_parameter_value(image_config_suffix[j].value,
5860                                     image_config_suffix[j].token,
5861                                     image_config_suffix[j].type);
5862
5863   // read settings for initial images from default custom artwork config
5864   char *gfx_config_filename = getPath3(options.graphics_directory,
5865                                        GFX_DEFAULT_SUBDIR,
5866                                        GRAPHICSINFO_FILENAME);
5867
5868   if (fileExists(gfx_config_filename))
5869   {
5870     SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5871
5872     if (setup_file_hash)
5873     {
5874       for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5875       {
5876         char *filename = getHashEntry(setup_file_hash, image_token[i]);
5877
5878         if (filename)
5879         {
5880           filename_image_initial[i] = getStringCopy(filename);
5881
5882           for (j = 0; image_config_suffix[j].token != NULL; j++)
5883           {
5884             int type = image_config_suffix[j].type;
5885             char *suffix = image_config_suffix[j].token;
5886             char *token = getStringCat2(image_token[i], suffix);
5887             char *value = getHashEntry(setup_file_hash, token);
5888
5889             checked_free(token);
5890
5891             if (value)
5892               parameter[i][j] =
5893                 get_graphic_parameter_value(value, suffix, type);
5894           }
5895         }
5896       }
5897
5898       // read values from custom graphics config file
5899       InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5900
5901       freeSetupFileHash(setup_file_hash);
5902     }
5903   }
5904
5905   for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5906   {
5907     if (filename_image_initial[i] == NULL)
5908     {
5909       int len_token = strlen(image_token[i]);
5910
5911       // read settings for initial images from static default artwork config
5912       for (j = 0; image_config[j].token != NULL; j++)
5913       {
5914         if (strEqual(image_config[j].token, image_token[i]))
5915         {
5916           filename_image_initial[i] = getStringCopy(image_config[j].value);
5917         }
5918         else if (strlen(image_config[j].token) > len_token &&
5919                  strncmp(image_config[j].token, image_token[i], len_token) == 0)
5920         {
5921           for (k = 0; image_config_suffix[k].token != NULL; k++)
5922           {
5923             if (strEqual(&image_config[j].token[len_token],
5924                          image_config_suffix[k].token))
5925               parameter[i][k] =
5926                 get_graphic_parameter_value(image_config[j].value,
5927                                             image_config_suffix[k].token,
5928                                             image_config_suffix[k].type);
5929           }
5930         }
5931       }
5932     }
5933   }
5934
5935   for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5936   {
5937     if (filename_image_initial[i] == NULL)      // should not happen
5938       Fail("cannot get filename for '%s'", image_token[i]);
5939
5940     image_initial[i].bitmaps =
5941       checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5942
5943     if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
5944       image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
5945         LoadCustomImage(filename_image_initial[i]);
5946
5947     checked_free(filename_image_initial[i]);
5948   }
5949
5950   for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5951     image_initial[i].use_image_size = TRUE;
5952
5953   graphic_info = image_initial;         // graphic == 0 => image_initial
5954
5955   for (i = 0; i < NUM_INITIAL_IMAGES; i++)
5956     set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
5957
5958   graphic_info = graphic_info_last;
5959
5960   for (i = 0; i < NUM_INITIAL_IMAGES_BUSY; i++)
5961   {
5962     // set image size for busy animations
5963     init_busy[i]->width  = image_initial[i].width;
5964     init_busy[i]->height = image_initial[i].height;
5965   }
5966
5967   SetLoadingBackgroundImage();
5968
5969   ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5970
5971   DrawProgramInfo();
5972
5973   InitGfxDrawBusyAnimFunction(DrawInitAnim);
5974   InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5975   InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5976   InitGfxDrawTileCursorFunction(DrawTileCursor);
5977   InitGfxDrawEnvelopeRequestFunction(DrawEnvelopeRequestToScreen);
5978
5979   gfx.fade_border_source_status = global.border_status;
5980   gfx.fade_border_target_status = global.border_status;
5981   gfx.masked_border_bitmap_ptr = backbuffer;
5982
5983   // use copy of busy animation to prevent change while reloading artwork
5984   init_last = init;
5985 }
5986
5987 static void InitGfxBackground(void)
5988 {
5989   fieldbuffer = bitmap_db_field;
5990   SetDrawtoField(DRAW_TO_BACKBUFFER);
5991
5992   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5993
5994   redraw_mask = REDRAW_ALL;
5995 }
5996
5997 static void InitSnd(void)
5998 {
5999   InitSoundSettings_Static();
6000
6001   // read settings for initial sounds from default custom artwork config
6002   char *snd_config_filename = getPath3(options.sounds_directory,
6003                                        SND_DEFAULT_SUBDIR,
6004                                        SOUNDSINFO_FILENAME);
6005
6006   if (fileExists(snd_config_filename))
6007   {
6008     SetupFileHash *setup_file_hash = loadSetupFileHash(snd_config_filename);
6009
6010     if (setup_file_hash)
6011     {
6012       // read values from custom sounds config file
6013       InitSoundSettings_FromHash(setup_file_hash, FALSE);
6014
6015       freeSetupFileHash(setup_file_hash);
6016     }
6017   }
6018 }
6019
6020 static void InitLevelInfo(void)
6021 {
6022   LoadLevelInfo();                              // global level info
6023   LoadLevelSetup_LastSeries();                  // last played series info
6024   LoadLevelSetup_SeriesInfo();                  // last played level info
6025
6026   if (global.autoplay_leveldir &&
6027       global.autoplay_mode != AUTOPLAY_MODE_TEST)
6028   {
6029     leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
6030                                                  global.autoplay_leveldir);
6031     if (leveldir_current == NULL)
6032       leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
6033   }
6034
6035   SetLevelSetInfo(leveldir_current->identifier, level_nr);
6036 }
6037
6038 static void InitLevelArtworkInfo(void)
6039 {
6040   LoadLevelArtworkInfo();
6041 }
6042
6043 static void InitImages(void)
6044 {
6045   print_timestamp_init("InitImages");
6046
6047 #if 0
6048   Debug("init:InitImages", "leveldir_current->identifier == '%s'",
6049         leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6050   Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
6051         leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6052   Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
6053         leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6054   Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6055         leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
6056 #endif
6057
6058   setLevelArtworkDir(artwork.gfx_first);
6059
6060 #if 0
6061   Debug("init:InitImages", "leveldir_current->identifier == '%s'",
6062         leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6063   Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
6064         leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6065   Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
6066          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6067   Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6068         leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
6069 #endif
6070
6071 #if 0
6072   Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
6073         leveldir_current->identifier,
6074         artwork.gfx_current_identifier,
6075         artwork.gfx_current->identifier,
6076         leveldir_current->graphics_set,
6077         leveldir_current->graphics_path);
6078 #endif
6079
6080   UPDATE_BUSY_STATE();
6081
6082   ReloadCustomImages();
6083   print_timestamp_time("ReloadCustomImages");
6084
6085   UPDATE_BUSY_STATE();
6086
6087   LoadCustomElementDescriptions();
6088   print_timestamp_time("LoadCustomElementDescriptions");
6089
6090   UPDATE_BUSY_STATE();
6091
6092   LoadMenuDesignSettings();
6093   print_timestamp_time("LoadMenuDesignSettings");
6094
6095   UPDATE_BUSY_STATE();
6096
6097   ReinitializeGraphics();
6098   print_timestamp_time("ReinitializeGraphics");
6099
6100   LoadMenuDesignSettings_AfterGraphics();
6101   print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
6102
6103   UPDATE_BUSY_STATE();
6104
6105   print_timestamp_done("InitImages");
6106 }
6107
6108 static void InitSound(void)
6109 {
6110   print_timestamp_init("InitSound");
6111
6112   // set artwork path to send it to the sound server process
6113   setLevelArtworkDir(artwork.snd_first);
6114
6115   InitReloadCustomSounds();
6116   print_timestamp_time("InitReloadCustomSounds");
6117
6118   LoadSoundSettings();
6119   print_timestamp_time("LoadSoundSettings");
6120
6121   ReinitializeSounds();
6122   print_timestamp_time("ReinitializeSounds");
6123
6124   print_timestamp_done("InitSound");
6125 }
6126
6127 static void InitMusic(void)
6128 {
6129   print_timestamp_init("InitMusic");
6130
6131   // set artwork path to send it to the sound server process
6132   setLevelArtworkDir(artwork.mus_first);
6133
6134   InitReloadCustomMusic();
6135   print_timestamp_time("InitReloadCustomMusic");
6136
6137   ReinitializeMusic();
6138   print_timestamp_time("ReinitializeMusic");
6139
6140   print_timestamp_done("InitMusic");
6141 }
6142
6143 static void InitArtworkDone(void)
6144 {
6145   if (program.headless)
6146     return;
6147
6148   InitGlobalAnimations();
6149 }
6150
6151 static void InitNetworkSettings(void)
6152 {
6153   boolean network_enabled = (options.network || setup.network_mode);
6154   char *network_server = (options.server_host != NULL ? options.server_host :
6155                           setup.network_server_hostname);
6156
6157   if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
6158     network_server = NULL;
6159
6160   InitNetworkInfo(network_enabled,
6161                   FALSE,
6162                   options.serveronly,
6163                   network_server,
6164                   options.server_port);
6165 }
6166
6167 void InitNetworkServer(void)
6168 {
6169   if (!network.enabled || network.connected)
6170     return;
6171
6172   LimitScreenUpdates(FALSE);
6173
6174   if (game_status == GAME_MODE_LOADING)
6175     DrawProgramInfo();
6176
6177   if (!ConnectToServer(network.server_host, network.server_port))
6178   {
6179     network.enabled = FALSE;
6180
6181     setup.network_mode = FALSE;
6182   }
6183   else
6184   {
6185     SendToServer_ProtocolVersion();
6186     SendToServer_PlayerName(setup.player_name);
6187     SendToServer_NrWanted(setup.network_player_nr + 1);
6188
6189     network.connected = TRUE;
6190   }
6191
6192   // short time to recognize result of network initialization
6193   if (game_status == GAME_MODE_LOADING)
6194     Delay_WithScreenUpdates(1000);
6195 }
6196
6197 static boolean CheckArtworkConfigForCustomElements(char *filename)
6198 {
6199   SetupFileHash *setup_file_hash;
6200   boolean redefined_ce_found = FALSE;
6201
6202   // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
6203
6204   if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
6205   {
6206     BEGIN_HASH_ITERATION(setup_file_hash, itr)
6207     {
6208       char *token = HASH_ITERATION_TOKEN(itr);
6209
6210       if (strPrefix(token, "custom_"))
6211       {
6212         redefined_ce_found = TRUE;
6213
6214         break;
6215       }
6216     }
6217     END_HASH_ITERATION(setup_file_hash, itr)
6218
6219     freeSetupFileHash(setup_file_hash);
6220   }
6221
6222   return redefined_ce_found;
6223 }
6224
6225 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
6226 {
6227   char *filename_base, *filename_local;
6228   boolean redefined_ce_found = FALSE;
6229
6230   setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
6231
6232 #if 0
6233   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6234         "leveldir_current->identifier == '%s'",
6235         leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
6236   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6237         "leveldir_current->graphics_path == '%s'",
6238         leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
6239   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6240         "leveldir_current->graphics_set == '%s'",
6241         leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
6242   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6243         "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
6244         leveldir_current == NULL ? "[NULL]" :
6245         LEVELDIR_ARTWORK_SET(leveldir_current, type));
6246 #endif
6247
6248   // first look for special artwork configured in level series config
6249   filename_base = getCustomArtworkLevelConfigFilename(type);
6250
6251 #if 0
6252   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6253         "filename_base == '%s'", filename_base);
6254 #endif
6255
6256   if (fileExists(filename_base))
6257     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
6258
6259   filename_local = getCustomArtworkConfigFilename(type);
6260
6261 #if 0
6262   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6263         "filename_local == '%s'", filename_local);
6264 #endif
6265
6266   if (filename_local != NULL && !strEqual(filename_base, filename_local))
6267     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
6268
6269 #if 0
6270   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
6271         "redefined_ce_found == %d", redefined_ce_found);
6272 #endif
6273
6274   return redefined_ce_found;
6275 }
6276
6277 static void InitOverrideArtwork(void)
6278 {
6279   boolean redefined_ce_found = FALSE;
6280
6281   // to check if this level set redefines any CEs, do not use overriding
6282   gfx.override_level_graphics = FALSE;
6283   gfx.override_level_sounds   = FALSE;
6284   gfx.override_level_music    = FALSE;
6285
6286   // now check if this level set has definitions for custom elements
6287   if (setup.override_level_graphics == STATE_AUTO ||
6288       setup.override_level_sounds   == STATE_AUTO ||
6289       setup.override_level_music    == STATE_AUTO)
6290     redefined_ce_found =
6291       (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
6292        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
6293        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
6294
6295 #if 0
6296   Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6297         redefined_ce_found);
6298 #endif
6299
6300   if (redefined_ce_found)
6301   {
6302     // this level set has CE definitions: change "MODE_AUTO" to "FALSE"
6303     gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6304     gfx.override_level_sounds   = (setup.override_level_sounds   == TRUE);
6305     gfx.override_level_music    = (setup.override_level_music    == TRUE);
6306   }
6307   else
6308   {
6309     // this level set has no CE definitions: change "MODE_AUTO" to "TRUE"
6310     gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6311     gfx.override_level_sounds   = (setup.override_level_sounds   != FALSE);
6312     gfx.override_level_music    = (setup.override_level_music    != FALSE);
6313   }
6314
6315 #if 0
6316   Debug("init:InitOverrideArtwork", "%d, %d, %d",
6317         gfx.override_level_graphics,
6318         gfx.override_level_sounds,
6319         gfx.override_level_music);
6320 #endif
6321 }
6322
6323 static char *setNewArtworkIdentifier(int type)
6324 {
6325   static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6326   static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6327   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6328   static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6329   static boolean initialized[3] = { FALSE, FALSE, FALSE };
6330   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6331   boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6332   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6333   char *leveldir_identifier = leveldir_current->identifier;
6334   // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6335   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6336   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6337   TreeInfo *custom_artwork_set =
6338     getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6339   boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6340   char *artwork_current_identifier;
6341   char *artwork_new_identifier = NULL;  // default: nothing has changed
6342
6343   // leveldir_current may be invalid (level group, parent link)
6344   if (!validLevelSeries(leveldir_current))
6345     return NULL;
6346
6347   /* 1st step: determine artwork set to be activated in descending order:
6348      --------------------------------------------------------------------
6349      1. setup artwork (when configured to override everything else)
6350      2. artwork set configured in "levelinfo.conf" of current level set
6351         (artwork in level directory will have priority when loading later)
6352      3. artwork in level directory (stored in artwork sub-directory)
6353      4. setup artwork (currently configured in setup menu) */
6354
6355   if (setup_override_artwork)
6356     artwork_current_identifier = setup_artwork_set;
6357   else if (has_level_artwork_set)
6358     artwork_current_identifier = leveldir_artwork_set;
6359   else if (has_custom_artwork_set)
6360     artwork_current_identifier = leveldir_identifier;
6361   else
6362     artwork_current_identifier = setup_artwork_set;
6363
6364   /* 2nd step: check if it is really needed to reload artwork set
6365      ------------------------------------------------------------ */
6366
6367   // ---------- reload if level set and also artwork set has changed ----------
6368   if (last_leveldir_identifier[type] != leveldir_identifier &&
6369       (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6370     artwork_new_identifier = artwork_current_identifier;
6371
6372   last_leveldir_identifier[type] = leveldir_identifier;
6373   last_has_custom_artwork_set[type] = has_custom_artwork_set;
6374
6375   // ---------- reload if "override artwork" setting has changed --------------
6376   if (last_override_level_artwork[type] != setup_override_artwork)
6377     artwork_new_identifier = artwork_current_identifier;
6378
6379   last_override_level_artwork[type] = setup_override_artwork;
6380
6381   // ---------- reload if current artwork identifier has changed --------------
6382   if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6383     artwork_new_identifier = artwork_current_identifier;
6384
6385   // (we cannot compare string pointers here, so copy string content itself)
6386   setString(&last_artwork_identifier[type], artwork_current_identifier);
6387
6388   // ---------- set new artwork identifier ----------
6389   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6390
6391   // ---------- do not reload directly after starting -------------------------
6392   if (!initialized[type])
6393     artwork_new_identifier = NULL;
6394
6395   initialized[type] = TRUE;
6396
6397   return artwork_new_identifier;
6398 }
6399
6400 static void InitArtworkIdentifier(void)
6401 {
6402   setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6403   setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6404   setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6405 }
6406
6407 void ReloadCustomArtwork(int force_reload)
6408 {
6409   int last_game_status = game_status;   // save current game status
6410   char *gfx_new_identifier;
6411   char *snd_new_identifier;
6412   char *mus_new_identifier;
6413   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6414   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6415   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6416   boolean reload_needed;
6417
6418   InitOverrideArtwork();
6419
6420   AdjustGraphicsForEMC();
6421   AdjustSoundsForEMC();
6422
6423   gfx_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6424   snd_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6425   mus_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6426
6427   reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6428                    snd_new_identifier != NULL || force_reload_snd ||
6429                    mus_new_identifier != NULL || force_reload_mus);
6430
6431   if (!reload_needed)
6432     return;
6433
6434   print_timestamp_init("ReloadCustomArtwork");
6435
6436   SetGameStatus(GAME_MODE_LOADING);
6437
6438   FadeOut(REDRAW_ALL);
6439
6440   SetLoadingBackgroundImage();
6441
6442   ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6443   print_timestamp_time("ClearRectangleOnBackground");
6444
6445   FadeIn(REDRAW_ALL);
6446
6447   UPDATE_BUSY_STATE();
6448
6449   InitMissingFileHash();
6450
6451   if (gfx_new_identifier != NULL || force_reload_gfx)
6452   {
6453 #if 0
6454     Debug("init:ReloadCustomArtwork",
6455           "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6456           artwork.gfx_current_identifier,
6457           gfx_new_identifier,
6458           artwork.gfx_current->identifier,
6459           leveldir_current->graphics_set);
6460 #endif
6461
6462     InitImages();
6463     print_timestamp_time("InitImages");
6464   }
6465
6466   if (snd_new_identifier != NULL || force_reload_snd)
6467   {
6468     InitSound();
6469     print_timestamp_time("InitSound");
6470   }
6471
6472   if (mus_new_identifier != NULL || force_reload_mus)
6473   {
6474     InitMusic();
6475     print_timestamp_time("InitMusic");
6476   }
6477
6478   InitArtworkDone();
6479
6480   SetGameStatus(last_game_status);      // restore current game status
6481
6482   FadeOut(REDRAW_ALL);
6483
6484   RedrawGlobalBorder();
6485
6486   // force redraw of (open or closed) door graphics
6487   SetDoorState(DOOR_OPEN_ALL);
6488   CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6489
6490   FadeSetEnterScreen();
6491   FadeSkipNextFadeOut();
6492
6493   print_timestamp_done("ReloadCustomArtwork");
6494
6495   LimitScreenUpdates(FALSE);
6496 }
6497
6498 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6499 {
6500   if (global.autoplay_leveldir == NULL)
6501     KeyboardAutoRepeatOff();
6502 }
6503
6504 void DisplayExitMessage(char *format, va_list ap)
6505 {
6506   // also check for initialized video (headless flag may be temporarily unset)
6507   if (program.headless || !video.initialized)
6508     return;
6509
6510   // check if draw buffer and fonts for exit message are already available
6511   if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6512     return;
6513
6514   int font_1 = FC_RED;
6515   int font_2 = FC_YELLOW;
6516   int font_3 = FC_BLUE;
6517   int font_width = getFontWidth(font_2);
6518   int font_height = getFontHeight(font_2);
6519   int sx = SX;
6520   int sy = SY;
6521   int sxsize = WIN_XSIZE - 2 * sx;
6522   int sysize = WIN_YSIZE - 2 * sy;
6523   int line_length = sxsize / font_width;
6524   int max_lines = sysize / font_height;
6525   int num_lines_printed;
6526
6527   gfx.sx = sx;
6528   gfx.sy = sy;
6529   gfx.sxsize = sxsize;
6530   gfx.sysize = sysize;
6531
6532   sy = 20;
6533
6534   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6535
6536   DrawTextSCentered(sy, font_1, "Fatal error:");
6537   sy += 3 * font_height;;
6538
6539   num_lines_printed =
6540     DrawTextBufferVA(sx, sy, format, ap, font_2,
6541                      line_length, line_length, max_lines,
6542                      0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6543   sy += (num_lines_printed + 3) * font_height;
6544
6545   DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6546   sy += 3 * font_height;
6547
6548   num_lines_printed =
6549     DrawTextBuffer(sx, sy, program.log_filename, font_2,
6550                    line_length, line_length, max_lines,
6551                    0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6552
6553   DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6554
6555   redraw_mask = REDRAW_ALL;
6556
6557   // force drawing exit message even if screen updates are currently limited
6558   LimitScreenUpdates(FALSE);
6559
6560   BackToFront();
6561
6562   // deactivate toons and global animations on error message screen
6563   setup.global_animations = FALSE;
6564
6565   WaitForEventToContinue();
6566 }
6567
6568
6569 // ============================================================================
6570 // OpenAll()
6571 // ============================================================================
6572
6573 void OpenAll(void)
6574 {
6575   print_timestamp_init("OpenAll");
6576
6577   SetGameStatus(GAME_MODE_LOADING);
6578
6579   InitCounter();
6580
6581   InitGlobal();                 // initialize some global variables
6582
6583   InitRND(NEW_RANDOMIZE);
6584   InitSimpleRandom(NEW_RANDOMIZE);
6585   InitBetterRandom(NEW_RANDOMIZE);
6586
6587   InitMissingFileHash();
6588
6589   print_timestamp_time("[init global stuff]");
6590
6591   InitSetup();
6592
6593   print_timestamp_time("[init setup/config stuff (1)]");
6594
6595   if (options.execute_command)
6596     Execute_Command(options.execute_command);
6597
6598   InitNetworkSettings();
6599
6600   InitRuntimeInfo();
6601
6602   if (network.serveronly)
6603   {
6604 #if defined(PLATFORM_UNIX)
6605     NetworkServer(network.server_port, TRUE);
6606 #else
6607     Warn("networking only supported in Unix version");
6608 #endif
6609
6610     exit(0);                    // never reached, server loops forever
6611   }
6612
6613   InitGameInfo();
6614   print_timestamp_time("[init setup/config stuff (2)]");
6615   InitPlayerInfo();
6616   print_timestamp_time("[init setup/config stuff (3)]");
6617   InitArtworkInfo();            // needed before loading gfx, sound & music
6618   print_timestamp_time("[init setup/config stuff (4)]");
6619   InitArtworkConfig();          // needed before forking sound child process
6620   print_timestamp_time("[init setup/config stuff (5)]");
6621   InitMixer();
6622   print_timestamp_time("[init setup/config stuff (6)]");
6623
6624   InitJoysticks();
6625
6626   print_timestamp_time("[init setup/config stuff]");
6627
6628   InitVideoDefaults();
6629   InitVideoDisplay();
6630   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6631   InitVideoOverlay();
6632
6633   InitEventFilter(FilterMouseMotionEvents);
6634
6635   print_timestamp_time("[init video stuff]");
6636
6637   InitElementPropertiesStatic();
6638   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6639   InitElementPropertiesGfxElement();
6640
6641   print_timestamp_time("[init element properties stuff]");
6642
6643   InitGfx();
6644   InitSnd();
6645
6646   print_timestamp_time("InitGfx");
6647
6648   InitLevelInfo();
6649   print_timestamp_time("InitLevelInfo");
6650
6651   InitLevelArtworkInfo();
6652   print_timestamp_time("InitLevelArtworkInfo");
6653
6654   InitOverrideArtwork();        // needs to know current level directory
6655   print_timestamp_time("InitOverrideArtwork");
6656
6657   InitArtworkIdentifier();      // needs to know current level directory
6658   print_timestamp_time("InitArtworkIdentifier");
6659
6660   InitImages();                 // needs to know current level directory
6661   print_timestamp_time("InitImages");
6662
6663   InitSound();                  // needs to know current level directory
6664   print_timestamp_time("InitSound");
6665
6666   InitMusic();                  // needs to know current level directory
6667   print_timestamp_time("InitMusic");
6668
6669   InitArtworkDone();
6670
6671   InitGfxBackground();
6672
6673   bd_open_all();
6674   em_open_all();
6675   sp_open_all();
6676   mm_open_all();
6677
6678   if (global.autoplay_leveldir)
6679   {
6680     AutoPlayTapes();
6681     return;
6682   }
6683   else if (global.patchtapes_leveldir)
6684   {
6685     PatchTapes();
6686     return;
6687   }
6688   else if (global.convert_leveldir)
6689   {
6690     ConvertLevels();
6691     return;
6692   }
6693   else if (global.dumplevel_leveldir)
6694   {
6695     DumpLevels();
6696     return;
6697   }
6698   else if (global.dumptape_leveldir)
6699   {
6700     DumpTapes();
6701     return;
6702   }
6703   else if (global.create_sketch_images_dir)
6704   {
6705     CreateLevelSketchImages();
6706     return;
6707   }
6708   else if (global.create_collect_images_dir)
6709   {
6710     CreateCollectElementImages();
6711     return;
6712   }
6713
6714   InitNetworkServer();
6715
6716   SetGameStatus(GAME_MODE_MAIN);
6717
6718   FadeSetEnterScreen();
6719   if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6720     FadeSkipNextFadeOut();
6721
6722   print_timestamp_time("[post-artwork]");
6723
6724   print_timestamp_done("OpenAll");
6725
6726   if (setup.ask_for_remaining_tapes)
6727     setup.ask_for_uploading_tapes = TRUE;
6728
6729   DrawMainMenu();
6730
6731 #if 0
6732   Debug("internal:path", "SDL_GetBasePath() == '%s'",
6733         SDL_GetBasePath());
6734   Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6735         SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6736 #if defined(PLATFORM_ANDROID)
6737   Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6738         SDL_AndroidGetInternalStoragePath());
6739   Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6740         SDL_AndroidGetExternalStoragePath());
6741   Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6742         (SDL_AndroidGetExternalStorageState() &
6743          SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6744          SDL_AndroidGetExternalStorageState() &
6745          SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6746 #endif
6747 #endif
6748 }
6749
6750 static boolean WaitForApiThreads(void)
6751 {
6752   DelayCounter thread_delay = { 10000 };
6753
6754   if (program.api_thread_count == 0)
6755     return TRUE;
6756
6757   // deactivate global animations (not accessible in game state "loading")
6758   setup.global_animations = FALSE;
6759
6760   // set game state to "loading" to be able to show busy animation
6761   SetGameStatus(GAME_MODE_LOADING);
6762
6763   ResetDelayCounter(&thread_delay);
6764
6765   // wait for threads to finish (and fail on timeout)
6766   while (program.api_thread_count > 0)
6767   {
6768     if (DelayReached(&thread_delay))
6769     {
6770       Error("failed waiting for threads - TIMEOUT");
6771
6772       return FALSE;
6773     }
6774
6775     UPDATE_BUSY_STATE();
6776
6777     Delay(20);
6778   }
6779
6780   return TRUE;
6781 }
6782
6783 void CloseAllAndExit(int exit_value)
6784 {
6785   WaitForApiThreads();
6786
6787   StopSounds();
6788   FreeAllSounds();
6789   FreeAllMusic();
6790   CloseAudio();         // called after freeing sounds (needed for SDL)
6791
6792   bd_close_all();
6793   em_close_all();
6794   sp_close_all();
6795
6796   FreeAllImages();
6797
6798   // !!! TODO !!!
6799   // set a flag to tell the network server thread to quit and wait for it
6800   // using SDL_WaitThread()
6801   //
6802   // Code used with SDL 1.2:
6803   // if (network.server_thread) // terminate network server
6804   //   SDL_KillThread(network.server_thread);
6805
6806   CloseVideoDisplay();
6807   ClosePlatformDependentStuff();
6808
6809   if (exit_value != 0 && !options.execute_command)
6810   {
6811     // fall back to default level set (current set may have caused an error)
6812     SaveLevelSetup_LastSeries_Deactivate();
6813
6814     // tell user where to find error log file which may contain more details
6815     // (error notification now directly displayed on screen inside R'n'D
6816     // NotifyUserAboutErrorFile();      // currently only works for Windows
6817   }
6818
6819   exit(exit_value);
6820 }