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