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