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