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