added fix to prevent Windows from complaining about program not responding
[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;
1721     int src_x, src_y;
1722     int width, height;
1723     int first_frame, 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     first_frame = 0;
1742     getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1743
1744     /* this avoids calculating wrong start position for out-of-bounds frame */
1745     src_x = graphic_info[i].src_x;
1746     src_y = graphic_info[i].src_y;
1747
1748     if (program.headless)
1749       continue;
1750
1751     if (src_x < 0 || src_y < 0 ||
1752         src_x + width  > src_bitmap_width ||
1753         src_y + height > src_bitmap_height)
1754     {
1755       Error(ERR_INFO_LINE, "-");
1756       Error(ERR_INFO, "warning: error found in config file:");
1757       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1758       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1759       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1760       Error(ERR_INFO, "- frame size: %d, %d", width, height);
1761       Error(ERR_INFO,
1762             "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1763             src_x, src_y, src_bitmap_width, src_bitmap_height);
1764       Error(ERR_INFO, "custom graphic rejected for this element/action");
1765
1766       if (i == fallback_graphic)
1767         Error(ERR_EXIT, "no fallback graphic available");
1768
1769       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1770       Error(ERR_INFO_LINE, "-");
1771
1772       graphic_info[i] = graphic_info[fallback_graphic];
1773     }
1774
1775     /* check if last animation frame is inside specified bitmap */
1776
1777     last_frame = graphic_info[i].anim_frames - 1;
1778     getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1779
1780     if (src_x < 0 || src_y < 0 ||
1781         src_x + width  > src_bitmap_width ||
1782         src_y + height > src_bitmap_height)
1783     {
1784       Error(ERR_INFO_LINE, "-");
1785       Error(ERR_INFO, "warning: error found in config file:");
1786       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1787       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1788       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1789       Error(ERR_INFO, "- frame size: %d, %d", width, height);
1790       Error(ERR_INFO,
1791             "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1792             last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1793       Error(ERR_INFO, "custom graphic rejected for this element/action");
1794
1795       if (i == fallback_graphic)
1796         Error(ERR_EXIT, "no fallback graphic available");
1797
1798       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1799       Error(ERR_INFO_LINE, "-");
1800
1801       graphic_info[i] = graphic_info[fallback_graphic];
1802     }
1803   }
1804 }
1805
1806 static void InitGraphicCompatibilityInfo()
1807 {
1808   struct FileInfo *fi_global_door =
1809     getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1810   int num_images = getImageListSize();
1811   int i;
1812
1813   /* the following compatibility handling is needed for the following case:
1814      versions up to 3.3.0.0 used one large bitmap "global.door" for various
1815      graphics mainly used for door and panel graphics, like editor, tape and
1816      in-game buttons with hard-coded bitmap positions and button sizes; as
1817      these graphics now have individual definitions, redefining "global.door"
1818      to change all these graphics at once like before does not work anymore
1819      (because all those individual definitions still have their default values);
1820      to solve this, remap all those individual definitions that are not
1821      redefined to the new bitmap of "global.door" if it was redefined */
1822
1823   /* special compatibility handling if image "global.door" was redefined */
1824   if (fi_global_door->redefined)
1825   {
1826     for (i = 0; i < num_images; i++)
1827     {
1828       struct FileInfo *fi = getImageListEntryFromImageID(i);
1829
1830       /* process only those images that still use the default settings */
1831       if (!fi->redefined)
1832       {
1833         /* process all images which default to same image as "global.door" */
1834         if (strEqual(fi->default_filename, fi_global_door->default_filename))
1835         {
1836           // printf("::: special treatment needed for token '%s'\n", fi->token);
1837
1838           graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1839           graphic_info[i].bitmap  = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1840         }
1841       }
1842     }
1843   }
1844
1845   InitGraphicCompatibilityInfo_Doors();
1846 }
1847
1848 static void InitElementSoundInfo()
1849 {
1850   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1851   int num_property_mappings = getSoundListPropertyMappingSize();
1852   int i, j, act;
1853
1854   /* set values to -1 to identify later as "uninitialized" values */
1855   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1856     for (act = 0; act < NUM_ACTIONS; act++)
1857       element_info[i].sound[act] = -1;
1858
1859   /* initialize element/sound mapping from static configuration */
1860   for (i = 0; element_to_sound[i].element > -1; i++)
1861   {
1862     int element      = element_to_sound[i].element;
1863     int action       = element_to_sound[i].action;
1864     int sound        = element_to_sound[i].sound;
1865     boolean is_class = element_to_sound[i].is_class;
1866
1867     if (action < 0)
1868       action = ACTION_DEFAULT;
1869
1870     if (!is_class)
1871       element_info[element].sound[action] = sound;
1872     else
1873       for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1874         if (strEqual(element_info[j].class_name,
1875                      element_info[element].class_name))
1876           element_info[j].sound[action] = sound;
1877   }
1878
1879   /* initialize element class/sound mapping from dynamic configuration */
1880   for (i = 0; i < num_property_mappings; i++)
1881   {
1882     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1883     int action        = property_mapping[i].ext1_index;
1884     int sound         = property_mapping[i].artwork_index;
1885
1886     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1887       continue;
1888
1889     if (action < 0)
1890       action = ACTION_DEFAULT;
1891
1892     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1893       if (strEqual(element_info[j].class_name,
1894                    element_info[element_class].class_name))
1895         element_info[j].sound[action] = sound;
1896   }
1897
1898   /* initialize element/sound mapping from dynamic configuration */
1899   for (i = 0; i < num_property_mappings; i++)
1900   {
1901     int element = property_mapping[i].base_index;
1902     int action  = property_mapping[i].ext1_index;
1903     int sound   = property_mapping[i].artwork_index;
1904
1905     if (element >= MAX_NUM_ELEMENTS)
1906       continue;
1907
1908     if (action < 0)
1909       action = ACTION_DEFAULT;
1910
1911     element_info[element].sound[action] = sound;
1912   }
1913
1914   /* now set all '-1' values to element specific default values */
1915   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1916   {
1917     for (act = 0; act < NUM_ACTIONS; act++)
1918     {
1919       /* generic default action sound (defined by "[default]" directive) */
1920       int default_action_sound = element_info[EL_DEFAULT].sound[act];
1921
1922       /* look for special default action sound (classic game specific) */
1923       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1924         default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1925       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1926         default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1927       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1928         default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1929
1930       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1931       /* !!! make this better !!! */
1932       if (i == EL_EMPTY_SPACE)
1933         default_action_sound = element_info[EL_DEFAULT].sound[act];
1934
1935       /* no sound for this specific action -- use default action sound */
1936       if (element_info[i].sound[act] == -1)
1937         element_info[i].sound[act] = default_action_sound;
1938     }
1939   }
1940
1941   /* copy sound settings to some elements that are only stored in level file
1942      in native R'n'D levels, but are used by game engine in native EM levels */
1943   for (i = 0; copy_properties[i][0] != -1; i++)
1944     for (j = 1; j <= 4; j++)
1945       for (act = 0; act < NUM_ACTIONS; act++)
1946         element_info[copy_properties[i][j]].sound[act] =
1947           element_info[copy_properties[i][0]].sound[act];
1948 }
1949
1950 static void InitGameModeSoundInfo()
1951 {
1952   int i;
1953
1954   /* set values to -1 to identify later as "uninitialized" values */
1955   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1956     menu.sound[i] = -1;
1957
1958   /* initialize gamemode/sound mapping from static configuration */
1959   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1960   {
1961     int gamemode = gamemode_to_sound[i].gamemode;
1962     int sound    = gamemode_to_sound[i].sound;
1963
1964     if (gamemode < 0)
1965       gamemode = GAME_MODE_DEFAULT;
1966
1967     menu.sound[gamemode] = sound;
1968   }
1969
1970   /* now set all '-1' values to levelset specific default values */
1971   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1972     if (menu.sound[i] == -1)
1973       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1974 }
1975
1976 static void set_sound_parameters(int sound, char **parameter_raw)
1977 {
1978   int parameter[NUM_SND_ARGS];
1979   int i;
1980
1981   /* get integer values from string parameters */
1982   for (i = 0; i < NUM_SND_ARGS; i++)
1983     parameter[i] =
1984       get_parameter_value(parameter_raw[i],
1985                           sound_config_suffix[i].token,
1986                           sound_config_suffix[i].type);
1987
1988   /* explicit loop mode setting in configuration overrides default value */
1989   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1990     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1991
1992   /* sound volume to change the original volume when loading the sound file */
1993   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1994
1995   /* sound priority to give certain sounds a higher or lower priority */
1996   sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1997 }
1998
1999 static void InitSoundInfo()
2000 {
2001   int *sound_effect_properties;
2002   int num_sounds = getSoundListSize();
2003   int i, j;
2004
2005   checked_free(sound_info);
2006
2007   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2008   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2009
2010   /* initialize sound effect for all elements to "no sound" */
2011   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2012     for (j = 0; j < NUM_ACTIONS; j++)
2013       element_info[i].sound[j] = SND_UNDEFINED;
2014
2015   for (i = 0; i < num_sounds; i++)
2016   {
2017     struct FileInfo *sound = getSoundListEntry(i);
2018     int len_effect_text = strlen(sound->token);
2019
2020     sound_effect_properties[i] = ACTION_OTHER;
2021     sound_info[i].loop = FALSE;         /* default: play sound only once */
2022
2023     /* determine all loop sounds and identify certain sound classes */
2024
2025     for (j = 0; element_action_info[j].suffix; j++)
2026     {
2027       int len_action_text = strlen(element_action_info[j].suffix);
2028
2029       if (len_action_text < len_effect_text &&
2030           strEqual(&sound->token[len_effect_text - len_action_text],
2031                    element_action_info[j].suffix))
2032       {
2033         sound_effect_properties[i] = element_action_info[j].value;
2034         sound_info[i].loop = element_action_info[j].is_loop_sound;
2035
2036         break;
2037       }
2038     }
2039
2040     /* associate elements and some selected sound actions */
2041
2042     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2043     {
2044       if (element_info[j].class_name)
2045       {
2046         int len_class_text = strlen(element_info[j].class_name);
2047
2048         if (len_class_text + 1 < len_effect_text &&
2049             strncmp(sound->token,
2050                     element_info[j].class_name, len_class_text) == 0 &&
2051             sound->token[len_class_text] == '.')
2052         {
2053           int sound_action_value = sound_effect_properties[i];
2054
2055           element_info[j].sound[sound_action_value] = i;
2056         }
2057       }
2058     }
2059
2060     set_sound_parameters(i, sound->parameter);
2061   }
2062
2063   free(sound_effect_properties);
2064 }
2065
2066 static void InitGameModeMusicInfo()
2067 {
2068   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2069   int num_property_mappings = getMusicListPropertyMappingSize();
2070   int default_levelset_music = -1;
2071   int i;
2072
2073   /* set values to -1 to identify later as "uninitialized" values */
2074   for (i = 0; i < MAX_LEVELS; i++)
2075     levelset.music[i] = -1;
2076   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2077     menu.music[i] = -1;
2078
2079   /* initialize gamemode/music mapping from static configuration */
2080   for (i = 0; gamemode_to_music[i].music > -1; i++)
2081   {
2082     int gamemode = gamemode_to_music[i].gamemode;
2083     int music    = gamemode_to_music[i].music;
2084
2085     if (gamemode < 0)
2086       gamemode = GAME_MODE_DEFAULT;
2087
2088     menu.music[gamemode] = music;
2089   }
2090
2091   /* initialize gamemode/music mapping from dynamic configuration */
2092   for (i = 0; i < num_property_mappings; i++)
2093   {
2094     int prefix   = property_mapping[i].base_index;
2095     int gamemode = property_mapping[i].ext2_index;
2096     int level    = property_mapping[i].ext3_index;
2097     int music    = property_mapping[i].artwork_index;
2098
2099     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2100       continue;
2101
2102     if (gamemode < 0)
2103       gamemode = GAME_MODE_DEFAULT;
2104
2105     /* level specific music only allowed for in-game music */
2106     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2107       gamemode = GAME_MODE_PLAYING;
2108
2109     if (level == -1)
2110     {
2111       level = 0;
2112       default_levelset_music = music;
2113     }
2114
2115     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2116       levelset.music[level] = music;
2117     if (gamemode != GAME_MODE_PLAYING)
2118       menu.music[gamemode] = music;
2119   }
2120
2121   /* now set all '-1' values to menu specific default values */
2122   /* (undefined values of "levelset.music[]" might stay at "-1" to
2123      allow dynamic selection of music files from music directory!) */
2124   for (i = 0; i < MAX_LEVELS; i++)
2125     if (levelset.music[i] == -1)
2126       levelset.music[i] = default_levelset_music;
2127   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2128     if (menu.music[i] == -1)
2129       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2130 }
2131
2132 static void set_music_parameters(int music, char **parameter_raw)
2133 {
2134   int parameter[NUM_MUS_ARGS];
2135   int i;
2136
2137   /* get integer values from string parameters */
2138   for (i = 0; i < NUM_MUS_ARGS; i++)
2139     parameter[i] =
2140       get_parameter_value(parameter_raw[i],
2141                           music_config_suffix[i].token,
2142                           music_config_suffix[i].type);
2143
2144   /* explicit loop mode setting in configuration overrides default value */
2145   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2146     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2147 }
2148
2149 static void InitMusicInfo()
2150 {
2151   int num_music = getMusicListSize();
2152   int i, j;
2153
2154   checked_free(music_info);
2155
2156   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2157
2158   for (i = 0; i < num_music; i++)
2159   {
2160     struct FileInfo *music = getMusicListEntry(i);
2161     int len_music_text = strlen(music->token);
2162
2163     music_info[i].loop = TRUE;          /* default: play music in loop mode */
2164
2165     /* determine all loop music */
2166
2167     for (j = 0; music_prefix_info[j].prefix; j++)
2168     {
2169       int len_prefix_text = strlen(music_prefix_info[j].prefix);
2170
2171       if (len_prefix_text < len_music_text &&
2172           strncmp(music->token,
2173                   music_prefix_info[j].prefix, len_prefix_text) == 0)
2174       {
2175         music_info[i].loop = music_prefix_info[j].is_loop_music;
2176
2177         break;
2178       }
2179     }
2180
2181     set_music_parameters(i, music->parameter);
2182   }
2183 }
2184
2185 static void ReinitializeGraphics()
2186 {
2187   print_timestamp_init("ReinitializeGraphics");
2188
2189   InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2190
2191   InitGraphicInfo();                    /* graphic properties mapping */
2192   print_timestamp_time("InitGraphicInfo");
2193   InitElementGraphicInfo();             /* element game graphic mapping */
2194   print_timestamp_time("InitElementGraphicInfo");
2195   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
2196   print_timestamp_time("InitElementSpecialGraphicInfo");
2197
2198   InitElementSmallImages();             /* scale elements to all needed sizes */
2199   print_timestamp_time("InitElementSmallImages");
2200   InitScaledImages();                   /* scale all other images, if needed */
2201   print_timestamp_time("InitScaledImages");
2202   InitBitmapPointers();                 /* set standard size bitmap pointers */
2203   print_timestamp_time("InitBitmapPointers");
2204   InitFontGraphicInfo();                /* initialize text drawing functions */
2205   print_timestamp_time("InitFontGraphicInfo");
2206   InitGlobalAnimGraphicInfo();          /* initialize global animation config */
2207   print_timestamp_time("InitGlobalAnimGraphicInfo");
2208
2209   InitImageTextures();                  /* create textures for certain images */
2210   print_timestamp_time("InitImageTextures");
2211
2212   InitGraphicInfo_EM();                 /* graphic mapping for EM engine */
2213   print_timestamp_time("InitGraphicInfo_EM");
2214
2215   InitGraphicCompatibilityInfo();
2216   print_timestamp_time("InitGraphicCompatibilityInfo");
2217
2218   SetMainBackgroundImage(IMG_BACKGROUND);
2219   print_timestamp_time("SetMainBackgroundImage");
2220   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2221   print_timestamp_time("SetDoorBackgroundImage");
2222
2223   InitGadgets();
2224   print_timestamp_time("InitGadgets");
2225   InitDoors();
2226   print_timestamp_time("InitDoors");
2227
2228   print_timestamp_done("ReinitializeGraphics");
2229 }
2230
2231 static void ReinitializeSounds()
2232 {
2233   InitSoundInfo();              /* sound properties mapping */
2234   InitElementSoundInfo();       /* element game sound mapping */
2235   InitGameModeSoundInfo();      /* game mode sound mapping */
2236   InitGlobalAnimSoundInfo();    /* global animation sound settings */
2237
2238   InitPlayLevelSound();         /* internal game sound settings */
2239 }
2240
2241 static void ReinitializeMusic()
2242 {
2243   InitMusicInfo();              /* music properties mapping */
2244   InitGameModeMusicInfo();      /* game mode music mapping */
2245   InitGlobalAnimMusicInfo();    /* global animation music settings */
2246 }
2247
2248 static int get_special_property_bit(int element, int property_bit_nr)
2249 {
2250   struct PropertyBitInfo
2251   {
2252     int element;
2253     int bit_nr;
2254   };
2255
2256   static struct PropertyBitInfo pb_can_move_into_acid[] =
2257   {
2258     /* the player may be able fall into acid when gravity is activated */
2259     { EL_PLAYER_1,              0       },
2260     { EL_PLAYER_2,              0       },
2261     { EL_PLAYER_3,              0       },
2262     { EL_PLAYER_4,              0       },
2263     { EL_SP_MURPHY,             0       },
2264     { EL_SOKOBAN_FIELD_PLAYER,  0       },
2265
2266     /* all elements that can move may be able to also move into acid */
2267     { EL_BUG,                   1       },
2268     { EL_BUG_LEFT,              1       },
2269     { EL_BUG_RIGHT,             1       },
2270     { EL_BUG_UP,                1       },
2271     { EL_BUG_DOWN,              1       },
2272     { EL_SPACESHIP,             2       },
2273     { EL_SPACESHIP_LEFT,        2       },
2274     { EL_SPACESHIP_RIGHT,       2       },
2275     { EL_SPACESHIP_UP,          2       },
2276     { EL_SPACESHIP_DOWN,        2       },
2277     { EL_BD_BUTTERFLY,          3       },
2278     { EL_BD_BUTTERFLY_LEFT,     3       },
2279     { EL_BD_BUTTERFLY_RIGHT,    3       },
2280     { EL_BD_BUTTERFLY_UP,       3       },
2281     { EL_BD_BUTTERFLY_DOWN,     3       },
2282     { EL_BD_FIREFLY,            4       },
2283     { EL_BD_FIREFLY_LEFT,       4       },
2284     { EL_BD_FIREFLY_RIGHT,      4       },
2285     { EL_BD_FIREFLY_UP,         4       },
2286     { EL_BD_FIREFLY_DOWN,       4       },
2287     { EL_YAMYAM,                5       },
2288     { EL_YAMYAM_LEFT,           5       },
2289     { EL_YAMYAM_RIGHT,          5       },
2290     { EL_YAMYAM_UP,             5       },
2291     { EL_YAMYAM_DOWN,           5       },
2292     { EL_DARK_YAMYAM,           6       },
2293     { EL_ROBOT,                 7       },
2294     { EL_PACMAN,                8       },
2295     { EL_PACMAN_LEFT,           8       },
2296     { EL_PACMAN_RIGHT,          8       },
2297     { EL_PACMAN_UP,             8       },
2298     { EL_PACMAN_DOWN,           8       },
2299     { EL_MOLE,                  9       },
2300     { EL_MOLE_LEFT,             9       },
2301     { EL_MOLE_RIGHT,            9       },
2302     { EL_MOLE_UP,               9       },
2303     { EL_MOLE_DOWN,             9       },
2304     { EL_PENGUIN,               10      },
2305     { EL_PIG,                   11      },
2306     { EL_DRAGON,                12      },
2307     { EL_SATELLITE,             13      },
2308     { EL_SP_SNIKSNAK,           14      },
2309     { EL_SP_ELECTRON,           15      },
2310     { EL_BALLOON,               16      },
2311     { EL_SPRING,                17      },
2312     { EL_EMC_ANDROID,           18      },
2313
2314     { -1,                       -1      },
2315   };
2316
2317   static struct PropertyBitInfo pb_dont_collide_with[] =
2318   {
2319     { EL_SP_SNIKSNAK,           0       },
2320     { EL_SP_ELECTRON,           1       },
2321
2322     { -1,                       -1      },
2323   };
2324
2325   static struct
2326   {
2327     int bit_nr;
2328     struct PropertyBitInfo *pb_info;
2329   } pb_definition[] =
2330   {
2331     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
2332     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
2333
2334     { -1,                       NULL                    },
2335   };
2336
2337   struct PropertyBitInfo *pb_info = NULL;
2338   int i;
2339
2340   for (i = 0; pb_definition[i].bit_nr != -1; i++)
2341     if (pb_definition[i].bit_nr == property_bit_nr)
2342       pb_info = pb_definition[i].pb_info;
2343
2344   if (pb_info == NULL)
2345     return -1;
2346
2347   for (i = 0; pb_info[i].element != -1; i++)
2348     if (pb_info[i].element == element)
2349       return pb_info[i].bit_nr;
2350
2351   return -1;
2352 }
2353
2354 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2355                          boolean property_value)
2356 {
2357   int bit_nr = get_special_property_bit(element, property_bit_nr);
2358
2359   if (bit_nr > -1)
2360   {
2361     if (property_value)
2362       *bitfield |=  (1 << bit_nr);
2363     else
2364       *bitfield &= ~(1 << bit_nr);
2365   }
2366 }
2367
2368 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2369 {
2370   int bit_nr = get_special_property_bit(element, property_bit_nr);
2371
2372   if (bit_nr > -1)
2373     return ((*bitfield & (1 << bit_nr)) != 0);
2374
2375   return FALSE;
2376 }
2377
2378 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2379 {
2380   static int group_nr;
2381   static struct ElementGroupInfo *group;
2382   struct ElementGroupInfo *actual_group = element_info[group_element].group;
2383   int i;
2384
2385   if (actual_group == NULL)                     /* not yet initialized */
2386     return;
2387
2388   if (recursion_depth > NUM_GROUP_ELEMENTS)     /* recursion too deep */
2389   {
2390     Error(ERR_WARN, "recursion too deep when resolving group element %d",
2391           group_element - EL_GROUP_START + 1);
2392
2393     /* replace element which caused too deep recursion by question mark */
2394     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2395
2396     return;
2397   }
2398
2399   if (recursion_depth == 0)                     /* initialization */
2400   {
2401     group = actual_group;
2402     group_nr = GROUP_NR(group_element);
2403
2404     group->num_elements_resolved = 0;
2405     group->choice_pos = 0;
2406
2407     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2408       element_info[i].in_group[group_nr] = FALSE;
2409   }
2410
2411   for (i = 0; i < actual_group->num_elements; i++)
2412   {
2413     int element = actual_group->element[i];
2414
2415     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2416       break;
2417
2418     if (IS_GROUP_ELEMENT(element))
2419       ResolveGroupElementExt(element, recursion_depth + 1);
2420     else
2421     {
2422       group->element_resolved[group->num_elements_resolved++] = element;
2423       element_info[element].in_group[group_nr] = TRUE;
2424     }
2425   }
2426 }
2427
2428 void ResolveGroupElement(int group_element)
2429 {
2430   ResolveGroupElementExt(group_element, 0);
2431 }
2432
2433 void InitElementPropertiesStatic()
2434 {
2435   static boolean clipboard_elements_initialized = FALSE;
2436
2437   static int ep_diggable[] =
2438   {
2439     EL_SAND,
2440     EL_SP_BASE,
2441     EL_SP_BUGGY_BASE,
2442     EL_SP_BUGGY_BASE_ACTIVATING,
2443     EL_TRAP,
2444     EL_INVISIBLE_SAND,
2445     EL_INVISIBLE_SAND_ACTIVE,
2446     EL_EMC_GRASS,
2447
2448     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2449     /* (if amoeba can grow into anything diggable, maybe keep these out) */
2450 #if 0
2451     EL_LANDMINE,
2452     EL_DC_LANDMINE,
2453     EL_TRAP_ACTIVE,
2454     EL_SP_BUGGY_BASE_ACTIVE,
2455     EL_EMC_PLANT,
2456 #endif
2457
2458     -1
2459   };
2460
2461   static int ep_collectible_only[] =
2462   {
2463     EL_BD_DIAMOND,
2464     EL_EMERALD,
2465     EL_DIAMOND,
2466     EL_EMERALD_YELLOW,
2467     EL_EMERALD_RED,
2468     EL_EMERALD_PURPLE,
2469     EL_KEY_1,
2470     EL_KEY_2,
2471     EL_KEY_3,
2472     EL_KEY_4,
2473     EL_EM_KEY_1,
2474     EL_EM_KEY_2,
2475     EL_EM_KEY_3,
2476     EL_EM_KEY_4,
2477     EL_EMC_KEY_5,
2478     EL_EMC_KEY_6,
2479     EL_EMC_KEY_7,
2480     EL_EMC_KEY_8,
2481     EL_DYNAMITE,
2482     EL_EM_DYNAMITE,
2483     EL_DYNABOMB_INCREASE_NUMBER,
2484     EL_DYNABOMB_INCREASE_SIZE,
2485     EL_DYNABOMB_INCREASE_POWER,
2486     EL_SP_INFOTRON,
2487     EL_SP_DISK_RED,
2488     EL_PEARL,
2489     EL_CRYSTAL,
2490     EL_DC_KEY_WHITE,
2491     EL_SHIELD_NORMAL,
2492     EL_SHIELD_DEADLY,
2493     EL_EXTRA_TIME,
2494     EL_ENVELOPE_1,
2495     EL_ENVELOPE_2,
2496     EL_ENVELOPE_3,
2497     EL_ENVELOPE_4,
2498     EL_SPEED_PILL,
2499     EL_EMC_LENSES,
2500     EL_EMC_MAGNIFIER,
2501
2502 #if 0
2503     /* !!! handle separately !!! */
2504     EL_DC_LANDMINE,     /* deadly when running into, but can be snapped */
2505 #endif
2506
2507     -1
2508   };
2509
2510   static int ep_dont_run_into[] =
2511   {
2512     /* same elements as in 'ep_dont_touch' */
2513     EL_BUG,
2514     EL_SPACESHIP,
2515     EL_BD_BUTTERFLY,
2516     EL_BD_FIREFLY,
2517
2518     /* same elements as in 'ep_dont_collide_with' */
2519     EL_YAMYAM,
2520     EL_DARK_YAMYAM,
2521     EL_ROBOT,
2522     EL_PACMAN,
2523     EL_SP_SNIKSNAK,
2524     EL_SP_ELECTRON,
2525
2526     /* new elements */
2527     EL_AMOEBA_DROP,
2528     EL_ACID,
2529
2530     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2531 #if 1
2532     EL_LANDMINE,
2533     EL_DC_LANDMINE,
2534     EL_TRAP_ACTIVE,
2535     EL_SP_BUGGY_BASE_ACTIVE,
2536     EL_EMC_PLANT,
2537 #endif
2538
2539     -1
2540   };
2541
2542   static int ep_dont_collide_with[] =
2543   {
2544     /* same elements as in 'ep_dont_touch' */
2545     EL_BUG,
2546     EL_SPACESHIP,
2547     EL_BD_BUTTERFLY,
2548     EL_BD_FIREFLY,
2549
2550     /* new elements */
2551     EL_YAMYAM,
2552     EL_DARK_YAMYAM,
2553     EL_ROBOT,
2554     EL_PACMAN,
2555     EL_SP_SNIKSNAK,
2556     EL_SP_ELECTRON,
2557
2558     -1
2559   };
2560
2561   static int ep_dont_touch[] =
2562   {
2563     EL_BUG,
2564     EL_SPACESHIP,
2565     EL_BD_BUTTERFLY,
2566     EL_BD_FIREFLY,
2567
2568     -1
2569   };
2570
2571   static int ep_indestructible[] =
2572   {
2573     EL_STEELWALL,
2574     EL_ACID,
2575     EL_ACID_POOL_TOPLEFT,
2576     EL_ACID_POOL_TOPRIGHT,
2577     EL_ACID_POOL_BOTTOMLEFT,
2578     EL_ACID_POOL_BOTTOM,
2579     EL_ACID_POOL_BOTTOMRIGHT,
2580     EL_SP_HARDWARE_GRAY,
2581     EL_SP_HARDWARE_GREEN,
2582     EL_SP_HARDWARE_BLUE,
2583     EL_SP_HARDWARE_RED,
2584     EL_SP_HARDWARE_YELLOW,
2585     EL_SP_HARDWARE_BASE_1,
2586     EL_SP_HARDWARE_BASE_2,
2587     EL_SP_HARDWARE_BASE_3,
2588     EL_SP_HARDWARE_BASE_4,
2589     EL_SP_HARDWARE_BASE_5,
2590     EL_SP_HARDWARE_BASE_6,
2591     EL_INVISIBLE_STEELWALL,
2592     EL_INVISIBLE_STEELWALL_ACTIVE,
2593     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2594     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2595     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2596     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2597     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2598     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2599     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2600     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2601     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2602     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2603     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2604     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2605     EL_LIGHT_SWITCH,
2606     EL_LIGHT_SWITCH_ACTIVE,
2607     EL_SIGN_EXCLAMATION,
2608     EL_SIGN_RADIOACTIVITY,
2609     EL_SIGN_STOP,
2610     EL_SIGN_WHEELCHAIR,
2611     EL_SIGN_PARKING,
2612     EL_SIGN_NO_ENTRY,
2613     EL_SIGN_UNUSED_1,
2614     EL_SIGN_GIVE_WAY,
2615     EL_SIGN_ENTRY_FORBIDDEN,
2616     EL_SIGN_EMERGENCY_EXIT,
2617     EL_SIGN_YIN_YANG,
2618     EL_SIGN_UNUSED_2,
2619     EL_SIGN_SPERMS,
2620     EL_SIGN_BULLET,
2621     EL_SIGN_HEART,
2622     EL_SIGN_CROSS,
2623     EL_SIGN_FRANKIE,
2624     EL_STEEL_EXIT_CLOSED,
2625     EL_STEEL_EXIT_OPEN,
2626     EL_STEEL_EXIT_OPENING,
2627     EL_STEEL_EXIT_CLOSING,
2628     EL_EM_STEEL_EXIT_CLOSED,
2629     EL_EM_STEEL_EXIT_OPEN,
2630     EL_EM_STEEL_EXIT_OPENING,
2631     EL_EM_STEEL_EXIT_CLOSING,
2632     EL_DC_STEELWALL_1_LEFT,
2633     EL_DC_STEELWALL_1_RIGHT,
2634     EL_DC_STEELWALL_1_TOP,
2635     EL_DC_STEELWALL_1_BOTTOM,
2636     EL_DC_STEELWALL_1_HORIZONTAL,
2637     EL_DC_STEELWALL_1_VERTICAL,
2638     EL_DC_STEELWALL_1_TOPLEFT,
2639     EL_DC_STEELWALL_1_TOPRIGHT,
2640     EL_DC_STEELWALL_1_BOTTOMLEFT,
2641     EL_DC_STEELWALL_1_BOTTOMRIGHT,
2642     EL_DC_STEELWALL_1_TOPLEFT_2,
2643     EL_DC_STEELWALL_1_TOPRIGHT_2,
2644     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2645     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2646     EL_DC_STEELWALL_2_LEFT,
2647     EL_DC_STEELWALL_2_RIGHT,
2648     EL_DC_STEELWALL_2_TOP,
2649     EL_DC_STEELWALL_2_BOTTOM,
2650     EL_DC_STEELWALL_2_HORIZONTAL,
2651     EL_DC_STEELWALL_2_VERTICAL,
2652     EL_DC_STEELWALL_2_MIDDLE,
2653     EL_DC_STEELWALL_2_SINGLE,
2654     EL_STEELWALL_SLIPPERY,
2655     EL_EMC_STEELWALL_1,
2656     EL_EMC_STEELWALL_2,
2657     EL_EMC_STEELWALL_3,
2658     EL_EMC_STEELWALL_4,
2659     EL_CRYSTAL,
2660     EL_GATE_1,
2661     EL_GATE_2,
2662     EL_GATE_3,
2663     EL_GATE_4,
2664     EL_GATE_1_GRAY,
2665     EL_GATE_2_GRAY,
2666     EL_GATE_3_GRAY,
2667     EL_GATE_4_GRAY,
2668     EL_GATE_1_GRAY_ACTIVE,
2669     EL_GATE_2_GRAY_ACTIVE,
2670     EL_GATE_3_GRAY_ACTIVE,
2671     EL_GATE_4_GRAY_ACTIVE,
2672     EL_EM_GATE_1,
2673     EL_EM_GATE_2,
2674     EL_EM_GATE_3,
2675     EL_EM_GATE_4,
2676     EL_EM_GATE_1_GRAY,
2677     EL_EM_GATE_2_GRAY,
2678     EL_EM_GATE_3_GRAY,
2679     EL_EM_GATE_4_GRAY,
2680     EL_EM_GATE_1_GRAY_ACTIVE,
2681     EL_EM_GATE_2_GRAY_ACTIVE,
2682     EL_EM_GATE_3_GRAY_ACTIVE,
2683     EL_EM_GATE_4_GRAY_ACTIVE,
2684     EL_EMC_GATE_5,
2685     EL_EMC_GATE_6,
2686     EL_EMC_GATE_7,
2687     EL_EMC_GATE_8,
2688     EL_EMC_GATE_5_GRAY,
2689     EL_EMC_GATE_6_GRAY,
2690     EL_EMC_GATE_7_GRAY,
2691     EL_EMC_GATE_8_GRAY,
2692     EL_EMC_GATE_5_GRAY_ACTIVE,
2693     EL_EMC_GATE_6_GRAY_ACTIVE,
2694     EL_EMC_GATE_7_GRAY_ACTIVE,
2695     EL_EMC_GATE_8_GRAY_ACTIVE,
2696     EL_DC_GATE_WHITE,
2697     EL_DC_GATE_WHITE_GRAY,
2698     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2699     EL_DC_GATE_FAKE_GRAY,
2700     EL_SWITCHGATE_OPEN,
2701     EL_SWITCHGATE_OPENING,
2702     EL_SWITCHGATE_CLOSED,
2703     EL_SWITCHGATE_CLOSING,
2704     EL_DC_SWITCHGATE_SWITCH_UP,
2705     EL_DC_SWITCHGATE_SWITCH_DOWN,
2706     EL_TIMEGATE_OPEN,
2707     EL_TIMEGATE_OPENING,
2708     EL_TIMEGATE_CLOSED,
2709     EL_TIMEGATE_CLOSING,
2710     EL_DC_TIMEGATE_SWITCH,
2711     EL_DC_TIMEGATE_SWITCH_ACTIVE,
2712     EL_TUBE_ANY,
2713     EL_TUBE_VERTICAL,
2714     EL_TUBE_HORIZONTAL,
2715     EL_TUBE_VERTICAL_LEFT,
2716     EL_TUBE_VERTICAL_RIGHT,
2717     EL_TUBE_HORIZONTAL_UP,
2718     EL_TUBE_HORIZONTAL_DOWN,
2719     EL_TUBE_LEFT_UP,
2720     EL_TUBE_LEFT_DOWN,
2721     EL_TUBE_RIGHT_UP,
2722     EL_TUBE_RIGHT_DOWN,
2723     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2724     EL_EXPANDABLE_STEELWALL_VERTICAL,
2725     EL_EXPANDABLE_STEELWALL_ANY,
2726
2727     -1
2728   };
2729
2730   static int ep_slippery[] =
2731   {
2732     EL_WALL_SLIPPERY,
2733     EL_BD_WALL,
2734     EL_ROCK,
2735     EL_BD_ROCK,
2736     EL_EMERALD,
2737     EL_BD_DIAMOND,
2738     EL_EMERALD_YELLOW,
2739     EL_EMERALD_RED,
2740     EL_EMERALD_PURPLE,
2741     EL_DIAMOND,
2742     EL_BOMB,
2743     EL_NUT,
2744     EL_ROBOT_WHEEL_ACTIVE,
2745     EL_ROBOT_WHEEL,
2746     EL_TIME_ORB_FULL,
2747     EL_TIME_ORB_EMPTY,
2748     EL_LAMP_ACTIVE,
2749     EL_LAMP,
2750     EL_ACID_POOL_TOPLEFT,
2751     EL_ACID_POOL_TOPRIGHT,
2752     EL_SATELLITE,
2753     EL_SP_ZONK,
2754     EL_SP_INFOTRON,
2755     EL_SP_CHIP_SINGLE,
2756     EL_SP_CHIP_LEFT,
2757     EL_SP_CHIP_RIGHT,
2758     EL_SP_CHIP_TOP,
2759     EL_SP_CHIP_BOTTOM,
2760     EL_SPEED_PILL,
2761     EL_STEELWALL_SLIPPERY,
2762     EL_PEARL,
2763     EL_CRYSTAL,
2764     EL_EMC_WALL_SLIPPERY_1,
2765     EL_EMC_WALL_SLIPPERY_2,
2766     EL_EMC_WALL_SLIPPERY_3,
2767     EL_EMC_WALL_SLIPPERY_4,
2768     EL_EMC_MAGIC_BALL,
2769     EL_EMC_MAGIC_BALL_ACTIVE,
2770
2771     -1
2772   };
2773
2774   static int ep_can_change[] =
2775   {
2776     -1
2777   };
2778
2779   static int ep_can_move[] =
2780   {
2781     /* same elements as in 'pb_can_move_into_acid' */
2782     EL_BUG,
2783     EL_SPACESHIP,
2784     EL_BD_BUTTERFLY,
2785     EL_BD_FIREFLY,
2786     EL_YAMYAM,
2787     EL_DARK_YAMYAM,
2788     EL_ROBOT,
2789     EL_PACMAN,
2790     EL_MOLE,
2791     EL_PENGUIN,
2792     EL_PIG,
2793     EL_DRAGON,
2794     EL_SATELLITE,
2795     EL_SP_SNIKSNAK,
2796     EL_SP_ELECTRON,
2797     EL_BALLOON,
2798     EL_SPRING,
2799     EL_EMC_ANDROID,
2800
2801     -1
2802   };
2803
2804   static int ep_can_fall[] =
2805   {
2806     EL_ROCK,
2807     EL_BD_ROCK,
2808     EL_EMERALD,
2809     EL_BD_DIAMOND,
2810     EL_EMERALD_YELLOW,
2811     EL_EMERALD_RED,
2812     EL_EMERALD_PURPLE,
2813     EL_DIAMOND,
2814     EL_BOMB,
2815     EL_NUT,
2816     EL_AMOEBA_DROP,
2817     EL_QUICKSAND_FULL,
2818     EL_QUICKSAND_FAST_FULL,
2819     EL_MAGIC_WALL_FULL,
2820     EL_BD_MAGIC_WALL_FULL,
2821     EL_DC_MAGIC_WALL_FULL,
2822     EL_TIME_ORB_FULL,
2823     EL_TIME_ORB_EMPTY,
2824     EL_SP_ZONK,
2825     EL_SP_INFOTRON,
2826     EL_SP_DISK_ORANGE,
2827     EL_PEARL,
2828     EL_CRYSTAL,
2829     EL_SPRING,
2830     EL_DX_SUPABOMB,
2831
2832     -1
2833   };
2834
2835   static int ep_can_smash_player[] =
2836   {
2837     EL_ROCK,
2838     EL_BD_ROCK,
2839     EL_EMERALD,
2840     EL_BD_DIAMOND,
2841     EL_EMERALD_YELLOW,
2842     EL_EMERALD_RED,
2843     EL_EMERALD_PURPLE,
2844     EL_DIAMOND,
2845     EL_BOMB,
2846     EL_NUT,
2847     EL_AMOEBA_DROP,
2848     EL_TIME_ORB_FULL,
2849     EL_TIME_ORB_EMPTY,
2850     EL_SP_ZONK,
2851     EL_SP_INFOTRON,
2852     EL_SP_DISK_ORANGE,
2853     EL_PEARL,
2854     EL_CRYSTAL,
2855     EL_SPRING,
2856     EL_DX_SUPABOMB,
2857
2858     -1
2859   };
2860
2861   static int ep_can_smash_enemies[] =
2862   {
2863     EL_ROCK,
2864     EL_BD_ROCK,
2865     EL_SP_ZONK,
2866
2867     -1
2868   };
2869
2870   static int ep_can_smash_everything[] =
2871   {
2872     EL_ROCK,
2873     EL_BD_ROCK,
2874     EL_SP_ZONK,
2875
2876     -1
2877   };
2878
2879   static int ep_explodes_by_fire[] =
2880   {
2881     /* same elements as in 'ep_explodes_impact' */
2882     EL_BOMB,
2883     EL_SP_DISK_ORANGE,
2884     EL_DX_SUPABOMB,
2885
2886     /* same elements as in 'ep_explodes_smashed' */
2887     EL_SATELLITE,
2888     EL_PIG,
2889     EL_DRAGON,
2890     EL_MOLE,
2891
2892     /* new elements */
2893     EL_DYNAMITE,
2894     EL_DYNAMITE_ACTIVE,
2895     EL_EM_DYNAMITE,
2896     EL_EM_DYNAMITE_ACTIVE,
2897     EL_DYNABOMB_PLAYER_1_ACTIVE,
2898     EL_DYNABOMB_PLAYER_2_ACTIVE,
2899     EL_DYNABOMB_PLAYER_3_ACTIVE,
2900     EL_DYNABOMB_PLAYER_4_ACTIVE,
2901     EL_DYNABOMB_INCREASE_NUMBER,
2902     EL_DYNABOMB_INCREASE_SIZE,
2903     EL_DYNABOMB_INCREASE_POWER,
2904     EL_SP_DISK_RED_ACTIVE,
2905     EL_BUG,
2906     EL_PENGUIN,
2907     EL_SP_DISK_RED,
2908     EL_SP_DISK_YELLOW,
2909     EL_SP_SNIKSNAK,
2910     EL_SP_ELECTRON,
2911 #if 0
2912     EL_BLACK_ORB,
2913 #endif
2914
2915     -1
2916   };
2917
2918   static int ep_explodes_smashed[] =
2919   {
2920     /* same elements as in 'ep_explodes_impact' */
2921     EL_BOMB,
2922     EL_SP_DISK_ORANGE,
2923     EL_DX_SUPABOMB,
2924
2925     /* new elements */
2926     EL_SATELLITE,
2927     EL_PIG,
2928     EL_DRAGON,
2929     EL_MOLE,
2930
2931     -1
2932   };
2933
2934   static int ep_explodes_impact[] =
2935   {
2936     EL_BOMB,
2937     EL_SP_DISK_ORANGE,
2938     EL_DX_SUPABOMB,
2939
2940     -1
2941   };
2942
2943   static int ep_walkable_over[] =
2944   {
2945     EL_EMPTY_SPACE,
2946     EL_SP_EMPTY_SPACE,
2947     EL_SOKOBAN_FIELD_EMPTY,
2948     EL_EXIT_OPEN,
2949     EL_EM_EXIT_OPEN,
2950     EL_EM_EXIT_OPENING,
2951     EL_SP_EXIT_OPEN,
2952     EL_SP_EXIT_OPENING,
2953     EL_STEEL_EXIT_OPEN,
2954     EL_EM_STEEL_EXIT_OPEN,
2955     EL_EM_STEEL_EXIT_OPENING,
2956     EL_GATE_1,
2957     EL_GATE_2,
2958     EL_GATE_3,
2959     EL_GATE_4,
2960     EL_GATE_1_GRAY,
2961     EL_GATE_2_GRAY,
2962     EL_GATE_3_GRAY,
2963     EL_GATE_4_GRAY,
2964     EL_GATE_1_GRAY_ACTIVE,
2965     EL_GATE_2_GRAY_ACTIVE,
2966     EL_GATE_3_GRAY_ACTIVE,
2967     EL_GATE_4_GRAY_ACTIVE,
2968     EL_PENGUIN,
2969     EL_PIG,
2970     EL_DRAGON,
2971
2972     -1
2973   };
2974
2975   static int ep_walkable_inside[] =
2976   {
2977     EL_TUBE_ANY,
2978     EL_TUBE_VERTICAL,
2979     EL_TUBE_HORIZONTAL,
2980     EL_TUBE_VERTICAL_LEFT,
2981     EL_TUBE_VERTICAL_RIGHT,
2982     EL_TUBE_HORIZONTAL_UP,
2983     EL_TUBE_HORIZONTAL_DOWN,
2984     EL_TUBE_LEFT_UP,
2985     EL_TUBE_LEFT_DOWN,
2986     EL_TUBE_RIGHT_UP,
2987     EL_TUBE_RIGHT_DOWN,
2988
2989     -1
2990   };
2991
2992   static int ep_walkable_under[] =
2993   {
2994     -1
2995   };
2996
2997   static int ep_passable_over[] =
2998   {
2999     EL_EM_GATE_1,
3000     EL_EM_GATE_2,
3001     EL_EM_GATE_3,
3002     EL_EM_GATE_4,
3003     EL_EM_GATE_1_GRAY,
3004     EL_EM_GATE_2_GRAY,
3005     EL_EM_GATE_3_GRAY,
3006     EL_EM_GATE_4_GRAY,
3007     EL_EM_GATE_1_GRAY_ACTIVE,
3008     EL_EM_GATE_2_GRAY_ACTIVE,
3009     EL_EM_GATE_3_GRAY_ACTIVE,
3010     EL_EM_GATE_4_GRAY_ACTIVE,
3011     EL_EMC_GATE_5,
3012     EL_EMC_GATE_6,
3013     EL_EMC_GATE_7,
3014     EL_EMC_GATE_8,
3015     EL_EMC_GATE_5_GRAY,
3016     EL_EMC_GATE_6_GRAY,
3017     EL_EMC_GATE_7_GRAY,
3018     EL_EMC_GATE_8_GRAY,
3019     EL_EMC_GATE_5_GRAY_ACTIVE,
3020     EL_EMC_GATE_6_GRAY_ACTIVE,
3021     EL_EMC_GATE_7_GRAY_ACTIVE,
3022     EL_EMC_GATE_8_GRAY_ACTIVE,
3023     EL_DC_GATE_WHITE,
3024     EL_DC_GATE_WHITE_GRAY,
3025     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3026     EL_SWITCHGATE_OPEN,
3027     EL_TIMEGATE_OPEN,
3028
3029     -1
3030   };
3031
3032   static int ep_passable_inside[] =
3033   {
3034     EL_SP_PORT_LEFT,
3035     EL_SP_PORT_RIGHT,
3036     EL_SP_PORT_UP,
3037     EL_SP_PORT_DOWN,
3038     EL_SP_PORT_HORIZONTAL,
3039     EL_SP_PORT_VERTICAL,
3040     EL_SP_PORT_ANY,
3041     EL_SP_GRAVITY_PORT_LEFT,
3042     EL_SP_GRAVITY_PORT_RIGHT,
3043     EL_SP_GRAVITY_PORT_UP,
3044     EL_SP_GRAVITY_PORT_DOWN,
3045     EL_SP_GRAVITY_ON_PORT_LEFT,
3046     EL_SP_GRAVITY_ON_PORT_RIGHT,
3047     EL_SP_GRAVITY_ON_PORT_UP,
3048     EL_SP_GRAVITY_ON_PORT_DOWN,
3049     EL_SP_GRAVITY_OFF_PORT_LEFT,
3050     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3051     EL_SP_GRAVITY_OFF_PORT_UP,
3052     EL_SP_GRAVITY_OFF_PORT_DOWN,
3053
3054     -1
3055   };
3056
3057   static int ep_passable_under[] =
3058   {
3059     -1
3060   };
3061
3062   static int ep_droppable[] =
3063   {
3064     -1
3065   };
3066
3067   static int ep_explodes_1x1_old[] =
3068   {
3069     -1
3070   };
3071
3072   static int ep_pushable[] =
3073   {
3074     EL_ROCK,
3075     EL_BOMB,
3076     EL_DX_SUPABOMB,
3077     EL_NUT,
3078     EL_TIME_ORB_EMPTY,
3079     EL_SP_ZONK,
3080     EL_SP_DISK_ORANGE,
3081     EL_SPRING,
3082     EL_BD_ROCK,
3083     EL_SOKOBAN_OBJECT,
3084     EL_SOKOBAN_FIELD_FULL,
3085     EL_SATELLITE,
3086     EL_SP_DISK_YELLOW,
3087     EL_BALLOON,
3088     EL_EMC_ANDROID,
3089
3090     -1
3091   };
3092
3093   static int ep_explodes_cross_old[] =
3094   {
3095     -1
3096   };
3097
3098   static int ep_protected[] =
3099   {
3100     /* same elements as in 'ep_walkable_inside' */
3101     EL_TUBE_ANY,
3102     EL_TUBE_VERTICAL,
3103     EL_TUBE_HORIZONTAL,
3104     EL_TUBE_VERTICAL_LEFT,
3105     EL_TUBE_VERTICAL_RIGHT,
3106     EL_TUBE_HORIZONTAL_UP,
3107     EL_TUBE_HORIZONTAL_DOWN,
3108     EL_TUBE_LEFT_UP,
3109     EL_TUBE_LEFT_DOWN,
3110     EL_TUBE_RIGHT_UP,
3111     EL_TUBE_RIGHT_DOWN,
3112
3113     /* same elements as in 'ep_passable_over' */
3114     EL_EM_GATE_1,
3115     EL_EM_GATE_2,
3116     EL_EM_GATE_3,
3117     EL_EM_GATE_4,
3118     EL_EM_GATE_1_GRAY,
3119     EL_EM_GATE_2_GRAY,
3120     EL_EM_GATE_3_GRAY,
3121     EL_EM_GATE_4_GRAY,
3122     EL_EM_GATE_1_GRAY_ACTIVE,
3123     EL_EM_GATE_2_GRAY_ACTIVE,
3124     EL_EM_GATE_3_GRAY_ACTIVE,
3125     EL_EM_GATE_4_GRAY_ACTIVE,
3126     EL_EMC_GATE_5,
3127     EL_EMC_GATE_6,
3128     EL_EMC_GATE_7,
3129     EL_EMC_GATE_8,
3130     EL_EMC_GATE_5_GRAY,
3131     EL_EMC_GATE_6_GRAY,
3132     EL_EMC_GATE_7_GRAY,
3133     EL_EMC_GATE_8_GRAY,
3134     EL_EMC_GATE_5_GRAY_ACTIVE,
3135     EL_EMC_GATE_6_GRAY_ACTIVE,
3136     EL_EMC_GATE_7_GRAY_ACTIVE,
3137     EL_EMC_GATE_8_GRAY_ACTIVE,
3138     EL_DC_GATE_WHITE,
3139     EL_DC_GATE_WHITE_GRAY,
3140     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3141     EL_SWITCHGATE_OPEN,
3142     EL_TIMEGATE_OPEN,
3143
3144     /* same elements as in 'ep_passable_inside' */
3145     EL_SP_PORT_LEFT,
3146     EL_SP_PORT_RIGHT,
3147     EL_SP_PORT_UP,
3148     EL_SP_PORT_DOWN,
3149     EL_SP_PORT_HORIZONTAL,
3150     EL_SP_PORT_VERTICAL,
3151     EL_SP_PORT_ANY,
3152     EL_SP_GRAVITY_PORT_LEFT,
3153     EL_SP_GRAVITY_PORT_RIGHT,
3154     EL_SP_GRAVITY_PORT_UP,
3155     EL_SP_GRAVITY_PORT_DOWN,
3156     EL_SP_GRAVITY_ON_PORT_LEFT,
3157     EL_SP_GRAVITY_ON_PORT_RIGHT,
3158     EL_SP_GRAVITY_ON_PORT_UP,
3159     EL_SP_GRAVITY_ON_PORT_DOWN,
3160     EL_SP_GRAVITY_OFF_PORT_LEFT,
3161     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3162     EL_SP_GRAVITY_OFF_PORT_UP,
3163     EL_SP_GRAVITY_OFF_PORT_DOWN,
3164
3165     -1
3166   };
3167
3168   static int ep_throwable[] =
3169   {
3170     -1
3171   };
3172
3173   static int ep_can_explode[] =
3174   {
3175     /* same elements as in 'ep_explodes_impact' */
3176     EL_BOMB,
3177     EL_SP_DISK_ORANGE,
3178     EL_DX_SUPABOMB,
3179
3180     /* same elements as in 'ep_explodes_smashed' */
3181     EL_SATELLITE,
3182     EL_PIG,
3183     EL_DRAGON,
3184     EL_MOLE,
3185
3186     /* elements that can explode by explosion or by dragonfire */
3187     EL_DYNAMITE,
3188     EL_DYNAMITE_ACTIVE,
3189     EL_EM_DYNAMITE,
3190     EL_EM_DYNAMITE_ACTIVE,
3191     EL_DYNABOMB_PLAYER_1_ACTIVE,
3192     EL_DYNABOMB_PLAYER_2_ACTIVE,
3193     EL_DYNABOMB_PLAYER_3_ACTIVE,
3194     EL_DYNABOMB_PLAYER_4_ACTIVE,
3195     EL_DYNABOMB_INCREASE_NUMBER,
3196     EL_DYNABOMB_INCREASE_SIZE,
3197     EL_DYNABOMB_INCREASE_POWER,
3198     EL_SP_DISK_RED_ACTIVE,
3199     EL_BUG,
3200     EL_PENGUIN,
3201     EL_SP_DISK_RED,
3202     EL_SP_DISK_YELLOW,
3203     EL_SP_SNIKSNAK,
3204     EL_SP_ELECTRON,
3205
3206     /* elements that can explode only by explosion */
3207     EL_BLACK_ORB,
3208
3209     -1
3210   };
3211
3212   static int ep_gravity_reachable[] =
3213   {
3214     EL_SAND,
3215     EL_SP_BASE,
3216     EL_TRAP,
3217     EL_INVISIBLE_SAND,
3218     EL_INVISIBLE_SAND_ACTIVE,
3219     EL_SP_PORT_LEFT,
3220     EL_SP_PORT_RIGHT,
3221     EL_SP_PORT_UP,
3222     EL_SP_PORT_DOWN,
3223     EL_SP_PORT_HORIZONTAL,
3224     EL_SP_PORT_VERTICAL,
3225     EL_SP_PORT_ANY,
3226     EL_SP_GRAVITY_PORT_LEFT,
3227     EL_SP_GRAVITY_PORT_RIGHT,
3228     EL_SP_GRAVITY_PORT_UP,
3229     EL_SP_GRAVITY_PORT_DOWN,
3230     EL_SP_GRAVITY_ON_PORT_LEFT,
3231     EL_SP_GRAVITY_ON_PORT_RIGHT,
3232     EL_SP_GRAVITY_ON_PORT_UP,
3233     EL_SP_GRAVITY_ON_PORT_DOWN,
3234     EL_SP_GRAVITY_OFF_PORT_LEFT,
3235     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3236     EL_SP_GRAVITY_OFF_PORT_UP,
3237     EL_SP_GRAVITY_OFF_PORT_DOWN,
3238     EL_EMC_GRASS,
3239
3240     -1
3241   };
3242
3243   static int ep_player[] =
3244   {
3245     EL_PLAYER_1,
3246     EL_PLAYER_2,
3247     EL_PLAYER_3,
3248     EL_PLAYER_4,
3249     EL_SP_MURPHY,
3250     EL_SOKOBAN_FIELD_PLAYER,
3251     EL_TRIGGER_PLAYER,
3252
3253     -1
3254   };
3255
3256   static int ep_can_pass_magic_wall[] =
3257   {
3258     EL_ROCK,
3259     EL_BD_ROCK,
3260     EL_EMERALD,
3261     EL_BD_DIAMOND,
3262     EL_EMERALD_YELLOW,
3263     EL_EMERALD_RED,
3264     EL_EMERALD_PURPLE,
3265     EL_DIAMOND,
3266
3267     -1
3268   };
3269
3270   static int ep_can_pass_dc_magic_wall[] =
3271   {
3272     EL_ROCK,
3273     EL_BD_ROCK,
3274     EL_EMERALD,
3275     EL_BD_DIAMOND,
3276     EL_EMERALD_YELLOW,
3277     EL_EMERALD_RED,
3278     EL_EMERALD_PURPLE,
3279     EL_DIAMOND,
3280     EL_PEARL,
3281     EL_CRYSTAL,
3282
3283     -1
3284   };
3285
3286   static int ep_switchable[] =
3287   {
3288     EL_ROBOT_WHEEL,
3289     EL_SP_TERMINAL,
3290     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3291     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3292     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3293     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3294     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3295     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3296     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3297     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3298     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3299     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3300     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3301     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3302     EL_SWITCHGATE_SWITCH_UP,
3303     EL_SWITCHGATE_SWITCH_DOWN,
3304     EL_DC_SWITCHGATE_SWITCH_UP,
3305     EL_DC_SWITCHGATE_SWITCH_DOWN,
3306     EL_LIGHT_SWITCH,
3307     EL_LIGHT_SWITCH_ACTIVE,
3308     EL_TIMEGATE_SWITCH,
3309     EL_DC_TIMEGATE_SWITCH,
3310     EL_BALLOON_SWITCH_LEFT,
3311     EL_BALLOON_SWITCH_RIGHT,
3312     EL_BALLOON_SWITCH_UP,
3313     EL_BALLOON_SWITCH_DOWN,
3314     EL_BALLOON_SWITCH_ANY,
3315     EL_BALLOON_SWITCH_NONE,
3316     EL_LAMP,
3317     EL_TIME_ORB_FULL,
3318     EL_EMC_MAGIC_BALL_SWITCH,
3319     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3320
3321     -1
3322   };
3323
3324   static int ep_bd_element[] =
3325   {
3326     EL_EMPTY,
3327     EL_SAND,
3328     EL_WALL_SLIPPERY,
3329     EL_BD_WALL,
3330     EL_ROCK,
3331     EL_BD_ROCK,
3332     EL_BD_DIAMOND,
3333     EL_BD_MAGIC_WALL,
3334     EL_EXIT_CLOSED,
3335     EL_EXIT_OPEN,
3336     EL_STEELWALL,
3337     EL_PLAYER_1,
3338     EL_PLAYER_2,
3339     EL_PLAYER_3,
3340     EL_PLAYER_4,
3341     EL_BD_FIREFLY,
3342     EL_BD_FIREFLY_1,
3343     EL_BD_FIREFLY_2,
3344     EL_BD_FIREFLY_3,
3345     EL_BD_FIREFLY_4,
3346     EL_BD_BUTTERFLY,
3347     EL_BD_BUTTERFLY_1,
3348     EL_BD_BUTTERFLY_2,
3349     EL_BD_BUTTERFLY_3,
3350     EL_BD_BUTTERFLY_4,
3351     EL_BD_AMOEBA,
3352     EL_CHAR_QUESTION,
3353     EL_UNKNOWN,
3354
3355     -1
3356   };
3357
3358   static int ep_sp_element[] =
3359   {
3360     /* should always be valid */
3361     EL_EMPTY,
3362
3363     /* standard classic Supaplex elements */
3364     EL_SP_EMPTY,
3365     EL_SP_ZONK,
3366     EL_SP_BASE,
3367     EL_SP_MURPHY,
3368     EL_SP_INFOTRON,
3369     EL_SP_CHIP_SINGLE,
3370     EL_SP_HARDWARE_GRAY,
3371     EL_SP_EXIT_CLOSED,
3372     EL_SP_EXIT_OPEN,
3373     EL_SP_DISK_ORANGE,
3374     EL_SP_PORT_RIGHT,
3375     EL_SP_PORT_DOWN,
3376     EL_SP_PORT_LEFT,
3377     EL_SP_PORT_UP,
3378     EL_SP_GRAVITY_PORT_RIGHT,
3379     EL_SP_GRAVITY_PORT_DOWN,
3380     EL_SP_GRAVITY_PORT_LEFT,
3381     EL_SP_GRAVITY_PORT_UP,
3382     EL_SP_SNIKSNAK,
3383     EL_SP_DISK_YELLOW,
3384     EL_SP_TERMINAL,
3385     EL_SP_DISK_RED,
3386     EL_SP_PORT_VERTICAL,
3387     EL_SP_PORT_HORIZONTAL,
3388     EL_SP_PORT_ANY,
3389     EL_SP_ELECTRON,
3390     EL_SP_BUGGY_BASE,
3391     EL_SP_CHIP_LEFT,
3392     EL_SP_CHIP_RIGHT,
3393     EL_SP_HARDWARE_BASE_1,
3394     EL_SP_HARDWARE_GREEN,
3395     EL_SP_HARDWARE_BLUE,
3396     EL_SP_HARDWARE_RED,
3397     EL_SP_HARDWARE_YELLOW,
3398     EL_SP_HARDWARE_BASE_2,
3399     EL_SP_HARDWARE_BASE_3,
3400     EL_SP_HARDWARE_BASE_4,
3401     EL_SP_HARDWARE_BASE_5,
3402     EL_SP_HARDWARE_BASE_6,
3403     EL_SP_CHIP_TOP,
3404     EL_SP_CHIP_BOTTOM,
3405
3406     /* additional elements that appeared in newer Supaplex levels */
3407     EL_INVISIBLE_WALL,
3408
3409     /* additional gravity port elements (not switching, but setting gravity) */
3410     EL_SP_GRAVITY_ON_PORT_LEFT,
3411     EL_SP_GRAVITY_ON_PORT_RIGHT,
3412     EL_SP_GRAVITY_ON_PORT_UP,
3413     EL_SP_GRAVITY_ON_PORT_DOWN,
3414     EL_SP_GRAVITY_OFF_PORT_LEFT,
3415     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3416     EL_SP_GRAVITY_OFF_PORT_UP,
3417     EL_SP_GRAVITY_OFF_PORT_DOWN,
3418
3419     /* more than one Murphy in a level results in an inactive clone */
3420     EL_SP_MURPHY_CLONE,
3421
3422     /* runtime Supaplex elements */
3423     EL_SP_DISK_RED_ACTIVE,
3424     EL_SP_TERMINAL_ACTIVE,
3425     EL_SP_BUGGY_BASE_ACTIVATING,
3426     EL_SP_BUGGY_BASE_ACTIVE,
3427     EL_SP_EXIT_OPENING,
3428     EL_SP_EXIT_CLOSING,
3429
3430     -1
3431   };
3432
3433   static int ep_sb_element[] =
3434   {
3435     EL_EMPTY,
3436     EL_STEELWALL,
3437     EL_SOKOBAN_OBJECT,
3438     EL_SOKOBAN_FIELD_EMPTY,
3439     EL_SOKOBAN_FIELD_FULL,
3440     EL_SOKOBAN_FIELD_PLAYER,
3441     EL_PLAYER_1,
3442     EL_PLAYER_2,
3443     EL_PLAYER_3,
3444     EL_PLAYER_4,
3445     EL_INVISIBLE_STEELWALL,
3446
3447     -1
3448   };
3449
3450   static int ep_gem[] =
3451   {
3452     EL_BD_DIAMOND,
3453     EL_EMERALD,
3454     EL_EMERALD_YELLOW,
3455     EL_EMERALD_RED,
3456     EL_EMERALD_PURPLE,
3457     EL_DIAMOND,
3458
3459     -1
3460   };
3461
3462   static int ep_food_dark_yamyam[] =
3463   {
3464     EL_SAND,
3465     EL_BUG,
3466     EL_SPACESHIP,
3467     EL_BD_BUTTERFLY,
3468     EL_BD_FIREFLY,
3469     EL_YAMYAM,
3470     EL_ROBOT,
3471     EL_PACMAN,
3472     EL_AMOEBA_DROP,
3473     EL_AMOEBA_DEAD,
3474     EL_AMOEBA_WET,
3475     EL_AMOEBA_DRY,
3476     EL_AMOEBA_FULL,
3477     EL_BD_AMOEBA,
3478     EL_EMERALD,
3479     EL_BD_DIAMOND,
3480     EL_EMERALD_YELLOW,
3481     EL_EMERALD_RED,
3482     EL_EMERALD_PURPLE,
3483     EL_DIAMOND,
3484     EL_PEARL,
3485     EL_CRYSTAL,
3486
3487     -1
3488   };
3489
3490   static int ep_food_penguin[] =
3491   {
3492     EL_EMERALD,
3493     EL_BD_DIAMOND,
3494     EL_EMERALD_YELLOW,
3495     EL_EMERALD_RED,
3496     EL_EMERALD_PURPLE,
3497     EL_DIAMOND,
3498     EL_PEARL,
3499     EL_CRYSTAL,
3500
3501     -1
3502   };
3503
3504   static int ep_food_pig[] =
3505   {
3506     EL_EMERALD,
3507     EL_BD_DIAMOND,
3508     EL_EMERALD_YELLOW,
3509     EL_EMERALD_RED,
3510     EL_EMERALD_PURPLE,
3511     EL_DIAMOND,
3512
3513     -1
3514   };
3515
3516   static int ep_historic_wall[] =
3517   {
3518     EL_STEELWALL,
3519     EL_GATE_1,
3520     EL_GATE_2,
3521     EL_GATE_3,
3522     EL_GATE_4,
3523     EL_GATE_1_GRAY,
3524     EL_GATE_2_GRAY,
3525     EL_GATE_3_GRAY,
3526     EL_GATE_4_GRAY,
3527     EL_GATE_1_GRAY_ACTIVE,
3528     EL_GATE_2_GRAY_ACTIVE,
3529     EL_GATE_3_GRAY_ACTIVE,
3530     EL_GATE_4_GRAY_ACTIVE,
3531     EL_EM_GATE_1,
3532     EL_EM_GATE_2,
3533     EL_EM_GATE_3,
3534     EL_EM_GATE_4,
3535     EL_EM_GATE_1_GRAY,
3536     EL_EM_GATE_2_GRAY,
3537     EL_EM_GATE_3_GRAY,
3538     EL_EM_GATE_4_GRAY,
3539     EL_EM_GATE_1_GRAY_ACTIVE,
3540     EL_EM_GATE_2_GRAY_ACTIVE,
3541     EL_EM_GATE_3_GRAY_ACTIVE,
3542     EL_EM_GATE_4_GRAY_ACTIVE,
3543     EL_EXIT_CLOSED,
3544     EL_EXIT_OPENING,
3545     EL_EXIT_OPEN,
3546     EL_WALL,
3547     EL_WALL_SLIPPERY,
3548     EL_EXPANDABLE_WALL,
3549     EL_EXPANDABLE_WALL_HORIZONTAL,
3550     EL_EXPANDABLE_WALL_VERTICAL,
3551     EL_EXPANDABLE_WALL_ANY,
3552     EL_EXPANDABLE_WALL_GROWING,
3553     EL_BD_EXPANDABLE_WALL,
3554     EL_BD_WALL,
3555     EL_SP_CHIP_SINGLE,
3556     EL_SP_CHIP_LEFT,
3557     EL_SP_CHIP_RIGHT,
3558     EL_SP_CHIP_TOP,
3559     EL_SP_CHIP_BOTTOM,
3560     EL_SP_HARDWARE_GRAY,
3561     EL_SP_HARDWARE_GREEN,
3562     EL_SP_HARDWARE_BLUE,
3563     EL_SP_HARDWARE_RED,
3564     EL_SP_HARDWARE_YELLOW,
3565     EL_SP_HARDWARE_BASE_1,
3566     EL_SP_HARDWARE_BASE_2,
3567     EL_SP_HARDWARE_BASE_3,
3568     EL_SP_HARDWARE_BASE_4,
3569     EL_SP_HARDWARE_BASE_5,
3570     EL_SP_HARDWARE_BASE_6,
3571     EL_SP_TERMINAL,
3572     EL_SP_TERMINAL_ACTIVE,
3573     EL_SP_EXIT_CLOSED,
3574     EL_SP_EXIT_OPEN,
3575     EL_INVISIBLE_STEELWALL,
3576     EL_INVISIBLE_STEELWALL_ACTIVE,
3577     EL_INVISIBLE_WALL,
3578     EL_INVISIBLE_WALL_ACTIVE,
3579     EL_STEELWALL_SLIPPERY,
3580     EL_EMC_STEELWALL_1,
3581     EL_EMC_STEELWALL_2,
3582     EL_EMC_STEELWALL_3,
3583     EL_EMC_STEELWALL_4,
3584     EL_EMC_WALL_1,
3585     EL_EMC_WALL_2,
3586     EL_EMC_WALL_3,
3587     EL_EMC_WALL_4,
3588     EL_EMC_WALL_5,
3589     EL_EMC_WALL_6,
3590     EL_EMC_WALL_7,
3591     EL_EMC_WALL_8,
3592
3593     -1
3594   };
3595
3596   static int ep_historic_solid[] =
3597   {
3598     EL_WALL,
3599     EL_EXPANDABLE_WALL,
3600     EL_EXPANDABLE_WALL_HORIZONTAL,
3601     EL_EXPANDABLE_WALL_VERTICAL,
3602     EL_EXPANDABLE_WALL_ANY,
3603     EL_BD_EXPANDABLE_WALL,
3604     EL_BD_WALL,
3605     EL_WALL_SLIPPERY,
3606     EL_EXIT_CLOSED,
3607     EL_EXIT_OPENING,
3608     EL_EXIT_OPEN,
3609     EL_AMOEBA_DEAD,
3610     EL_AMOEBA_WET,
3611     EL_AMOEBA_DRY,
3612     EL_AMOEBA_FULL,
3613     EL_BD_AMOEBA,
3614     EL_QUICKSAND_EMPTY,
3615     EL_QUICKSAND_FULL,
3616     EL_QUICKSAND_FILLING,
3617     EL_QUICKSAND_EMPTYING,
3618     EL_MAGIC_WALL,
3619     EL_MAGIC_WALL_ACTIVE,
3620     EL_MAGIC_WALL_EMPTYING,
3621     EL_MAGIC_WALL_FILLING,
3622     EL_MAGIC_WALL_FULL,
3623     EL_MAGIC_WALL_DEAD,
3624     EL_BD_MAGIC_WALL,
3625     EL_BD_MAGIC_WALL_ACTIVE,
3626     EL_BD_MAGIC_WALL_EMPTYING,
3627     EL_BD_MAGIC_WALL_FULL,
3628     EL_BD_MAGIC_WALL_FILLING,
3629     EL_BD_MAGIC_WALL_DEAD,
3630     EL_GAME_OF_LIFE,
3631     EL_BIOMAZE,
3632     EL_SP_CHIP_SINGLE,
3633     EL_SP_CHIP_LEFT,
3634     EL_SP_CHIP_RIGHT,
3635     EL_SP_CHIP_TOP,
3636     EL_SP_CHIP_BOTTOM,
3637     EL_SP_TERMINAL,
3638     EL_SP_TERMINAL_ACTIVE,
3639     EL_SP_EXIT_CLOSED,
3640     EL_SP_EXIT_OPEN,
3641     EL_INVISIBLE_WALL,
3642     EL_INVISIBLE_WALL_ACTIVE,
3643     EL_SWITCHGATE_SWITCH_UP,
3644     EL_SWITCHGATE_SWITCH_DOWN,
3645     EL_DC_SWITCHGATE_SWITCH_UP,
3646     EL_DC_SWITCHGATE_SWITCH_DOWN,
3647     EL_TIMEGATE_SWITCH,
3648     EL_TIMEGATE_SWITCH_ACTIVE,
3649     EL_DC_TIMEGATE_SWITCH,
3650     EL_DC_TIMEGATE_SWITCH_ACTIVE,
3651     EL_EMC_WALL_1,
3652     EL_EMC_WALL_2,
3653     EL_EMC_WALL_3,
3654     EL_EMC_WALL_4,
3655     EL_EMC_WALL_5,
3656     EL_EMC_WALL_6,
3657     EL_EMC_WALL_7,
3658     EL_EMC_WALL_8,
3659     EL_WALL_PEARL,
3660     EL_WALL_CRYSTAL,
3661
3662     /* the following elements are a direct copy of "indestructible" elements,
3663        except "EL_ACID", which is "indestructible", but not "solid"! */
3664 #if 0
3665     EL_ACID,
3666 #endif
3667     EL_STEELWALL,
3668     EL_ACID_POOL_TOPLEFT,
3669     EL_ACID_POOL_TOPRIGHT,
3670     EL_ACID_POOL_BOTTOMLEFT,
3671     EL_ACID_POOL_BOTTOM,
3672     EL_ACID_POOL_BOTTOMRIGHT,
3673     EL_SP_HARDWARE_GRAY,
3674     EL_SP_HARDWARE_GREEN,
3675     EL_SP_HARDWARE_BLUE,
3676     EL_SP_HARDWARE_RED,
3677     EL_SP_HARDWARE_YELLOW,
3678     EL_SP_HARDWARE_BASE_1,
3679     EL_SP_HARDWARE_BASE_2,
3680     EL_SP_HARDWARE_BASE_3,
3681     EL_SP_HARDWARE_BASE_4,
3682     EL_SP_HARDWARE_BASE_5,
3683     EL_SP_HARDWARE_BASE_6,
3684     EL_INVISIBLE_STEELWALL,
3685     EL_INVISIBLE_STEELWALL_ACTIVE,
3686     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3687     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3688     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3689     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3690     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3691     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3692     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3693     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3694     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3695     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3696     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3697     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3698     EL_LIGHT_SWITCH,
3699     EL_LIGHT_SWITCH_ACTIVE,
3700     EL_SIGN_EXCLAMATION,
3701     EL_SIGN_RADIOACTIVITY,
3702     EL_SIGN_STOP,
3703     EL_SIGN_WHEELCHAIR,
3704     EL_SIGN_PARKING,
3705     EL_SIGN_NO_ENTRY,
3706     EL_SIGN_UNUSED_1,
3707     EL_SIGN_GIVE_WAY,
3708     EL_SIGN_ENTRY_FORBIDDEN,
3709     EL_SIGN_EMERGENCY_EXIT,
3710     EL_SIGN_YIN_YANG,
3711     EL_SIGN_UNUSED_2,
3712     EL_SIGN_SPERMS,
3713     EL_SIGN_BULLET,
3714     EL_SIGN_HEART,
3715     EL_SIGN_CROSS,
3716     EL_SIGN_FRANKIE,
3717     EL_STEEL_EXIT_CLOSED,
3718     EL_STEEL_EXIT_OPEN,
3719     EL_DC_STEELWALL_1_LEFT,
3720     EL_DC_STEELWALL_1_RIGHT,
3721     EL_DC_STEELWALL_1_TOP,
3722     EL_DC_STEELWALL_1_BOTTOM,
3723     EL_DC_STEELWALL_1_HORIZONTAL,
3724     EL_DC_STEELWALL_1_VERTICAL,
3725     EL_DC_STEELWALL_1_TOPLEFT,
3726     EL_DC_STEELWALL_1_TOPRIGHT,
3727     EL_DC_STEELWALL_1_BOTTOMLEFT,
3728     EL_DC_STEELWALL_1_BOTTOMRIGHT,
3729     EL_DC_STEELWALL_1_TOPLEFT_2,
3730     EL_DC_STEELWALL_1_TOPRIGHT_2,
3731     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3732     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3733     EL_DC_STEELWALL_2_LEFT,
3734     EL_DC_STEELWALL_2_RIGHT,
3735     EL_DC_STEELWALL_2_TOP,
3736     EL_DC_STEELWALL_2_BOTTOM,
3737     EL_DC_STEELWALL_2_HORIZONTAL,
3738     EL_DC_STEELWALL_2_VERTICAL,
3739     EL_DC_STEELWALL_2_MIDDLE,
3740     EL_DC_STEELWALL_2_SINGLE,
3741     EL_STEELWALL_SLIPPERY,
3742     EL_EMC_STEELWALL_1,
3743     EL_EMC_STEELWALL_2,
3744     EL_EMC_STEELWALL_3,
3745     EL_EMC_STEELWALL_4,
3746     EL_CRYSTAL,
3747     EL_GATE_1,
3748     EL_GATE_2,
3749     EL_GATE_3,
3750     EL_GATE_4,
3751     EL_GATE_1_GRAY,
3752     EL_GATE_2_GRAY,
3753     EL_GATE_3_GRAY,
3754     EL_GATE_4_GRAY,
3755     EL_GATE_1_GRAY_ACTIVE,
3756     EL_GATE_2_GRAY_ACTIVE,
3757     EL_GATE_3_GRAY_ACTIVE,
3758     EL_GATE_4_GRAY_ACTIVE,
3759     EL_EM_GATE_1,
3760     EL_EM_GATE_2,
3761     EL_EM_GATE_3,
3762     EL_EM_GATE_4,
3763     EL_EM_GATE_1_GRAY,
3764     EL_EM_GATE_2_GRAY,
3765     EL_EM_GATE_3_GRAY,
3766     EL_EM_GATE_4_GRAY,
3767     EL_EM_GATE_1_GRAY_ACTIVE,
3768     EL_EM_GATE_2_GRAY_ACTIVE,
3769     EL_EM_GATE_3_GRAY_ACTIVE,
3770     EL_EM_GATE_4_GRAY_ACTIVE,
3771     EL_SWITCHGATE_OPEN,
3772     EL_SWITCHGATE_OPENING,
3773     EL_SWITCHGATE_CLOSED,
3774     EL_SWITCHGATE_CLOSING,
3775     EL_TIMEGATE_OPEN,
3776     EL_TIMEGATE_OPENING,
3777     EL_TIMEGATE_CLOSED,
3778     EL_TIMEGATE_CLOSING,
3779     EL_TUBE_ANY,
3780     EL_TUBE_VERTICAL,
3781     EL_TUBE_HORIZONTAL,
3782     EL_TUBE_VERTICAL_LEFT,
3783     EL_TUBE_VERTICAL_RIGHT,
3784     EL_TUBE_HORIZONTAL_UP,
3785     EL_TUBE_HORIZONTAL_DOWN,
3786     EL_TUBE_LEFT_UP,
3787     EL_TUBE_LEFT_DOWN,
3788     EL_TUBE_RIGHT_UP,
3789     EL_TUBE_RIGHT_DOWN,
3790
3791     -1
3792   };
3793
3794   static int ep_classic_enemy[] =
3795   {
3796     EL_BUG,
3797     EL_SPACESHIP,
3798     EL_BD_BUTTERFLY,
3799     EL_BD_FIREFLY,
3800
3801     EL_YAMYAM,
3802     EL_DARK_YAMYAM,
3803     EL_ROBOT,
3804     EL_PACMAN,
3805     EL_SP_SNIKSNAK,
3806     EL_SP_ELECTRON,
3807
3808     -1
3809   };
3810
3811   static int ep_belt[] =
3812   {
3813     EL_CONVEYOR_BELT_1_LEFT,
3814     EL_CONVEYOR_BELT_1_MIDDLE,
3815     EL_CONVEYOR_BELT_1_RIGHT,
3816     EL_CONVEYOR_BELT_2_LEFT,
3817     EL_CONVEYOR_BELT_2_MIDDLE,
3818     EL_CONVEYOR_BELT_2_RIGHT,
3819     EL_CONVEYOR_BELT_3_LEFT,
3820     EL_CONVEYOR_BELT_3_MIDDLE,
3821     EL_CONVEYOR_BELT_3_RIGHT,
3822     EL_CONVEYOR_BELT_4_LEFT,
3823     EL_CONVEYOR_BELT_4_MIDDLE,
3824     EL_CONVEYOR_BELT_4_RIGHT,
3825
3826     -1
3827   };
3828
3829   static int ep_belt_active[] =
3830   {
3831     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3832     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3833     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3834     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3835     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3836     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3837     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3838     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3839     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3840     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3841     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3842     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3843
3844     -1
3845   };
3846
3847   static int ep_belt_switch[] =
3848   {
3849     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3850     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3851     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3852     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3853     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3854     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3855     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3856     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3857     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3858     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3859     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3860     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3861
3862     -1
3863   };
3864
3865   static int ep_tube[] =
3866   {
3867     EL_TUBE_LEFT_UP,
3868     EL_TUBE_LEFT_DOWN,
3869     EL_TUBE_RIGHT_UP,
3870     EL_TUBE_RIGHT_DOWN,
3871     EL_TUBE_HORIZONTAL,
3872     EL_TUBE_HORIZONTAL_UP,
3873     EL_TUBE_HORIZONTAL_DOWN,
3874     EL_TUBE_VERTICAL,
3875     EL_TUBE_VERTICAL_LEFT,
3876     EL_TUBE_VERTICAL_RIGHT,
3877     EL_TUBE_ANY,
3878
3879     -1
3880   };
3881
3882   static int ep_acid_pool[] =
3883   {
3884     EL_ACID_POOL_TOPLEFT,
3885     EL_ACID_POOL_TOPRIGHT,
3886     EL_ACID_POOL_BOTTOMLEFT,
3887     EL_ACID_POOL_BOTTOM,
3888     EL_ACID_POOL_BOTTOMRIGHT,
3889
3890     -1
3891   };
3892
3893   static int ep_keygate[] =
3894   {
3895     EL_GATE_1,
3896     EL_GATE_2,
3897     EL_GATE_3,
3898     EL_GATE_4,
3899     EL_GATE_1_GRAY,
3900     EL_GATE_2_GRAY,
3901     EL_GATE_3_GRAY,
3902     EL_GATE_4_GRAY,
3903     EL_GATE_1_GRAY_ACTIVE,
3904     EL_GATE_2_GRAY_ACTIVE,
3905     EL_GATE_3_GRAY_ACTIVE,
3906     EL_GATE_4_GRAY_ACTIVE,
3907     EL_EM_GATE_1,
3908     EL_EM_GATE_2,
3909     EL_EM_GATE_3,
3910     EL_EM_GATE_4,
3911     EL_EM_GATE_1_GRAY,
3912     EL_EM_GATE_2_GRAY,
3913     EL_EM_GATE_3_GRAY,
3914     EL_EM_GATE_4_GRAY,
3915     EL_EM_GATE_1_GRAY_ACTIVE,
3916     EL_EM_GATE_2_GRAY_ACTIVE,
3917     EL_EM_GATE_3_GRAY_ACTIVE,
3918     EL_EM_GATE_4_GRAY_ACTIVE,
3919     EL_EMC_GATE_5,
3920     EL_EMC_GATE_6,
3921     EL_EMC_GATE_7,
3922     EL_EMC_GATE_8,
3923     EL_EMC_GATE_5_GRAY,
3924     EL_EMC_GATE_6_GRAY,
3925     EL_EMC_GATE_7_GRAY,
3926     EL_EMC_GATE_8_GRAY,
3927     EL_EMC_GATE_5_GRAY_ACTIVE,
3928     EL_EMC_GATE_6_GRAY_ACTIVE,
3929     EL_EMC_GATE_7_GRAY_ACTIVE,
3930     EL_EMC_GATE_8_GRAY_ACTIVE,
3931     EL_DC_GATE_WHITE,
3932     EL_DC_GATE_WHITE_GRAY,
3933     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3934
3935     -1
3936   };
3937
3938   static int ep_amoeboid[] =
3939   {
3940     EL_AMOEBA_DEAD,
3941     EL_AMOEBA_WET,
3942     EL_AMOEBA_DRY,
3943     EL_AMOEBA_FULL,
3944     EL_BD_AMOEBA,
3945     EL_EMC_DRIPPER,
3946
3947     -1
3948   };
3949
3950   static int ep_amoebalive[] =
3951   {
3952     EL_AMOEBA_WET,
3953     EL_AMOEBA_DRY,
3954     EL_AMOEBA_FULL,
3955     EL_BD_AMOEBA,
3956     EL_EMC_DRIPPER,
3957
3958     -1
3959   };
3960
3961   static int ep_has_editor_content[] =
3962   {
3963     EL_PLAYER_1,
3964     EL_PLAYER_2,
3965     EL_PLAYER_3,
3966     EL_PLAYER_4,
3967     EL_SOKOBAN_FIELD_PLAYER,
3968     EL_SP_MURPHY,
3969     EL_YAMYAM,
3970     EL_YAMYAM_LEFT,
3971     EL_YAMYAM_RIGHT,
3972     EL_YAMYAM_UP,
3973     EL_YAMYAM_DOWN,
3974     EL_AMOEBA_WET,
3975     EL_AMOEBA_DRY,
3976     EL_AMOEBA_FULL,
3977     EL_BD_AMOEBA,
3978     EL_EMC_MAGIC_BALL,
3979     EL_EMC_ANDROID,
3980
3981     -1
3982   };
3983
3984   static int ep_can_turn_each_move[] =
3985   {
3986     /* !!! do something with this one !!! */
3987     -1
3988   };
3989
3990   static int ep_can_grow[] =
3991   {
3992     EL_BD_AMOEBA,
3993     EL_AMOEBA_DROP,
3994     EL_AMOEBA_WET,
3995     EL_AMOEBA_DRY,
3996     EL_AMOEBA_FULL,
3997     EL_GAME_OF_LIFE,
3998     EL_BIOMAZE,
3999     EL_EMC_DRIPPER,
4000
4001     -1
4002   };
4003
4004   static int ep_active_bomb[] =
4005   {
4006     EL_DYNAMITE_ACTIVE,
4007     EL_EM_DYNAMITE_ACTIVE,
4008     EL_DYNABOMB_PLAYER_1_ACTIVE,
4009     EL_DYNABOMB_PLAYER_2_ACTIVE,
4010     EL_DYNABOMB_PLAYER_3_ACTIVE,
4011     EL_DYNABOMB_PLAYER_4_ACTIVE,
4012     EL_SP_DISK_RED_ACTIVE,
4013
4014     -1
4015   };
4016
4017   static int ep_inactive[] =
4018   {
4019     EL_EMPTY,
4020     EL_SAND,
4021     EL_WALL,
4022     EL_BD_WALL,
4023     EL_WALL_SLIPPERY,
4024     EL_STEELWALL,
4025     EL_AMOEBA_DEAD,
4026     EL_QUICKSAND_EMPTY,
4027     EL_QUICKSAND_FAST_EMPTY,
4028     EL_STONEBLOCK,
4029     EL_ROBOT_WHEEL,
4030     EL_KEY_1,
4031     EL_KEY_2,
4032     EL_KEY_3,
4033     EL_KEY_4,
4034     EL_EM_KEY_1,
4035     EL_EM_KEY_2,
4036     EL_EM_KEY_3,
4037     EL_EM_KEY_4,
4038     EL_EMC_KEY_5,
4039     EL_EMC_KEY_6,
4040     EL_EMC_KEY_7,
4041     EL_EMC_KEY_8,
4042     EL_GATE_1,
4043     EL_GATE_2,
4044     EL_GATE_3,
4045     EL_GATE_4,
4046     EL_GATE_1_GRAY,
4047     EL_GATE_2_GRAY,
4048     EL_GATE_3_GRAY,
4049     EL_GATE_4_GRAY,
4050     EL_GATE_1_GRAY_ACTIVE,
4051     EL_GATE_2_GRAY_ACTIVE,
4052     EL_GATE_3_GRAY_ACTIVE,
4053     EL_GATE_4_GRAY_ACTIVE,
4054     EL_EM_GATE_1,
4055     EL_EM_GATE_2,
4056     EL_EM_GATE_3,
4057     EL_EM_GATE_4,
4058     EL_EM_GATE_1_GRAY,
4059     EL_EM_GATE_2_GRAY,
4060     EL_EM_GATE_3_GRAY,
4061     EL_EM_GATE_4_GRAY,
4062     EL_EM_GATE_1_GRAY_ACTIVE,
4063     EL_EM_GATE_2_GRAY_ACTIVE,
4064     EL_EM_GATE_3_GRAY_ACTIVE,
4065     EL_EM_GATE_4_GRAY_ACTIVE,
4066     EL_EMC_GATE_5,
4067     EL_EMC_GATE_6,
4068     EL_EMC_GATE_7,
4069     EL_EMC_GATE_8,
4070     EL_EMC_GATE_5_GRAY,
4071     EL_EMC_GATE_6_GRAY,
4072     EL_EMC_GATE_7_GRAY,
4073     EL_EMC_GATE_8_GRAY,
4074     EL_EMC_GATE_5_GRAY_ACTIVE,
4075     EL_EMC_GATE_6_GRAY_ACTIVE,
4076     EL_EMC_GATE_7_GRAY_ACTIVE,
4077     EL_EMC_GATE_8_GRAY_ACTIVE,
4078     EL_DC_GATE_WHITE,
4079     EL_DC_GATE_WHITE_GRAY,
4080     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4081     EL_DC_GATE_FAKE_GRAY,
4082     EL_DYNAMITE,
4083     EL_EM_DYNAMITE,
4084     EL_INVISIBLE_STEELWALL,
4085     EL_INVISIBLE_WALL,
4086     EL_INVISIBLE_SAND,
4087     EL_LAMP,
4088     EL_LAMP_ACTIVE,
4089     EL_WALL_EMERALD,
4090     EL_WALL_DIAMOND,
4091     EL_WALL_BD_DIAMOND,
4092     EL_WALL_EMERALD_YELLOW,
4093     EL_DYNABOMB_INCREASE_NUMBER,
4094     EL_DYNABOMB_INCREASE_SIZE,
4095     EL_DYNABOMB_INCREASE_POWER,
4096 #if 0
4097     EL_SOKOBAN_OBJECT,
4098 #endif
4099     EL_SOKOBAN_FIELD_EMPTY,
4100     EL_SOKOBAN_FIELD_FULL,
4101     EL_WALL_EMERALD_RED,
4102     EL_WALL_EMERALD_PURPLE,
4103     EL_ACID_POOL_TOPLEFT,
4104     EL_ACID_POOL_TOPRIGHT,
4105     EL_ACID_POOL_BOTTOMLEFT,
4106     EL_ACID_POOL_BOTTOM,
4107     EL_ACID_POOL_BOTTOMRIGHT,
4108     EL_MAGIC_WALL,
4109     EL_MAGIC_WALL_DEAD,
4110     EL_BD_MAGIC_WALL,
4111     EL_BD_MAGIC_WALL_DEAD,
4112     EL_DC_MAGIC_WALL,
4113     EL_DC_MAGIC_WALL_DEAD,
4114     EL_AMOEBA_TO_DIAMOND,
4115     EL_BLOCKED,
4116     EL_SP_EMPTY,
4117     EL_SP_BASE,
4118     EL_SP_PORT_RIGHT,
4119     EL_SP_PORT_DOWN,
4120     EL_SP_PORT_LEFT,
4121     EL_SP_PORT_UP,
4122     EL_SP_GRAVITY_PORT_RIGHT,
4123     EL_SP_GRAVITY_PORT_DOWN,
4124     EL_SP_GRAVITY_PORT_LEFT,
4125     EL_SP_GRAVITY_PORT_UP,
4126     EL_SP_PORT_HORIZONTAL,
4127     EL_SP_PORT_VERTICAL,
4128     EL_SP_PORT_ANY,
4129     EL_SP_DISK_RED,
4130 #if 0
4131     EL_SP_DISK_YELLOW,
4132 #endif
4133     EL_SP_CHIP_SINGLE,
4134     EL_SP_CHIP_LEFT,
4135     EL_SP_CHIP_RIGHT,
4136     EL_SP_CHIP_TOP,
4137     EL_SP_CHIP_BOTTOM,
4138     EL_SP_HARDWARE_GRAY,
4139     EL_SP_HARDWARE_GREEN,
4140     EL_SP_HARDWARE_BLUE,
4141     EL_SP_HARDWARE_RED,
4142     EL_SP_HARDWARE_YELLOW,
4143     EL_SP_HARDWARE_BASE_1,
4144     EL_SP_HARDWARE_BASE_2,
4145     EL_SP_HARDWARE_BASE_3,
4146     EL_SP_HARDWARE_BASE_4,
4147     EL_SP_HARDWARE_BASE_5,
4148     EL_SP_HARDWARE_BASE_6,
4149     EL_SP_GRAVITY_ON_PORT_LEFT,
4150     EL_SP_GRAVITY_ON_PORT_RIGHT,
4151     EL_SP_GRAVITY_ON_PORT_UP,
4152     EL_SP_GRAVITY_ON_PORT_DOWN,
4153     EL_SP_GRAVITY_OFF_PORT_LEFT,
4154     EL_SP_GRAVITY_OFF_PORT_RIGHT,
4155     EL_SP_GRAVITY_OFF_PORT_UP,
4156     EL_SP_GRAVITY_OFF_PORT_DOWN,
4157     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4158     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4159     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4160     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4161     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4162     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4163     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4164     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4165     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4166     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4167     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4168     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4169     EL_SIGN_EXCLAMATION,
4170     EL_SIGN_RADIOACTIVITY,
4171     EL_SIGN_STOP,
4172     EL_SIGN_WHEELCHAIR,
4173     EL_SIGN_PARKING,
4174     EL_SIGN_NO_ENTRY,
4175     EL_SIGN_UNUSED_1,
4176     EL_SIGN_GIVE_WAY,
4177     EL_SIGN_ENTRY_FORBIDDEN,
4178     EL_SIGN_EMERGENCY_EXIT,
4179     EL_SIGN_YIN_YANG,
4180     EL_SIGN_UNUSED_2,
4181     EL_SIGN_SPERMS,
4182     EL_SIGN_BULLET,
4183     EL_SIGN_HEART,
4184     EL_SIGN_CROSS,
4185     EL_SIGN_FRANKIE,
4186     EL_DC_STEELWALL_1_LEFT,
4187     EL_DC_STEELWALL_1_RIGHT,
4188     EL_DC_STEELWALL_1_TOP,
4189     EL_DC_STEELWALL_1_BOTTOM,
4190     EL_DC_STEELWALL_1_HORIZONTAL,
4191     EL_DC_STEELWALL_1_VERTICAL,
4192     EL_DC_STEELWALL_1_TOPLEFT,
4193     EL_DC_STEELWALL_1_TOPRIGHT,
4194     EL_DC_STEELWALL_1_BOTTOMLEFT,
4195     EL_DC_STEELWALL_1_BOTTOMRIGHT,
4196     EL_DC_STEELWALL_1_TOPLEFT_2,
4197     EL_DC_STEELWALL_1_TOPRIGHT_2,
4198     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4199     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4200     EL_DC_STEELWALL_2_LEFT,
4201     EL_DC_STEELWALL_2_RIGHT,
4202     EL_DC_STEELWALL_2_TOP,
4203     EL_DC_STEELWALL_2_BOTTOM,
4204     EL_DC_STEELWALL_2_HORIZONTAL,
4205     EL_DC_STEELWALL_2_VERTICAL,
4206     EL_DC_STEELWALL_2_MIDDLE,
4207     EL_DC_STEELWALL_2_SINGLE,
4208     EL_STEELWALL_SLIPPERY,
4209     EL_EMC_STEELWALL_1,
4210     EL_EMC_STEELWALL_2,
4211     EL_EMC_STEELWALL_3,
4212     EL_EMC_STEELWALL_4,
4213     EL_EMC_WALL_SLIPPERY_1,
4214     EL_EMC_WALL_SLIPPERY_2,
4215     EL_EMC_WALL_SLIPPERY_3,
4216     EL_EMC_WALL_SLIPPERY_4,
4217     EL_EMC_WALL_1,
4218     EL_EMC_WALL_2,
4219     EL_EMC_WALL_3,
4220     EL_EMC_WALL_4,
4221     EL_EMC_WALL_5,
4222     EL_EMC_WALL_6,
4223     EL_EMC_WALL_7,
4224     EL_EMC_WALL_8,
4225     EL_EMC_WALL_9,
4226     EL_EMC_WALL_10,
4227     EL_EMC_WALL_11,
4228     EL_EMC_WALL_12,
4229     EL_EMC_WALL_13,
4230     EL_EMC_WALL_14,
4231     EL_EMC_WALL_15,
4232     EL_EMC_WALL_16,
4233
4234     -1
4235   };
4236
4237   static int ep_em_slippery_wall[] =
4238   {
4239     -1
4240   };
4241
4242   static int ep_gfx_crumbled[] =
4243   {
4244     EL_SAND,
4245     EL_LANDMINE,
4246     EL_DC_LANDMINE,
4247     EL_TRAP,
4248     EL_TRAP_ACTIVE,
4249
4250     -1
4251   };
4252
4253   static int ep_editor_cascade_active[] =
4254   {
4255     EL_INTERNAL_CASCADE_BD_ACTIVE,
4256     EL_INTERNAL_CASCADE_EM_ACTIVE,
4257     EL_INTERNAL_CASCADE_EMC_ACTIVE,
4258     EL_INTERNAL_CASCADE_RND_ACTIVE,
4259     EL_INTERNAL_CASCADE_SB_ACTIVE,
4260     EL_INTERNAL_CASCADE_SP_ACTIVE,
4261     EL_INTERNAL_CASCADE_DC_ACTIVE,
4262     EL_INTERNAL_CASCADE_DX_ACTIVE,
4263     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4264     EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4265     EL_INTERNAL_CASCADE_CE_ACTIVE,
4266     EL_INTERNAL_CASCADE_GE_ACTIVE,
4267     EL_INTERNAL_CASCADE_REF_ACTIVE,
4268     EL_INTERNAL_CASCADE_USER_ACTIVE,
4269     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4270
4271     -1
4272   };
4273
4274   static int ep_editor_cascade_inactive[] =
4275   {
4276     EL_INTERNAL_CASCADE_BD,
4277     EL_INTERNAL_CASCADE_EM,
4278     EL_INTERNAL_CASCADE_EMC,
4279     EL_INTERNAL_CASCADE_RND,
4280     EL_INTERNAL_CASCADE_SB,
4281     EL_INTERNAL_CASCADE_SP,
4282     EL_INTERNAL_CASCADE_DC,
4283     EL_INTERNAL_CASCADE_DX,
4284     EL_INTERNAL_CASCADE_CHARS,
4285     EL_INTERNAL_CASCADE_STEEL_CHARS,
4286     EL_INTERNAL_CASCADE_CE,
4287     EL_INTERNAL_CASCADE_GE,
4288     EL_INTERNAL_CASCADE_REF,
4289     EL_INTERNAL_CASCADE_USER,
4290     EL_INTERNAL_CASCADE_DYNAMIC,
4291
4292     -1
4293   };
4294
4295   static int ep_obsolete[] =
4296   {
4297     EL_PLAYER_OBSOLETE,
4298     EL_KEY_OBSOLETE,
4299     EL_EM_KEY_1_FILE_OBSOLETE,
4300     EL_EM_KEY_2_FILE_OBSOLETE,
4301     EL_EM_KEY_3_FILE_OBSOLETE,
4302     EL_EM_KEY_4_FILE_OBSOLETE,
4303     EL_ENVELOPE_OBSOLETE,
4304
4305     -1
4306   };
4307
4308   static struct
4309   {
4310     int *elements;
4311     int property;
4312   } element_properties[] =
4313   {
4314     { ep_diggable,                      EP_DIGGABLE                     },
4315     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
4316     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
4317     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
4318     { ep_dont_touch,                    EP_DONT_TOUCH                   },
4319     { ep_indestructible,                EP_INDESTRUCTIBLE               },
4320     { ep_slippery,                      EP_SLIPPERY                     },
4321     { ep_can_change,                    EP_CAN_CHANGE                   },
4322     { ep_can_move,                      EP_CAN_MOVE                     },
4323     { ep_can_fall,                      EP_CAN_FALL                     },
4324     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
4325     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
4326     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
4327     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
4328     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
4329     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
4330     { ep_walkable_over,                 EP_WALKABLE_OVER                },
4331     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
4332     { ep_walkable_under,                EP_WALKABLE_UNDER               },
4333     { ep_passable_over,                 EP_PASSABLE_OVER                },
4334     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
4335     { ep_passable_under,                EP_PASSABLE_UNDER               },
4336     { ep_droppable,                     EP_DROPPABLE                    },
4337     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
4338     { ep_pushable,                      EP_PUSHABLE                     },
4339     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
4340     { ep_protected,                     EP_PROTECTED                    },
4341     { ep_throwable,                     EP_THROWABLE                    },
4342     { ep_can_explode,                   EP_CAN_EXPLODE                  },
4343     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
4344
4345     { ep_player,                        EP_PLAYER                       },
4346     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
4347     { ep_can_pass_dc_magic_wall,        EP_CAN_PASS_DC_MAGIC_WALL       },
4348     { ep_switchable,                    EP_SWITCHABLE                   },
4349     { ep_bd_element,                    EP_BD_ELEMENT                   },
4350     { ep_sp_element,                    EP_SP_ELEMENT                   },
4351     { ep_sb_element,                    EP_SB_ELEMENT                   },
4352     { ep_gem,                           EP_GEM                          },
4353     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
4354     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
4355     { ep_food_pig,                      EP_FOOD_PIG                     },
4356     { ep_historic_wall,                 EP_HISTORIC_WALL                },
4357     { ep_historic_solid,                EP_HISTORIC_SOLID               },
4358     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
4359     { ep_belt,                          EP_BELT                         },
4360     { ep_belt_active,                   EP_BELT_ACTIVE                  },
4361     { ep_belt_switch,                   EP_BELT_SWITCH                  },
4362     { ep_tube,                          EP_TUBE                         },
4363     { ep_acid_pool,                     EP_ACID_POOL                    },
4364     { ep_keygate,                       EP_KEYGATE                      },
4365     { ep_amoeboid,                      EP_AMOEBOID                     },
4366     { ep_amoebalive,                    EP_AMOEBALIVE                   },
4367     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
4368     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
4369     { ep_can_grow,                      EP_CAN_GROW                     },
4370     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
4371     { ep_inactive,                      EP_INACTIVE                     },
4372
4373     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
4374
4375     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
4376
4377     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
4378     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
4379
4380     { ep_obsolete,                      EP_OBSOLETE                     },
4381
4382     { NULL,                             -1                              }
4383   };
4384
4385   int i, j, k;
4386
4387   /* always start with reliable default values (element has no properties) */
4388   /* (but never initialize clipboard elements after the very first time) */
4389   /* (to be able to use clipboard elements between several levels) */
4390   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4391     if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4392       for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4393         SET_PROPERTY(i, j, FALSE);
4394
4395   /* set all base element properties from above array definitions */
4396   for (i = 0; element_properties[i].elements != NULL; i++)
4397     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4398       SET_PROPERTY((element_properties[i].elements)[j],
4399                    element_properties[i].property, TRUE);
4400
4401   /* copy properties to some elements that are only stored in level file */
4402   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4403     for (j = 0; copy_properties[j][0] != -1; j++)
4404       if (HAS_PROPERTY(copy_properties[j][0], i))
4405         for (k = 1; k <= 4; k++)
4406           SET_PROPERTY(copy_properties[j][k], i, TRUE);
4407
4408   /* set static element properties that are not listed in array definitions */
4409   for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4410     SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4411
4412   clipboard_elements_initialized = TRUE;
4413 }
4414
4415 void InitElementPropertiesEngine(int engine_version)
4416 {
4417   static int no_wall_properties[] =
4418   {
4419     EP_DIGGABLE,
4420     EP_COLLECTIBLE_ONLY,
4421     EP_DONT_RUN_INTO,
4422     EP_DONT_COLLIDE_WITH,
4423     EP_CAN_MOVE,
4424     EP_CAN_FALL,
4425     EP_CAN_SMASH_PLAYER,
4426     EP_CAN_SMASH_ENEMIES,
4427     EP_CAN_SMASH_EVERYTHING,
4428     EP_PUSHABLE,
4429
4430     EP_PLAYER,
4431     EP_GEM,
4432     EP_FOOD_DARK_YAMYAM,
4433     EP_FOOD_PENGUIN,
4434     EP_BELT,
4435     EP_BELT_ACTIVE,
4436     EP_TUBE,
4437     EP_AMOEBOID,
4438     EP_AMOEBALIVE,
4439     EP_ACTIVE_BOMB,
4440
4441     EP_ACCESSIBLE,
4442
4443     -1
4444   };
4445
4446   int i, j;
4447
4448   /* important: after initialization in InitElementPropertiesStatic(), the
4449      elements are not again initialized to a default value; therefore all
4450      changes have to make sure that they leave the element with a defined
4451      property (which means that conditional property changes must be set to
4452      a reliable default value before) */
4453
4454   /* resolve group elements */
4455   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4456     ResolveGroupElement(EL_GROUP_START + i);
4457
4458   /* set all special, combined or engine dependent element properties */
4459   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4460   {
4461     /* do not change (already initialized) clipboard elements here */
4462     if (IS_CLIPBOARD_ELEMENT(i))
4463       continue;
4464
4465     /* ---------- INACTIVE ------------------------------------------------- */
4466     SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4467                                    i <= EL_CHAR_END) ||
4468                                   (i >= EL_STEEL_CHAR_START &&
4469                                    i <= EL_STEEL_CHAR_END)));
4470
4471     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4472     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4473                                   IS_WALKABLE_INSIDE(i) ||
4474                                   IS_WALKABLE_UNDER(i)));
4475
4476     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4477                                   IS_PASSABLE_INSIDE(i) ||
4478                                   IS_PASSABLE_UNDER(i)));
4479
4480     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4481                                          IS_PASSABLE_OVER(i)));
4482
4483     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4484                                            IS_PASSABLE_INSIDE(i)));
4485
4486     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4487                                           IS_PASSABLE_UNDER(i)));
4488
4489     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4490                                     IS_PASSABLE(i)));
4491
4492     /* ---------- COLLECTIBLE ---------------------------------------------- */
4493     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4494                                      IS_DROPPABLE(i) ||
4495                                      IS_THROWABLE(i)));
4496
4497     /* ---------- SNAPPABLE ------------------------------------------------ */
4498     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4499                                    IS_COLLECTIBLE(i) ||
4500                                    IS_SWITCHABLE(i) ||
4501                                    i == EL_BD_ROCK));
4502
4503     /* ---------- WALL ----------------------------------------------------- */
4504     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
4505
4506     for (j = 0; no_wall_properties[j] != -1; j++)
4507       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4508           i >= EL_FIRST_RUNTIME_UNREAL)
4509         SET_PROPERTY(i, EP_WALL, FALSE);
4510
4511     if (IS_HISTORIC_WALL(i))
4512       SET_PROPERTY(i, EP_WALL, TRUE);
4513
4514     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4515     if (engine_version < VERSION_IDENT(2,2,0,0))
4516       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4517     else
4518       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4519                                              !IS_DIGGABLE(i) &&
4520                                              !IS_COLLECTIBLE(i)));
4521
4522     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4523     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4524       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4525     else
4526       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4527                                             IS_INDESTRUCTIBLE(i)));
4528
4529     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4530     if (i == EL_FLAMES)
4531       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4532     else if (engine_version < VERSION_IDENT(2,2,0,0))
4533       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4534     else
4535       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4536                                            (!IS_WALKABLE(i) ||
4537                                             IS_PROTECTED(i))));
4538
4539     if (IS_CUSTOM_ELEMENT(i))
4540     {
4541       /* these are additional properties which are initially false when set */
4542
4543       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4544       if (DONT_TOUCH(i))
4545         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4546       if (DONT_COLLIDE_WITH(i))
4547         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4548
4549       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4550       if (CAN_SMASH_EVERYTHING(i))
4551         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4552       if (CAN_SMASH_ENEMIES(i))
4553         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4554     }
4555
4556     /* ---------- CAN_SMASH ------------------------------------------------ */
4557     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4558                                    CAN_SMASH_ENEMIES(i) ||
4559                                    CAN_SMASH_EVERYTHING(i)));
4560
4561     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4562     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4563                                              EXPLODES_BY_FIRE(i)));
4564
4565     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4566     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4567                                              EXPLODES_SMASHED(i)));
4568
4569     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4570     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4571                                             EXPLODES_IMPACT(i)));
4572
4573     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4574     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4575
4576     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4577     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4578                                                   i == EL_BLACK_ORB));
4579
4580     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4581     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4582                                               CAN_MOVE(i) ||
4583                                               IS_CUSTOM_ELEMENT(i)));
4584
4585     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4586     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4587                                                  i == EL_SP_ELECTRON));
4588
4589     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4590     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4591       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4592                    getMoveIntoAcidProperty(&level, i));
4593
4594     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4595     if (MAYBE_DONT_COLLIDE_WITH(i))
4596       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4597                    getDontCollideWithProperty(&level, i));
4598
4599     /* ---------- SP_PORT -------------------------------------------------- */
4600     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4601                                  IS_PASSABLE_INSIDE(i)));
4602
4603     /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4604     for (j = 0; j < level.num_android_clone_elements; j++)
4605       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4606                    (i != EL_EMPTY &&
4607                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4608
4609     /* ---------- CAN_CHANGE ----------------------------------------------- */
4610     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
4611     for (j = 0; j < element_info[i].num_change_pages; j++)
4612       if (element_info[i].change_page[j].can_change)
4613         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4614
4615     /* ---------- HAS_ACTION ----------------------------------------------- */
4616     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      /* default: has no action */
4617     for (j = 0; j < element_info[i].num_change_pages; j++)
4618       if (element_info[i].change_page[j].has_action)
4619         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4620
4621     /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4622     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4623                                                   HAS_ACTION(i)));
4624
4625     /* ---------- GFX_CRUMBLED --------------------------------------------- */
4626     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4627                  element_info[i].crumbled[ACTION_DEFAULT] !=
4628                  element_info[i].graphic[ACTION_DEFAULT]);
4629
4630     /* ---------- EDITOR_CASCADE ------------------------------------------- */
4631     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4632                                         IS_EDITOR_CASCADE_INACTIVE(i)));
4633   }
4634
4635   /* dynamically adjust element properties according to game engine version */
4636   {
4637     static int ep_em_slippery_wall[] =
4638     {
4639       EL_WALL,
4640       EL_STEELWALL,
4641       EL_EXPANDABLE_WALL,
4642       EL_EXPANDABLE_WALL_HORIZONTAL,
4643       EL_EXPANDABLE_WALL_VERTICAL,
4644       EL_EXPANDABLE_WALL_ANY,
4645       EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4646       EL_EXPANDABLE_STEELWALL_VERTICAL,
4647       EL_EXPANDABLE_STEELWALL_ANY,
4648       EL_EXPANDABLE_STEELWALL_GROWING,
4649       -1
4650     };
4651
4652     static int ep_em_explodes_by_fire[] =
4653     {
4654       EL_EM_DYNAMITE,
4655       EL_EM_DYNAMITE_ACTIVE,
4656       EL_MOLE,
4657       -1
4658     };
4659
4660     /* special EM style gems behaviour */
4661     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4662       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4663                    level.em_slippery_gems);
4664
4665     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4666     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4667                  (level.em_slippery_gems &&
4668                   engine_version > VERSION_IDENT(2,0,1,0)));
4669
4670     /* special EM style explosion behaviour regarding chain reactions */
4671     for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4672       SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4673                    level.em_explodes_by_fire);
4674   }
4675
4676   /* this is needed because some graphics depend on element properties */
4677   if (game_status == GAME_MODE_PLAYING)
4678     InitElementGraphicInfo();
4679 }
4680
4681 void InitElementPropertiesAfterLoading(int engine_version)
4682 {
4683   int i;
4684
4685   /* set some other uninitialized values of custom elements in older levels */
4686   if (engine_version < VERSION_IDENT(3,1,0,0))
4687   {
4688     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4689     {
4690       int element = EL_CUSTOM_START + i;
4691
4692       element_info[element].access_direction = MV_ALL_DIRECTIONS;
4693
4694       element_info[element].explosion_delay = 17;
4695       element_info[element].ignition_delay = 8;
4696     }
4697   }
4698 }
4699
4700 void InitElementPropertiesGfxElement()
4701 {
4702   int i;
4703
4704   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4705   {
4706     struct ElementInfo *ei = &element_info[i];
4707
4708     ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4709   }
4710 }
4711
4712 static void InitGlobal()
4713 {
4714   int graphic;
4715   int i;
4716
4717   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4718   {
4719     /* check if element_name_info entry defined for each element in "main.h" */
4720     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4721       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4722
4723     element_info[i].token_name = element_name_info[i].token_name;
4724     element_info[i].class_name = element_name_info[i].class_name;
4725     element_info[i].editor_description= element_name_info[i].editor_description;
4726   }
4727
4728   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4729   {
4730     /* check if global_anim_name_info defined for each entry in "main.h" */
4731     if (i < NUM_GLOBAL_ANIM_TOKENS &&
4732         global_anim_name_info[i].token_name == NULL)
4733       Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4734
4735     global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4736   }
4737
4738   /* create hash from image config list */
4739   image_config_hash = newSetupFileHash();
4740   for (i = 0; image_config[i].token != NULL; i++)
4741     setHashEntry(image_config_hash,
4742                  image_config[i].token,
4743                  image_config[i].value);
4744
4745   /* create hash from element token list */
4746   element_token_hash = newSetupFileHash();
4747   for (i = 0; element_name_info[i].token_name != NULL; i++)
4748     setHashEntry(element_token_hash,
4749                  element_name_info[i].token_name,
4750                  int2str(i, 0));
4751
4752   /* create hash from graphic token list */
4753   graphic_token_hash = newSetupFileHash();
4754   for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4755     if (strSuffix(image_config[i].value, ".png") ||
4756         strSuffix(image_config[i].value, ".pcx") ||
4757         strSuffix(image_config[i].value, ".wav") ||
4758         strEqual(image_config[i].value, UNDEFINED_FILENAME))
4759       setHashEntry(graphic_token_hash,
4760                    image_config[i].token,
4761                    int2str(graphic++, 0));
4762
4763   /* create hash from font token list */
4764   font_token_hash = newSetupFileHash();
4765   for (i = 0; font_info[i].token_name != NULL; i++)
4766     setHashEntry(font_token_hash,
4767                  font_info[i].token_name,
4768                  int2str(i, 0));
4769
4770   /* set default filenames for all cloned graphics in static configuration */
4771   for (i = 0; image_config[i].token != NULL; i++)
4772   {
4773     if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4774     {
4775       char *token = image_config[i].token;
4776       char *token_clone_from = getStringCat2(token, ".clone_from");
4777       char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4778
4779       if (token_cloned != NULL)
4780       {
4781         char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4782
4783         if (value_cloned != NULL)
4784         {
4785           /* set default filename in static configuration */
4786           image_config[i].value = value_cloned;
4787
4788           /* set default filename in image config hash */
4789           setHashEntry(image_config_hash, token, value_cloned);
4790         }
4791       }
4792
4793       free(token_clone_from);
4794     }
4795   }
4796
4797   /* always start with reliable default values (all elements) */
4798   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4799     ActiveElement[i] = i;
4800
4801   /* now add all entries that have an active state (active elements) */
4802   for (i = 0; element_with_active_state[i].element != -1; i++)
4803   {
4804     int element = element_with_active_state[i].element;
4805     int element_active = element_with_active_state[i].element_active;
4806
4807     ActiveElement[element] = element_active;
4808   }
4809
4810   /* always start with reliable default values (all buttons) */
4811   for (i = 0; i < NUM_IMAGE_FILES; i++)
4812     ActiveButton[i] = i;
4813
4814   /* now add all entries that have an active state (active buttons) */
4815   for (i = 0; button_with_active_state[i].button != -1; i++)
4816   {
4817     int button = button_with_active_state[i].button;
4818     int button_active = button_with_active_state[i].button_active;
4819
4820     ActiveButton[button] = button_active;
4821   }
4822
4823   /* always start with reliable default values (all fonts) */
4824   for (i = 0; i < NUM_FONTS; i++)
4825     ActiveFont[i] = i;
4826
4827   /* now add all entries that have an active state (active fonts) */
4828   for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4829   {
4830     int font = font_with_active_state[i].font_nr;
4831     int font_active = font_with_active_state[i].font_nr_active;
4832
4833     ActiveFont[font] = font_active;
4834   }
4835
4836   global.autoplay_leveldir = NULL;
4837   global.convert_leveldir = NULL;
4838   global.create_images_dir = NULL;
4839
4840   global.frames_per_second = 0;
4841   global.show_frames_per_second = FALSE;
4842
4843   global.border_status = GAME_MODE_LOADING;
4844   global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4845
4846   global.use_envelope_request = FALSE;
4847 }
4848
4849 void Execute_Command(char *command)
4850 {
4851   int i;
4852
4853   if (strEqual(command, "print graphicsinfo.conf"))
4854   {
4855     Print("# You can configure additional/alternative image files here.\n");
4856     Print("# (The entries below are default and therefore commented out.)\n");
4857     Print("\n");
4858     Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4859     Print("\n");
4860     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4861     Print("\n");
4862
4863     for (i = 0; image_config[i].token != NULL; i++)
4864       Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4865                                              image_config[i].value));
4866
4867     exit(0);
4868   }
4869   else if (strEqual(command, "print soundsinfo.conf"))
4870   {
4871     Print("# You can configure additional/alternative sound files here.\n");
4872     Print("# (The entries below are default and therefore commented out.)\n");
4873     Print("\n");
4874     Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4875     Print("\n");
4876     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4877     Print("\n");
4878
4879     for (i = 0; sound_config[i].token != NULL; i++)
4880       Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4881                                              sound_config[i].value));
4882
4883     exit(0);
4884   }
4885   else if (strEqual(command, "print musicinfo.conf"))
4886   {
4887     Print("# You can configure additional/alternative music files here.\n");
4888     Print("# (The entries below are default and therefore commented out.)\n");
4889     Print("\n");
4890     Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4891     Print("\n");
4892     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4893     Print("\n");
4894
4895     for (i = 0; music_config[i].token != NULL; i++)
4896       Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4897                                              music_config[i].value));
4898
4899     exit(0);
4900   }
4901   else if (strEqual(command, "print editorsetup.conf"))
4902   {
4903     Print("# You can configure your personal editor element list here.\n");
4904     Print("# (The entries below are default and therefore commented out.)\n");
4905     Print("\n");
4906
4907     /* this is needed to be able to check element list for cascade elements */
4908     InitElementPropertiesStatic();
4909     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4910
4911     PrintEditorElementList();
4912
4913     exit(0);
4914   }
4915   else if (strEqual(command, "print helpanim.conf"))
4916   {
4917     Print("# You can configure different element help animations here.\n");
4918     Print("# (The entries below are default and therefore commented out.)\n");
4919     Print("\n");
4920
4921     for (i = 0; helpanim_config[i].token != NULL; i++)
4922     {
4923       Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4924                                              helpanim_config[i].value));
4925
4926       if (strEqual(helpanim_config[i].token, "end"))
4927         Print("#\n");
4928     }
4929
4930     exit(0);
4931   }
4932   else if (strEqual(command, "print helptext.conf"))
4933   {
4934     Print("# You can configure different element help text here.\n");
4935     Print("# (The entries below are default and therefore commented out.)\n");
4936     Print("\n");
4937
4938     for (i = 0; helptext_config[i].token != NULL; i++)
4939       Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4940                                              helptext_config[i].value));
4941
4942     exit(0);
4943   }
4944   else if (strPrefix(command, "dump level "))
4945   {
4946     char *filename = &command[11];
4947
4948     if (!fileExists(filename))
4949       Error(ERR_EXIT, "cannot open file '%s'", filename);
4950
4951     LoadLevelFromFilename(&level, filename);
4952     DumpLevel(&level);
4953
4954     exit(0);
4955   }
4956   else if (strPrefix(command, "dump tape "))
4957   {
4958     char *filename = &command[10];
4959
4960     if (!fileExists(filename))
4961       Error(ERR_EXIT, "cannot open file '%s'", filename);
4962
4963     LoadTapeFromFilename(filename);
4964     DumpTape(&tape);
4965
4966     exit(0);
4967   }
4968   else if (strPrefix(command, "autotest ") ||
4969            strPrefix(command, "autoplay ") ||
4970            strPrefix(command, "autoffwd ") ||
4971            strPrefix(command, "autowarp "))
4972   {
4973     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4974
4975     global.autoplay_mode =
4976       (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4977        strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4978        strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4979        strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4980        AUTOPLAY_MODE_NONE);
4981
4982     while (*str_ptr != '\0')                    /* continue parsing string */
4983     {
4984       /* cut leading whitespace from string, replace it by string terminator */
4985       while (*str_ptr == ' ' || *str_ptr == '\t')
4986         *str_ptr++ = '\0';
4987
4988       if (*str_ptr == '\0')                     /* end of string reached */
4989         break;
4990
4991       if (global.autoplay_leveldir == NULL)     /* read level set string */
4992       {
4993         global.autoplay_leveldir = str_ptr;
4994         global.autoplay_all = TRUE;             /* default: play all tapes */
4995
4996         for (i = 0; i < MAX_TAPES_PER_SET; i++)
4997           global.autoplay_level[i] = FALSE;
4998       }
4999       else                                      /* read level number string */
5000       {
5001         int level_nr = atoi(str_ptr);           /* get level_nr value */
5002
5003         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5004           global.autoplay_level[level_nr] = TRUE;
5005
5006         global.autoplay_all = FALSE;
5007       }
5008
5009       /* advance string pointer to the next whitespace (or end of string) */
5010       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5011         str_ptr++;
5012     }
5013
5014     if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5015       program.headless = TRUE;
5016   }
5017   else if (strPrefix(command, "convert "))
5018   {
5019     char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5020     char *str_ptr = strchr(str_copy, ' ');
5021
5022     global.convert_leveldir = str_copy;
5023     global.convert_level_nr = -1;
5024
5025     if (str_ptr != NULL)                        /* level number follows */
5026     {
5027       *str_ptr++ = '\0';                        /* terminate leveldir string */
5028       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
5029     }
5030
5031     program.headless = TRUE;
5032   }
5033   else if (strPrefix(command, "create images "))
5034   {
5035     global.create_images_dir = getStringCopy(&command[14]);
5036
5037     if (access(global.create_images_dir, W_OK) != 0)
5038       Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5039             global.create_images_dir);
5040   }
5041   else if (strPrefix(command, "create CE image "))
5042   {
5043     CreateCustomElementImages(&command[16]);
5044
5045     exit(0);
5046   }
5047   else
5048   {
5049     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5050   }
5051 }
5052
5053 static void InitSetup()
5054 {
5055   LoadSetup();                                  /* global setup info */
5056
5057   /* set some options from setup file */
5058
5059   if (setup.options.verbose)
5060     options.verbose = TRUE;
5061
5062   if (setup.debug.show_frames_per_second)
5063     global.show_frames_per_second = TRUE;
5064 }
5065
5066 static void InitGameInfo()
5067 {
5068   game.restart_level = FALSE;
5069 }
5070
5071 static void InitPlayerInfo()
5072 {
5073   int i;
5074
5075   /* choose default local player */
5076   local_player = &stored_player[0];
5077
5078   for (i = 0; i < MAX_PLAYERS; i++)
5079     stored_player[i].connected = FALSE;
5080
5081   local_player->connected = TRUE;
5082 }
5083
5084 static void InitArtworkInfo()
5085 {
5086   LoadArtworkInfo();
5087 }
5088
5089 static char *get_string_in_brackets(char *string)
5090 {
5091   char *string_in_brackets = checked_malloc(strlen(string) + 3);
5092
5093   sprintf(string_in_brackets, "[%s]", string);
5094
5095   return string_in_brackets;
5096 }
5097
5098 static char *get_level_id_suffix(int id_nr)
5099 {
5100   char *id_suffix = checked_malloc(1 + 3 + 1);
5101
5102   if (id_nr < 0 || id_nr > 999)
5103     id_nr = 0;
5104
5105   sprintf(id_suffix, ".%03d", id_nr);
5106
5107   return id_suffix;
5108 }
5109
5110 static void InitArtworkConfig()
5111 {
5112   static char *image_id_prefix[MAX_NUM_ELEMENTS +
5113                                NUM_FONTS +
5114                                NUM_GLOBAL_ANIM_TOKENS + 1];
5115   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5116                                NUM_GLOBAL_ANIM_TOKENS + 1];
5117   static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5118                                NUM_GLOBAL_ANIM_TOKENS + 1];
5119   static char *action_id_suffix[NUM_ACTIONS + 1];
5120   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5121   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5122   static char *level_id_suffix[MAX_LEVELS + 1];
5123   static char *dummy[1] = { NULL };
5124   static char *ignore_generic_tokens[] =
5125   {
5126     "name",
5127     "sort_priority",
5128     NULL
5129   };
5130   static char **ignore_image_tokens;
5131   static char **ignore_sound_tokens;
5132   static char **ignore_music_tokens;
5133   int num_ignore_generic_tokens;
5134   int num_ignore_image_tokens;
5135   int num_ignore_sound_tokens;
5136   int num_ignore_music_tokens;
5137   int i;
5138
5139   /* dynamically determine list of generic tokens to be ignored */
5140   num_ignore_generic_tokens = 0;
5141   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5142     num_ignore_generic_tokens++;
5143
5144   /* dynamically determine list of image tokens to be ignored */
5145   num_ignore_image_tokens = num_ignore_generic_tokens;
5146   for (i = 0; image_config_vars[i].token != NULL; i++)
5147     num_ignore_image_tokens++;
5148   ignore_image_tokens =
5149     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5150   for (i = 0; i < num_ignore_generic_tokens; i++)
5151     ignore_image_tokens[i] = ignore_generic_tokens[i];
5152   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5153     ignore_image_tokens[num_ignore_generic_tokens + i] =
5154       image_config_vars[i].token;
5155   ignore_image_tokens[num_ignore_image_tokens] = NULL;
5156
5157   /* dynamically determine list of sound tokens to be ignored */
5158   num_ignore_sound_tokens = num_ignore_generic_tokens;
5159   ignore_sound_tokens =
5160     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5161   for (i = 0; i < num_ignore_generic_tokens; i++)
5162     ignore_sound_tokens[i] = ignore_generic_tokens[i];
5163   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5164
5165   /* dynamically determine list of music tokens to be ignored */
5166   num_ignore_music_tokens = num_ignore_generic_tokens;
5167   ignore_music_tokens =
5168     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5169   for (i = 0; i < num_ignore_generic_tokens; i++)
5170     ignore_music_tokens[i] = ignore_generic_tokens[i];
5171   ignore_music_tokens[num_ignore_music_tokens] = NULL;
5172
5173   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5174     image_id_prefix[i] = element_info[i].token_name;
5175   for (i = 0; i < NUM_FONTS; i++)
5176     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5177   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5178     image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5179       global_anim_info[i].token_name;
5180   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5181
5182   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5183     sound_id_prefix[i] = element_info[i].token_name;
5184   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5185     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5186       get_string_in_brackets(element_info[i].class_name);
5187   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5188     sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5189       global_anim_info[i].token_name;
5190   sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5191
5192   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5193     music_id_prefix[i] = music_prefix_info[i].prefix;
5194   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5195     music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5196       global_anim_info[i].token_name;
5197   music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5198
5199   for (i = 0; i < NUM_ACTIONS; i++)
5200     action_id_suffix[i] = element_action_info[i].suffix;
5201   action_id_suffix[NUM_ACTIONS] = NULL;
5202
5203   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5204     direction_id_suffix[i] = element_direction_info[i].suffix;
5205   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5206
5207   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5208     special_id_suffix[i] = special_suffix_info[i].suffix;
5209   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5210
5211   for (i = 0; i < MAX_LEVELS; i++)
5212     level_id_suffix[i] = get_level_id_suffix(i);
5213   level_id_suffix[MAX_LEVELS] = NULL;
5214
5215   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5216                 image_id_prefix, action_id_suffix, direction_id_suffix,
5217                 special_id_suffix, ignore_image_tokens);
5218   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5219                 sound_id_prefix, action_id_suffix, dummy,
5220                 special_id_suffix, ignore_sound_tokens);
5221   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5222                 music_id_prefix, action_id_suffix, special_id_suffix,
5223                 level_id_suffix, ignore_music_tokens);
5224 }
5225
5226 static void InitMixer()
5227 {
5228   OpenAudio();
5229
5230   StartMixer();
5231 }
5232
5233 void InitGfxBuffers()
5234 {
5235   static int win_xsize_last = -1;
5236   static int win_ysize_last = -1;
5237
5238   /* create additional image buffers for double-buffering and cross-fading */
5239
5240   if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5241   {
5242     /* used to temporarily store the backbuffer -- only re-create if changed */
5243     ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5244     ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5245
5246     win_xsize_last = WIN_XSIZE;
5247     win_ysize_last = WIN_YSIZE;
5248   }
5249
5250   ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5251   ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5252   ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5253   ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5254
5255   /* initialize screen properties */
5256   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5257                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5258                    bitmap_db_field);
5259   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5260   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5261   InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5262   InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5263   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5264   InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5265
5266   /* required if door size definitions have changed */
5267   InitGraphicCompatibilityInfo_Doors();
5268
5269   InitGfxBuffers_EM();
5270   InitGfxBuffers_SP();
5271 }
5272
5273 void InitGfx()
5274 {
5275   struct GraphicInfo *graphic_info_last = graphic_info;
5276   char *filename_font_initial = NULL;
5277   char *filename_anim_initial = NULL;
5278   Bitmap *bitmap_font_initial = NULL;
5279   int font_height;
5280   int i, j;
5281
5282   /* determine settings for initial font (for displaying startup messages) */
5283   for (i = 0; image_config[i].token != NULL; i++)
5284   {
5285     for (j = 0; j < NUM_INITIAL_FONTS; j++)
5286     {
5287       char font_token[128];
5288       int len_font_token;
5289
5290       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5291       len_font_token = strlen(font_token);
5292
5293       if (strEqual(image_config[i].token, font_token))
5294         filename_font_initial = image_config[i].value;
5295       else if (strlen(image_config[i].token) > len_font_token &&
5296                strncmp(image_config[i].token, font_token, len_font_token) == 0)
5297       {
5298         if (strEqual(&image_config[i].token[len_font_token], ".x"))
5299           font_initial[j].src_x = atoi(image_config[i].value);
5300         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5301           font_initial[j].src_y = atoi(image_config[i].value);
5302         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5303           font_initial[j].width = atoi(image_config[i].value);
5304         else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5305           font_initial[j].height = atoi(image_config[i].value);
5306       }
5307     }
5308   }
5309
5310   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5311   {
5312     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5313     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5314   }
5315
5316   if (filename_font_initial == NULL)    /* should not happen */
5317     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5318
5319   InitGfxBuffers();
5320   InitGfxCustomArtworkInfo();
5321   InitGfxOtherSettings();
5322
5323   bitmap_font_initial = LoadCustomImage(filename_font_initial);
5324
5325   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5326     font_initial[j].bitmap = bitmap_font_initial;
5327
5328   InitFontGraphicInfo();
5329
5330   font_height = getFontHeight(FC_RED);
5331
5332   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5333   DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5334   DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5335                FC_RED);
5336
5337   DrawInitText("Loading graphics", 120, FC_GREEN);
5338
5339   /* initialize settings for busy animation with default values */
5340   int parameter[NUM_GFX_ARGS];
5341   for (i = 0; i < NUM_GFX_ARGS; i++)
5342     parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5343                                                image_config_suffix[i].token,
5344                                                image_config_suffix[i].type);
5345
5346   char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5347   int len_anim_token = strlen(anim_token);
5348
5349   /* read settings for busy animation from default custom artwork config */
5350   char *gfx_config_filename = getPath3(options.graphics_directory,
5351                                        GFX_DEFAULT_SUBDIR,
5352                                        GRAPHICSINFO_FILENAME);
5353
5354   if (fileExists(gfx_config_filename))
5355   {
5356     SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5357
5358     if (setup_file_hash)
5359     {
5360       char *filename = getHashEntry(setup_file_hash, anim_token);
5361
5362       if (filename)
5363       {
5364         filename_anim_initial = getStringCopy(filename);
5365
5366         for (j = 0; image_config_suffix[j].token != NULL; j++)
5367         {
5368           int type = image_config_suffix[j].type;
5369           char *suffix = image_config_suffix[j].token;
5370           char *token = getStringCat2(anim_token, suffix);
5371           char *value = getHashEntry(setup_file_hash, token);
5372
5373           checked_free(token);
5374
5375           if (value)
5376             parameter[j] = get_graphic_parameter_value(value, suffix, type);
5377         }
5378       }
5379
5380       freeSetupFileHash(setup_file_hash);
5381     }
5382   }
5383
5384   if (filename_anim_initial == NULL)
5385   {
5386     /* read settings for busy animation from static default artwork config */
5387     for (i = 0; image_config[i].token != NULL; i++)
5388     {
5389       if (strEqual(image_config[i].token, anim_token))
5390         filename_anim_initial = getStringCopy(image_config[i].value);
5391       else if (strlen(image_config[i].token) > len_anim_token &&
5392                strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5393       {
5394         for (j = 0; image_config_suffix[j].token != NULL; j++)
5395         {
5396           if (strEqual(&image_config[i].token[len_anim_token],
5397                        image_config_suffix[j].token))
5398             parameter[j] =
5399               get_graphic_parameter_value(image_config[i].value,
5400                                           image_config_suffix[j].token,
5401                                           image_config_suffix[j].type);
5402         }
5403       }
5404     }
5405   }
5406
5407   if (filename_anim_initial == NULL)    /* should not happen */
5408     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5409
5410   anim_initial.bitmaps =
5411     checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5412
5413   anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5414     LoadCustomImage(filename_anim_initial);
5415
5416   checked_free(filename_anim_initial);
5417
5418   graphic_info = &anim_initial;         /* graphic == 0 => anim_initial */
5419
5420   set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5421
5422   graphic_info = graphic_info_last;
5423
5424   init.busy.width  = anim_initial.width;
5425   init.busy.height = anim_initial.height;
5426
5427   InitMenuDesignSettings_Static();
5428
5429   InitGfxDrawBusyAnimFunction(DrawInitAnim);
5430   InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5431   InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5432
5433   gfx.fade_border_source_status = global.border_status;
5434   gfx.fade_border_target_status = global.border_status;
5435   gfx.masked_border_bitmap_ptr = backbuffer;
5436
5437   /* use copy of busy animation to prevent change while reloading artwork */
5438   init_last = init;
5439 }
5440
5441 void InitGfxBackground()
5442 {
5443   fieldbuffer = bitmap_db_field;
5444   SetDrawtoField(DRAW_TO_BACKBUFFER);
5445
5446   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5447
5448   redraw_mask = REDRAW_ALL;
5449 }
5450
5451 static void InitLevelInfo()
5452 {
5453   LoadLevelInfo();                              /* global level info */
5454   LoadLevelSetup_LastSeries();                  /* last played series info */
5455   LoadLevelSetup_SeriesInfo();                  /* last played level info */
5456
5457   if (global.autoplay_leveldir &&
5458       global.autoplay_mode != AUTOPLAY_MODE_TEST)
5459   {
5460     leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5461                                                  global.autoplay_leveldir);
5462     if (leveldir_current == NULL)
5463       leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5464   }
5465 }
5466
5467 static void InitLevelArtworkInfo()
5468 {
5469   LoadLevelArtworkInfo();
5470 }
5471
5472 static void InitImages()
5473 {
5474   print_timestamp_init("InitImages");
5475
5476 #if 0
5477   printf("::: leveldir_current->identifier == '%s'\n",
5478          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5479   printf("::: leveldir_current->graphics_path == '%s'\n",
5480          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5481   printf("::: leveldir_current->graphics_set == '%s'\n",
5482          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5483   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5484          leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5485 #endif
5486
5487   setLevelArtworkDir(artwork.gfx_first);
5488
5489 #if 0
5490   printf("::: leveldir_current->identifier == '%s'\n",
5491          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5492   printf("::: leveldir_current->graphics_path == '%s'\n",
5493          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5494   printf("::: leveldir_current->graphics_set == '%s'\n",
5495          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5496   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5497          leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5498 #endif
5499
5500 #if 0
5501   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5502          leveldir_current->identifier,
5503          artwork.gfx_current_identifier,
5504          artwork.gfx_current->identifier,
5505          leveldir_current->graphics_set,
5506          leveldir_current->graphics_path);
5507 #endif
5508
5509   UPDATE_BUSY_STATE();
5510
5511   ReloadCustomImages();
5512   print_timestamp_time("ReloadCustomImages");
5513
5514   UPDATE_BUSY_STATE();
5515
5516   LoadCustomElementDescriptions();
5517   print_timestamp_time("LoadCustomElementDescriptions");
5518
5519   UPDATE_BUSY_STATE();
5520
5521   LoadMenuDesignSettings();
5522   print_timestamp_time("LoadMenuDesignSettings");
5523
5524   UPDATE_BUSY_STATE();
5525
5526   ReinitializeGraphics();
5527   print_timestamp_time("ReinitializeGraphics");
5528
5529   LoadMenuDesignSettings_AfterGraphics();
5530   print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5531
5532   UPDATE_BUSY_STATE();
5533
5534   print_timestamp_done("InitImages");
5535 }
5536
5537 static void InitSound(char *identifier)
5538 {
5539   print_timestamp_init("InitSound");
5540
5541   if (identifier == NULL)
5542     identifier = artwork.snd_current->identifier;
5543
5544   /* set artwork path to send it to the sound server process */
5545   setLevelArtworkDir(artwork.snd_first);
5546
5547   InitReloadCustomSounds(identifier);
5548   print_timestamp_time("InitReloadCustomSounds");
5549
5550   ReinitializeSounds();
5551   print_timestamp_time("ReinitializeSounds");
5552
5553   print_timestamp_done("InitSound");
5554 }
5555
5556 static void InitMusic(char *identifier)
5557 {
5558   print_timestamp_init("InitMusic");
5559
5560   if (identifier == NULL)
5561     identifier = artwork.mus_current->identifier;
5562
5563   /* set artwork path to send it to the sound server process */
5564   setLevelArtworkDir(artwork.mus_first);
5565
5566   InitReloadCustomMusic(identifier);
5567   print_timestamp_time("InitReloadCustomMusic");
5568
5569   ReinitializeMusic();
5570   print_timestamp_time("ReinitializeMusic");
5571
5572   print_timestamp_done("InitMusic");
5573 }
5574
5575 static void InitArtworkDone()
5576 {
5577   if (program.headless)
5578     return;
5579
5580   InitGlobalAnimations();
5581 }
5582
5583 void InitNetworkServer()
5584 {
5585 #if defined(NETWORK_AVALIABLE)
5586   int nr_wanted;
5587 #endif
5588
5589   if (!options.network)
5590     return;
5591
5592 #if defined(NETWORK_AVALIABLE)
5593   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5594
5595   if (!ConnectToServer(options.server_host, options.server_port))
5596     Error(ERR_EXIT, "cannot connect to network game server");
5597
5598   SendToServer_PlayerName(setup.player_name);
5599   SendToServer_ProtocolVersion();
5600
5601   if (nr_wanted)
5602     SendToServer_NrWanted(nr_wanted);
5603 #endif
5604 }
5605
5606 static boolean CheckArtworkConfigForCustomElements(char *filename)
5607 {
5608   SetupFileHash *setup_file_hash;
5609   boolean redefined_ce_found = FALSE;
5610
5611   /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5612
5613   if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5614   {
5615     BEGIN_HASH_ITERATION(setup_file_hash, itr)
5616     {
5617       char *token = HASH_ITERATION_TOKEN(itr);
5618
5619       if (strPrefix(token, "custom_"))
5620       {
5621         redefined_ce_found = TRUE;
5622
5623         break;
5624       }
5625     }
5626     END_HASH_ITERATION(setup_file_hash, itr)
5627
5628     freeSetupFileHash(setup_file_hash);
5629   }
5630
5631   return redefined_ce_found;
5632 }
5633
5634 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5635 {
5636   char *filename_base, *filename_local;
5637   boolean redefined_ce_found = FALSE;
5638
5639   setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5640
5641 #if 0
5642   printf("::: leveldir_current->identifier == '%s'\n",
5643          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5644   printf("::: leveldir_current->graphics_path == '%s'\n",
5645          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5646   printf("::: leveldir_current->graphics_set == '%s'\n",
5647          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5648   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5649          leveldir_current == NULL ? "[NULL]" :
5650          LEVELDIR_ARTWORK_SET(leveldir_current, type));
5651 #endif
5652
5653   /* first look for special artwork configured in level series config */
5654   filename_base = getCustomArtworkLevelConfigFilename(type);
5655
5656 #if 0
5657   printf("::: filename_base == '%s'\n", filename_base);
5658 #endif
5659
5660   if (fileExists(filename_base))
5661     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5662
5663   filename_local = getCustomArtworkConfigFilename(type);
5664
5665 #if 0
5666   printf("::: filename_local == '%s'\n", filename_local);
5667 #endif
5668
5669   if (filename_local != NULL && !strEqual(filename_base, filename_local))
5670     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5671
5672 #if 0
5673   printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5674 #endif
5675
5676   return redefined_ce_found;
5677 }
5678
5679 static void InitOverrideArtwork()
5680 {
5681   boolean redefined_ce_found = FALSE;
5682
5683   /* to check if this level set redefines any CEs, do not use overriding */
5684   gfx.override_level_graphics = FALSE;
5685   gfx.override_level_sounds   = FALSE;
5686   gfx.override_level_music    = FALSE;
5687
5688   /* now check if this level set has definitions for custom elements */
5689   if (setup.override_level_graphics == AUTO ||
5690       setup.override_level_sounds   == AUTO ||
5691       setup.override_level_music    == AUTO)
5692     redefined_ce_found =
5693       (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5694        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5695        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5696
5697 #if 0
5698   printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5699 #endif
5700
5701   if (redefined_ce_found)
5702   {
5703     /* this level set has CE definitions: change "AUTO" to "FALSE" */
5704     gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5705     gfx.override_level_sounds   = (setup.override_level_sounds   == TRUE);
5706     gfx.override_level_music    = (setup.override_level_music    == TRUE);
5707   }
5708   else
5709   {
5710     /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5711     gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5712     gfx.override_level_sounds   = (setup.override_level_sounds   != FALSE);
5713     gfx.override_level_music    = (setup.override_level_music    != FALSE);
5714   }
5715
5716 #if 0
5717   printf("::: => %d, %d, %d\n",
5718          gfx.override_level_graphics,
5719          gfx.override_level_sounds,
5720          gfx.override_level_music);
5721 #endif
5722 }
5723
5724 static char *getNewArtworkIdentifier(int type)
5725 {
5726   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5727   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5728   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5729   static boolean initialized[3] = { FALSE, FALSE, FALSE };
5730   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5731   boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5732   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5733   char *leveldir_identifier = leveldir_current->identifier;
5734   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5735   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5736   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5737   char *artwork_current_identifier;
5738   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
5739
5740   /* leveldir_current may be invalid (level group, parent link) */
5741   if (!validLevelSeries(leveldir_current))
5742     return NULL;
5743
5744   /* 1st step: determine artwork set to be activated in descending order:
5745      --------------------------------------------------------------------
5746      1. setup artwork (when configured to override everything else)
5747      2. artwork set configured in "levelinfo.conf" of current level set
5748         (artwork in level directory will have priority when loading later)
5749      3. artwork in level directory (stored in artwork sub-directory)
5750      4. setup artwork (currently configured in setup menu) */
5751
5752   if (setup_override_artwork)
5753     artwork_current_identifier = setup_artwork_set;
5754   else if (leveldir_artwork_set != NULL)
5755     artwork_current_identifier = leveldir_artwork_set;
5756   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5757     artwork_current_identifier = leveldir_identifier;
5758   else
5759     artwork_current_identifier = setup_artwork_set;
5760
5761
5762   /* 2nd step: check if it is really needed to reload artwork set
5763      ------------------------------------------------------------ */
5764
5765   /* ---------- reload if level set and also artwork set has changed ------- */
5766   if (leveldir_current_identifier[type] != leveldir_identifier &&
5767       (last_has_level_artwork_set[type] || has_level_artwork_set))
5768     artwork_new_identifier = artwork_current_identifier;
5769
5770   leveldir_current_identifier[type] = leveldir_identifier;
5771   last_has_level_artwork_set[type] = has_level_artwork_set;
5772
5773   /* ---------- reload if "override artwork" setting has changed ----------- */
5774   if (last_override_level_artwork[type] != setup_override_artwork)
5775     artwork_new_identifier = artwork_current_identifier;
5776
5777   last_override_level_artwork[type] = setup_override_artwork;
5778
5779   /* ---------- reload if current artwork identifier has changed ----------- */
5780   if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5781                 artwork_current_identifier))
5782     artwork_new_identifier = artwork_current_identifier;
5783
5784   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5785
5786   /* ---------- do not reload directly after starting ---------------------- */
5787   if (!initialized[type])
5788     artwork_new_identifier = NULL;
5789
5790   initialized[type] = TRUE;
5791
5792   return artwork_new_identifier;
5793 }
5794
5795 void ReloadCustomArtwork(int force_reload)
5796 {
5797   int last_game_status = game_status;   /* save current game status */
5798   char *gfx_new_identifier;
5799   char *snd_new_identifier;
5800   char *mus_new_identifier;
5801   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5802   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5803   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5804   boolean reload_needed;
5805
5806   InitOverrideArtwork();
5807
5808   force_reload_gfx |= AdjustGraphicsForEMC();
5809
5810   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5811   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5812   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5813
5814   reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5815                    snd_new_identifier != NULL || force_reload_snd ||
5816                    mus_new_identifier != NULL || force_reload_mus);
5817
5818   if (!reload_needed)
5819     return;
5820
5821   print_timestamp_init("ReloadCustomArtwork");
5822
5823   SetGameStatus(GAME_MODE_LOADING);
5824
5825   FadeOut(REDRAW_ALL);
5826
5827   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5828   print_timestamp_time("ClearRectangle");
5829
5830   FadeIn(REDRAW_ALL);
5831
5832   if (gfx_new_identifier != NULL || force_reload_gfx)
5833   {
5834 #if 0
5835     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5836            artwork.gfx_current_identifier,
5837            gfx_new_identifier,
5838            artwork.gfx_current->identifier,
5839            leveldir_current->graphics_set);
5840 #endif
5841
5842     InitImages();
5843     print_timestamp_time("InitImages");
5844   }
5845
5846   if (snd_new_identifier != NULL || force_reload_snd)
5847   {
5848     InitSound(snd_new_identifier);
5849     print_timestamp_time("InitSound");
5850   }
5851
5852   if (mus_new_identifier != NULL || force_reload_mus)
5853   {
5854     InitMusic(mus_new_identifier);
5855     print_timestamp_time("InitMusic");
5856   }
5857
5858   InitArtworkDone();
5859
5860   SetGameStatus(last_game_status);      /* restore current game status */
5861
5862   init_last = init;                     /* switch to new busy animation */
5863
5864   FadeOut(REDRAW_ALL);
5865
5866   RedrawGlobalBorder();
5867
5868   /* force redraw of (open or closed) door graphics */
5869   SetDoorState(DOOR_OPEN_ALL);
5870   CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5871
5872   FadeSetEnterScreen();
5873   FadeSkipNextFadeOut();
5874
5875   print_timestamp_done("ReloadCustomArtwork");
5876
5877   LimitScreenUpdates(FALSE);
5878 }
5879
5880 void KeyboardAutoRepeatOffUnlessAutoplay()
5881 {
5882   if (global.autoplay_leveldir == NULL)
5883     KeyboardAutoRepeatOff();
5884 }
5885
5886 void DisplayExitMessage(char *format, va_list ap)
5887 {
5888   // check if draw buffer and fonts for exit message are already available
5889   if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5890     return;
5891
5892   int font_1 = FC_RED;
5893   int font_2 = FC_YELLOW;
5894   int font_3 = FC_BLUE;
5895   int font_width = getFontWidth(font_2);
5896   int font_height = getFontHeight(font_2);
5897   int sx = SX;
5898   int sy = SY;
5899   int sxsize = WIN_XSIZE - 2 * sx;
5900   int sysize = WIN_YSIZE - 2 * sy;
5901   int line_length = sxsize / font_width;
5902   int max_lines = sysize / font_height;
5903   int num_lines_printed;
5904
5905   gfx.sx = sx;
5906   gfx.sy = sy;
5907   gfx.sxsize = sxsize;
5908   gfx.sysize = sysize;
5909
5910   sy = 20;
5911
5912   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5913
5914   DrawTextSCentered(sy, font_1, "Fatal error:");
5915   sy += 3 * font_height;;
5916
5917   num_lines_printed =
5918     DrawTextBufferVA(sx, sy, format, ap, font_2,
5919                      line_length, line_length, max_lines,
5920                      0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5921   sy += (num_lines_printed + 3) * font_height;
5922
5923   DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5924   sy += 3 * font_height;
5925
5926   num_lines_printed =
5927     DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5928                    line_length, line_length, max_lines,
5929                    0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5930
5931   DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5932
5933   redraw_mask = REDRAW_ALL;
5934
5935   /* force drawing exit message even if screen updates are currently limited */
5936   LimitScreenUpdates(FALSE);
5937
5938   BackToFront();
5939
5940   /* deactivate toons on error message screen */
5941   setup.toons = FALSE;
5942
5943   WaitForEventToContinue();
5944 }
5945
5946
5947 /* ========================================================================= */
5948 /* OpenAll()                                                                 */
5949 /* ========================================================================= */
5950
5951 void OpenAll()
5952 {
5953   print_timestamp_init("OpenAll");
5954
5955   SetGameStatus(GAME_MODE_LOADING);
5956
5957   InitCounter();
5958
5959   InitGlobal();                 /* initialize some global variables */
5960
5961   print_timestamp_time("[init global stuff]");
5962
5963   InitSetup();
5964
5965   print_timestamp_time("[init setup/config stuff (1)]");
5966
5967   InitScoresInfo();
5968
5969   if (options.execute_command)
5970     Execute_Command(options.execute_command);
5971
5972   if (options.serveronly)
5973   {
5974 #if defined(PLATFORM_UNIX)
5975     NetworkServer(options.server_port, options.serveronly);
5976 #else
5977     Error(ERR_WARN, "networking only supported in Unix version");
5978 #endif
5979
5980     exit(0);                    /* never reached, server loops forever */
5981   }
5982
5983   InitGameInfo();
5984   print_timestamp_time("[init setup/config stuff (2)]");
5985   InitPlayerInfo();
5986   print_timestamp_time("[init setup/config stuff (3)]");
5987   InitArtworkInfo();            /* needed before loading gfx, sound & music */
5988   print_timestamp_time("[init setup/config stuff (4)]");
5989   InitArtworkConfig();          /* needed before forking sound child process */
5990   print_timestamp_time("[init setup/config stuff (5)]");
5991   InitMixer();
5992   print_timestamp_time("[init setup/config stuff (6)]");
5993
5994   InitRND(NEW_RANDOMIZE);
5995   InitSimpleRandom(NEW_RANDOMIZE);
5996
5997   InitJoysticks();
5998
5999   print_timestamp_time("[init setup/config stuff]");
6000
6001   InitVideoDisplay();
6002   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6003
6004   InitOverlayInfo();
6005
6006   print_timestamp_time("[init video stuff]");
6007
6008   InitElementPropertiesStatic();
6009   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6010   InitElementPropertiesGfxElement();
6011
6012   print_timestamp_time("[init element properties stuff]");
6013
6014   InitGfx();
6015
6016   print_timestamp_time("InitGfx");
6017
6018   InitLevelInfo();
6019   print_timestamp_time("InitLevelInfo");
6020
6021   InitLevelArtworkInfo();
6022   print_timestamp_time("InitLevelArtworkInfo");
6023
6024   InitOverrideArtwork();        /* needs to know current level directory */
6025   print_timestamp_time("InitOverrideArtwork");
6026
6027   InitImages();                 /* needs to know current level directory */
6028   print_timestamp_time("InitImages");
6029
6030   InitSound(NULL);              /* needs to know current level directory */
6031   print_timestamp_time("InitSound");
6032
6033   InitMusic(NULL);              /* needs to know current level directory */
6034   print_timestamp_time("InitMusic");
6035
6036   InitArtworkDone();
6037
6038   InitGfxBackground();
6039
6040   em_open_all();
6041   sp_open_all();
6042
6043   if (global.autoplay_leveldir)
6044   {
6045     AutoPlayTape();
6046     return;
6047   }
6048   else if (global.convert_leveldir)
6049   {
6050     ConvertLevels();
6051     return;
6052   }
6053   else if (global.create_images_dir)
6054   {
6055     CreateLevelSketchImages();
6056     return;
6057   }
6058
6059   SetGameStatus(GAME_MODE_MAIN);
6060
6061   FadeSetEnterScreen();
6062   if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6063     FadeSkipNextFadeOut();
6064
6065   print_timestamp_time("[post-artwork]");
6066
6067   print_timestamp_done("OpenAll");
6068
6069   DrawMainMenu();
6070
6071   InitNetworkServer();
6072
6073 #if 0
6074   Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6075         SDL_GetBasePath());
6076   Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6077         SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6078 #if defined(PLATFORM_ANDROID)
6079   Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6080         SDL_AndroidGetInternalStoragePath());
6081   Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6082         SDL_AndroidGetExternalStoragePath());
6083   Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6084         (SDL_AndroidGetExternalStorageState() &
6085          SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6086          SDL_AndroidGetExternalStorageState() &
6087          SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6088 #endif
6089 #endif
6090 }
6091
6092 void CloseAllAndExit(int exit_value)
6093 {
6094   StopSounds();
6095   FreeAllSounds();
6096   FreeAllMusic();
6097   CloseAudio();         /* called after freeing sounds (needed for SDL) */
6098
6099   em_close_all();
6100   sp_close_all();
6101
6102   FreeAllImages();
6103
6104 #if defined(TARGET_SDL)
6105 #if defined(TARGET_SDL2)
6106   // !!! TODO !!!
6107   // set a flag to tell the network server thread to quit and wait for it
6108   // using SDL_WaitThread()
6109 #else
6110   if (network_server)   /* terminate network server */
6111     SDL_KillThread(server_thread);
6112 #endif
6113 #endif
6114
6115   CloseVideoDisplay();
6116   ClosePlatformDependentStuff();
6117
6118   if (exit_value != 0)
6119   {
6120     /* fall back to default level set (current set may have caused an error) */
6121     SaveLevelSetup_LastSeries_Deactivate();
6122
6123     /* tell user where to find error log file which may contain more details */
6124     // (error notification now directly displayed on screen inside R'n'D
6125     // NotifyUserAboutErrorFile();      /* currently only works for Windows */
6126   }
6127
6128   exit(exit_value);
6129 }