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