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