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