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