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