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