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