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