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