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