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