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