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