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