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