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