extended automatic tape playing modes
[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, "autotest ") ||
4682            strPrefix(command, "autoplay ") ||
4683            strPrefix(command, "autoffwd "))
4684   {
4685     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4686
4687     global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4688                             strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4689                             strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4690
4691     while (*str_ptr != '\0')                    /* continue parsing string */
4692     {
4693       /* cut leading whitespace from string, replace it by string terminator */
4694       while (*str_ptr == ' ' || *str_ptr == '\t')
4695         *str_ptr++ = '\0';
4696
4697       if (*str_ptr == '\0')                     /* end of string reached */
4698         break;
4699
4700       if (global.autoplay_leveldir == NULL)     /* read level set string */
4701       {
4702         global.autoplay_leveldir = str_ptr;
4703         global.autoplay_all = TRUE;             /* default: play all tapes */
4704
4705         for (i = 0; i < MAX_TAPES_PER_SET; i++)
4706           global.autoplay_level[i] = FALSE;
4707       }
4708       else                                      /* read level number string */
4709       {
4710         int level_nr = atoi(str_ptr);           /* get level_nr value */
4711
4712         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4713           global.autoplay_level[level_nr] = TRUE;
4714
4715         global.autoplay_all = FALSE;
4716       }
4717
4718       /* advance string pointer to the next whitespace (or end of string) */
4719       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4720         str_ptr++;
4721     }
4722   }
4723   else if (strPrefix(command, "convert "))
4724   {
4725     char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4726     char *str_ptr = strchr(str_copy, ' ');
4727
4728     global.convert_leveldir = str_copy;
4729     global.convert_level_nr = -1;
4730
4731     if (str_ptr != NULL)                        /* level number follows */
4732     {
4733       *str_ptr++ = '\0';                        /* terminate leveldir string */
4734       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
4735     }
4736   }
4737   else if (strPrefix(command, "create images "))
4738   {
4739     global.create_images_dir = getStringCopy(&command[14]);
4740
4741     if (access(global.create_images_dir, W_OK) != 0)
4742       Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4743             global.create_images_dir);
4744   }
4745   else if (strPrefix(command, "create CE image "))
4746   {
4747     CreateCustomElementImages(&command[16]);
4748
4749     exit(0);
4750   }
4751
4752 #if DEBUG
4753 #if defined(TARGET_SDL2)
4754   else if (strEqual(command, "SDL_ListModes"))
4755   {
4756     SDL_Init(SDL_INIT_VIDEO);
4757
4758     int num_displays = SDL_GetNumVideoDisplays();
4759
4760     // check if there are any displays available
4761     if (num_displays < 0)
4762     {
4763       Print("No displays available: %s\n", SDL_GetError());
4764
4765       exit(-1);
4766     }
4767
4768     for (i = 0; i < num_displays; i++)
4769     {
4770       int num_modes = SDL_GetNumDisplayModes(i);
4771       int j;
4772
4773       Print("Available display modes for display %d:\n", i);
4774
4775       // check if there are any display modes available for this display
4776       if (num_modes < 0)
4777       {
4778         Print("No display modes available for display %d: %s\n",
4779               i, SDL_GetError());
4780
4781         exit(-1);
4782       }
4783
4784       for (j = 0; j < num_modes; j++)
4785       {
4786         SDL_DisplayMode mode;
4787
4788         if (SDL_GetDisplayMode(i, j, &mode) < 0)
4789         {
4790           Print("Cannot get display mode %d for display %d: %s\n",
4791                 j, i, SDL_GetError());
4792
4793           exit(-1);
4794         }
4795
4796         Print("- %d x %d\n", mode.w, mode.h);
4797       }
4798     }
4799
4800     exit(0);
4801   }
4802 #elif defined(TARGET_SDL)
4803   else if (strEqual(command, "SDL_ListModes"))
4804   {
4805     SDL_Rect **modes;
4806     int i;
4807
4808     SDL_Init(SDL_INIT_VIDEO);
4809
4810     /* get available fullscreen/hardware modes */
4811     modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4812
4813     /* check if there are any modes available */
4814     if (modes == NULL)
4815     {
4816       Print("No modes available!\n");
4817
4818       exit(-1);
4819     }
4820
4821     /* check if our resolution is restricted */
4822     if (modes == (SDL_Rect **)-1)
4823     {
4824       Print("All resolutions available.\n");
4825     }
4826     else
4827     {
4828       Print("Available display modes:\n");
4829
4830       for (i = 0; modes[i]; i++)
4831         Print("- %d x %d\n", modes[i]->w, modes[i]->h);
4832     }
4833
4834     exit(0);
4835   }
4836 #endif
4837 #endif
4838
4839   else
4840   {
4841     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4842   }
4843 }
4844
4845 static void InitSetup()
4846 {
4847   LoadSetup();                                  /* global setup info */
4848
4849   /* set some options from setup file */
4850
4851   if (setup.options.verbose)
4852     options.verbose = TRUE;
4853 }
4854
4855 static void InitGameInfo()
4856 {
4857   game.restart_level = FALSE;
4858 }
4859
4860 static void InitPlayerInfo()
4861 {
4862   int i;
4863
4864   /* choose default local player */
4865   local_player = &stored_player[0];
4866
4867   for (i = 0; i < MAX_PLAYERS; i++)
4868     stored_player[i].connected = FALSE;
4869
4870   local_player->connected = TRUE;
4871 }
4872
4873 static void InitArtworkInfo()
4874 {
4875   LoadArtworkInfo();
4876 }
4877
4878 static char *get_string_in_brackets(char *string)
4879 {
4880   char *string_in_brackets = checked_malloc(strlen(string) + 3);
4881
4882   sprintf(string_in_brackets, "[%s]", string);
4883
4884   return string_in_brackets;
4885 }
4886
4887 static char *get_level_id_suffix(int id_nr)
4888 {
4889   char *id_suffix = checked_malloc(1 + 3 + 1);
4890
4891   if (id_nr < 0 || id_nr > 999)
4892     id_nr = 0;
4893
4894   sprintf(id_suffix, ".%03d", id_nr);
4895
4896   return id_suffix;
4897 }
4898
4899 static void InitArtworkConfig()
4900 {
4901   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4902   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4903   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4904   static char *action_id_suffix[NUM_ACTIONS + 1];
4905   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4906   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4907   static char *level_id_suffix[MAX_LEVELS + 1];
4908   static char *dummy[1] = { NULL };
4909   static char *ignore_generic_tokens[] =
4910   {
4911     "name",
4912     "sort_priority",
4913     NULL
4914   };
4915   static char **ignore_image_tokens;
4916   static char **ignore_sound_tokens;
4917   static char **ignore_music_tokens;
4918   int num_ignore_generic_tokens;
4919   int num_ignore_image_tokens;
4920   int num_ignore_sound_tokens;
4921   int num_ignore_music_tokens;
4922   int i;
4923
4924   /* dynamically determine list of generic tokens to be ignored */
4925   num_ignore_generic_tokens = 0;
4926   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4927     num_ignore_generic_tokens++;
4928
4929   /* dynamically determine list of image tokens to be ignored */
4930   num_ignore_image_tokens = num_ignore_generic_tokens;
4931   for (i = 0; image_config_vars[i].token != NULL; i++)
4932     num_ignore_image_tokens++;
4933   ignore_image_tokens =
4934     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4935   for (i = 0; i < num_ignore_generic_tokens; i++)
4936     ignore_image_tokens[i] = ignore_generic_tokens[i];
4937   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4938     ignore_image_tokens[num_ignore_generic_tokens + i] =
4939       image_config_vars[i].token;
4940   ignore_image_tokens[num_ignore_image_tokens] = NULL;
4941
4942   /* dynamically determine list of sound tokens to be ignored */
4943   num_ignore_sound_tokens = num_ignore_generic_tokens;
4944   ignore_sound_tokens =
4945     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4946   for (i = 0; i < num_ignore_generic_tokens; i++)
4947     ignore_sound_tokens[i] = ignore_generic_tokens[i];
4948   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4949
4950   /* dynamically determine list of music tokens to be ignored */
4951   num_ignore_music_tokens = num_ignore_generic_tokens;
4952   ignore_music_tokens =
4953     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4954   for (i = 0; i < num_ignore_generic_tokens; i++)
4955     ignore_music_tokens[i] = ignore_generic_tokens[i];
4956   ignore_music_tokens[num_ignore_music_tokens] = NULL;
4957
4958   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4959     image_id_prefix[i] = element_info[i].token_name;
4960   for (i = 0; i < NUM_FONTS; i++)
4961     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4962   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4963
4964   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4965     sound_id_prefix[i] = element_info[i].token_name;
4966   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4967     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4968       get_string_in_brackets(element_info[i].class_name);
4969   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4970
4971   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4972     music_id_prefix[i] = music_prefix_info[i].prefix;
4973   music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4974
4975   for (i = 0; i < NUM_ACTIONS; i++)
4976     action_id_suffix[i] = element_action_info[i].suffix;
4977   action_id_suffix[NUM_ACTIONS] = NULL;
4978
4979   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4980     direction_id_suffix[i] = element_direction_info[i].suffix;
4981   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4982
4983   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4984     special_id_suffix[i] = special_suffix_info[i].suffix;
4985   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4986
4987   for (i = 0; i < MAX_LEVELS; i++)
4988     level_id_suffix[i] = get_level_id_suffix(i);
4989   level_id_suffix[MAX_LEVELS] = NULL;
4990
4991   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4992                 image_id_prefix, action_id_suffix, direction_id_suffix,
4993                 special_id_suffix, ignore_image_tokens);
4994   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4995                 sound_id_prefix, action_id_suffix, dummy,
4996                 special_id_suffix, ignore_sound_tokens);
4997   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4998                 music_id_prefix, special_id_suffix, level_id_suffix,
4999                 dummy, ignore_music_tokens);
5000 }
5001
5002 static void InitMixer()
5003 {
5004   OpenAudio();
5005
5006   StartMixer();
5007 }
5008
5009 void InitGfxBuffers()
5010 {
5011   static int win_xsize_last = -1;
5012   static int win_ysize_last = -1;
5013
5014   /* create additional image buffers for double-buffering and cross-fading */
5015
5016   if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5017   {
5018     /* may contain content for cross-fading -- only re-create if changed */
5019     ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5020     ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5021
5022     win_xsize_last = WIN_XSIZE;
5023     win_ysize_last = WIN_YSIZE;
5024   }
5025
5026   ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5027   ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5028   ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5029   ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5030   ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5031
5032   /* initialize screen properties */
5033   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5034                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5035                    bitmap_db_field);
5036   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5037   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5038   InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5039   InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5040   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5041   InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5042
5043   /* required if door size definitions have changed */
5044   InitGraphicCompatibilityInfo_Doors();
5045
5046   InitGfxBuffers_EM();
5047   InitGfxBuffers_SP();
5048 }
5049
5050 void InitGfx()
5051 {
5052   struct GraphicInfo *graphic_info_last = graphic_info;
5053   char *filename_font_initial = NULL;
5054   char *filename_anim_initial = NULL;
5055   Bitmap *bitmap_font_initial = NULL;
5056   int font_height;
5057   int i, j;
5058
5059   /* determine settings for initial font (for displaying startup messages) */
5060   for (i = 0; image_config[i].token != NULL; i++)
5061   {
5062     for (j = 0; j < NUM_INITIAL_FONTS; j++)
5063     {
5064       char font_token[128];
5065       int len_font_token;
5066
5067       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5068       len_font_token = strlen(font_token);
5069
5070       if (strEqual(image_config[i].token, font_token))
5071         filename_font_initial = image_config[i].value;
5072       else if (strlen(image_config[i].token) > len_font_token &&
5073                strncmp(image_config[i].token, font_token, len_font_token) == 0)
5074       {
5075         if (strEqual(&image_config[i].token[len_font_token], ".x"))
5076           font_initial[j].src_x = atoi(image_config[i].value);
5077         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5078           font_initial[j].src_y = atoi(image_config[i].value);
5079         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5080           font_initial[j].width = atoi(image_config[i].value);
5081         else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5082           font_initial[j].height = atoi(image_config[i].value);
5083       }
5084     }
5085   }
5086
5087   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5088   {
5089     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5090     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5091   }
5092
5093   if (filename_font_initial == NULL)    /* should not happen */
5094     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5095
5096   InitGfxBuffers();
5097   InitGfxCustomArtworkInfo();
5098   InitGfxOtherSettings();
5099
5100   bitmap_font_initial = LoadCustomImage(filename_font_initial);
5101
5102   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5103     font_initial[j].bitmap = bitmap_font_initial;
5104
5105   InitFontGraphicInfo();
5106
5107   font_height = getFontHeight(FC_RED);
5108
5109   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5110   DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5111   DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5112                FC_RED);
5113
5114   DrawInitText("Loading graphics", 120, FC_GREEN);
5115
5116   /* initialize settings for busy animation with default values */
5117   int parameter[NUM_GFX_ARGS];
5118   for (i = 0; i < NUM_GFX_ARGS; i++)
5119     parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5120                                                image_config_suffix[i].token,
5121                                                image_config_suffix[i].type);
5122
5123   char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5124   int len_anim_token = strlen(anim_token);
5125
5126   /* read settings for busy animation from default custom artwork config */
5127   char *gfx_config_filename = getPath3(options.graphics_directory,
5128                                        GFX_DEFAULT_SUBDIR,
5129                                        GRAPHICSINFO_FILENAME);
5130
5131   if (fileExists(gfx_config_filename))
5132   {
5133     SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5134
5135     if (setup_file_hash)
5136     {
5137       char *filename = getHashEntry(setup_file_hash, anim_token);
5138
5139       if (filename)
5140       {
5141         filename_anim_initial = getStringCopy(filename);
5142
5143         for (j = 0; image_config_suffix[j].token != NULL; j++)
5144         {
5145           int type = image_config_suffix[j].type;
5146           char *suffix = image_config_suffix[j].token;
5147           char *token = getStringCat2(anim_token, suffix);
5148           char *value = getHashEntry(setup_file_hash, token);
5149
5150           checked_free(token);
5151
5152           if (value)
5153             parameter[j] = get_graphic_parameter_value(value, suffix, type);
5154         }
5155       }
5156
5157       freeSetupFileHash(setup_file_hash);
5158     }
5159   }
5160
5161   if (filename_anim_initial == NULL)
5162   {
5163     /* read settings for busy animation from static default artwork config */
5164     for (i = 0; image_config[i].token != NULL; i++)
5165     {
5166       if (strEqual(image_config[i].token, anim_token))
5167         filename_anim_initial = getStringCopy(image_config[i].value);
5168       else if (strlen(image_config[i].token) > len_anim_token &&
5169                strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5170       {
5171         for (j = 0; image_config_suffix[j].token != NULL; j++)
5172         {
5173           if (strEqual(&image_config[i].token[len_anim_token],
5174                        image_config_suffix[j].token))
5175             parameter[j] =
5176               get_graphic_parameter_value(image_config[i].value,
5177                                           image_config_suffix[j].token,
5178                                           image_config_suffix[j].type);
5179         }
5180       }
5181     }
5182   }
5183
5184   if (filename_anim_initial == NULL)    /* should not happen */
5185     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5186
5187   anim_initial.bitmaps =
5188     checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5189
5190   anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5191     LoadCustomImage(filename_anim_initial);
5192
5193   checked_free(filename_anim_initial);
5194
5195   graphic_info = &anim_initial;         /* graphic == 0 => anim_initial */
5196
5197   set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5198
5199   graphic_info = graphic_info_last;
5200
5201   init.busy.width  = anim_initial.width;
5202   init.busy.height = anim_initial.height;
5203
5204   InitMenuDesignSettings_Static();
5205   InitGfxDrawBusyAnimFunction(DrawInitAnim);
5206
5207   /* use copy of busy animation to prevent change while reloading artwork */
5208   init_last = init;
5209 }
5210
5211 void InitGfxBackground()
5212 {
5213   fieldbuffer = bitmap_db_field;
5214   SetDrawtoField(DRAW_BACKBUFFER);
5215
5216   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5217
5218   redraw_mask = REDRAW_ALL;
5219 }
5220
5221 static void InitLevelInfo()
5222 {
5223   LoadLevelInfo();                              /* global level info */
5224   LoadLevelSetup_LastSeries();                  /* last played series info */
5225   LoadLevelSetup_SeriesInfo();                  /* last played level info */
5226
5227   if (global.autoplay_leveldir &&
5228       global.autoplay_mode != AUTOPLAY_TEST)
5229   {
5230     leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5231                                                  global.autoplay_leveldir);
5232     if (leveldir_current == NULL)
5233       leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5234   }
5235 }
5236
5237 static void InitLevelArtworkInfo()
5238 {
5239   LoadLevelArtworkInfo();
5240 }
5241
5242 static void InitImages()
5243 {
5244   print_timestamp_init("InitImages");
5245
5246 #if 0
5247   printf("::: leveldir_current->identifier == '%s'\n",
5248          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5249   printf("::: leveldir_current->graphics_path == '%s'\n",
5250          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5251   printf("::: leveldir_current->graphics_set == '%s'\n",
5252          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5253   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5254          leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5255 #endif
5256
5257   setLevelArtworkDir(artwork.gfx_first);
5258
5259 #if 0
5260   printf("::: leveldir_current->identifier == '%s'\n",
5261          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5262   printf("::: leveldir_current->graphics_path == '%s'\n",
5263          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5264   printf("::: leveldir_current->graphics_set == '%s'\n",
5265          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5266   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5267          leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5268 #endif
5269
5270 #if 0
5271   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5272          leveldir_current->identifier,
5273          artwork.gfx_current_identifier,
5274          artwork.gfx_current->identifier,
5275          leveldir_current->graphics_set,
5276          leveldir_current->graphics_path);
5277 #endif
5278
5279   UPDATE_BUSY_STATE();
5280
5281   ReloadCustomImages();
5282   print_timestamp_time("ReloadCustomImages");
5283
5284   UPDATE_BUSY_STATE();
5285
5286   LoadCustomElementDescriptions();
5287   print_timestamp_time("LoadCustomElementDescriptions");
5288
5289   UPDATE_BUSY_STATE();
5290
5291   LoadMenuDesignSettings();
5292   print_timestamp_time("LoadMenuDesignSettings");
5293
5294   UPDATE_BUSY_STATE();
5295
5296   ReinitializeGraphics();
5297   print_timestamp_time("ReinitializeGraphics");
5298
5299   UPDATE_BUSY_STATE();
5300
5301   print_timestamp_done("InitImages");
5302 }
5303
5304 static void InitSound(char *identifier)
5305 {
5306   print_timestamp_init("InitSound");
5307
5308   if (identifier == NULL)
5309     identifier = artwork.snd_current->identifier;
5310
5311   /* set artwork path to send it to the sound server process */
5312   setLevelArtworkDir(artwork.snd_first);
5313
5314   InitReloadCustomSounds(identifier);
5315   print_timestamp_time("InitReloadCustomSounds");
5316
5317   ReinitializeSounds();
5318   print_timestamp_time("ReinitializeSounds");
5319
5320   print_timestamp_done("InitSound");
5321 }
5322
5323 static void InitMusic(char *identifier)
5324 {
5325   print_timestamp_init("InitMusic");
5326
5327   if (identifier == NULL)
5328     identifier = artwork.mus_current->identifier;
5329
5330   /* set artwork path to send it to the sound server process */
5331   setLevelArtworkDir(artwork.mus_first);
5332
5333   InitReloadCustomMusic(identifier);
5334   print_timestamp_time("InitReloadCustomMusic");
5335
5336   ReinitializeMusic();
5337   print_timestamp_time("ReinitializeMusic");
5338
5339   print_timestamp_done("InitMusic");
5340 }
5341
5342 void InitNetworkServer()
5343 {
5344 #if defined(NETWORK_AVALIABLE)
5345   int nr_wanted;
5346 #endif
5347
5348   if (!options.network)
5349     return;
5350
5351 #if defined(NETWORK_AVALIABLE)
5352   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5353
5354   if (!ConnectToServer(options.server_host, options.server_port))
5355     Error(ERR_EXIT, "cannot connect to network game server");
5356
5357   SendToServer_PlayerName(setup.player_name);
5358   SendToServer_ProtocolVersion();
5359
5360   if (nr_wanted)
5361     SendToServer_NrWanted(nr_wanted);
5362 #endif
5363 }
5364
5365 static boolean CheckArtworkConfigForCustomElements(char *filename)
5366 {
5367   SetupFileHash *setup_file_hash;
5368   boolean redefined_ce_found = FALSE;
5369
5370   /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5371
5372   if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5373   {
5374     BEGIN_HASH_ITERATION(setup_file_hash, itr)
5375     {
5376       char *token = HASH_ITERATION_TOKEN(itr);
5377
5378       if (strPrefix(token, "custom_"))
5379       {
5380         redefined_ce_found = TRUE;
5381
5382         break;
5383       }
5384     }
5385     END_HASH_ITERATION(setup_file_hash, itr)
5386
5387     freeSetupFileHash(setup_file_hash);
5388   }
5389
5390   return redefined_ce_found;
5391 }
5392
5393 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5394 {
5395   char *filename_base, *filename_local;
5396   boolean redefined_ce_found = FALSE;
5397
5398   setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5399
5400 #if 0
5401   printf("::: leveldir_current->identifier == '%s'\n",
5402          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5403   printf("::: leveldir_current->graphics_path == '%s'\n",
5404          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5405   printf("::: leveldir_current->graphics_set == '%s'\n",
5406          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5407   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5408          leveldir_current == NULL ? "[NULL]" :
5409          LEVELDIR_ARTWORK_SET(leveldir_current, type));
5410 #endif
5411
5412   /* first look for special artwork configured in level series config */
5413   filename_base = getCustomArtworkLevelConfigFilename(type);
5414
5415 #if 0
5416   printf("::: filename_base == '%s'\n", filename_base);
5417 #endif
5418
5419   if (fileExists(filename_base))
5420     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5421
5422   filename_local = getCustomArtworkConfigFilename(type);
5423
5424 #if 0
5425   printf("::: filename_local == '%s'\n", filename_local);
5426 #endif
5427
5428   if (filename_local != NULL && !strEqual(filename_base, filename_local))
5429     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5430
5431 #if 0
5432   printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5433 #endif
5434
5435   return redefined_ce_found;
5436 }
5437
5438 static void InitOverrideArtwork()
5439 {
5440   boolean redefined_ce_found = FALSE;
5441
5442   /* to check if this level set redefines any CEs, do not use overriding */
5443   gfx.override_level_graphics = FALSE;
5444   gfx.override_level_sounds   = FALSE;
5445   gfx.override_level_music    = FALSE;
5446
5447   /* now check if this level set has definitions for custom elements */
5448   if (setup.override_level_graphics == AUTO ||
5449       setup.override_level_sounds   == AUTO ||
5450       setup.override_level_music    == AUTO)
5451     redefined_ce_found =
5452       (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5453        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5454        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5455
5456 #if 0
5457   printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5458 #endif
5459
5460   if (redefined_ce_found)
5461   {
5462     /* this level set has CE definitions: change "AUTO" to "FALSE" */
5463     gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5464     gfx.override_level_sounds   = (setup.override_level_sounds   == TRUE);
5465     gfx.override_level_music    = (setup.override_level_music    == TRUE);
5466   }
5467   else
5468   {
5469     /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5470     gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5471     gfx.override_level_sounds   = (setup.override_level_sounds   != FALSE);
5472     gfx.override_level_music    = (setup.override_level_music    != FALSE);
5473   }
5474
5475 #if 0
5476   printf("::: => %d, %d, %d\n",
5477          gfx.override_level_graphics,
5478          gfx.override_level_sounds,
5479          gfx.override_level_music);
5480 #endif
5481 }
5482
5483 static char *getNewArtworkIdentifier(int type)
5484 {
5485   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5486   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5487   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5488   static boolean initialized[3] = { FALSE, FALSE, FALSE };
5489   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5490   boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5491   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5492   char *leveldir_identifier = leveldir_current->identifier;
5493   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5494   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5495   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5496   char *artwork_current_identifier;
5497   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
5498
5499   /* leveldir_current may be invalid (level group, parent link) */
5500   if (!validLevelSeries(leveldir_current))
5501     return NULL;
5502
5503   /* 1st step: determine artwork set to be activated in descending order:
5504      --------------------------------------------------------------------
5505      1. setup artwork (when configured to override everything else)
5506      2. artwork set configured in "levelinfo.conf" of current level set
5507         (artwork in level directory will have priority when loading later)
5508      3. artwork in level directory (stored in artwork sub-directory)
5509      4. setup artwork (currently configured in setup menu) */
5510
5511   if (setup_override_artwork)
5512     artwork_current_identifier = setup_artwork_set;
5513   else if (leveldir_artwork_set != NULL)
5514     artwork_current_identifier = leveldir_artwork_set;
5515   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5516     artwork_current_identifier = leveldir_identifier;
5517   else
5518     artwork_current_identifier = setup_artwork_set;
5519
5520
5521   /* 2nd step: check if it is really needed to reload artwork set
5522      ------------------------------------------------------------ */
5523
5524   /* ---------- reload if level set and also artwork set has changed ------- */
5525   if (leveldir_current_identifier[type] != leveldir_identifier &&
5526       (last_has_level_artwork_set[type] || has_level_artwork_set))
5527     artwork_new_identifier = artwork_current_identifier;
5528
5529   leveldir_current_identifier[type] = leveldir_identifier;
5530   last_has_level_artwork_set[type] = has_level_artwork_set;
5531
5532   /* ---------- reload if "override artwork" setting has changed ----------- */
5533   if (last_override_level_artwork[type] != setup_override_artwork)
5534     artwork_new_identifier = artwork_current_identifier;
5535
5536   last_override_level_artwork[type] = setup_override_artwork;
5537
5538   /* ---------- reload if current artwork identifier has changed ----------- */
5539   if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5540                 artwork_current_identifier))
5541     artwork_new_identifier = artwork_current_identifier;
5542
5543   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5544
5545   /* ---------- do not reload directly after starting ---------------------- */
5546   if (!initialized[type])
5547     artwork_new_identifier = NULL;
5548
5549   initialized[type] = TRUE;
5550
5551   return artwork_new_identifier;
5552 }
5553
5554 void ReloadCustomArtwork(int force_reload)
5555 {
5556   int last_game_status = game_status;   /* save current game status */
5557   char *gfx_new_identifier;
5558   char *snd_new_identifier;
5559   char *mus_new_identifier;
5560   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5561   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5562   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5563   boolean reload_needed;
5564
5565   InitOverrideArtwork();
5566
5567   force_reload_gfx |= AdjustGraphicsForEMC();
5568
5569   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5570   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5571   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5572
5573   reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5574                    snd_new_identifier != NULL || force_reload_snd ||
5575                    mus_new_identifier != NULL || force_reload_mus);
5576
5577   if (!reload_needed)
5578     return;
5579
5580   print_timestamp_init("ReloadCustomArtwork");
5581
5582   game_status = GAME_MODE_LOADING;
5583
5584   FadeOut(REDRAW_ALL);
5585
5586   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5587   print_timestamp_time("ClearRectangle");
5588
5589   FadeIn(REDRAW_ALL);
5590
5591   if (gfx_new_identifier != NULL || force_reload_gfx)
5592   {
5593 #if 0
5594     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5595            artwork.gfx_current_identifier,
5596            gfx_new_identifier,
5597            artwork.gfx_current->identifier,
5598            leveldir_current->graphics_set);
5599 #endif
5600
5601     InitImages();
5602     print_timestamp_time("InitImages");
5603   }
5604
5605   if (snd_new_identifier != NULL || force_reload_snd)
5606   {
5607     InitSound(snd_new_identifier);
5608     print_timestamp_time("InitSound");
5609   }
5610
5611   if (mus_new_identifier != NULL || force_reload_mus)
5612   {
5613     InitMusic(mus_new_identifier);
5614     print_timestamp_time("InitMusic");
5615   }
5616
5617   game_status = last_game_status;       /* restore current game status */
5618
5619   init_last = init;                     /* switch to new busy animation */
5620
5621   FadeOut(REDRAW_ALL);
5622
5623   RedrawGlobalBorder();
5624
5625   /* force redraw of (open or closed) door graphics */
5626   SetDoorState(DOOR_OPEN_ALL);
5627   CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5628
5629   FadeSetEnterScreen();
5630   FadeSkipNextFadeOut();
5631
5632   print_timestamp_done("ReloadCustomArtwork");
5633
5634   LimitScreenUpdates(FALSE);
5635 }
5636
5637 void KeyboardAutoRepeatOffUnlessAutoplay()
5638 {
5639   if (global.autoplay_leveldir == NULL)
5640     KeyboardAutoRepeatOff();
5641 }
5642
5643 void DisplayExitMessage(char *format, va_list ap)
5644 {
5645   // check if draw buffer and fonts for exit message are already available
5646   if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5647     return;
5648
5649   int font_1 = FC_RED;
5650   int font_2 = FC_YELLOW;
5651   int font_3 = FC_BLUE;
5652   int font_width = getFontWidth(font_2);
5653   int font_height = getFontHeight(font_2);
5654   int sx = SX;
5655   int sy = SY;
5656   int sxsize = WIN_XSIZE - 2 * sx;
5657   int sysize = WIN_YSIZE - 2 * sy;
5658   int line_length = sxsize / font_width;
5659   int max_lines = sysize / font_height;
5660   int num_lines_printed;
5661
5662   gfx.sx = sx;
5663   gfx.sy = sy;
5664   gfx.sxsize = sxsize;
5665   gfx.sysize = sysize;
5666
5667   sy = 20;
5668
5669   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5670
5671   DrawTextSCentered(sy, font_1, "Fatal error:");
5672   sy += 3 * font_height;;
5673
5674   num_lines_printed =
5675     DrawTextBufferVA(sx, sy, format, ap, font_2,
5676                      line_length, line_length, max_lines,
5677                      0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5678   sy += (num_lines_printed + 3) * font_height;
5679
5680   DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5681   sy += 3 * font_height;
5682
5683   num_lines_printed =
5684     DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5685                    line_length, line_length, max_lines,
5686                    0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5687
5688   DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5689
5690   redraw_mask = REDRAW_ALL;
5691
5692   /* force drawing exit message even if screen updates are currently limited */
5693   LimitScreenUpdates(FALSE);
5694
5695   BackToFront();
5696
5697   /* deactivate toons on error message screen */
5698   setup.toons = FALSE;
5699
5700   WaitForEventToContinue();
5701 }
5702
5703
5704 /* ========================================================================= */
5705 /* OpenAll()                                                                 */
5706 /* ========================================================================= */
5707
5708 void OpenAll()
5709 {
5710   print_timestamp_init("OpenAll");
5711
5712   game_status = GAME_MODE_LOADING;
5713
5714   InitCounter();
5715
5716   InitGlobal();                 /* initialize some global variables */
5717
5718   print_timestamp_time("[init global stuff]");
5719
5720   InitSetup();
5721
5722   print_timestamp_time("[init setup/config stuff (1)]");
5723
5724   if (options.execute_command)
5725     Execute_Command(options.execute_command);
5726
5727   if (options.serveronly)
5728   {
5729 #if defined(PLATFORM_UNIX)
5730     NetworkServer(options.server_port, options.serveronly);
5731 #else
5732     Error(ERR_WARN, "networking only supported in Unix version");
5733 #endif
5734
5735     exit(0);                    /* never reached, server loops forever */
5736   }
5737
5738   InitGameInfo();
5739   print_timestamp_time("[init setup/config stuff (2)]");
5740   InitPlayerInfo();
5741   print_timestamp_time("[init setup/config stuff (3)]");
5742   InitArtworkInfo();            /* needed before loading gfx, sound & music */
5743   print_timestamp_time("[init setup/config stuff (4)]");
5744   InitArtworkConfig();          /* needed before forking sound child process */
5745   print_timestamp_time("[init setup/config stuff (5)]");
5746   InitMixer();
5747   print_timestamp_time("[init setup/config stuff (6)]");
5748
5749   InitRND(NEW_RANDOMIZE);
5750   InitSimpleRandom(NEW_RANDOMIZE);
5751
5752   InitJoysticks();
5753
5754   print_timestamp_time("[init setup/config stuff]");
5755
5756   InitVideoDisplay();
5757   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5758
5759   InitEventFilter(FilterEvents);
5760
5761   print_timestamp_time("[init video stuff]");
5762
5763   InitElementPropertiesStatic();
5764   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5765   InitElementPropertiesGfxElement();
5766
5767   print_timestamp_time("[init element properties stuff]");
5768
5769   InitGfx();
5770
5771   print_timestamp_time("InitGfx");
5772
5773   InitLevelInfo();
5774   print_timestamp_time("InitLevelInfo");
5775
5776   InitLevelArtworkInfo();
5777   print_timestamp_time("InitLevelArtworkInfo");
5778
5779   InitOverrideArtwork();        /* needs to know current level directory */
5780   print_timestamp_time("InitOverrideArtwork");
5781
5782   InitImages();                 /* needs to know current level directory */
5783   print_timestamp_time("InitImages");
5784
5785   InitSound(NULL);              /* needs to know current level directory */
5786   print_timestamp_time("InitSound");
5787
5788   InitMusic(NULL);              /* needs to know current level directory */
5789   print_timestamp_time("InitMusic");
5790
5791   InitGfxBackground();
5792
5793   em_open_all();
5794   sp_open_all();
5795
5796   if (global.autoplay_leveldir)
5797   {
5798     AutoPlayTape();
5799     return;
5800   }
5801   else if (global.convert_leveldir)
5802   {
5803     ConvertLevels();
5804     return;
5805   }
5806   else if (global.create_images_dir)
5807   {
5808     CreateLevelSketchImages();
5809     return;
5810   }
5811
5812   game_status = GAME_MODE_MAIN;
5813
5814   FadeSetEnterScreen();
5815   if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5816     FadeSkipNextFadeOut();
5817
5818   print_timestamp_time("[post-artwork]");
5819
5820   print_timestamp_done("OpenAll");
5821
5822   DrawMainMenu();
5823
5824   InitNetworkServer();
5825
5826 #if 0
5827   Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5828         SDL_GetBasePath());
5829   Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5830         SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5831 #if defined(PLATFORM_ANDROID)
5832   Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5833         SDL_AndroidGetInternalStoragePath());
5834   Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5835         SDL_AndroidGetExternalStoragePath());
5836   Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5837         (SDL_AndroidGetExternalStorageState() ==
5838          SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5839          SDL_AndroidGetExternalStorageState() ==
5840          SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5841 #endif
5842 #endif
5843 }
5844
5845 void CloseAllAndExit(int exit_value)
5846 {
5847   StopSounds();
5848   FreeAllSounds();
5849   FreeAllMusic();
5850   CloseAudio();         /* called after freeing sounds (needed for SDL) */
5851
5852   em_close_all();
5853   sp_close_all();
5854
5855   FreeAllImages();
5856
5857 #if defined(TARGET_SDL)
5858 #if defined(TARGET_SDL2)
5859   // !!! TODO !!!
5860   // set a flag to tell the network server thread to quit and wait for it
5861   // using SDL_WaitThread()
5862 #else
5863   if (network_server)   /* terminate network server */
5864     SDL_KillThread(server_thread);
5865 #endif
5866 #endif
5867
5868   CloseVideoDisplay();
5869   ClosePlatformDependentStuff();
5870
5871   if (exit_value != 0)
5872   {
5873     /* fall back to default level set (current set may have caused an error) */
5874     SaveLevelSetup_LastSeries_Deactivate();
5875
5876     /* tell user where to find error log file which may contain more details */
5877     // (error notification now directly displayed on screen inside R'n'D
5878     // NotifyUserAboutErrorFile();      /* currently only works for Windows */
5879   }
5880
5881   exit(exit_value);
5882 }