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