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