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