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