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