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