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