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