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