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