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