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