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