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