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