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