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