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