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