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