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