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