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