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