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