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