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