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