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