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