rnd-20061020-1-src
[rocksndiamonds.git] / src / init.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * init.c                                                   *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "init.h"
17 #include "events.h"
18 #include "screens.h"
19 #include "editor.h"
20 #include "game.h"
21 #include "tape.h"
22 #include "tools.h"
23 #include "files.h"
24 #include "network.h"
25 #include "netserv.h"
26 #include "cartoons.h"
27 #include "config.h"
28
29 #include "conf_e2g.c"   /* include auto-generated data structure definitions */
30 #include "conf_esg.c"   /* include auto-generated data structure definitions */
31 #include "conf_e2s.c"   /* include auto-generated data structure definitions */
32 #include "conf_fnt.c"   /* include auto-generated data structure definitions */
33 #include "conf_g2s.c"   /* include auto-generated data structure definitions */
34 #include "conf_g2m.c"   /* include auto-generated data structure definitions */
35
36
37 #define CONFIG_TOKEN_FONT_INITIAL               "font.initial"
38
39
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41
42 static int copy_properties[][5] =
43 {
44   {
45     EL_BUG,
46     EL_BUG_LEFT,                EL_BUG_RIGHT,
47     EL_BUG_UP,                  EL_BUG_DOWN
48   },
49   {
50     EL_SPACESHIP,
51     EL_SPACESHIP_LEFT,          EL_SPACESHIP_RIGHT,
52     EL_SPACESHIP_UP,            EL_SPACESHIP_DOWN
53   },
54   {
55     EL_BD_BUTTERFLY,
56     EL_BD_BUTTERFLY_LEFT,       EL_BD_BUTTERFLY_RIGHT,
57     EL_BD_BUTTERFLY_UP,         EL_BD_BUTTERFLY_DOWN
58   },
59   {
60     EL_BD_FIREFLY,
61     EL_BD_FIREFLY_LEFT,         EL_BD_FIREFLY_RIGHT,
62     EL_BD_FIREFLY_UP,           EL_BD_FIREFLY_DOWN
63   },
64   {
65     EL_PACMAN,
66     EL_PACMAN_LEFT,             EL_PACMAN_RIGHT,
67     EL_PACMAN_UP,               EL_PACMAN_DOWN
68   },
69   {
70     EL_YAMYAM,
71     EL_YAMYAM_LEFT,             EL_YAMYAM_RIGHT,
72     EL_YAMYAM_UP,               EL_YAMYAM_DOWN
73   },
74   {
75     EL_MOLE,
76     EL_MOLE_LEFT,               EL_MOLE_RIGHT,
77     EL_MOLE_UP,                 EL_MOLE_DOWN
78   },
79   {
80     -1,
81     -1, -1, -1, -1
82   }
83 };
84
85 void FreeGadgets()
86 {
87   FreeLevelEditorGadgets();
88   FreeGameButtons();
89   FreeTapeButtons();
90   FreeToolButtons();
91   FreeScreenGadgets();
92 }
93
94 void InitGadgets()
95 {
96   static boolean gadgets_initialized = FALSE;
97
98   if (gadgets_initialized)
99     FreeGadgets();
100
101   CreateLevelEditorGadgets();
102   CreateGameButtons();
103   CreateTapeButtons();
104   CreateToolButtons();
105   CreateScreenGadgets();
106
107   gadgets_initialized = TRUE;
108 }
109
110 inline void InitElementSmallImagesScaledUp(int graphic)
111 {
112   CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
113 }
114
115 void InitElementSmallImages()
116 {
117   static int special_graphics[] =
118   {
119     IMG_EDITOR_ELEMENT_BORDER,
120     IMG_EDITOR_ELEMENT_BORDER_INPUT,
121     IMG_EDITOR_CASCADE_LIST,
122     IMG_EDITOR_CASCADE_LIST_ACTIVE,
123     -1
124   };
125   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
126   int num_property_mappings = getImageListPropertyMappingSize();
127   int i;
128
129   /* initialize normal images from static configuration */
130   for (i = 0; element_to_graphic[i].element > -1; i++)
131     InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
132
133   /* initialize special images from static configuration */
134   for (i = 0; element_to_special_graphic[i].element > -1; i++)
135     InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
136
137   /* initialize images from dynamic configuration (may be elements or other) */
138   for (i = 0; i < num_property_mappings; i++)
139     InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
140
141   /* initialize special images from above list (non-element images) */
142   for (i = 0; special_graphics[i] > -1; i++)
143     InitElementSmallImagesScaledUp(special_graphics[i]);
144 }
145
146 void InitScaledImages()
147 {
148   int i;
149
150   /* scale normal images from static configuration, if not already scaled */
151   for (i = 0; i < NUM_IMAGE_FILES; i++)
152     ScaleImage(i, graphic_info[i].scale_up_factor);
153 }
154
155 #if 1
156 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
157 void SetBitmaps_EM(Bitmap **em_bitmap)
158 {
159   em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
160   em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
161 }
162 #endif
163
164 static int getFontBitmapID(int font_nr)
165 {
166   int special = -1;
167
168   if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
169     special = game_status;
170   else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
171     special = GFX_SPECIAL_ARG_MAIN;
172   else if (game_status == GAME_MODE_PLAYING)
173     special = GFX_SPECIAL_ARG_DOOR;
174
175   if (special != -1)
176     return font_info[font_nr].special_bitmap_id[special];
177   else
178     return font_nr;
179 }
180
181 void InitFontGraphicInfo()
182 {
183   static struct FontBitmapInfo *font_bitmap_info = NULL;
184   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
185   int num_property_mappings = getImageListPropertyMappingSize();
186   int num_font_bitmaps = NUM_FONTS;
187   int i, j;
188
189   if (graphic_info == NULL)             /* still at startup phase */
190   {
191     InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
192
193     return;
194   }
195
196   /* ---------- initialize font graphic definitions ---------- */
197
198   /* always start with reliable default values (normal font graphics) */
199   for (i = 0; i < NUM_FONTS; i++)
200     font_info[i].graphic = IMG_FONT_INITIAL_1;
201
202   /* initialize normal font/graphic mapping from static configuration */
203   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
204   {
205     int font_nr = font_to_graphic[i].font_nr;
206     int special = font_to_graphic[i].special;
207     int graphic = font_to_graphic[i].graphic;
208
209     if (special != -1)
210       continue;
211
212     font_info[font_nr].graphic = graphic;
213   }
214
215   /* always start with reliable default values (special font graphics) */
216   for (i = 0; i < NUM_FONTS; i++)
217   {
218     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
219     {
220       font_info[i].special_graphic[j] = font_info[i].graphic;
221       font_info[i].special_bitmap_id[j] = i;
222     }
223   }
224
225   /* initialize special font/graphic mapping from static configuration */
226   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
227   {
228     int font_nr      = font_to_graphic[i].font_nr;
229     int special      = font_to_graphic[i].special;
230     int graphic      = font_to_graphic[i].graphic;
231     int base_graphic = font2baseimg(font_nr);
232
233     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
234     {
235       boolean base_redefined =
236         getImageListEntryFromImageID(base_graphic)->redefined;
237       boolean special_redefined =
238         getImageListEntryFromImageID(graphic)->redefined;
239
240       /* if the base font ("font.title_1", for example) has been redefined,
241          but not the special font ("font.title_1.LEVELS", for example), do not
242          use an existing (in this case considered obsolete) special font
243          anymore, but use the automatically determined default font */
244       if (base_redefined && !special_redefined)
245         continue;
246
247       font_info[font_nr].special_graphic[special] = graphic;
248       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
249       num_font_bitmaps++;
250     }
251   }
252
253   /* initialize special font/graphic mapping from dynamic configuration */
254   for (i = 0; i < num_property_mappings; i++)
255   {
256     int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
257     int special = property_mapping[i].ext3_index;
258     int graphic = property_mapping[i].artwork_index;
259
260     if (font_nr < 0)
261       continue;
262
263     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
264     {
265       font_info[font_nr].special_graphic[special] = graphic;
266       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
267       num_font_bitmaps++;
268     }
269   }
270
271   /* reset non-redefined ".active" font graphics if normal font is redefined */
272   /* (this different treatment is needed because normal and active fonts are
273      independently defined ("active" is not a property of font definitions!) */
274   for (i = 0; i < NUM_FONTS; i++)
275   {
276     int font_nr_base = i;
277     int font_nr_active = FONT_ACTIVE(font_nr_base);
278
279     /* check only those fonts with exist as normal and ".active" variant */
280     if (font_nr_base != font_nr_active)
281     {
282       int base_graphic = font_info[font_nr_base].graphic;
283       int active_graphic = font_info[font_nr_active].graphic;
284       boolean base_redefined =
285         getImageListEntryFromImageID(base_graphic)->redefined;
286       boolean active_redefined =
287         getImageListEntryFromImageID(active_graphic)->redefined;
288
289       /* if the base font ("font.menu_1", for example) has been redefined,
290          but not the active font ("font.menu_1.active", for example), do not
291          use an existing (in this case considered obsolete) active font
292          anymore, but use the automatically determined default font */
293       if (base_redefined && !active_redefined)
294         font_info[font_nr_active].graphic = base_graphic;
295
296       /* now also check each "special" font (which may be the same as above) */
297       for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
298       {
299         int base_graphic = font_info[font_nr_base].special_graphic[j];
300         int active_graphic = font_info[font_nr_active].special_graphic[j];
301         boolean base_redefined =
302           getImageListEntryFromImageID(base_graphic)->redefined;
303         boolean active_redefined =
304           getImageListEntryFromImageID(active_graphic)->redefined;
305
306         /* same as above, but check special graphic definitions, for example:
307            redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
308         if (base_redefined && !active_redefined)
309         {
310           font_info[font_nr_active].special_graphic[j] =
311             font_info[font_nr_base].special_graphic[j];
312           font_info[font_nr_active].special_bitmap_id[j] =
313             font_info[font_nr_base].special_bitmap_id[j];
314         }
315       }
316     }
317   }
318
319   /* ---------- initialize font bitmap array ---------- */
320
321   if (font_bitmap_info != NULL)
322     FreeFontInfo(font_bitmap_info);
323
324   font_bitmap_info =
325     checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
326
327   /* ---------- initialize font bitmap definitions ---------- */
328
329   for (i = 0; i < NUM_FONTS; i++)
330   {
331     if (i < NUM_INITIAL_FONTS)
332     {
333       font_bitmap_info[i] = font_initial[i];
334       continue;
335     }
336
337     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
338     {
339       int font_bitmap_id = font_info[i].special_bitmap_id[j];
340       int graphic = font_info[i].special_graphic[j];
341
342       /* set 'graphic_info' for font entries, if uninitialized (guessed) */
343       if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
344       {
345         graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
346         graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
347       }
348
349       /* copy font relevant information from graphics information */
350       font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
351       font_bitmap_info[font_bitmap_id].src_x  = graphic_info[graphic].src_x;
352       font_bitmap_info[font_bitmap_id].src_y  = graphic_info[graphic].src_y;
353       font_bitmap_info[font_bitmap_id].width  = graphic_info[graphic].width;
354       font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
355
356       font_bitmap_info[font_bitmap_id].draw_xoffset =
357         graphic_info[graphic].draw_xoffset;
358       font_bitmap_info[font_bitmap_id].draw_yoffset =
359         graphic_info[graphic].draw_yoffset;
360
361       font_bitmap_info[font_bitmap_id].num_chars =
362         graphic_info[graphic].anim_frames;
363       font_bitmap_info[font_bitmap_id].num_chars_per_line =
364         graphic_info[graphic].anim_frames_per_line;
365     }
366   }
367
368   InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
369 }
370
371 void InitElementGraphicInfo()
372 {
373   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
374   int num_property_mappings = getImageListPropertyMappingSize();
375   int i, act, dir;
376
377   if (graphic_info == NULL)             /* still at startup phase */
378     return;
379
380   /* set values to -1 to identify later as "uninitialized" values */
381   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
382   {
383     for (act = 0; act < NUM_ACTIONS; act++)
384     {
385       element_info[i].graphic[act] = -1;
386       element_info[i].crumbled[act] = -1;
387
388       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
389       {
390         element_info[i].direction_graphic[act][dir] = -1;
391         element_info[i].direction_crumbled[act][dir] = -1;
392       }
393     }
394   }
395
396   /* initialize normal element/graphic mapping from static configuration */
397   for (i = 0; element_to_graphic[i].element > -1; i++)
398   {
399     int element      = element_to_graphic[i].element;
400     int action       = element_to_graphic[i].action;
401     int direction    = element_to_graphic[i].direction;
402     boolean crumbled = element_to_graphic[i].crumbled;
403     int graphic      = element_to_graphic[i].graphic;
404     int base_graphic = el2baseimg(element);
405
406     if (graphic_info[graphic].bitmap == NULL)
407       continue;
408
409     if ((action > -1 || direction > -1 || crumbled == TRUE) &&
410         base_graphic != -1)
411     {
412       boolean base_redefined =
413         getImageListEntryFromImageID(base_graphic)->redefined;
414       boolean act_dir_redefined =
415         getImageListEntryFromImageID(graphic)->redefined;
416
417       /* if the base graphic ("emerald", for example) has been redefined,
418          but not the action graphic ("emerald.falling", for example), do not
419          use an existing (in this case considered obsolete) action graphic
420          anymore, but use the automatically determined default graphic */
421       if (base_redefined && !act_dir_redefined)
422         continue;
423     }
424
425     if (action < 0)
426       action = ACTION_DEFAULT;
427
428     if (crumbled)
429     {
430       if (direction > -1)
431         element_info[element].direction_crumbled[action][direction] = graphic;
432       else
433         element_info[element].crumbled[action] = graphic;
434     }
435     else
436     {
437       if (direction > -1)
438         element_info[element].direction_graphic[action][direction] = graphic;
439       else
440         element_info[element].graphic[action] = graphic;
441     }
442   }
443
444   /* initialize normal element/graphic mapping from dynamic configuration */
445   for (i = 0; i < num_property_mappings; i++)
446   {
447     int element   = property_mapping[i].base_index;
448     int action    = property_mapping[i].ext1_index;
449     int direction = property_mapping[i].ext2_index;
450     int special   = property_mapping[i].ext3_index;
451     int graphic   = property_mapping[i].artwork_index;
452     boolean crumbled = FALSE;
453
454     if (special == GFX_SPECIAL_ARG_CRUMBLED)
455     {
456       special = -1;
457       crumbled = TRUE;
458     }
459
460     if (graphic_info[graphic].bitmap == NULL)
461       continue;
462
463     if (element >= MAX_NUM_ELEMENTS || special != -1)
464       continue;
465
466     if (action < 0)
467       action = ACTION_DEFAULT;
468
469     if (crumbled)
470     {
471       if (direction < 0)
472         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
473           element_info[element].direction_crumbled[action][dir] = -1;
474
475       if (direction > -1)
476         element_info[element].direction_crumbled[action][direction] = graphic;
477       else
478         element_info[element].crumbled[action] = graphic;
479     }
480     else
481     {
482       if (direction < 0)
483         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
484           element_info[element].direction_graphic[action][dir] = -1;
485
486       if (direction > -1)
487         element_info[element].direction_graphic[action][direction] = graphic;
488       else
489         element_info[element].graphic[action] = graphic;
490     }
491   }
492
493   /* now copy all graphics that are defined to be cloned from other graphics */
494   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
495   {
496     int graphic = element_info[i].graphic[ACTION_DEFAULT];
497     int crumbled_like, diggable_like;
498
499     if (graphic == -1)
500       continue;
501
502     crumbled_like = graphic_info[graphic].crumbled_like;
503     diggable_like = graphic_info[graphic].diggable_like;
504
505     if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
506     {
507       for (act = 0; act < NUM_ACTIONS; act++)
508         element_info[i].crumbled[act] =
509           element_info[crumbled_like].crumbled[act];
510       for (act = 0; act < NUM_ACTIONS; act++)
511         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
512           element_info[i].direction_crumbled[act][dir] =
513             element_info[crumbled_like].direction_crumbled[act][dir];
514     }
515
516     if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
517     {
518       element_info[i].graphic[ACTION_DIGGING] =
519         element_info[diggable_like].graphic[ACTION_DIGGING];
520       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
521         element_info[i].direction_graphic[ACTION_DIGGING][dir] =
522           element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
523     }
524   }
525
526 #if 1
527   /* set hardcoded definitions for some runtime elements without graphic */
528   element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
529 #endif
530
531 #if 1
532   /* set hardcoded definitions for some internal elements without graphic */
533   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
534   {
535     if (IS_EDITOR_CASCADE_INACTIVE(i))
536       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
537     else if (IS_EDITOR_CASCADE_ACTIVE(i))
538       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
539   }
540 #endif
541
542   /* now set all undefined/invalid graphics to -1 to set to default after it */
543   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
544   {
545     for (act = 0; act < NUM_ACTIONS; act++)
546     {
547       int graphic;
548
549       graphic = element_info[i].graphic[act];
550       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
551         element_info[i].graphic[act] = -1;
552
553       graphic = element_info[i].crumbled[act];
554       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
555         element_info[i].crumbled[act] = -1;
556
557       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
558       {
559         graphic = element_info[i].direction_graphic[act][dir];
560         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
561           element_info[i].direction_graphic[act][dir] = -1;
562
563         graphic = element_info[i].direction_crumbled[act][dir];
564         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
565           element_info[i].direction_crumbled[act][dir] = -1;
566       }
567     }
568   }
569
570   /* adjust graphics with 2nd tile for movement according to direction
571      (do this before correcting '-1' values to minimize calculations) */
572   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
573   {
574     for (act = 0; act < NUM_ACTIONS; act++)
575     {
576       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
577       {
578         int graphic = element_info[i].direction_graphic[act][dir];
579         int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
580
581         if (act == ACTION_FALLING)      /* special case */
582           graphic = element_info[i].graphic[act];
583
584         if (graphic != -1 &&
585             graphic_info[graphic].double_movement &&
586             graphic_info[graphic].swap_double_tiles != 0)
587         {
588           struct GraphicInfo *g = &graphic_info[graphic];
589           int src_x_front = g->src_x;
590           int src_y_front = g->src_y;
591           int src_x_back = g->src_x + g->offset2_x;
592           int src_y_back = g->src_y + g->offset2_y;
593           boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
594                                                    g->offset_y != 0);
595           boolean front_is_left_or_upper = (src_x_front < src_x_back ||
596                                             src_y_front < src_y_back);
597           boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
598           boolean swap_movement_tiles_autodetected =
599             (!frames_are_ordered_diagonally &&
600              ((move_dir == MV_BIT_LEFT  && !front_is_left_or_upper) ||
601               (move_dir == MV_BIT_UP    && !front_is_left_or_upper) ||
602               (move_dir == MV_BIT_RIGHT &&  front_is_left_or_upper) ||
603               (move_dir == MV_BIT_DOWN  &&  front_is_left_or_upper)));
604           Bitmap *dummy;
605
606           /* swap frontside and backside graphic tile coordinates, if needed */
607           if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
608           {
609             /* get current (wrong) backside tile coordinates */
610             getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
611                                 TRUE);
612
613             /* set frontside tile coordinates to backside tile coordinates */
614             g->src_x = src_x_back;
615             g->src_y = src_y_back;
616
617             /* invert tile offset to point to new backside tile coordinates */
618             g->offset2_x *= -1;
619             g->offset2_y *= -1;
620
621             /* do not swap front and backside tiles again after correction */
622             g->swap_double_tiles = 0;
623           }
624         }
625       }
626     }
627   }
628
629   /* now set all '-1' values to element specific default values */
630   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
631   {
632     int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
633     int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
634     int default_direction_graphic[NUM_DIRECTIONS_FULL];
635     int default_direction_crumbled[NUM_DIRECTIONS_FULL];
636
637     if (default_graphic == -1)
638       default_graphic = IMG_UNKNOWN;
639 #if 1
640     if (default_crumbled == -1)
641       default_crumbled = default_graphic;
642 #else
643     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
644     if (default_crumbled == -1)
645       default_crumbled = IMG_EMPTY;
646 #endif
647
648     for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
649     {
650       default_direction_graphic[dir] =
651         element_info[i].direction_graphic[ACTION_DEFAULT][dir];
652       default_direction_crumbled[dir] =
653         element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
654
655       if (default_direction_graphic[dir] == -1)
656         default_direction_graphic[dir] = default_graphic;
657 #if 1
658       if (default_direction_crumbled[dir] == -1)
659         default_direction_crumbled[dir] = default_direction_graphic[dir];
660 #else
661       /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
662       if (default_direction_crumbled[dir] == -1)
663         default_direction_crumbled[dir] = default_crumbled;
664 #endif
665     }
666
667     for (act = 0; act < NUM_ACTIONS; act++)
668     {
669       boolean act_remove = ((IS_DIGGABLE(i)    && act == ACTION_DIGGING)  ||
670                             (IS_SNAPPABLE(i)   && act == ACTION_SNAPPING) ||
671                             (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
672       boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
673                              act == ACTION_TURNING_FROM_RIGHT ||
674                              act == ACTION_TURNING_FROM_UP ||
675                              act == ACTION_TURNING_FROM_DOWN);
676
677       /* generic default action graphic (defined by "[default]" directive) */
678       int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
679       int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
680       int default_remove_graphic = IMG_EMPTY;
681
682       if (act_remove && default_action_graphic != -1)
683         default_remove_graphic = default_action_graphic;
684
685       /* look for special default action graphic (classic game specific) */
686       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
687         default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
688       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
689         default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
690       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
691         default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
692
693       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
694         default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
695       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
696         default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
697       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
698         default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
699
700 #if 1
701       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
702       /* !!! make this better !!! */
703       if (i == EL_EMPTY_SPACE)
704       {
705         default_action_graphic = element_info[EL_DEFAULT].graphic[act];
706         default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
707       }
708 #endif
709
710       if (default_action_graphic == -1)
711         default_action_graphic = default_graphic;
712 #if 1
713       if (default_action_crumbled == -1)
714         default_action_crumbled = default_action_graphic;
715 #else
716       /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
717       if (default_action_crumbled == -1)
718         default_action_crumbled = default_crumbled;
719 #endif
720
721       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
722       {
723         /* use action graphic as the default direction graphic, if undefined */
724         int default_action_direction_graphic = element_info[i].graphic[act];
725         int default_action_direction_crumbled = element_info[i].crumbled[act];
726
727         /* no graphic for current action -- use default direction graphic */
728         if (default_action_direction_graphic == -1)
729           default_action_direction_graphic =
730             (act_remove ? default_remove_graphic :
731              act_turning ?
732              element_info[i].direction_graphic[ACTION_TURNING][dir] :
733              default_action_graphic != default_graphic ?
734              default_action_graphic :
735              default_direction_graphic[dir]);
736
737         if (element_info[i].direction_graphic[act][dir] == -1)
738           element_info[i].direction_graphic[act][dir] =
739             default_action_direction_graphic;
740
741 #if 1
742         if (default_action_direction_crumbled == -1)
743           default_action_direction_crumbled =
744             element_info[i].direction_graphic[act][dir];
745 #else
746         if (default_action_direction_crumbled == -1)
747           default_action_direction_crumbled =
748             (act_remove ? default_remove_graphic :
749              act_turning ?
750              element_info[i].direction_crumbled[ACTION_TURNING][dir] :
751              default_action_crumbled != default_crumbled ?
752              default_action_crumbled :
753              default_direction_crumbled[dir]);
754 #endif
755
756         if (element_info[i].direction_crumbled[act][dir] == -1)
757           element_info[i].direction_crumbled[act][dir] =
758             default_action_direction_crumbled;
759       }
760
761       /* no graphic for this specific action -- use default action graphic */
762       if (element_info[i].graphic[act] == -1)
763         element_info[i].graphic[act] =
764           (act_remove ? default_remove_graphic :
765            act_turning ? element_info[i].graphic[ACTION_TURNING] :
766            default_action_graphic);
767 #if 1
768       if (element_info[i].crumbled[act] == -1)
769         element_info[i].crumbled[act] = element_info[i].graphic[act];
770 #else
771       if (element_info[i].crumbled[act] == -1)
772         element_info[i].crumbled[act] =
773           (act_remove ? default_remove_graphic :
774            act_turning ? element_info[i].crumbled[ACTION_TURNING] :
775            default_action_crumbled);
776 #endif
777     }
778   }
779
780 #if 0
781   /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
782   /* set animation mode to "none" for each graphic with only 1 frame */
783   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
784   {
785     for (act = 0; act < NUM_ACTIONS; act++)
786     {
787       int graphic = element_info[i].graphic[act];
788       int crumbled = element_info[i].crumbled[act];
789
790       if (graphic_info[graphic].anim_frames == 1)
791         graphic_info[graphic].anim_mode = ANIM_NONE;
792       if (graphic_info[crumbled].anim_frames == 1)
793         graphic_info[crumbled].anim_mode = ANIM_NONE;
794
795       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
796       {
797         graphic = element_info[i].direction_graphic[act][dir];
798         crumbled = element_info[i].direction_crumbled[act][dir];
799
800         if (graphic_info[graphic].anim_frames == 1)
801           graphic_info[graphic].anim_mode = ANIM_NONE;
802         if (graphic_info[crumbled].anim_frames == 1)
803           graphic_info[crumbled].anim_mode = ANIM_NONE;
804       }
805     }
806   }
807 #endif
808
809 #if 0
810 #if DEBUG
811   if (options.verbose)
812   {
813     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
814       if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
815           i != EL_UNKNOWN)
816         Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
817               element_info[i].token_name, i);
818   }
819 #endif
820 #endif
821 }
822
823 void InitElementSpecialGraphicInfo()
824 {
825   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
826   int num_property_mappings = getImageListPropertyMappingSize();
827   int i, j;
828
829   /* always start with reliable default values */
830   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
831     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
832       element_info[i].special_graphic[j] =
833         element_info[i].graphic[ACTION_DEFAULT];
834
835   /* initialize special element/graphic mapping from static configuration */
836   for (i = 0; element_to_special_graphic[i].element > -1; i++)
837   {
838     int element = element_to_special_graphic[i].element;
839     int special = element_to_special_graphic[i].special;
840     int graphic = element_to_special_graphic[i].graphic;
841     int base_graphic = el2baseimg(element);
842     boolean base_redefined =
843       getImageListEntryFromImageID(base_graphic)->redefined;
844     boolean special_redefined =
845       getImageListEntryFromImageID(graphic)->redefined;
846
847     /* if the base graphic ("emerald", for example) has been redefined,
848        but not the special graphic ("emerald.EDITOR", for example), do not
849        use an existing (in this case considered obsolete) special graphic
850        anymore, but use the automatically created (down-scaled) graphic */
851     if (base_redefined && !special_redefined)
852       continue;
853
854     element_info[element].special_graphic[special] = graphic;
855   }
856
857   /* initialize special element/graphic mapping from dynamic configuration */
858   for (i = 0; i < num_property_mappings; i++)
859   {
860     int element = property_mapping[i].base_index;
861     int special = property_mapping[i].ext3_index;
862     int graphic = property_mapping[i].artwork_index;
863
864     if (element >= MAX_NUM_ELEMENTS)
865       continue;
866
867     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
868       element_info[element].special_graphic[special] = graphic;
869   }
870
871   /* now set all undefined/invalid graphics to default */
872   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
873     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
874       if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
875         element_info[i].special_graphic[j] =
876           element_info[i].graphic[ACTION_DEFAULT];
877 }
878
879 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
880 {
881   int i;
882   int x = 0;
883
884   if (type != TYPE_TOKEN)
885     return get_parameter_value(value_raw, suffix, type);
886
887   if (strEqual(value_raw, ARG_UNDEFINED))
888     return ARG_UNDEFINED_VALUE;
889
890   /* !!! OPTIMIZE THIS BY USING HASH !!! */
891   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
892     if (strEqual(element_info[i].token_name, value_raw))
893       return i;
894
895   /* !!! OPTIMIZE THIS BY USING HASH !!! */
896   for (i = 0; image_config[i].token != NULL; i++)
897   {
898     int len_config_value = strlen(image_config[i].value);
899
900     if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
901         !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
902         !strEqual(image_config[i].value, UNDEFINED_FILENAME))
903       continue;
904
905     if (strEqual(image_config[i].token, value_raw))
906       return x;
907
908     x++;
909   }
910
911   return -1;
912 }
913
914 static int get_scaled_graphic_width(int graphic)
915 {
916   int original_width = getOriginalImageWidthFromImageID(graphic);
917   int scale_up_factor = graphic_info[graphic].scale_up_factor;
918
919   return original_width * scale_up_factor;
920 }
921
922 static int get_scaled_graphic_height(int graphic)
923 {
924   int original_height = getOriginalImageHeightFromImageID(graphic);
925   int scale_up_factor = graphic_info[graphic].scale_up_factor;
926
927   return original_height * scale_up_factor;
928 }
929
930 static void set_graphic_parameters(int graphic)
931 {
932   struct FileInfo *image = getImageListEntryFromImageID(graphic);
933   char **parameter_raw = image->parameter;
934   Bitmap *src_bitmap = getBitmapFromImageID(graphic);
935   int parameter[NUM_GFX_ARGS];
936   int anim_frames_per_row = 1, anim_frames_per_col = 1;
937   int anim_frames_per_line = 1;
938   int i;
939
940   /* if fallback to default artwork is done, also use the default parameters */
941   if (image->fallback_to_default)
942     parameter_raw = image->default_parameter;
943
944   /* get integer values from string parameters */
945   for (i = 0; i < NUM_GFX_ARGS; i++)
946     parameter[i] = get_graphic_parameter_value(parameter_raw[i],
947                                                image_config_suffix[i].token,
948                                                image_config_suffix[i].type);
949
950   graphic_info[graphic].bitmap = src_bitmap;
951
952   /* start with reliable default values */
953   graphic_info[graphic].src_image_width = 0;
954   graphic_info[graphic].src_image_height = 0;
955   graphic_info[graphic].src_x = 0;
956   graphic_info[graphic].src_y = 0;
957   graphic_info[graphic].width = TILEX;
958   graphic_info[graphic].height = TILEY;
959   graphic_info[graphic].offset_x = 0;   /* one or both of these values ... */
960   graphic_info[graphic].offset_y = 0;   /* ... will be corrected later */
961   graphic_info[graphic].offset2_x = 0;  /* one or both of these values ... */
962   graphic_info[graphic].offset2_y = 0;  /* ... will be corrected later */
963   graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
964   graphic_info[graphic].crumbled_like = -1;     /* do not use clone element */
965   graphic_info[graphic].diggable_like = -1;     /* do not use clone element */
966   graphic_info[graphic].border_size = TILEX / 8;  /* "CRUMBLED" border size */
967   graphic_info[graphic].scale_up_factor = 1;    /* default: no scaling up */
968   graphic_info[graphic].clone_from = -1;        /* do not use clone graphic */
969   graphic_info[graphic].anim_delay_fixed = 0;
970   graphic_info[graphic].anim_delay_random = 0;
971   graphic_info[graphic].post_delay_fixed = 0;
972   graphic_info[graphic].post_delay_random = 0;
973   graphic_info[graphic].fade_delay = -1;
974   graphic_info[graphic].post_delay = -1;
975   graphic_info[graphic].auto_delay = -1;
976
977   /* optional x and y tile position of animation frame sequence */
978   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
979     graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
980   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
981     graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
982
983   /* optional x and y pixel position of animation frame sequence */
984   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
985     graphic_info[graphic].src_x = parameter[GFX_ARG_X];
986   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
987     graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
988
989   /* optional width and height of each animation frame */
990   if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
991     graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
992   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
993     graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
994
995   /* optional zoom factor for scaling up the image to a larger size */
996   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
997     graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
998   if (graphic_info[graphic].scale_up_factor < 1)
999     graphic_info[graphic].scale_up_factor = 1;          /* no scaling */
1000
1001   if (src_bitmap)
1002   {
1003     /* get final bitmap size (with scaling, but without small images) */
1004     int src_image_width  = get_scaled_graphic_width(graphic);
1005     int src_image_height = get_scaled_graphic_height(graphic);
1006
1007     anim_frames_per_row = src_image_width  / graphic_info[graphic].width;
1008     anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1009
1010     graphic_info[graphic].src_image_width  = src_image_width;
1011     graphic_info[graphic].src_image_height = src_image_height;
1012   }
1013
1014   /* correct x or y offset dependent of vertical or horizontal frame order */
1015   if (parameter[GFX_ARG_VERTICAL])      /* frames are ordered vertically */
1016   {
1017     graphic_info[graphic].offset_y =
1018       (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1019        parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1020     anim_frames_per_line = anim_frames_per_col;
1021   }
1022   else                                  /* frames are ordered horizontally */
1023   {
1024     graphic_info[graphic].offset_x =
1025       (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1026        parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1027     anim_frames_per_line = anim_frames_per_row;
1028   }
1029
1030   /* optionally, the x and y offset of frames can be specified directly */
1031   if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1032     graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1033   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1034     graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1035
1036   /* optionally, moving animations may have separate start and end graphics */
1037   graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1038
1039   if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1040     parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1041
1042   /* correct x or y offset2 dependent of vertical or horizontal frame order */
1043   if (parameter[GFX_ARG_2ND_VERTICAL])  /* frames are ordered vertically */
1044     graphic_info[graphic].offset2_y =
1045       (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1046        parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1047   else                                  /* frames are ordered horizontally */
1048     graphic_info[graphic].offset2_x =
1049       (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1050        parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1051
1052   /* optionally, the x and y offset of 2nd graphic can be specified directly */
1053   if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1054     graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1055   if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1056     graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1057
1058   /* optionally, the second movement tile can be specified as start tile */
1059   if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1060     graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1061
1062   /* automatically determine correct number of frames, if not defined */
1063   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1064     graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1065   else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1066     graphic_info[graphic].anim_frames = anim_frames_per_row;
1067   else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1068     graphic_info[graphic].anim_frames = anim_frames_per_col;
1069   else
1070     graphic_info[graphic].anim_frames = 1;
1071
1072   if (graphic_info[graphic].anim_frames == 0)   /* frames must be at least 1 */
1073     graphic_info[graphic].anim_frames = 1;
1074
1075   graphic_info[graphic].anim_frames_per_line =
1076     (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1077      parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1078
1079   graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1080   if (graphic_info[graphic].anim_delay == 0)    /* delay must be at least 1 */
1081     graphic_info[graphic].anim_delay = 1;
1082
1083   graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1084 #if 0
1085   if (graphic_info[graphic].anim_frames == 1)
1086     graphic_info[graphic].anim_mode = ANIM_NONE;
1087 #endif
1088
1089   /* automatically determine correct start frame, if not defined */
1090   if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1091     graphic_info[graphic].anim_start_frame = 0;
1092   else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1093     graphic_info[graphic].anim_start_frame =
1094       graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1095   else
1096     graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1097
1098   /* animation synchronized with global frame counter, not move position */
1099   graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1100
1101   /* optional element for cloning crumble graphics */
1102   if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1103     graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1104
1105   /* optional element for cloning digging graphics */
1106   if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1107     graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1108
1109   /* optional border size for "crumbling" diggable graphics */
1110   if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1111     graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1112
1113   /* this is only used for player "boring" and "sleeping" actions */
1114   if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1115     graphic_info[graphic].anim_delay_fixed =
1116       parameter[GFX_ARG_ANIM_DELAY_FIXED];
1117   if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1118     graphic_info[graphic].anim_delay_random =
1119       parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1120   if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1121     graphic_info[graphic].post_delay_fixed =
1122       parameter[GFX_ARG_POST_DELAY_FIXED];
1123   if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1124     graphic_info[graphic].post_delay_random =
1125       parameter[GFX_ARG_POST_DELAY_RANDOM];
1126
1127   /* this is only used for toon animations */
1128   graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1129   graphic_info[graphic].step_delay  = parameter[GFX_ARG_STEP_DELAY];
1130
1131   /* this is only used for drawing font characters */
1132   graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1133   graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1134
1135   /* this is only used for drawing envelope graphics */
1136   graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1137
1138   /* optional graphic for cloning all graphics settings */
1139   if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1140     graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1141
1142   /* optional settings for drawing title screens */
1143   if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1144     graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1145   if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1146     graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1147   if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1148     graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1149 }
1150
1151 static void set_cloned_graphic_parameters(int graphic)
1152 {
1153   int fallback_graphic = IMG_CHAR_EXCLAM;
1154   int max_num_images = getImageListSize();
1155   int clone_graphic = graphic_info[graphic].clone_from;
1156   int num_references_followed = 1;
1157
1158   while (graphic_info[clone_graphic].clone_from != -1 &&
1159          num_references_followed < max_num_images)
1160   {
1161     clone_graphic = graphic_info[clone_graphic].clone_from;
1162
1163     num_references_followed++;
1164   }
1165
1166   if (num_references_followed >= max_num_images)
1167   {
1168     Error(ERR_RETURN_LINE, "-");
1169     Error(ERR_RETURN, "warning: error found in config file:");
1170     Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1171     Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1172     Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1173     Error(ERR_RETURN, "custom graphic rejected for this element/action");
1174
1175     if (graphic == fallback_graphic)
1176       Error(ERR_EXIT, "fatal error: no fallback graphic available");
1177
1178     Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1179     Error(ERR_RETURN_LINE, "-");
1180
1181     graphic_info[graphic] = graphic_info[fallback_graphic];
1182   }
1183   else
1184   {
1185     graphic_info[graphic] = graphic_info[clone_graphic];
1186     graphic_info[graphic].clone_from = clone_graphic;
1187   }
1188 }
1189
1190 static void InitGraphicInfo()
1191 {
1192   int fallback_graphic = IMG_CHAR_EXCLAM;
1193   int num_images = getImageListSize();
1194   int i;
1195
1196 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1197   static boolean clipmasks_initialized = FALSE;
1198   Pixmap src_pixmap;
1199   XGCValues clip_gc_values;
1200   unsigned long clip_gc_valuemask;
1201   GC copy_clipmask_gc = None;
1202 #endif
1203
1204   checked_free(graphic_info);
1205
1206   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1207
1208 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1209   if (clipmasks_initialized)
1210   {
1211     for (i = 0; i < num_images; i++)
1212     {
1213       if (graphic_info[i].clip_mask)
1214         XFreePixmap(display, graphic_info[i].clip_mask);
1215       if (graphic_info[i].clip_gc)
1216         XFreeGC(display, graphic_info[i].clip_gc);
1217
1218       graphic_info[i].clip_mask = None;
1219       graphic_info[i].clip_gc = None;
1220     }
1221   }
1222 #endif
1223
1224   /* first set all graphic paramaters ... */
1225   for (i = 0; i < num_images; i++)
1226     set_graphic_parameters(i);
1227
1228   /* ... then copy these parameters for cloned graphics */
1229   for (i = 0; i < num_images; i++)
1230     if (graphic_info[i].clone_from != -1)
1231       set_cloned_graphic_parameters(i);
1232
1233   for (i = 0; i < num_images; i++)
1234   {
1235     Bitmap *src_bitmap;
1236     int src_x, src_y;
1237     int first_frame, last_frame;
1238     int src_bitmap_width, src_bitmap_height;
1239
1240     /* now check if no animation frames are outside of the loaded image */
1241
1242     if (graphic_info[i].bitmap == NULL)
1243       continue;         /* skip check for optional images that are undefined */
1244
1245     /* get final bitmap size (with scaling, but without small images) */
1246     src_bitmap_width  = graphic_info[i].src_image_width;
1247     src_bitmap_height = graphic_info[i].src_image_height;
1248
1249     /* check if first animation frame is inside specified bitmap */
1250
1251     first_frame = 0;
1252     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1253
1254     if (src_x < 0 || src_y < 0 ||
1255         src_x + TILEX > src_bitmap_width ||
1256         src_y + TILEY > src_bitmap_height)
1257     {
1258       Error(ERR_RETURN_LINE, "-");
1259       Error(ERR_RETURN, "warning: error found in config file:");
1260       Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1261       Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1262       Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1263       Error(ERR_RETURN,
1264             "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1265             src_x, src_y, src_bitmap_width, src_bitmap_height);
1266       Error(ERR_RETURN, "custom graphic rejected for this element/action");
1267
1268       if (i == fallback_graphic)
1269         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1270
1271       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1272       Error(ERR_RETURN_LINE, "-");
1273
1274       graphic_info[i] = graphic_info[fallback_graphic];
1275     }
1276
1277     /* check if last animation frame is inside specified bitmap */
1278
1279     last_frame = graphic_info[i].anim_frames - 1;
1280     getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1281
1282     if (src_x < 0 || src_y < 0 ||
1283         src_x + TILEX > src_bitmap_width ||
1284         src_y + TILEY > src_bitmap_height)
1285     {
1286       Error(ERR_RETURN_LINE, "-");
1287       Error(ERR_RETURN, "warning: error found in config file:");
1288       Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1289       Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1290       Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1291       Error(ERR_RETURN,
1292             "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1293             last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1294       Error(ERR_RETURN, "custom graphic rejected for this element/action");
1295
1296       if (i == fallback_graphic)
1297         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1298
1299       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1300       Error(ERR_RETURN_LINE, "-");
1301
1302       graphic_info[i] = graphic_info[fallback_graphic];
1303     }
1304
1305 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1306     /* currently we only need a tile clip mask from the first frame */
1307     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1308
1309     if (copy_clipmask_gc == None)
1310     {
1311       clip_gc_values.graphics_exposures = False;
1312       clip_gc_valuemask = GCGraphicsExposures;
1313       copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1314                                    clip_gc_valuemask, &clip_gc_values);
1315     }
1316
1317     graphic_info[i].clip_mask =
1318       XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1319
1320     src_pixmap = src_bitmap->clip_mask;
1321     XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1322               copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1323
1324     clip_gc_values.graphics_exposures = False;
1325     clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1326     clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1327
1328     graphic_info[i].clip_gc =
1329       XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1330 #endif
1331   }
1332
1333 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1334   if (copy_clipmask_gc)
1335     XFreeGC(display, copy_clipmask_gc);
1336
1337   clipmasks_initialized = TRUE;
1338 #endif
1339 }
1340
1341 static void InitElementSoundInfo()
1342 {
1343   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1344   int num_property_mappings = getSoundListPropertyMappingSize();
1345   int i, j, act;
1346
1347   /* set values to -1 to identify later as "uninitialized" values */
1348   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1349     for (act = 0; act < NUM_ACTIONS; act++)
1350       element_info[i].sound[act] = -1;
1351
1352   /* initialize element/sound mapping from static configuration */
1353   for (i = 0; element_to_sound[i].element > -1; i++)
1354   {
1355     int element      = element_to_sound[i].element;
1356     int action       = element_to_sound[i].action;
1357     int sound        = element_to_sound[i].sound;
1358     boolean is_class = element_to_sound[i].is_class;
1359
1360     if (action < 0)
1361       action = ACTION_DEFAULT;
1362
1363     if (!is_class)
1364       element_info[element].sound[action] = sound;
1365     else
1366       for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1367         if (strEqual(element_info[j].class_name,
1368                      element_info[element].class_name))
1369           element_info[j].sound[action] = sound;
1370   }
1371
1372   /* initialize element class/sound mapping from dynamic configuration */
1373   for (i = 0; i < num_property_mappings; i++)
1374   {
1375     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1376     int action        = property_mapping[i].ext1_index;
1377     int sound         = property_mapping[i].artwork_index;
1378
1379     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1380       continue;
1381
1382     if (action < 0)
1383       action = ACTION_DEFAULT;
1384
1385     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1386       if (strEqual(element_info[j].class_name,
1387                    element_info[element_class].class_name))
1388         element_info[j].sound[action] = sound;
1389   }
1390
1391   /* initialize element/sound mapping from dynamic configuration */
1392   for (i = 0; i < num_property_mappings; i++)
1393   {
1394     int element = property_mapping[i].base_index;
1395     int action  = property_mapping[i].ext1_index;
1396     int sound   = property_mapping[i].artwork_index;
1397
1398     if (element >= MAX_NUM_ELEMENTS)
1399       continue;
1400
1401     if (action < 0)
1402       action = ACTION_DEFAULT;
1403
1404     element_info[element].sound[action] = sound;
1405   }
1406
1407   /* now set all '-1' values to element specific default values */
1408   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1409   {
1410     for (act = 0; act < NUM_ACTIONS; act++)
1411     {
1412       /* generic default action sound (defined by "[default]" directive) */
1413       int default_action_sound = element_info[EL_DEFAULT].sound[act];
1414
1415       /* look for special default action sound (classic game specific) */
1416       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1417         default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1418       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1419         default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1420       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1421         default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1422
1423       /* !!! there's no such thing as a "default action sound" !!! */
1424 #if 0
1425       /* look for element specific default sound (independent from action) */
1426       if (element_info[i].sound[ACTION_DEFAULT] != -1)
1427         default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1428 #endif
1429
1430 #if 1
1431       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1432       /* !!! make this better !!! */
1433       if (i == EL_EMPTY_SPACE)
1434         default_action_sound = element_info[EL_DEFAULT].sound[act];
1435 #endif
1436
1437       /* no sound for this specific action -- use default action sound */
1438       if (element_info[i].sound[act] == -1)
1439         element_info[i].sound[act] = default_action_sound;
1440     }
1441   }
1442
1443   /* copy sound settings to some elements that are only stored in level file
1444      in native R'n'D levels, but are used by game engine in native EM levels */
1445   for (i = 0; copy_properties[i][0] != -1; i++)
1446     for (j = 1; j <= 4; j++)
1447       for (act = 0; act < NUM_ACTIONS; act++)
1448         element_info[copy_properties[i][j]].sound[act] =
1449           element_info[copy_properties[i][0]].sound[act];
1450 }
1451
1452 static void InitGameModeSoundInfo()
1453 {
1454   int i;
1455
1456   /* set values to -1 to identify later as "uninitialized" values */
1457   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1458     menu.sound[i] = -1;
1459
1460   /* initialize gamemode/sound mapping from static configuration */
1461   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1462   {
1463     int gamemode = gamemode_to_sound[i].gamemode;
1464     int sound    = gamemode_to_sound[i].sound;
1465
1466     if (gamemode < 0)
1467       gamemode = GAME_MODE_DEFAULT;
1468
1469     menu.sound[gamemode] = sound;
1470   }
1471
1472   /* now set all '-1' values to levelset specific default values */
1473   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1474     if (menu.sound[i] == -1)
1475       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1476
1477 #if 0
1478   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1479     if (menu.sound[i] != -1)
1480       printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1481 #endif
1482 }
1483
1484 static void set_sound_parameters(int sound, char **parameter_raw)
1485 {
1486   int parameter[NUM_SND_ARGS];
1487   int i;
1488
1489   /* get integer values from string parameters */
1490   for (i = 0; i < NUM_SND_ARGS; i++)
1491     parameter[i] =
1492       get_parameter_value(parameter_raw[i],
1493                           sound_config_suffix[i].token,
1494                           sound_config_suffix[i].type);
1495
1496   /* explicit loop mode setting in configuration overrides default value */
1497   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1498     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1499
1500   /* sound volume to change the original volume when loading the sound file */
1501   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1502
1503   /* sound priority to give certain sounds a higher or lower priority */
1504   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1505 }
1506
1507 static void InitSoundInfo()
1508 {
1509   int *sound_effect_properties;
1510   int num_sounds = getSoundListSize();
1511   int i, j;
1512
1513   checked_free(sound_info);
1514
1515   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1516   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1517
1518   /* initialize sound effect for all elements to "no sound" */
1519   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1520     for (j = 0; j < NUM_ACTIONS; j++)
1521       element_info[i].sound[j] = SND_UNDEFINED;
1522
1523   for (i = 0; i < num_sounds; i++)
1524   {
1525     struct FileInfo *sound = getSoundListEntry(i);
1526     int len_effect_text = strlen(sound->token);
1527
1528     sound_effect_properties[i] = ACTION_OTHER;
1529     sound_info[i].loop = FALSE;         /* default: play sound only once */
1530
1531 #if 0
1532     printf("::: sound %d: '%s'\n", i, sound->token);
1533 #endif
1534
1535     /* determine all loop sounds and identify certain sound classes */
1536
1537     for (j = 0; element_action_info[j].suffix; j++)
1538     {
1539       int len_action_text = strlen(element_action_info[j].suffix);
1540
1541       if (len_action_text < len_effect_text &&
1542           strEqual(&sound->token[len_effect_text - len_action_text],
1543                    element_action_info[j].suffix))
1544       {
1545         sound_effect_properties[i] = element_action_info[j].value;
1546         sound_info[i].loop = element_action_info[j].is_loop_sound;
1547
1548         break;
1549       }
1550     }
1551
1552     /* associate elements and some selected sound actions */
1553
1554     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1555     {
1556       if (element_info[j].class_name)
1557       {
1558         int len_class_text = strlen(element_info[j].class_name);
1559
1560         if (len_class_text + 1 < len_effect_text &&
1561             strncmp(sound->token,
1562                     element_info[j].class_name, len_class_text) == 0 &&
1563             sound->token[len_class_text] == '.')
1564         {
1565           int sound_action_value = sound_effect_properties[i];
1566
1567           element_info[j].sound[sound_action_value] = i;
1568         }
1569       }
1570     }
1571
1572     set_sound_parameters(i, sound->parameter);
1573   }
1574
1575   free(sound_effect_properties);
1576 }
1577
1578 static void InitGameModeMusicInfo()
1579 {
1580   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1581   int num_property_mappings = getMusicListPropertyMappingSize();
1582   int default_levelset_music = -1;
1583   int i;
1584
1585   /* set values to -1 to identify later as "uninitialized" values */
1586   for (i = 0; i < MAX_LEVELS; i++)
1587     levelset.music[i] = -1;
1588   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1589     menu.music[i] = -1;
1590
1591   /* initialize gamemode/music mapping from static configuration */
1592   for (i = 0; gamemode_to_music[i].music > -1; i++)
1593   {
1594     int gamemode = gamemode_to_music[i].gamemode;
1595     int music    = gamemode_to_music[i].music;
1596
1597 #if 0
1598     printf("::: gamemode == %d, music == %d\n", gamemode, music);
1599 #endif
1600
1601     if (gamemode < 0)
1602       gamemode = GAME_MODE_DEFAULT;
1603
1604     menu.music[gamemode] = music;
1605   }
1606
1607   /* initialize gamemode/music mapping from dynamic configuration */
1608   for (i = 0; i < num_property_mappings; i++)
1609   {
1610     int prefix   = property_mapping[i].base_index;
1611     int gamemode = property_mapping[i].ext1_index;
1612     int level    = property_mapping[i].ext2_index;
1613     int music    = property_mapping[i].artwork_index;
1614
1615 #if 0
1616     printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1617            prefix, gamemode, level, music);
1618 #endif
1619
1620     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1621       continue;
1622
1623     if (gamemode < 0)
1624       gamemode = GAME_MODE_DEFAULT;
1625
1626     /* level specific music only allowed for in-game music */
1627     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1628       gamemode = GAME_MODE_PLAYING;
1629
1630     if (level == -1)
1631     {
1632       level = 0;
1633       default_levelset_music = music;
1634     }
1635
1636     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1637       levelset.music[level] = music;
1638     if (gamemode != GAME_MODE_PLAYING)
1639       menu.music[gamemode] = music;
1640   }
1641
1642   /* now set all '-1' values to menu specific default values */
1643   /* (undefined values of "levelset.music[]" might stay at "-1" to
1644      allow dynamic selection of music files from music directory!) */
1645   for (i = 0; i < MAX_LEVELS; i++)
1646     if (levelset.music[i] == -1)
1647       levelset.music[i] = default_levelset_music;
1648   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1649     if (menu.music[i] == -1)
1650       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1651
1652 #if 0
1653   for (i = 0; i < MAX_LEVELS; i++)
1654     if (levelset.music[i] != -1)
1655       printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1656   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1657     if (menu.music[i] != -1)
1658       printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1659 #endif
1660 }
1661
1662 static void set_music_parameters(int music, char **parameter_raw)
1663 {
1664   int parameter[NUM_MUS_ARGS];
1665   int i;
1666
1667   /* get integer values from string parameters */
1668   for (i = 0; i < NUM_MUS_ARGS; i++)
1669     parameter[i] =
1670       get_parameter_value(parameter_raw[i],
1671                           music_config_suffix[i].token,
1672                           music_config_suffix[i].type);
1673
1674   /* explicit loop mode setting in configuration overrides default value */
1675   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1676     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1677 }
1678
1679 static void InitMusicInfo()
1680 {
1681   int num_music = getMusicListSize();
1682   int i, j;
1683
1684   checked_free(music_info);
1685
1686   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1687
1688   for (i = 0; i < num_music; i++)
1689   {
1690     struct FileInfo *music = getMusicListEntry(i);
1691     int len_music_text = strlen(music->token);
1692
1693     music_info[i].loop = TRUE;          /* default: play music in loop mode */
1694
1695     /* determine all loop music */
1696
1697     for (j = 0; music_prefix_info[j].prefix; j++)
1698     {
1699       int len_prefix_text = strlen(music_prefix_info[j].prefix);
1700
1701       if (len_prefix_text < len_music_text &&
1702           strncmp(music->token,
1703                   music_prefix_info[j].prefix, len_prefix_text) == 0)
1704       {
1705         music_info[i].loop = music_prefix_info[j].is_loop_music;
1706
1707         break;
1708       }
1709     }
1710
1711     set_music_parameters(i, music->parameter);
1712   }
1713 }
1714
1715 static void ReinitializeGraphics()
1716 {
1717   InitGraphicInfo();                    /* graphic properties mapping */
1718   InitElementGraphicInfo();             /* element game graphic mapping */
1719   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
1720
1721   InitElementSmallImages();             /* scale elements to all needed sizes */
1722   InitScaledImages();                   /* scale all other images, if needed */
1723   InitFontGraphicInfo();                /* initialize text drawing functions */
1724
1725   InitGraphicInfo_EM();                 /* graphic mapping for EM engine */
1726
1727   SetMainBackgroundImage(IMG_BACKGROUND);
1728   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1729
1730   InitGadgets();
1731   InitToons();
1732 }
1733
1734 static void ReinitializeSounds()
1735 {
1736   InitSoundInfo();              /* sound properties mapping */
1737   InitElementSoundInfo();       /* element game sound mapping */
1738   InitGameModeSoundInfo();      /* game mode sound mapping */
1739
1740   InitPlayLevelSound();         /* internal game sound settings */
1741 }
1742
1743 static void ReinitializeMusic()
1744 {
1745   InitMusicInfo();              /* music properties mapping */
1746   InitGameModeMusicInfo();      /* game mode music mapping */
1747 }
1748
1749 static int get_special_property_bit(int element, int property_bit_nr)
1750 {
1751   struct PropertyBitInfo
1752   {
1753     int element;
1754     int bit_nr;
1755   };
1756
1757   static struct PropertyBitInfo pb_can_move_into_acid[] =
1758   {
1759     /* the player may be able fall into acid when gravity is activated */
1760     { EL_PLAYER_1,              0       },
1761     { EL_PLAYER_2,              0       },
1762     { EL_PLAYER_3,              0       },
1763     { EL_PLAYER_4,              0       },
1764     { EL_SP_MURPHY,             0       },
1765     { EL_SOKOBAN_FIELD_PLAYER,  0       },
1766
1767     /* all elements that can move may be able to also move into acid */
1768     { EL_BUG,                   1       },
1769     { EL_BUG_LEFT,              1       },
1770     { EL_BUG_RIGHT,             1       },
1771     { EL_BUG_UP,                1       },
1772     { EL_BUG_DOWN,              1       },
1773     { EL_SPACESHIP,             2       },
1774     { EL_SPACESHIP_LEFT,        2       },
1775     { EL_SPACESHIP_RIGHT,       2       },
1776     { EL_SPACESHIP_UP,          2       },
1777     { EL_SPACESHIP_DOWN,        2       },
1778     { EL_BD_BUTTERFLY,          3       },
1779     { EL_BD_BUTTERFLY_LEFT,     3       },
1780     { EL_BD_BUTTERFLY_RIGHT,    3       },
1781     { EL_BD_BUTTERFLY_UP,       3       },
1782     { EL_BD_BUTTERFLY_DOWN,     3       },
1783     { EL_BD_FIREFLY,            4       },
1784     { EL_BD_FIREFLY_LEFT,       4       },
1785     { EL_BD_FIREFLY_RIGHT,      4       },
1786     { EL_BD_FIREFLY_UP,         4       },
1787     { EL_BD_FIREFLY_DOWN,       4       },
1788     { EL_YAMYAM,                5       },
1789     { EL_YAMYAM_LEFT,           5       },
1790     { EL_YAMYAM_RIGHT,          5       },
1791     { EL_YAMYAM_UP,             5       },
1792     { EL_YAMYAM_DOWN,           5       },
1793     { EL_DARK_YAMYAM,           6       },
1794     { EL_ROBOT,                 7       },
1795     { EL_PACMAN,                8       },
1796     { EL_PACMAN_LEFT,           8       },
1797     { EL_PACMAN_RIGHT,          8       },
1798     { EL_PACMAN_UP,             8       },
1799     { EL_PACMAN_DOWN,           8       },
1800     { EL_MOLE,                  9       },
1801     { EL_MOLE_LEFT,             9       },
1802     { EL_MOLE_RIGHT,            9       },
1803     { EL_MOLE_UP,               9       },
1804     { EL_MOLE_DOWN,             9       },
1805     { EL_PENGUIN,               10      },
1806     { EL_PIG,                   11      },
1807     { EL_DRAGON,                12      },
1808     { EL_SATELLITE,             13      },
1809     { EL_SP_SNIKSNAK,           14      },
1810     { EL_SP_ELECTRON,           15      },
1811     { EL_BALLOON,               16      },
1812     { EL_SPRING,                17      },
1813     { EL_EMC_ANDROID,           18      },
1814
1815     { -1,                       -1      },
1816   };
1817
1818   static struct PropertyBitInfo pb_dont_collide_with[] =
1819   {
1820     { EL_SP_SNIKSNAK,           0       },
1821     { EL_SP_ELECTRON,           1       },
1822
1823     { -1,                       -1      },
1824   };
1825
1826   static struct
1827   {
1828     int bit_nr;
1829     struct PropertyBitInfo *pb_info;
1830   } pb_definition[] =
1831   {
1832     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
1833     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
1834
1835     { -1,                       NULL                    },
1836   };
1837
1838   struct PropertyBitInfo *pb_info = NULL;
1839   int i;
1840
1841   for (i = 0; pb_definition[i].bit_nr != -1; i++)
1842     if (pb_definition[i].bit_nr == property_bit_nr)
1843       pb_info = pb_definition[i].pb_info;
1844
1845   if (pb_info == NULL)
1846     return -1;
1847
1848   for (i = 0; pb_info[i].element != -1; i++)
1849     if (pb_info[i].element == element)
1850       return pb_info[i].bit_nr;
1851
1852   return -1;
1853 }
1854
1855 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1856                          boolean property_value)
1857 {
1858   int bit_nr = get_special_property_bit(element, property_bit_nr);
1859
1860   if (bit_nr > -1)
1861   {
1862     if (property_value)
1863       *bitfield |=  (1 << bit_nr);
1864     else
1865       *bitfield &= ~(1 << bit_nr);
1866   }
1867 }
1868
1869 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1870 {
1871   int bit_nr = get_special_property_bit(element, property_bit_nr);
1872
1873   if (bit_nr > -1)
1874     return ((*bitfield & (1 << bit_nr)) != 0);
1875
1876   return FALSE;
1877 }
1878
1879 static void resolve_group_element(int group_element, int recursion_depth)
1880 {
1881   static int group_nr;
1882   static struct ElementGroupInfo *group;
1883   struct ElementGroupInfo *actual_group = element_info[group_element].group;
1884   int i;
1885
1886   if (actual_group == NULL)                     /* not yet initialized */
1887     return;
1888
1889   if (recursion_depth > NUM_GROUP_ELEMENTS)     /* recursion too deep */
1890   {
1891     Error(ERR_WARN, "recursion too deep when resolving group element %d",
1892           group_element - EL_GROUP_START + 1);
1893
1894     /* replace element which caused too deep recursion by question mark */
1895     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1896
1897     return;
1898   }
1899
1900   if (recursion_depth == 0)                     /* initialization */
1901   {
1902     group = actual_group;
1903     group_nr = group_element - EL_GROUP_START;
1904
1905     group->num_elements_resolved = 0;
1906     group->choice_pos = 0;
1907   }
1908
1909   for (i = 0; i < actual_group->num_elements; i++)
1910   {
1911     int element = actual_group->element[i];
1912
1913     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1914       break;
1915
1916     if (IS_GROUP_ELEMENT(element))
1917       resolve_group_element(element, recursion_depth + 1);
1918     else
1919     {
1920       group->element_resolved[group->num_elements_resolved++] = element;
1921       element_info[element].in_group[group_nr] = TRUE;
1922     }
1923   }
1924 }
1925
1926 void InitElementPropertiesStatic()
1927 {
1928   static int ep_diggable[] =
1929   {
1930     EL_SAND,
1931     EL_SP_BASE,
1932     EL_SP_BUGGY_BASE,
1933     EL_SP_BUGGY_BASE_ACTIVATING,
1934     EL_TRAP,
1935     EL_INVISIBLE_SAND,
1936     EL_INVISIBLE_SAND_ACTIVE,
1937     EL_EMC_GRASS,
1938
1939     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1940     /* (if amoeba can grow into anything diggable, maybe keep these out) */
1941 #if 0
1942     EL_LANDMINE,
1943     EL_TRAP_ACTIVE,
1944     EL_SP_BUGGY_BASE_ACTIVE,
1945     EL_EMC_PLANT,
1946 #endif
1947
1948     -1
1949   };
1950
1951   static int ep_collectible_only[] =
1952   {
1953     EL_BD_DIAMOND,
1954     EL_EMERALD,
1955     EL_DIAMOND,
1956     EL_EMERALD_YELLOW,
1957     EL_EMERALD_RED,
1958     EL_EMERALD_PURPLE,
1959     EL_KEY_1,
1960     EL_KEY_2,
1961     EL_KEY_3,
1962     EL_KEY_4,
1963     EL_EM_KEY_1,
1964     EL_EM_KEY_2,
1965     EL_EM_KEY_3,
1966     EL_EM_KEY_4,
1967     EL_EMC_KEY_5,
1968     EL_EMC_KEY_6,
1969     EL_EMC_KEY_7,
1970     EL_EMC_KEY_8,
1971     EL_DYNAMITE,
1972     EL_EM_DYNAMITE,
1973     EL_DYNABOMB_INCREASE_NUMBER,
1974     EL_DYNABOMB_INCREASE_SIZE,
1975     EL_DYNABOMB_INCREASE_POWER,
1976     EL_SP_INFOTRON,
1977     EL_SP_DISK_RED,
1978     EL_PEARL,
1979     EL_CRYSTAL,
1980     EL_KEY_WHITE,
1981     EL_SHIELD_NORMAL,
1982     EL_SHIELD_DEADLY,
1983     EL_EXTRA_TIME,
1984     EL_ENVELOPE_1,
1985     EL_ENVELOPE_2,
1986     EL_ENVELOPE_3,
1987     EL_ENVELOPE_4,
1988     EL_SPEED_PILL,
1989     EL_EMC_LENSES,
1990     EL_EMC_MAGNIFIER,
1991
1992     -1
1993   };
1994
1995   static int ep_dont_run_into[] =
1996   {
1997     /* same elements as in 'ep_dont_touch' */
1998     EL_BUG,
1999     EL_SPACESHIP,
2000     EL_BD_BUTTERFLY,
2001     EL_BD_FIREFLY,
2002
2003     /* same elements as in 'ep_dont_collide_with' */
2004     EL_YAMYAM,
2005     EL_DARK_YAMYAM,
2006     EL_ROBOT,
2007     EL_PACMAN,
2008     EL_SP_SNIKSNAK,
2009     EL_SP_ELECTRON,
2010
2011     /* new elements */
2012     EL_AMOEBA_DROP,
2013     EL_ACID,
2014
2015     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2016 #if 1
2017     EL_LANDMINE,
2018     EL_TRAP_ACTIVE,
2019     EL_SP_BUGGY_BASE_ACTIVE,
2020     EL_EMC_PLANT,
2021 #endif
2022
2023     -1
2024   };
2025
2026   static int ep_dont_collide_with[] =
2027   {
2028     /* same elements as in 'ep_dont_touch' */
2029     EL_BUG,
2030     EL_SPACESHIP,
2031     EL_BD_BUTTERFLY,
2032     EL_BD_FIREFLY,
2033
2034     /* new elements */
2035     EL_YAMYAM,
2036     EL_DARK_YAMYAM,
2037     EL_ROBOT,
2038     EL_PACMAN,
2039     EL_SP_SNIKSNAK,
2040     EL_SP_ELECTRON,
2041
2042     -1
2043   };
2044
2045   static int ep_dont_touch[] =
2046   {
2047     EL_BUG,
2048     EL_SPACESHIP,
2049     EL_BD_BUTTERFLY,
2050     EL_BD_FIREFLY,
2051
2052     -1
2053   };
2054
2055   static int ep_indestructible[] =
2056   {
2057     EL_STEELWALL,
2058     EL_ACID,
2059     EL_ACID_POOL_TOPLEFT,
2060     EL_ACID_POOL_TOPRIGHT,
2061     EL_ACID_POOL_BOTTOMLEFT,
2062     EL_ACID_POOL_BOTTOM,
2063     EL_ACID_POOL_BOTTOMRIGHT,
2064     EL_SP_HARDWARE_GRAY,
2065     EL_SP_HARDWARE_GREEN,
2066     EL_SP_HARDWARE_BLUE,
2067     EL_SP_HARDWARE_RED,
2068     EL_SP_HARDWARE_YELLOW,
2069     EL_SP_HARDWARE_BASE_1,
2070     EL_SP_HARDWARE_BASE_2,
2071     EL_SP_HARDWARE_BASE_3,
2072     EL_SP_HARDWARE_BASE_4,
2073     EL_SP_HARDWARE_BASE_5,
2074     EL_SP_HARDWARE_BASE_6,
2075     EL_INVISIBLE_STEELWALL,
2076     EL_INVISIBLE_STEELWALL_ACTIVE,
2077     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2078     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2079     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2080     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2081     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2082     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2083     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2084     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2085     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2086     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2087     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2088     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2089     EL_LIGHT_SWITCH,
2090     EL_LIGHT_SWITCH_ACTIVE,
2091     EL_SIGN_EXCLAMATION,
2092     EL_SIGN_RADIOACTIVITY,
2093     EL_SIGN_STOP,
2094     EL_SIGN_WHEELCHAIR,
2095     EL_SIGN_PARKING,
2096     EL_SIGN_ONEWAY,
2097     EL_SIGN_HEART,
2098     EL_SIGN_TRIANGLE,
2099     EL_SIGN_ROUND,
2100     EL_SIGN_EXIT,
2101     EL_SIGN_YINYANG,
2102     EL_SIGN_OTHER,
2103     EL_STEELWALL_SLIPPERY,
2104     EL_EMC_STEELWALL_1,
2105     EL_EMC_STEELWALL_2,
2106     EL_EMC_STEELWALL_3,
2107     EL_EMC_STEELWALL_4,
2108     EL_CRYSTAL,
2109     EL_GATE_1,
2110     EL_GATE_2,
2111     EL_GATE_3,
2112     EL_GATE_4,
2113     EL_GATE_1_GRAY,
2114     EL_GATE_2_GRAY,
2115     EL_GATE_3_GRAY,
2116     EL_GATE_4_GRAY,
2117     EL_GATE_1_GRAY_ACTIVE,
2118     EL_GATE_2_GRAY_ACTIVE,
2119     EL_GATE_3_GRAY_ACTIVE,
2120     EL_GATE_4_GRAY_ACTIVE,
2121     EL_EM_GATE_1,
2122     EL_EM_GATE_2,
2123     EL_EM_GATE_3,
2124     EL_EM_GATE_4,
2125     EL_EM_GATE_1_GRAY,
2126     EL_EM_GATE_2_GRAY,
2127     EL_EM_GATE_3_GRAY,
2128     EL_EM_GATE_4_GRAY,
2129     EL_EM_GATE_1_GRAY_ACTIVE,
2130     EL_EM_GATE_2_GRAY_ACTIVE,
2131     EL_EM_GATE_3_GRAY_ACTIVE,
2132     EL_EM_GATE_4_GRAY_ACTIVE,
2133     EL_EMC_GATE_5,
2134     EL_EMC_GATE_6,
2135     EL_EMC_GATE_7,
2136     EL_EMC_GATE_8,
2137     EL_EMC_GATE_5_GRAY,
2138     EL_EMC_GATE_6_GRAY,
2139     EL_EMC_GATE_7_GRAY,
2140     EL_EMC_GATE_8_GRAY,
2141     EL_EMC_GATE_5_GRAY_ACTIVE,
2142     EL_EMC_GATE_6_GRAY_ACTIVE,
2143     EL_EMC_GATE_7_GRAY_ACTIVE,
2144     EL_EMC_GATE_8_GRAY_ACTIVE,
2145     EL_SWITCHGATE_OPEN,
2146     EL_SWITCHGATE_OPENING,
2147     EL_SWITCHGATE_CLOSED,
2148     EL_SWITCHGATE_CLOSING,
2149 #if 0
2150     EL_SWITCHGATE_SWITCH_UP,
2151     EL_SWITCHGATE_SWITCH_DOWN,
2152 #endif
2153     EL_TIMEGATE_OPEN,
2154     EL_TIMEGATE_OPENING,
2155     EL_TIMEGATE_CLOSED,
2156     EL_TIMEGATE_CLOSING,
2157 #if 0
2158     EL_TIMEGATE_SWITCH,
2159     EL_TIMEGATE_SWITCH_ACTIVE,
2160 #endif
2161     EL_TUBE_ANY,
2162     EL_TUBE_VERTICAL,
2163     EL_TUBE_HORIZONTAL,
2164     EL_TUBE_VERTICAL_LEFT,
2165     EL_TUBE_VERTICAL_RIGHT,
2166     EL_TUBE_HORIZONTAL_UP,
2167     EL_TUBE_HORIZONTAL_DOWN,
2168     EL_TUBE_LEFT_UP,
2169     EL_TUBE_LEFT_DOWN,
2170     EL_TUBE_RIGHT_UP,
2171     EL_TUBE_RIGHT_DOWN,
2172
2173     -1
2174   };
2175
2176   static int ep_slippery[] =
2177   {
2178     EL_WALL_SLIPPERY,
2179     EL_BD_WALL,
2180     EL_ROCK,
2181     EL_BD_ROCK,
2182     EL_EMERALD,
2183     EL_BD_DIAMOND,
2184     EL_EMERALD_YELLOW,
2185     EL_EMERALD_RED,
2186     EL_EMERALD_PURPLE,
2187     EL_DIAMOND,
2188     EL_BOMB,
2189     EL_NUT,
2190     EL_ROBOT_WHEEL_ACTIVE,
2191     EL_ROBOT_WHEEL,
2192     EL_TIME_ORB_FULL,
2193     EL_TIME_ORB_EMPTY,
2194     EL_LAMP_ACTIVE,
2195     EL_LAMP,
2196     EL_ACID_POOL_TOPLEFT,
2197     EL_ACID_POOL_TOPRIGHT,
2198     EL_SATELLITE,
2199     EL_SP_ZONK,
2200     EL_SP_INFOTRON,
2201     EL_SP_CHIP_SINGLE,
2202     EL_SP_CHIP_LEFT,
2203     EL_SP_CHIP_RIGHT,
2204     EL_SP_CHIP_TOP,
2205     EL_SP_CHIP_BOTTOM,
2206     EL_SPEED_PILL,
2207     EL_STEELWALL_SLIPPERY,
2208     EL_PEARL,
2209     EL_CRYSTAL,
2210     EL_EMC_WALL_SLIPPERY_1,
2211     EL_EMC_WALL_SLIPPERY_2,
2212     EL_EMC_WALL_SLIPPERY_3,
2213     EL_EMC_WALL_SLIPPERY_4,
2214     EL_EMC_MAGIC_BALL,
2215     EL_EMC_MAGIC_BALL_ACTIVE,
2216
2217     -1
2218   };
2219
2220   static int ep_can_change[] =
2221   {
2222     -1
2223   };
2224
2225   static int ep_can_move[] =
2226   {
2227     /* same elements as in 'pb_can_move_into_acid' */
2228     EL_BUG,
2229     EL_SPACESHIP,
2230     EL_BD_BUTTERFLY,
2231     EL_BD_FIREFLY,
2232     EL_YAMYAM,
2233     EL_DARK_YAMYAM,
2234     EL_ROBOT,
2235     EL_PACMAN,
2236     EL_MOLE,
2237     EL_PENGUIN,
2238     EL_PIG,
2239     EL_DRAGON,
2240     EL_SATELLITE,
2241     EL_SP_SNIKSNAK,
2242     EL_SP_ELECTRON,
2243     EL_BALLOON,
2244     EL_SPRING,
2245     EL_EMC_ANDROID,
2246
2247     -1
2248   };
2249
2250   static int ep_can_fall[] =
2251   {
2252     EL_ROCK,
2253     EL_BD_ROCK,
2254     EL_EMERALD,
2255     EL_BD_DIAMOND,
2256     EL_EMERALD_YELLOW,
2257     EL_EMERALD_RED,
2258     EL_EMERALD_PURPLE,
2259     EL_DIAMOND,
2260     EL_BOMB,
2261     EL_NUT,
2262     EL_AMOEBA_DROP,
2263     EL_QUICKSAND_FULL,
2264     EL_MAGIC_WALL_FULL,
2265     EL_BD_MAGIC_WALL_FULL,
2266     EL_TIME_ORB_FULL,
2267     EL_TIME_ORB_EMPTY,
2268     EL_SP_ZONK,
2269     EL_SP_INFOTRON,
2270     EL_SP_DISK_ORANGE,
2271     EL_PEARL,
2272     EL_CRYSTAL,
2273     EL_SPRING,
2274     EL_DX_SUPABOMB,
2275
2276     -1
2277   };
2278
2279   static int ep_can_smash_player[] =
2280   {
2281     EL_ROCK,
2282     EL_BD_ROCK,
2283     EL_EMERALD,
2284     EL_BD_DIAMOND,
2285     EL_EMERALD_YELLOW,
2286     EL_EMERALD_RED,
2287     EL_EMERALD_PURPLE,
2288     EL_DIAMOND,
2289     EL_BOMB,
2290     EL_NUT,
2291     EL_AMOEBA_DROP,
2292     EL_TIME_ORB_FULL,
2293     EL_TIME_ORB_EMPTY,
2294     EL_SP_ZONK,
2295     EL_SP_INFOTRON,
2296     EL_SP_DISK_ORANGE,
2297     EL_PEARL,
2298     EL_CRYSTAL,
2299     EL_SPRING,
2300     EL_DX_SUPABOMB,
2301
2302     -1
2303   };
2304
2305   static int ep_can_smash_enemies[] =
2306   {
2307     EL_ROCK,
2308     EL_BD_ROCK,
2309     EL_SP_ZONK,
2310
2311     -1
2312   };
2313
2314   static int ep_can_smash_everything[] =
2315   {
2316     EL_ROCK,
2317     EL_BD_ROCK,
2318     EL_SP_ZONK,
2319
2320     -1
2321   };
2322
2323   static int ep_explodes_by_fire[] =
2324   {
2325     /* same elements as in 'ep_explodes_impact' */
2326     EL_BOMB,
2327     EL_SP_DISK_ORANGE,
2328     EL_DX_SUPABOMB,
2329
2330     /* same elements as in 'ep_explodes_smashed' */
2331     EL_SATELLITE,
2332     EL_PIG,
2333     EL_DRAGON,
2334     EL_MOLE,
2335
2336     /* new elements */
2337     EL_DYNAMITE,
2338     EL_DYNAMITE_ACTIVE,
2339     EL_EM_DYNAMITE,
2340     EL_EM_DYNAMITE_ACTIVE,
2341     EL_DYNABOMB_PLAYER_1_ACTIVE,
2342     EL_DYNABOMB_PLAYER_2_ACTIVE,
2343     EL_DYNABOMB_PLAYER_3_ACTIVE,
2344     EL_DYNABOMB_PLAYER_4_ACTIVE,
2345     EL_DYNABOMB_INCREASE_NUMBER,
2346     EL_DYNABOMB_INCREASE_SIZE,
2347     EL_DYNABOMB_INCREASE_POWER,
2348     EL_SP_DISK_RED_ACTIVE,
2349     EL_BUG,
2350     EL_PENGUIN,
2351     EL_SP_DISK_RED,
2352     EL_SP_DISK_YELLOW,
2353     EL_SP_SNIKSNAK,
2354     EL_SP_ELECTRON,
2355 #if 0
2356     EL_BLACK_ORB,
2357 #endif
2358
2359     -1
2360   };
2361
2362   static int ep_explodes_smashed[] =
2363   {
2364     /* same elements as in 'ep_explodes_impact' */
2365     EL_BOMB,
2366     EL_SP_DISK_ORANGE,
2367     EL_DX_SUPABOMB,
2368
2369     /* new elements */
2370     EL_SATELLITE,
2371     EL_PIG,
2372     EL_DRAGON,
2373     EL_MOLE,
2374
2375     -1
2376   };
2377
2378   static int ep_explodes_impact[] =
2379   {
2380     EL_BOMB,
2381     EL_SP_DISK_ORANGE,
2382     EL_DX_SUPABOMB,
2383
2384     -1
2385   };
2386
2387   static int ep_walkable_over[] =
2388   {
2389     EL_EMPTY_SPACE,
2390     EL_SP_EMPTY_SPACE,
2391     EL_SOKOBAN_FIELD_EMPTY,
2392     EL_EXIT_OPEN,
2393     EL_SP_EXIT_OPEN,
2394     EL_SP_EXIT_OPENING,
2395     EL_GATE_1,
2396     EL_GATE_2,
2397     EL_GATE_3,
2398     EL_GATE_4,
2399     EL_GATE_1_GRAY,
2400     EL_GATE_2_GRAY,
2401     EL_GATE_3_GRAY,
2402     EL_GATE_4_GRAY,
2403     EL_GATE_1_GRAY_ACTIVE,
2404     EL_GATE_2_GRAY_ACTIVE,
2405     EL_GATE_3_GRAY_ACTIVE,
2406     EL_GATE_4_GRAY_ACTIVE,
2407     EL_PENGUIN,
2408     EL_PIG,
2409     EL_DRAGON,
2410
2411     -1
2412   };
2413
2414   static int ep_walkable_inside[] =
2415   {
2416     EL_TUBE_ANY,
2417     EL_TUBE_VERTICAL,
2418     EL_TUBE_HORIZONTAL,
2419     EL_TUBE_VERTICAL_LEFT,
2420     EL_TUBE_VERTICAL_RIGHT,
2421     EL_TUBE_HORIZONTAL_UP,
2422     EL_TUBE_HORIZONTAL_DOWN,
2423     EL_TUBE_LEFT_UP,
2424     EL_TUBE_LEFT_DOWN,
2425     EL_TUBE_RIGHT_UP,
2426     EL_TUBE_RIGHT_DOWN,
2427
2428     -1
2429   };
2430
2431   static int ep_walkable_under[] =
2432   {
2433     -1
2434   };
2435
2436   static int ep_passable_over[] =
2437   {
2438     EL_EM_GATE_1,
2439     EL_EM_GATE_2,
2440     EL_EM_GATE_3,
2441     EL_EM_GATE_4,
2442     EL_EM_GATE_1_GRAY,
2443     EL_EM_GATE_2_GRAY,
2444     EL_EM_GATE_3_GRAY,
2445     EL_EM_GATE_4_GRAY,
2446     EL_EM_GATE_1_GRAY_ACTIVE,
2447     EL_EM_GATE_2_GRAY_ACTIVE,
2448     EL_EM_GATE_3_GRAY_ACTIVE,
2449     EL_EM_GATE_4_GRAY_ACTIVE,
2450     EL_EMC_GATE_5,
2451     EL_EMC_GATE_6,
2452     EL_EMC_GATE_7,
2453     EL_EMC_GATE_8,
2454     EL_EMC_GATE_5_GRAY,
2455     EL_EMC_GATE_6_GRAY,
2456     EL_EMC_GATE_7_GRAY,
2457     EL_EMC_GATE_8_GRAY,
2458     EL_EMC_GATE_5_GRAY_ACTIVE,
2459     EL_EMC_GATE_6_GRAY_ACTIVE,
2460     EL_EMC_GATE_7_GRAY_ACTIVE,
2461     EL_EMC_GATE_8_GRAY_ACTIVE,
2462     EL_SWITCHGATE_OPEN,
2463     EL_TIMEGATE_OPEN,
2464
2465     -1
2466   };
2467
2468   static int ep_passable_inside[] =
2469   {
2470     EL_SP_PORT_LEFT,
2471     EL_SP_PORT_RIGHT,
2472     EL_SP_PORT_UP,
2473     EL_SP_PORT_DOWN,
2474     EL_SP_PORT_HORIZONTAL,
2475     EL_SP_PORT_VERTICAL,
2476     EL_SP_PORT_ANY,
2477     EL_SP_GRAVITY_PORT_LEFT,
2478     EL_SP_GRAVITY_PORT_RIGHT,
2479     EL_SP_GRAVITY_PORT_UP,
2480     EL_SP_GRAVITY_PORT_DOWN,
2481     EL_SP_GRAVITY_ON_PORT_LEFT,
2482     EL_SP_GRAVITY_ON_PORT_RIGHT,
2483     EL_SP_GRAVITY_ON_PORT_UP,
2484     EL_SP_GRAVITY_ON_PORT_DOWN,
2485     EL_SP_GRAVITY_OFF_PORT_LEFT,
2486     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2487     EL_SP_GRAVITY_OFF_PORT_UP,
2488     EL_SP_GRAVITY_OFF_PORT_DOWN,
2489
2490     -1
2491   };
2492
2493   static int ep_passable_under[] =
2494   {
2495     -1
2496   };
2497
2498   static int ep_droppable[] =
2499   {
2500     -1
2501   };
2502
2503   static int ep_explodes_1x1_old[] =
2504   {
2505     -1
2506   };
2507
2508   static int ep_pushable[] =
2509   {
2510     EL_ROCK,
2511     EL_BOMB,
2512     EL_DX_SUPABOMB,
2513     EL_NUT,
2514     EL_TIME_ORB_EMPTY,
2515     EL_SP_ZONK,
2516     EL_SP_DISK_ORANGE,
2517     EL_SPRING,
2518     EL_BD_ROCK,
2519     EL_SOKOBAN_OBJECT,
2520     EL_SOKOBAN_FIELD_FULL,
2521     EL_SATELLITE,
2522     EL_SP_DISK_YELLOW,
2523     EL_BALLOON,
2524     EL_EMC_ANDROID,
2525
2526     -1
2527   };
2528
2529   static int ep_explodes_cross_old[] =
2530   {
2531     -1
2532   };
2533
2534   static int ep_protected[] =
2535   {
2536     /* same elements as in 'ep_walkable_inside' */
2537     EL_TUBE_ANY,
2538     EL_TUBE_VERTICAL,
2539     EL_TUBE_HORIZONTAL,
2540     EL_TUBE_VERTICAL_LEFT,
2541     EL_TUBE_VERTICAL_RIGHT,
2542     EL_TUBE_HORIZONTAL_UP,
2543     EL_TUBE_HORIZONTAL_DOWN,
2544     EL_TUBE_LEFT_UP,
2545     EL_TUBE_LEFT_DOWN,
2546     EL_TUBE_RIGHT_UP,
2547     EL_TUBE_RIGHT_DOWN,
2548
2549     /* same elements as in 'ep_passable_over' */
2550     EL_EM_GATE_1,
2551     EL_EM_GATE_2,
2552     EL_EM_GATE_3,
2553     EL_EM_GATE_4,
2554     EL_EM_GATE_1_GRAY,
2555     EL_EM_GATE_2_GRAY,
2556     EL_EM_GATE_3_GRAY,
2557     EL_EM_GATE_4_GRAY,
2558     EL_EM_GATE_1_GRAY_ACTIVE,
2559     EL_EM_GATE_2_GRAY_ACTIVE,
2560     EL_EM_GATE_3_GRAY_ACTIVE,
2561     EL_EM_GATE_4_GRAY_ACTIVE,
2562     EL_EMC_GATE_5,
2563     EL_EMC_GATE_6,
2564     EL_EMC_GATE_7,
2565     EL_EMC_GATE_8,
2566     EL_EMC_GATE_5_GRAY,
2567     EL_EMC_GATE_6_GRAY,
2568     EL_EMC_GATE_7_GRAY,
2569     EL_EMC_GATE_8_GRAY,
2570     EL_EMC_GATE_5_GRAY_ACTIVE,
2571     EL_EMC_GATE_6_GRAY_ACTIVE,
2572     EL_EMC_GATE_7_GRAY_ACTIVE,
2573     EL_EMC_GATE_8_GRAY_ACTIVE,
2574     EL_SWITCHGATE_OPEN,
2575     EL_TIMEGATE_OPEN,
2576
2577     /* same elements as in 'ep_passable_inside' */
2578     EL_SP_PORT_LEFT,
2579     EL_SP_PORT_RIGHT,
2580     EL_SP_PORT_UP,
2581     EL_SP_PORT_DOWN,
2582     EL_SP_PORT_HORIZONTAL,
2583     EL_SP_PORT_VERTICAL,
2584     EL_SP_PORT_ANY,
2585     EL_SP_GRAVITY_PORT_LEFT,
2586     EL_SP_GRAVITY_PORT_RIGHT,
2587     EL_SP_GRAVITY_PORT_UP,
2588     EL_SP_GRAVITY_PORT_DOWN,
2589     EL_SP_GRAVITY_ON_PORT_LEFT,
2590     EL_SP_GRAVITY_ON_PORT_RIGHT,
2591     EL_SP_GRAVITY_ON_PORT_UP,
2592     EL_SP_GRAVITY_ON_PORT_DOWN,
2593     EL_SP_GRAVITY_OFF_PORT_LEFT,
2594     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2595     EL_SP_GRAVITY_OFF_PORT_UP,
2596     EL_SP_GRAVITY_OFF_PORT_DOWN,
2597
2598     -1
2599   };
2600
2601   static int ep_throwable[] =
2602   {
2603     -1
2604   };
2605
2606   static int ep_can_explode[] =
2607   {
2608     /* same elements as in 'ep_explodes_impact' */
2609     EL_BOMB,
2610     EL_SP_DISK_ORANGE,
2611     EL_DX_SUPABOMB,
2612
2613     /* same elements as in 'ep_explodes_smashed' */
2614     EL_SATELLITE,
2615     EL_PIG,
2616     EL_DRAGON,
2617     EL_MOLE,
2618
2619     /* elements that can explode by explosion or by dragonfire */
2620     EL_DYNAMITE,
2621     EL_DYNAMITE_ACTIVE,
2622     EL_EM_DYNAMITE,
2623     EL_EM_DYNAMITE_ACTIVE,
2624     EL_DYNABOMB_PLAYER_1_ACTIVE,
2625     EL_DYNABOMB_PLAYER_2_ACTIVE,
2626     EL_DYNABOMB_PLAYER_3_ACTIVE,
2627     EL_DYNABOMB_PLAYER_4_ACTIVE,
2628     EL_DYNABOMB_INCREASE_NUMBER,
2629     EL_DYNABOMB_INCREASE_SIZE,
2630     EL_DYNABOMB_INCREASE_POWER,
2631     EL_SP_DISK_RED_ACTIVE,
2632     EL_BUG,
2633     EL_PENGUIN,
2634     EL_SP_DISK_RED,
2635     EL_SP_DISK_YELLOW,
2636     EL_SP_SNIKSNAK,
2637     EL_SP_ELECTRON,
2638
2639     /* elements that can explode only by explosion */
2640     EL_BLACK_ORB,
2641
2642     -1
2643   };
2644
2645   static int ep_gravity_reachable[] =
2646   {
2647     EL_SAND,
2648     EL_SP_BASE,
2649     EL_TRAP,
2650     EL_INVISIBLE_SAND,
2651     EL_INVISIBLE_SAND_ACTIVE,
2652     EL_SP_PORT_LEFT,
2653     EL_SP_PORT_RIGHT,
2654     EL_SP_PORT_UP,
2655     EL_SP_PORT_DOWN,
2656     EL_SP_PORT_HORIZONTAL,
2657     EL_SP_PORT_VERTICAL,
2658     EL_SP_PORT_ANY,
2659     EL_SP_GRAVITY_PORT_LEFT,
2660     EL_SP_GRAVITY_PORT_RIGHT,
2661     EL_SP_GRAVITY_PORT_UP,
2662     EL_SP_GRAVITY_PORT_DOWN,
2663     EL_SP_GRAVITY_ON_PORT_LEFT,
2664     EL_SP_GRAVITY_ON_PORT_RIGHT,
2665     EL_SP_GRAVITY_ON_PORT_UP,
2666     EL_SP_GRAVITY_ON_PORT_DOWN,
2667     EL_SP_GRAVITY_OFF_PORT_LEFT,
2668     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2669     EL_SP_GRAVITY_OFF_PORT_UP,
2670     EL_SP_GRAVITY_OFF_PORT_DOWN,
2671     EL_EMC_GRASS,
2672
2673     -1
2674   };
2675
2676   static int ep_player[] =
2677   {
2678     EL_PLAYER_1,
2679     EL_PLAYER_2,
2680     EL_PLAYER_3,
2681     EL_PLAYER_4,
2682     EL_SP_MURPHY,
2683     EL_SOKOBAN_FIELD_PLAYER,
2684     EL_TRIGGER_PLAYER,
2685
2686     -1
2687   };
2688
2689   static int ep_can_pass_magic_wall[] =
2690   {
2691     EL_ROCK,
2692     EL_BD_ROCK,
2693     EL_EMERALD,
2694     EL_BD_DIAMOND,
2695     EL_EMERALD_YELLOW,
2696     EL_EMERALD_RED,
2697     EL_EMERALD_PURPLE,
2698     EL_DIAMOND,
2699
2700     -1
2701   };
2702
2703   static int ep_switchable[] =
2704   {
2705     EL_ROBOT_WHEEL,
2706     EL_SP_TERMINAL,
2707     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2708     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2709     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2710     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2711     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2712     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2713     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2714     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2715     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2716     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2717     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2718     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2719     EL_SWITCHGATE_SWITCH_UP,
2720     EL_SWITCHGATE_SWITCH_DOWN,
2721     EL_LIGHT_SWITCH,
2722     EL_LIGHT_SWITCH_ACTIVE,
2723     EL_TIMEGATE_SWITCH,
2724     EL_BALLOON_SWITCH_LEFT,
2725     EL_BALLOON_SWITCH_RIGHT,
2726     EL_BALLOON_SWITCH_UP,
2727     EL_BALLOON_SWITCH_DOWN,
2728     EL_BALLOON_SWITCH_ANY,
2729     EL_BALLOON_SWITCH_NONE,
2730     EL_LAMP,
2731     EL_TIME_ORB_FULL,
2732     EL_EMC_MAGIC_BALL_SWITCH,
2733     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2734
2735     -1
2736   };
2737
2738   static int ep_bd_element[] =
2739   {
2740     EL_EMPTY,
2741     EL_SAND,
2742     EL_WALL_SLIPPERY,
2743     EL_BD_WALL,
2744     EL_ROCK,
2745     EL_BD_ROCK,
2746     EL_BD_DIAMOND,
2747     EL_BD_MAGIC_WALL,
2748     EL_EXIT_CLOSED,
2749     EL_EXIT_OPEN,
2750     EL_STEELWALL,
2751     EL_PLAYER_1,
2752     EL_PLAYER_2,
2753     EL_PLAYER_3,
2754     EL_PLAYER_4,
2755     EL_BD_FIREFLY,
2756     EL_BD_FIREFLY_1,
2757     EL_BD_FIREFLY_2,
2758     EL_BD_FIREFLY_3,
2759     EL_BD_FIREFLY_4,
2760     EL_BD_BUTTERFLY,
2761     EL_BD_BUTTERFLY_1,
2762     EL_BD_BUTTERFLY_2,
2763     EL_BD_BUTTERFLY_3,
2764     EL_BD_BUTTERFLY_4,
2765     EL_BD_AMOEBA,
2766     EL_CHAR_QUESTION,
2767     EL_UNKNOWN,
2768
2769     -1
2770   };
2771
2772   static int ep_sp_element[] =
2773   {
2774     /* should always be valid */
2775     EL_EMPTY,
2776
2777     /* standard classic Supaplex elements */
2778     EL_SP_EMPTY,
2779     EL_SP_ZONK,
2780     EL_SP_BASE,
2781     EL_SP_MURPHY,
2782     EL_SP_INFOTRON,
2783     EL_SP_CHIP_SINGLE,
2784     EL_SP_HARDWARE_GRAY,
2785     EL_SP_EXIT_CLOSED,
2786     EL_SP_EXIT_OPEN,
2787     EL_SP_DISK_ORANGE,
2788     EL_SP_PORT_RIGHT,
2789     EL_SP_PORT_DOWN,
2790     EL_SP_PORT_LEFT,
2791     EL_SP_PORT_UP,
2792     EL_SP_GRAVITY_PORT_RIGHT,
2793     EL_SP_GRAVITY_PORT_DOWN,
2794     EL_SP_GRAVITY_PORT_LEFT,
2795     EL_SP_GRAVITY_PORT_UP,
2796     EL_SP_SNIKSNAK,
2797     EL_SP_DISK_YELLOW,
2798     EL_SP_TERMINAL,
2799     EL_SP_DISK_RED,
2800     EL_SP_PORT_VERTICAL,
2801     EL_SP_PORT_HORIZONTAL,
2802     EL_SP_PORT_ANY,
2803     EL_SP_ELECTRON,
2804     EL_SP_BUGGY_BASE,
2805     EL_SP_CHIP_LEFT,
2806     EL_SP_CHIP_RIGHT,
2807     EL_SP_HARDWARE_BASE_1,
2808     EL_SP_HARDWARE_GREEN,
2809     EL_SP_HARDWARE_BLUE,
2810     EL_SP_HARDWARE_RED,
2811     EL_SP_HARDWARE_YELLOW,
2812     EL_SP_HARDWARE_BASE_2,
2813     EL_SP_HARDWARE_BASE_3,
2814     EL_SP_HARDWARE_BASE_4,
2815     EL_SP_HARDWARE_BASE_5,
2816     EL_SP_HARDWARE_BASE_6,
2817     EL_SP_CHIP_TOP,
2818     EL_SP_CHIP_BOTTOM,
2819
2820     /* additional elements that appeared in newer Supaplex levels */
2821     EL_INVISIBLE_WALL,
2822
2823     /* additional gravity port elements (not switching, but setting gravity) */
2824     EL_SP_GRAVITY_ON_PORT_LEFT,
2825     EL_SP_GRAVITY_ON_PORT_RIGHT,
2826     EL_SP_GRAVITY_ON_PORT_UP,
2827     EL_SP_GRAVITY_ON_PORT_DOWN,
2828     EL_SP_GRAVITY_OFF_PORT_LEFT,
2829     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2830     EL_SP_GRAVITY_OFF_PORT_UP,
2831     EL_SP_GRAVITY_OFF_PORT_DOWN,
2832
2833     /* more than one Murphy in a level results in an inactive clone */
2834     EL_SP_MURPHY_CLONE,
2835
2836     /* runtime Supaplex elements */
2837     EL_SP_DISK_RED_ACTIVE,
2838     EL_SP_TERMINAL_ACTIVE,
2839     EL_SP_BUGGY_BASE_ACTIVATING,
2840     EL_SP_BUGGY_BASE_ACTIVE,
2841     EL_SP_EXIT_OPENING,
2842     EL_SP_EXIT_CLOSING,
2843
2844     -1
2845   };
2846
2847   static int ep_sb_element[] =
2848   {
2849     EL_EMPTY,
2850     EL_STEELWALL,
2851     EL_SOKOBAN_OBJECT,
2852     EL_SOKOBAN_FIELD_EMPTY,
2853     EL_SOKOBAN_FIELD_FULL,
2854     EL_SOKOBAN_FIELD_PLAYER,
2855     EL_PLAYER_1,
2856     EL_PLAYER_2,
2857     EL_PLAYER_3,
2858     EL_PLAYER_4,
2859     EL_INVISIBLE_STEELWALL,
2860
2861     -1
2862   };
2863
2864   static int ep_gem[] =
2865   {
2866     EL_BD_DIAMOND,
2867     EL_EMERALD,
2868     EL_EMERALD_YELLOW,
2869     EL_EMERALD_RED,
2870     EL_EMERALD_PURPLE,
2871     EL_DIAMOND,
2872
2873     -1
2874   };
2875
2876   static int ep_food_dark_yamyam[] =
2877   {
2878     EL_SAND,
2879     EL_BUG,
2880     EL_SPACESHIP,
2881     EL_BD_BUTTERFLY,
2882     EL_BD_FIREFLY,
2883     EL_YAMYAM,
2884     EL_ROBOT,
2885     EL_PACMAN,
2886     EL_AMOEBA_DROP,
2887     EL_AMOEBA_DEAD,
2888     EL_AMOEBA_WET,
2889     EL_AMOEBA_DRY,
2890     EL_AMOEBA_FULL,
2891     EL_BD_AMOEBA,
2892     EL_EMERALD,
2893     EL_BD_DIAMOND,
2894     EL_EMERALD_YELLOW,
2895     EL_EMERALD_RED,
2896     EL_EMERALD_PURPLE,
2897     EL_DIAMOND,
2898     EL_PEARL,
2899     EL_CRYSTAL,
2900
2901     -1
2902   };
2903
2904   static int ep_food_penguin[] =
2905   {
2906     EL_EMERALD,
2907     EL_BD_DIAMOND,
2908     EL_EMERALD_YELLOW,
2909     EL_EMERALD_RED,
2910     EL_EMERALD_PURPLE,
2911     EL_DIAMOND,
2912     EL_PEARL,
2913     EL_CRYSTAL,
2914
2915     -1
2916   };
2917
2918   static int ep_food_pig[] =
2919   {
2920     EL_EMERALD,
2921     EL_BD_DIAMOND,
2922     EL_EMERALD_YELLOW,
2923     EL_EMERALD_RED,
2924     EL_EMERALD_PURPLE,
2925     EL_DIAMOND,
2926
2927     -1
2928   };
2929
2930   static int ep_historic_wall[] =
2931   {
2932     EL_STEELWALL,
2933     EL_GATE_1,
2934     EL_GATE_2,
2935     EL_GATE_3,
2936     EL_GATE_4,
2937     EL_GATE_1_GRAY,
2938     EL_GATE_2_GRAY,
2939     EL_GATE_3_GRAY,
2940     EL_GATE_4_GRAY,
2941     EL_GATE_1_GRAY_ACTIVE,
2942     EL_GATE_2_GRAY_ACTIVE,
2943     EL_GATE_3_GRAY_ACTIVE,
2944     EL_GATE_4_GRAY_ACTIVE,
2945     EL_EM_GATE_1,
2946     EL_EM_GATE_2,
2947     EL_EM_GATE_3,
2948     EL_EM_GATE_4,
2949     EL_EM_GATE_1_GRAY,
2950     EL_EM_GATE_2_GRAY,
2951     EL_EM_GATE_3_GRAY,
2952     EL_EM_GATE_4_GRAY,
2953     EL_EM_GATE_1_GRAY_ACTIVE,
2954     EL_EM_GATE_2_GRAY_ACTIVE,
2955     EL_EM_GATE_3_GRAY_ACTIVE,
2956     EL_EM_GATE_4_GRAY_ACTIVE,
2957     EL_EXIT_CLOSED,
2958     EL_EXIT_OPENING,
2959     EL_EXIT_OPEN,
2960     EL_WALL,
2961     EL_WALL_SLIPPERY,
2962     EL_EXPANDABLE_WALL,
2963     EL_EXPANDABLE_WALL_HORIZONTAL,
2964     EL_EXPANDABLE_WALL_VERTICAL,
2965     EL_EXPANDABLE_WALL_ANY,
2966     EL_EXPANDABLE_WALL_GROWING,
2967     EL_BD_EXPANDABLE_WALL,
2968     EL_BD_WALL,
2969     EL_SP_CHIP_SINGLE,
2970     EL_SP_CHIP_LEFT,
2971     EL_SP_CHIP_RIGHT,
2972     EL_SP_CHIP_TOP,
2973     EL_SP_CHIP_BOTTOM,
2974     EL_SP_HARDWARE_GRAY,
2975     EL_SP_HARDWARE_GREEN,
2976     EL_SP_HARDWARE_BLUE,
2977     EL_SP_HARDWARE_RED,
2978     EL_SP_HARDWARE_YELLOW,
2979     EL_SP_HARDWARE_BASE_1,
2980     EL_SP_HARDWARE_BASE_2,
2981     EL_SP_HARDWARE_BASE_3,
2982     EL_SP_HARDWARE_BASE_4,
2983     EL_SP_HARDWARE_BASE_5,
2984     EL_SP_HARDWARE_BASE_6,
2985     EL_SP_TERMINAL,
2986     EL_SP_TERMINAL_ACTIVE,
2987     EL_SP_EXIT_CLOSED,
2988     EL_SP_EXIT_OPEN,
2989     EL_INVISIBLE_STEELWALL,
2990     EL_INVISIBLE_STEELWALL_ACTIVE,
2991     EL_INVISIBLE_WALL,
2992     EL_INVISIBLE_WALL_ACTIVE,
2993     EL_STEELWALL_SLIPPERY,
2994     EL_EMC_STEELWALL_1,
2995     EL_EMC_STEELWALL_2,
2996     EL_EMC_STEELWALL_3,
2997     EL_EMC_STEELWALL_4,
2998     EL_EMC_WALL_1,
2999     EL_EMC_WALL_2,
3000     EL_EMC_WALL_3,
3001     EL_EMC_WALL_4,
3002     EL_EMC_WALL_5,
3003     EL_EMC_WALL_6,
3004     EL_EMC_WALL_7,
3005     EL_EMC_WALL_8,
3006
3007     -1
3008   };
3009
3010   static int ep_historic_solid[] =
3011   {
3012     EL_WALL,
3013     EL_EXPANDABLE_WALL,
3014     EL_EXPANDABLE_WALL_HORIZONTAL,
3015     EL_EXPANDABLE_WALL_VERTICAL,
3016     EL_EXPANDABLE_WALL_ANY,
3017     EL_BD_EXPANDABLE_WALL,
3018     EL_BD_WALL,
3019     EL_WALL_SLIPPERY,
3020     EL_EXIT_CLOSED,
3021     EL_EXIT_OPENING,
3022     EL_EXIT_OPEN,
3023     EL_AMOEBA_DEAD,
3024     EL_AMOEBA_WET,
3025     EL_AMOEBA_DRY,
3026     EL_AMOEBA_FULL,
3027     EL_BD_AMOEBA,
3028     EL_QUICKSAND_EMPTY,
3029     EL_QUICKSAND_FULL,
3030     EL_QUICKSAND_FILLING,
3031     EL_QUICKSAND_EMPTYING,
3032     EL_MAGIC_WALL,
3033     EL_MAGIC_WALL_ACTIVE,
3034     EL_MAGIC_WALL_EMPTYING,
3035     EL_MAGIC_WALL_FILLING,
3036     EL_MAGIC_WALL_FULL,
3037     EL_MAGIC_WALL_DEAD,
3038     EL_BD_MAGIC_WALL,
3039     EL_BD_MAGIC_WALL_ACTIVE,
3040     EL_BD_MAGIC_WALL_EMPTYING,
3041     EL_BD_MAGIC_WALL_FULL,
3042     EL_BD_MAGIC_WALL_FILLING,
3043     EL_BD_MAGIC_WALL_DEAD,
3044     EL_GAME_OF_LIFE,
3045     EL_BIOMAZE,
3046     EL_SP_CHIP_SINGLE,
3047     EL_SP_CHIP_LEFT,
3048     EL_SP_CHIP_RIGHT,
3049     EL_SP_CHIP_TOP,
3050     EL_SP_CHIP_BOTTOM,
3051     EL_SP_TERMINAL,
3052     EL_SP_TERMINAL_ACTIVE,
3053     EL_SP_EXIT_CLOSED,
3054     EL_SP_EXIT_OPEN,
3055     EL_INVISIBLE_WALL,
3056     EL_INVISIBLE_WALL_ACTIVE,
3057     EL_SWITCHGATE_SWITCH_UP,
3058     EL_SWITCHGATE_SWITCH_DOWN,
3059     EL_TIMEGATE_SWITCH,
3060     EL_TIMEGATE_SWITCH_ACTIVE,
3061     EL_EMC_WALL_1,
3062     EL_EMC_WALL_2,
3063     EL_EMC_WALL_3,
3064     EL_EMC_WALL_4,
3065     EL_EMC_WALL_5,
3066     EL_EMC_WALL_6,
3067     EL_EMC_WALL_7,
3068     EL_EMC_WALL_8,
3069     EL_WALL_PEARL,
3070     EL_WALL_CRYSTAL,
3071
3072     /* the following elements are a direct copy of "indestructible" elements,
3073        except "EL_ACID", which is "indestructible", but not "solid"! */
3074 #if 0
3075     EL_ACID,
3076 #endif
3077     EL_STEELWALL,
3078     EL_ACID_POOL_TOPLEFT,
3079     EL_ACID_POOL_TOPRIGHT,
3080     EL_ACID_POOL_BOTTOMLEFT,
3081     EL_ACID_POOL_BOTTOM,
3082     EL_ACID_POOL_BOTTOMRIGHT,
3083     EL_SP_HARDWARE_GRAY,
3084     EL_SP_HARDWARE_GREEN,
3085     EL_SP_HARDWARE_BLUE,
3086     EL_SP_HARDWARE_RED,
3087     EL_SP_HARDWARE_YELLOW,
3088     EL_SP_HARDWARE_BASE_1,
3089     EL_SP_HARDWARE_BASE_2,
3090     EL_SP_HARDWARE_BASE_3,
3091     EL_SP_HARDWARE_BASE_4,
3092     EL_SP_HARDWARE_BASE_5,
3093     EL_SP_HARDWARE_BASE_6,
3094     EL_INVISIBLE_STEELWALL,
3095     EL_INVISIBLE_STEELWALL_ACTIVE,
3096     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3097     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3098     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3099     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3100     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3101     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3102     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3103     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3104     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3105     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3106     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3107     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3108     EL_LIGHT_SWITCH,
3109     EL_LIGHT_SWITCH_ACTIVE,
3110     EL_SIGN_EXCLAMATION,
3111     EL_SIGN_RADIOACTIVITY,
3112     EL_SIGN_STOP,
3113     EL_SIGN_WHEELCHAIR,
3114     EL_SIGN_PARKING,
3115     EL_SIGN_ONEWAY,
3116     EL_SIGN_HEART,
3117     EL_SIGN_TRIANGLE,
3118     EL_SIGN_ROUND,
3119     EL_SIGN_EXIT,
3120     EL_SIGN_YINYANG,
3121     EL_SIGN_OTHER,
3122     EL_STEELWALL_SLIPPERY,
3123     EL_EMC_STEELWALL_1,
3124     EL_EMC_STEELWALL_2,
3125     EL_EMC_STEELWALL_3,
3126     EL_EMC_STEELWALL_4,
3127     EL_CRYSTAL,
3128     EL_GATE_1,
3129     EL_GATE_2,
3130     EL_GATE_3,
3131     EL_GATE_4,
3132     EL_GATE_1_GRAY,
3133     EL_GATE_2_GRAY,
3134     EL_GATE_3_GRAY,
3135     EL_GATE_4_GRAY,
3136     EL_GATE_1_GRAY_ACTIVE,
3137     EL_GATE_2_GRAY_ACTIVE,
3138     EL_GATE_3_GRAY_ACTIVE,
3139     EL_GATE_4_GRAY_ACTIVE,
3140     EL_EM_GATE_1,
3141     EL_EM_GATE_2,
3142     EL_EM_GATE_3,
3143     EL_EM_GATE_4,
3144     EL_EM_GATE_1_GRAY,
3145     EL_EM_GATE_2_GRAY,
3146     EL_EM_GATE_3_GRAY,
3147     EL_EM_GATE_4_GRAY,
3148     EL_EM_GATE_1_GRAY_ACTIVE,
3149     EL_EM_GATE_2_GRAY_ACTIVE,
3150     EL_EM_GATE_3_GRAY_ACTIVE,
3151     EL_EM_GATE_4_GRAY_ACTIVE,
3152     EL_SWITCHGATE_OPEN,
3153     EL_SWITCHGATE_OPENING,
3154     EL_SWITCHGATE_CLOSED,
3155     EL_SWITCHGATE_CLOSING,
3156     EL_TIMEGATE_OPEN,
3157     EL_TIMEGATE_OPENING,
3158     EL_TIMEGATE_CLOSED,
3159     EL_TIMEGATE_CLOSING,
3160     EL_TUBE_ANY,
3161     EL_TUBE_VERTICAL,
3162     EL_TUBE_HORIZONTAL,
3163     EL_TUBE_VERTICAL_LEFT,
3164     EL_TUBE_VERTICAL_RIGHT,
3165     EL_TUBE_HORIZONTAL_UP,
3166     EL_TUBE_HORIZONTAL_DOWN,
3167     EL_TUBE_LEFT_UP,
3168     EL_TUBE_LEFT_DOWN,
3169     EL_TUBE_RIGHT_UP,
3170     EL_TUBE_RIGHT_DOWN,
3171
3172     -1
3173   };
3174
3175   static int ep_classic_enemy[] =
3176   {
3177     EL_BUG,
3178     EL_SPACESHIP,
3179     EL_BD_BUTTERFLY,
3180     EL_BD_FIREFLY,
3181
3182     EL_YAMYAM,
3183     EL_DARK_YAMYAM,
3184     EL_ROBOT,
3185     EL_PACMAN,
3186     EL_SP_SNIKSNAK,
3187     EL_SP_ELECTRON,
3188
3189     -1
3190   };
3191
3192   static int ep_belt[] =
3193   {
3194     EL_CONVEYOR_BELT_1_LEFT,
3195     EL_CONVEYOR_BELT_1_MIDDLE,
3196     EL_CONVEYOR_BELT_1_RIGHT,
3197     EL_CONVEYOR_BELT_2_LEFT,
3198     EL_CONVEYOR_BELT_2_MIDDLE,
3199     EL_CONVEYOR_BELT_2_RIGHT,
3200     EL_CONVEYOR_BELT_3_LEFT,
3201     EL_CONVEYOR_BELT_3_MIDDLE,
3202     EL_CONVEYOR_BELT_3_RIGHT,
3203     EL_CONVEYOR_BELT_4_LEFT,
3204     EL_CONVEYOR_BELT_4_MIDDLE,
3205     EL_CONVEYOR_BELT_4_RIGHT,
3206
3207     -1
3208   };
3209
3210   static int ep_belt_active[] =
3211   {
3212     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3213     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3214     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3215     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3216     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3217     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3218     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3219     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3220     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3221     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3222     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3223     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3224
3225     -1
3226   };
3227
3228   static int ep_belt_switch[] =
3229   {
3230     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3231     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3232     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3233     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3234     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3235     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3236     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3237     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3238     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3239     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3240     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3241     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3242
3243     -1
3244   };
3245
3246   static int ep_tube[] =
3247   {
3248     EL_TUBE_LEFT_UP,
3249     EL_TUBE_LEFT_DOWN,
3250     EL_TUBE_RIGHT_UP,
3251     EL_TUBE_RIGHT_DOWN,
3252     EL_TUBE_HORIZONTAL,
3253     EL_TUBE_HORIZONTAL_UP,
3254     EL_TUBE_HORIZONTAL_DOWN,
3255     EL_TUBE_VERTICAL,
3256     EL_TUBE_VERTICAL_LEFT,
3257     EL_TUBE_VERTICAL_RIGHT,
3258     EL_TUBE_ANY,
3259
3260     -1
3261   };
3262
3263   static int ep_keygate[] =
3264   {
3265     EL_GATE_1,
3266     EL_GATE_2,
3267     EL_GATE_3,
3268     EL_GATE_4,
3269     EL_GATE_1_GRAY,
3270     EL_GATE_2_GRAY,
3271     EL_GATE_3_GRAY,
3272     EL_GATE_4_GRAY,
3273     EL_GATE_1_GRAY_ACTIVE,
3274     EL_GATE_2_GRAY_ACTIVE,
3275     EL_GATE_3_GRAY_ACTIVE,
3276     EL_GATE_4_GRAY_ACTIVE,
3277     EL_EM_GATE_1,
3278     EL_EM_GATE_2,
3279     EL_EM_GATE_3,
3280     EL_EM_GATE_4,
3281     EL_EM_GATE_1_GRAY,
3282     EL_EM_GATE_2_GRAY,
3283     EL_EM_GATE_3_GRAY,
3284     EL_EM_GATE_4_GRAY,
3285     EL_EM_GATE_1_GRAY_ACTIVE,
3286     EL_EM_GATE_2_GRAY_ACTIVE,
3287     EL_EM_GATE_3_GRAY_ACTIVE,
3288     EL_EM_GATE_4_GRAY_ACTIVE,
3289     EL_EMC_GATE_5,
3290     EL_EMC_GATE_6,
3291     EL_EMC_GATE_7,
3292     EL_EMC_GATE_8,
3293     EL_EMC_GATE_5_GRAY,
3294     EL_EMC_GATE_6_GRAY,
3295     EL_EMC_GATE_7_GRAY,
3296     EL_EMC_GATE_8_GRAY,
3297     EL_EMC_GATE_5_GRAY_ACTIVE,
3298     EL_EMC_GATE_6_GRAY_ACTIVE,
3299     EL_EMC_GATE_7_GRAY_ACTIVE,
3300     EL_EMC_GATE_8_GRAY_ACTIVE,
3301
3302     -1
3303   };
3304
3305   static int ep_amoeboid[] =
3306   {
3307     EL_AMOEBA_DEAD,
3308     EL_AMOEBA_WET,
3309     EL_AMOEBA_DRY,
3310     EL_AMOEBA_FULL,
3311     EL_BD_AMOEBA,
3312     EL_EMC_DRIPPER,
3313
3314     -1
3315   };
3316
3317   static int ep_amoebalive[] =
3318   {
3319     EL_AMOEBA_WET,
3320     EL_AMOEBA_DRY,
3321     EL_AMOEBA_FULL,
3322     EL_BD_AMOEBA,
3323     EL_EMC_DRIPPER,
3324
3325     -1
3326   };
3327
3328   static int ep_has_editor_content[] =
3329   {
3330     EL_PLAYER_1,
3331     EL_PLAYER_2,
3332     EL_PLAYER_3,
3333     EL_PLAYER_4,
3334     EL_SP_MURPHY,
3335     EL_YAMYAM,
3336     EL_YAMYAM_LEFT,
3337     EL_YAMYAM_RIGHT,
3338     EL_YAMYAM_UP,
3339     EL_YAMYAM_DOWN,
3340     EL_AMOEBA_WET,
3341     EL_AMOEBA_DRY,
3342     EL_AMOEBA_FULL,
3343     EL_BD_AMOEBA,
3344     EL_EMC_MAGIC_BALL,
3345     EL_EMC_ANDROID,
3346
3347     -1
3348   };
3349
3350   static int ep_can_turn_each_move[] =
3351   {
3352     /* !!! do something with this one !!! */
3353     -1
3354   };
3355
3356   static int ep_can_grow[] =
3357   {
3358     EL_BD_AMOEBA,
3359     EL_AMOEBA_DROP,
3360     EL_AMOEBA_WET,
3361     EL_AMOEBA_DRY,
3362     EL_AMOEBA_FULL,
3363     EL_GAME_OF_LIFE,
3364     EL_BIOMAZE,
3365     EL_EMC_DRIPPER,
3366
3367     -1
3368   };
3369
3370   static int ep_active_bomb[] =
3371   {
3372     EL_DYNAMITE_ACTIVE,
3373     EL_EM_DYNAMITE_ACTIVE,
3374     EL_DYNABOMB_PLAYER_1_ACTIVE,
3375     EL_DYNABOMB_PLAYER_2_ACTIVE,
3376     EL_DYNABOMB_PLAYER_3_ACTIVE,
3377     EL_DYNABOMB_PLAYER_4_ACTIVE,
3378     EL_SP_DISK_RED_ACTIVE,
3379
3380     -1
3381   };
3382
3383   static int ep_inactive[] =
3384   {
3385     EL_EMPTY,
3386     EL_SAND,
3387     EL_WALL,
3388     EL_BD_WALL,
3389     EL_WALL_SLIPPERY,
3390     EL_STEELWALL,
3391     EL_AMOEBA_DEAD,
3392     EL_QUICKSAND_EMPTY,
3393     EL_STONEBLOCK,
3394     EL_ROBOT_WHEEL,
3395     EL_KEY_1,
3396     EL_KEY_2,
3397     EL_KEY_3,
3398     EL_KEY_4,
3399     EL_EM_KEY_1,
3400     EL_EM_KEY_2,
3401     EL_EM_KEY_3,
3402     EL_EM_KEY_4,
3403     EL_EMC_KEY_5,
3404     EL_EMC_KEY_6,
3405     EL_EMC_KEY_7,
3406     EL_EMC_KEY_8,
3407     EL_GATE_1,
3408     EL_GATE_2,
3409     EL_GATE_3,
3410     EL_GATE_4,
3411     EL_GATE_1_GRAY,
3412     EL_GATE_2_GRAY,
3413     EL_GATE_3_GRAY,
3414     EL_GATE_4_GRAY,
3415     EL_GATE_1_GRAY_ACTIVE,
3416     EL_GATE_2_GRAY_ACTIVE,
3417     EL_GATE_3_GRAY_ACTIVE,
3418     EL_GATE_4_GRAY_ACTIVE,
3419     EL_EM_GATE_1,
3420     EL_EM_GATE_2,
3421     EL_EM_GATE_3,
3422     EL_EM_GATE_4,
3423     EL_EM_GATE_1_GRAY,
3424     EL_EM_GATE_2_GRAY,
3425     EL_EM_GATE_3_GRAY,
3426     EL_EM_GATE_4_GRAY,
3427     EL_EM_GATE_1_GRAY_ACTIVE,
3428     EL_EM_GATE_2_GRAY_ACTIVE,
3429     EL_EM_GATE_3_GRAY_ACTIVE,
3430     EL_EM_GATE_4_GRAY_ACTIVE,
3431     EL_EMC_GATE_5,
3432     EL_EMC_GATE_6,
3433     EL_EMC_GATE_7,
3434     EL_EMC_GATE_8,
3435     EL_EMC_GATE_5_GRAY,
3436     EL_EMC_GATE_6_GRAY,
3437     EL_EMC_GATE_7_GRAY,
3438     EL_EMC_GATE_8_GRAY,
3439     EL_EMC_GATE_5_GRAY_ACTIVE,
3440     EL_EMC_GATE_6_GRAY_ACTIVE,
3441     EL_EMC_GATE_7_GRAY_ACTIVE,
3442     EL_EMC_GATE_8_GRAY_ACTIVE,
3443     EL_DYNAMITE,
3444     EL_EM_DYNAMITE,
3445     EL_INVISIBLE_STEELWALL,
3446     EL_INVISIBLE_WALL,
3447     EL_INVISIBLE_SAND,
3448     EL_LAMP,
3449     EL_LAMP_ACTIVE,
3450     EL_WALL_EMERALD,
3451     EL_WALL_DIAMOND,
3452     EL_WALL_BD_DIAMOND,
3453     EL_WALL_EMERALD_YELLOW,
3454     EL_DYNABOMB_INCREASE_NUMBER,
3455     EL_DYNABOMB_INCREASE_SIZE,
3456     EL_DYNABOMB_INCREASE_POWER,
3457 #if 0
3458     EL_SOKOBAN_OBJECT,
3459 #endif
3460     EL_SOKOBAN_FIELD_EMPTY,
3461     EL_SOKOBAN_FIELD_FULL,
3462     EL_WALL_EMERALD_RED,
3463     EL_WALL_EMERALD_PURPLE,
3464     EL_ACID_POOL_TOPLEFT,
3465     EL_ACID_POOL_TOPRIGHT,
3466     EL_ACID_POOL_BOTTOMLEFT,
3467     EL_ACID_POOL_BOTTOM,
3468     EL_ACID_POOL_BOTTOMRIGHT,
3469     EL_MAGIC_WALL,
3470     EL_MAGIC_WALL_DEAD,
3471     EL_BD_MAGIC_WALL,
3472     EL_BD_MAGIC_WALL_DEAD,
3473     EL_AMOEBA_TO_DIAMOND,
3474     EL_BLOCKED,
3475     EL_SP_EMPTY,
3476     EL_SP_BASE,
3477     EL_SP_PORT_RIGHT,
3478     EL_SP_PORT_DOWN,
3479     EL_SP_PORT_LEFT,
3480     EL_SP_PORT_UP,
3481     EL_SP_GRAVITY_PORT_RIGHT,
3482     EL_SP_GRAVITY_PORT_DOWN,
3483     EL_SP_GRAVITY_PORT_LEFT,
3484     EL_SP_GRAVITY_PORT_UP,
3485     EL_SP_PORT_HORIZONTAL,
3486     EL_SP_PORT_VERTICAL,
3487     EL_SP_PORT_ANY,
3488     EL_SP_DISK_RED,
3489 #if 0
3490     EL_SP_DISK_YELLOW,
3491 #endif
3492     EL_SP_CHIP_SINGLE,
3493     EL_SP_CHIP_LEFT,
3494     EL_SP_CHIP_RIGHT,
3495     EL_SP_CHIP_TOP,
3496     EL_SP_CHIP_BOTTOM,
3497     EL_SP_HARDWARE_GRAY,
3498     EL_SP_HARDWARE_GREEN,
3499     EL_SP_HARDWARE_BLUE,
3500     EL_SP_HARDWARE_RED,
3501     EL_SP_HARDWARE_YELLOW,
3502     EL_SP_HARDWARE_BASE_1,
3503     EL_SP_HARDWARE_BASE_2,
3504     EL_SP_HARDWARE_BASE_3,
3505     EL_SP_HARDWARE_BASE_4,
3506     EL_SP_HARDWARE_BASE_5,
3507     EL_SP_HARDWARE_BASE_6,
3508     EL_SP_GRAVITY_ON_PORT_LEFT,
3509     EL_SP_GRAVITY_ON_PORT_RIGHT,
3510     EL_SP_GRAVITY_ON_PORT_UP,
3511     EL_SP_GRAVITY_ON_PORT_DOWN,
3512     EL_SP_GRAVITY_OFF_PORT_LEFT,
3513     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3514     EL_SP_GRAVITY_OFF_PORT_UP,
3515     EL_SP_GRAVITY_OFF_PORT_DOWN,
3516     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3517     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3518     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3519     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3520     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3521     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3522     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3523     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3524     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3525     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3526     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3527     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3528     EL_SIGN_EXCLAMATION,
3529     EL_SIGN_RADIOACTIVITY,
3530     EL_SIGN_STOP,
3531     EL_SIGN_WHEELCHAIR,
3532     EL_SIGN_PARKING,
3533     EL_SIGN_ONEWAY,
3534     EL_SIGN_HEART,
3535     EL_SIGN_TRIANGLE,
3536     EL_SIGN_ROUND,
3537     EL_SIGN_EXIT,
3538     EL_SIGN_YINYANG,
3539     EL_SIGN_OTHER,
3540     EL_STEELWALL_SLIPPERY,
3541     EL_EMC_STEELWALL_1,
3542     EL_EMC_STEELWALL_2,
3543     EL_EMC_STEELWALL_3,
3544     EL_EMC_STEELWALL_4,
3545     EL_EMC_WALL_SLIPPERY_1,
3546     EL_EMC_WALL_SLIPPERY_2,
3547     EL_EMC_WALL_SLIPPERY_3,
3548     EL_EMC_WALL_SLIPPERY_4,
3549     EL_EMC_WALL_1,
3550     EL_EMC_WALL_2,
3551     EL_EMC_WALL_3,
3552     EL_EMC_WALL_4,
3553     EL_EMC_WALL_5,
3554     EL_EMC_WALL_6,
3555     EL_EMC_WALL_7,
3556     EL_EMC_WALL_8,
3557     EL_EMC_WALL_9,
3558     EL_EMC_WALL_10,
3559     EL_EMC_WALL_11,
3560     EL_EMC_WALL_12,
3561     EL_EMC_WALL_13,
3562     EL_EMC_WALL_14,
3563     EL_EMC_WALL_15,
3564     EL_EMC_WALL_16,
3565
3566     -1
3567   };
3568
3569   static int ep_em_slippery_wall[] =
3570   {
3571     -1
3572   };
3573
3574   static int ep_gfx_crumbled[] =
3575   {
3576     EL_SAND,
3577     EL_LANDMINE,
3578     EL_TRAP,
3579     EL_TRAP_ACTIVE,
3580
3581     -1
3582   };
3583
3584   static int ep_editor_cascade_active[] =
3585   {
3586     EL_INTERNAL_CASCADE_BD_ACTIVE,
3587     EL_INTERNAL_CASCADE_EM_ACTIVE,
3588     EL_INTERNAL_CASCADE_EMC_ACTIVE,
3589     EL_INTERNAL_CASCADE_RND_ACTIVE,
3590     EL_INTERNAL_CASCADE_SB_ACTIVE,
3591     EL_INTERNAL_CASCADE_SP_ACTIVE,
3592     EL_INTERNAL_CASCADE_DC_ACTIVE,
3593     EL_INTERNAL_CASCADE_DX_ACTIVE,
3594     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3595     EL_INTERNAL_CASCADE_CE_ACTIVE,
3596     EL_INTERNAL_CASCADE_GE_ACTIVE,
3597     EL_INTERNAL_CASCADE_REF_ACTIVE,
3598     EL_INTERNAL_CASCADE_USER_ACTIVE,
3599     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3600
3601     -1
3602   };
3603
3604   static int ep_editor_cascade_inactive[] =
3605   {
3606     EL_INTERNAL_CASCADE_BD,
3607     EL_INTERNAL_CASCADE_EM,
3608     EL_INTERNAL_CASCADE_EMC,
3609     EL_INTERNAL_CASCADE_RND,
3610     EL_INTERNAL_CASCADE_SB,
3611     EL_INTERNAL_CASCADE_SP,
3612     EL_INTERNAL_CASCADE_DC,
3613     EL_INTERNAL_CASCADE_DX,
3614     EL_INTERNAL_CASCADE_CHARS,
3615     EL_INTERNAL_CASCADE_CE,
3616     EL_INTERNAL_CASCADE_GE,
3617     EL_INTERNAL_CASCADE_REF,
3618     EL_INTERNAL_CASCADE_USER,
3619     EL_INTERNAL_CASCADE_DYNAMIC,
3620
3621     -1
3622   };
3623
3624   static int ep_obsolete[] =
3625   {
3626     EL_PLAYER_OBSOLETE,
3627     EL_KEY_OBSOLETE,
3628     EL_EM_KEY_1_FILE_OBSOLETE,
3629     EL_EM_KEY_2_FILE_OBSOLETE,
3630     EL_EM_KEY_3_FILE_OBSOLETE,
3631     EL_EM_KEY_4_FILE_OBSOLETE,
3632     EL_ENVELOPE_OBSOLETE,
3633
3634     -1
3635   };
3636
3637   static struct
3638   {
3639     int *elements;
3640     int property;
3641   } element_properties[] =
3642   {
3643     { ep_diggable,                      EP_DIGGABLE                     },
3644     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
3645     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
3646     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
3647     { ep_dont_touch,                    EP_DONT_TOUCH                   },
3648     { ep_indestructible,                EP_INDESTRUCTIBLE               },
3649     { ep_slippery,                      EP_SLIPPERY                     },
3650     { ep_can_change,                    EP_CAN_CHANGE                   },
3651     { ep_can_move,                      EP_CAN_MOVE                     },
3652     { ep_can_fall,                      EP_CAN_FALL                     },
3653     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
3654     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
3655     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
3656     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
3657     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
3658     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
3659     { ep_walkable_over,                 EP_WALKABLE_OVER                },
3660     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
3661     { ep_walkable_under,                EP_WALKABLE_UNDER               },
3662     { ep_passable_over,                 EP_PASSABLE_OVER                },
3663     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
3664     { ep_passable_under,                EP_PASSABLE_UNDER               },
3665     { ep_droppable,                     EP_DROPPABLE                    },
3666     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
3667     { ep_pushable,                      EP_PUSHABLE                     },
3668     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
3669     { ep_protected,                     EP_PROTECTED                    },
3670     { ep_throwable,                     EP_THROWABLE                    },
3671     { ep_can_explode,                   EP_CAN_EXPLODE                  },
3672     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
3673
3674     { ep_player,                        EP_PLAYER                       },
3675     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
3676     { ep_switchable,                    EP_SWITCHABLE                   },
3677     { ep_bd_element,                    EP_BD_ELEMENT                   },
3678     { ep_sp_element,                    EP_SP_ELEMENT                   },
3679     { ep_sb_element,                    EP_SB_ELEMENT                   },
3680     { ep_gem,                           EP_GEM                          },
3681     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
3682     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
3683     { ep_food_pig,                      EP_FOOD_PIG                     },
3684     { ep_historic_wall,                 EP_HISTORIC_WALL                },
3685     { ep_historic_solid,                EP_HISTORIC_SOLID               },
3686     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
3687     { ep_belt,                          EP_BELT                         },
3688     { ep_belt_active,                   EP_BELT_ACTIVE                  },
3689     { ep_belt_switch,                   EP_BELT_SWITCH                  },
3690     { ep_tube,                          EP_TUBE                         },
3691     { ep_keygate,                       EP_KEYGATE                      },
3692     { ep_amoeboid,                      EP_AMOEBOID                     },
3693     { ep_amoebalive,                    EP_AMOEBALIVE                   },
3694     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
3695     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
3696     { ep_can_grow,                      EP_CAN_GROW                     },
3697     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
3698     { ep_inactive,                      EP_INACTIVE                     },
3699
3700     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
3701
3702     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
3703
3704     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
3705     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
3706
3707     { ep_obsolete,                      EP_OBSOLETE                     },
3708
3709     { NULL,                             -1                              }
3710   };
3711
3712   int i, j, k;
3713
3714   /* always start with reliable default values (element has no properties) */
3715   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3716     for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3717       SET_PROPERTY(i, j, FALSE);
3718
3719   /* set all base element properties from above array definitions */
3720   for (i = 0; element_properties[i].elements != NULL; i++)
3721     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3722       SET_PROPERTY((element_properties[i].elements)[j],
3723                    element_properties[i].property, TRUE);
3724
3725   /* copy properties to some elements that are only stored in level file */
3726   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3727     for (j = 0; copy_properties[j][0] != -1; j++)
3728       if (HAS_PROPERTY(copy_properties[j][0], i))
3729         for (k = 1; k <= 4; k++)
3730           SET_PROPERTY(copy_properties[j][k], i, TRUE);
3731 }
3732
3733 void InitElementPropertiesEngine(int engine_version)
3734 {
3735   static int no_wall_properties[] =
3736   {
3737     EP_DIGGABLE,
3738     EP_COLLECTIBLE_ONLY,
3739     EP_DONT_RUN_INTO,
3740     EP_DONT_COLLIDE_WITH,
3741     EP_CAN_MOVE,
3742     EP_CAN_FALL,
3743     EP_CAN_SMASH_PLAYER,
3744     EP_CAN_SMASH_ENEMIES,
3745     EP_CAN_SMASH_EVERYTHING,
3746     EP_PUSHABLE,
3747
3748     EP_PLAYER,
3749     EP_GEM,
3750     EP_FOOD_DARK_YAMYAM,
3751     EP_FOOD_PENGUIN,
3752     EP_BELT,
3753     EP_BELT_ACTIVE,
3754     EP_TUBE,
3755     EP_AMOEBOID,
3756     EP_AMOEBALIVE,
3757     EP_ACTIVE_BOMB,
3758
3759     EP_ACCESSIBLE,
3760
3761     -1
3762   };
3763
3764   int i, j;
3765
3766   /* important: after initialization in InitElementPropertiesStatic(), the
3767      elements are not again initialized to a default value; therefore all
3768      changes have to make sure that they leave the element with a defined
3769      property (which means that conditional property changes must be set to
3770      a reliable default value before) */
3771
3772   /* ---------- recursively resolve group elements ------------------------- */
3773
3774   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3775     for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3776       element_info[i].in_group[j] = FALSE;
3777
3778   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3779     resolve_group_element(EL_GROUP_START + i, 0);
3780
3781   /* set all special, combined or engine dependent element properties */
3782   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3783   {
3784     /* ---------- INACTIVE ------------------------------------------------- */
3785     SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3786
3787     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3788     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3789                                   IS_WALKABLE_INSIDE(i) ||
3790                                   IS_WALKABLE_UNDER(i)));
3791
3792     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3793                                   IS_PASSABLE_INSIDE(i) ||
3794                                   IS_PASSABLE_UNDER(i)));
3795
3796     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3797                                          IS_PASSABLE_OVER(i)));
3798
3799     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3800                                            IS_PASSABLE_INSIDE(i)));
3801
3802     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3803                                           IS_PASSABLE_UNDER(i)));
3804
3805     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3806                                     IS_PASSABLE(i)));
3807
3808     /* ---------- COLLECTIBLE ---------------------------------------------- */
3809     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3810                                      IS_DROPPABLE(i) ||
3811                                      IS_THROWABLE(i)));
3812
3813     /* ---------- SNAPPABLE ------------------------------------------------ */
3814     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3815                                    IS_COLLECTIBLE(i) ||
3816                                    IS_SWITCHABLE(i) ||
3817                                    i == EL_BD_ROCK));
3818
3819     /* ---------- WALL ----------------------------------------------------- */
3820     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
3821
3822     for (j = 0; no_wall_properties[j] != -1; j++)
3823       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3824           i >= EL_FIRST_RUNTIME_UNREAL)
3825         SET_PROPERTY(i, EP_WALL, FALSE);
3826
3827     if (IS_HISTORIC_WALL(i))
3828       SET_PROPERTY(i, EP_WALL, TRUE);
3829
3830     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3831     if (engine_version < VERSION_IDENT(2,2,0,0))
3832       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3833     else
3834       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3835                                              !IS_DIGGABLE(i) &&
3836                                              !IS_COLLECTIBLE(i)));
3837
3838     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3839
3840     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3841       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3842     else
3843       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3844                                             IS_INDESTRUCTIBLE(i)));
3845
3846     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3847     if (i == EL_FLAMES)
3848       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3849     else if (engine_version < VERSION_IDENT(2,2,0,0))
3850       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3851     else
3852       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3853                                            (!IS_WALKABLE(i) ||
3854                                             IS_PROTECTED(i))));
3855
3856     if (IS_CUSTOM_ELEMENT(i))
3857     {
3858       /* these are additional properties which are initially false when set */
3859
3860       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3861       if (DONT_TOUCH(i))
3862         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3863       if (DONT_COLLIDE_WITH(i))
3864         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3865
3866       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3867       if (CAN_SMASH_EVERYTHING(i))
3868         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3869       if (CAN_SMASH_ENEMIES(i))
3870         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3871     }
3872
3873     /* ---------- CAN_SMASH ------------------------------------------------ */
3874     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3875                                    CAN_SMASH_ENEMIES(i) ||
3876                                    CAN_SMASH_EVERYTHING(i)));
3877
3878     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3879     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3880                                              EXPLODES_BY_FIRE(i)));
3881
3882     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3883     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3884                                              EXPLODES_SMASHED(i)));
3885
3886     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3887     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3888                                             EXPLODES_IMPACT(i)));
3889
3890     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3891     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3892
3893     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3894     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3895                                                   i == EL_BLACK_ORB));
3896
3897     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3898     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3899                                               CAN_MOVE(i) ||
3900                                               IS_CUSTOM_ELEMENT(i)));
3901
3902     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3903     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3904                                                  i == EL_SP_ELECTRON));
3905
3906     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3907     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3908       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3909                    getMoveIntoAcidProperty(&level, i));
3910
3911     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3912     if (MAYBE_DONT_COLLIDE_WITH(i))
3913       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3914                    getDontCollideWithProperty(&level, i));
3915
3916     /* ---------- SP_PORT -------------------------------------------------- */
3917     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3918                                  IS_PASSABLE_INSIDE(i)));
3919
3920     /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
3921     for (j = 0; j < level.num_android_clone_elements; j++)
3922       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
3923                    (i != EL_EMPTY &&
3924                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
3925
3926     /* ---------- CAN_CHANGE ----------------------------------------------- */
3927     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
3928     for (j = 0; j < element_info[i].num_change_pages; j++)
3929       if (element_info[i].change_page[j].can_change)
3930         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3931
3932     /* ---------- HAS_ACTION ----------------------------------------------- */
3933     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      /* default: has no action */
3934     for (j = 0; j < element_info[i].num_change_pages; j++)
3935       if (element_info[i].change_page[j].has_action)
3936         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3937
3938     /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3939     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3940                                                   HAS_ACTION(i)));
3941
3942     /* ---------- GFX_CRUMBLED --------------------------------------------- */
3943 #if 1
3944     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3945                  element_info[i].crumbled[ACTION_DEFAULT] !=
3946                  element_info[i].graphic[ACTION_DEFAULT]);
3947 #else
3948     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3949     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3950                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3951 #endif
3952
3953     /* ---------- EDITOR_CASCADE ------------------------------------------- */
3954     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
3955                                         IS_EDITOR_CASCADE_INACTIVE(i)));
3956   }
3957
3958   /* dynamically adjust element properties according to game engine version */
3959   {
3960     static int ep_em_slippery_wall[] =
3961     {
3962       EL_STEELWALL,
3963       EL_WALL,
3964       EL_EXPANDABLE_WALL,
3965       EL_EXPANDABLE_WALL_HORIZONTAL,
3966       EL_EXPANDABLE_WALL_VERTICAL,
3967       EL_EXPANDABLE_WALL_ANY,
3968       -1
3969     };
3970
3971     /* special EM style gems behaviour */
3972     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3973       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3974                    level.em_slippery_gems);
3975
3976     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3977     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3978                  (level.em_slippery_gems &&
3979                   engine_version > VERSION_IDENT(2,0,1,0)));
3980   }
3981
3982   /* this is needed because some graphics depend on element properties */
3983   if (game_status == GAME_MODE_PLAYING)
3984     InitElementGraphicInfo();
3985 }
3986
3987 void InitElementPropertiesAfterLoading(int engine_version)
3988 {
3989   int i;
3990
3991   /* set some other uninitialized values of custom elements in older levels */
3992   if (engine_version < VERSION_IDENT(3,1,0,0))
3993   {
3994     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3995     {
3996       int element = EL_CUSTOM_START + i;
3997
3998       element_info[element].access_direction = MV_ALL_DIRECTIONS;
3999
4000       element_info[element].explosion_delay = 17;
4001       element_info[element].ignition_delay = 8;
4002     }
4003   }
4004 }
4005
4006 static void InitGlobal()
4007 {
4008   int i;
4009
4010   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4011   {
4012     /* check if element_name_info entry defined for each element in "main.h" */
4013     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4014       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4015
4016     element_info[i].token_name = element_name_info[i].token_name;
4017     element_info[i].class_name = element_name_info[i].class_name;
4018     element_info[i].editor_description=element_name_info[i].editor_description;
4019   }
4020
4021   global.autoplay_leveldir = NULL;
4022   global.convert_leveldir = NULL;
4023
4024   global.frames_per_second = 0;
4025   global.fps_slowdown = FALSE;
4026   global.fps_slowdown_factor = 1;
4027 }
4028
4029 void Execute_Command(char *command)
4030 {
4031   int i;
4032
4033   if (strEqual(command, "print graphicsinfo.conf"))
4034   {
4035     printf("# You can configure additional/alternative image files here.\n");
4036     printf("# (The entries below are default and therefore commented out.)\n");
4037     printf("\n");
4038     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4039     printf("\n");
4040     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4041     printf("\n");
4042
4043     for (i = 0; image_config[i].token != NULL; i++)
4044       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4045                                               image_config[i].value));
4046
4047     exit(0);
4048   }
4049   else if (strEqual(command, "print soundsinfo.conf"))
4050   {
4051     printf("# You can configure additional/alternative sound files here.\n");
4052     printf("# (The entries below are default and therefore commented out.)\n");
4053     printf("\n");
4054     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4055     printf("\n");
4056     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4057     printf("\n");
4058
4059     for (i = 0; sound_config[i].token != NULL; i++)
4060       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4061                                               sound_config[i].value));
4062
4063     exit(0);
4064   }
4065   else if (strEqual(command, "print musicinfo.conf"))
4066   {
4067     printf("# You can configure additional/alternative music files here.\n");
4068     printf("# (The entries below are default and therefore commented out.)\n");
4069     printf("\n");
4070     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4071     printf("\n");
4072     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4073     printf("\n");
4074
4075     for (i = 0; music_config[i].token != NULL; i++)
4076       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4077                                               music_config[i].value));
4078
4079     exit(0);
4080   }
4081   else if (strEqual(command, "print editorsetup.conf"))
4082   {
4083     printf("# You can configure your personal editor element list here.\n");
4084     printf("# (The entries below are default and therefore commented out.)\n");
4085     printf("\n");
4086
4087     /* this is needed to be able to check element list for cascade elements */
4088     InitElementPropertiesStatic();
4089     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4090
4091     PrintEditorElementList();
4092
4093     exit(0);
4094   }
4095   else if (strEqual(command, "print helpanim.conf"))
4096   {
4097     printf("# You can configure different element help animations here.\n");
4098     printf("# (The entries below are default and therefore commented out.)\n");
4099     printf("\n");
4100
4101     for (i = 0; helpanim_config[i].token != NULL; i++)
4102     {
4103       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4104                                               helpanim_config[i].value));
4105
4106       if (strEqual(helpanim_config[i].token, "end"))
4107         printf("#\n");
4108     }
4109
4110     exit(0);
4111   }
4112   else if (strEqual(command, "print helptext.conf"))
4113   {
4114     printf("# You can configure different element help text here.\n");
4115     printf("# (The entries below are default and therefore commented out.)\n");
4116     printf("\n");
4117
4118     for (i = 0; helptext_config[i].token != NULL; i++)
4119       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4120                                               helptext_config[i].value));
4121
4122     exit(0);
4123   }
4124   else if (strncmp(command, "dump level ", 11) == 0)
4125   {
4126     char *filename = &command[11];
4127
4128     if (!fileExists(filename))
4129       Error(ERR_EXIT, "cannot open file '%s'", filename);
4130
4131     LoadLevelFromFilename(&level, filename);
4132     DumpLevel(&level);
4133
4134     exit(0);
4135   }
4136   else if (strncmp(command, "dump tape ", 10) == 0)
4137   {
4138     char *filename = &command[10];
4139
4140     if (!fileExists(filename))
4141       Error(ERR_EXIT, "cannot open file '%s'", filename);
4142
4143     LoadTapeFromFilename(filename);
4144     DumpTape(&tape);
4145
4146     exit(0);
4147   }
4148   else if (strncmp(command, "autoplay ", 9) == 0)
4149   {
4150     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4151
4152     while (*str_ptr != '\0')                    /* continue parsing string */
4153     {
4154       /* cut leading whitespace from string, replace it by string terminator */
4155       while (*str_ptr == ' ' || *str_ptr == '\t')
4156         *str_ptr++ = '\0';
4157
4158       if (*str_ptr == '\0')                     /* end of string reached */
4159         break;
4160
4161       if (global.autoplay_leveldir == NULL)     /* read level set string */
4162       {
4163         global.autoplay_leveldir = str_ptr;
4164         global.autoplay_all = TRUE;             /* default: play all tapes */
4165
4166         for (i = 0; i < MAX_TAPES_PER_SET; i++)
4167           global.autoplay_level[i] = FALSE;
4168       }
4169       else                                      /* read level number string */
4170       {
4171         int level_nr = atoi(str_ptr);           /* get level_nr value */
4172
4173         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4174           global.autoplay_level[level_nr] = TRUE;
4175
4176         global.autoplay_all = FALSE;
4177       }
4178
4179       /* advance string pointer to the next whitespace (or end of string) */
4180       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4181         str_ptr++;
4182     }
4183   }
4184   else if (strncmp(command, "convert ", 8) == 0)
4185   {
4186     char *str_copy = getStringCopy(&command[8]);
4187     char *str_ptr = strchr(str_copy, ' ');
4188
4189     global.convert_leveldir = str_copy;
4190     global.convert_level_nr = -1;
4191
4192     if (str_ptr != NULL)                        /* level number follows */
4193     {
4194       *str_ptr++ = '\0';                        /* terminate leveldir string */
4195       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
4196     }
4197   }
4198
4199 #if DEBUG
4200 #if defined(TARGET_SDL)
4201   else if (strEqual(command, "SDL_ListModes"))
4202   {
4203     SDL_Rect **modes;
4204     int i;
4205
4206     SDL_Init(SDL_INIT_VIDEO);
4207
4208     /* get available fullscreen/hardware modes */
4209     modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4210
4211     /* check if there are any modes available */
4212     if (modes == NULL)
4213     {
4214       printf("No modes available!\n");
4215
4216       exit(-1);
4217     }
4218
4219     /* check if our resolution is restricted */
4220     if (modes == (SDL_Rect **)-1)
4221     {
4222       printf("All resolutions available.\n");
4223     }
4224     else
4225     {
4226       printf("Available Modes:\n");
4227
4228       for(i = 0; modes[i]; i++)
4229         printf("  %d x %d\n", modes[i]->w, modes[i]->h);
4230     }
4231
4232     exit(0);
4233   }
4234 #endif
4235 #endif
4236
4237   else
4238   {
4239     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4240   }
4241 }
4242
4243 static void InitSetup()
4244 {
4245   LoadSetup();                                  /* global setup info */
4246
4247   /* set some options from setup file */
4248
4249   if (setup.options.verbose)
4250     options.verbose = TRUE;
4251 }
4252
4253 static void InitGameInfo()
4254 {
4255   game.restart_level = FALSE;
4256 }
4257
4258 static void InitPlayerInfo()
4259 {
4260   int i;
4261
4262   /* choose default local player */
4263   local_player = &stored_player[0];
4264
4265   for (i = 0; i < MAX_PLAYERS; i++)
4266     stored_player[i].connected = FALSE;
4267
4268   local_player->connected = TRUE;
4269 }
4270
4271 static void InitArtworkInfo()
4272 {
4273   LoadArtworkInfo();
4274 }
4275
4276 static char *get_string_in_brackets(char *string)
4277 {
4278   char *string_in_brackets = checked_malloc(strlen(string) + 3);
4279
4280   sprintf(string_in_brackets, "[%s]", string);
4281
4282   return string_in_brackets;
4283 }
4284
4285 static char *get_level_id_suffix(int id_nr)
4286 {
4287   char *id_suffix = checked_malloc(1 + 3 + 1);
4288
4289   if (id_nr < 0 || id_nr > 999)
4290     id_nr = 0;
4291
4292   sprintf(id_suffix, ".%03d", id_nr);
4293
4294   return id_suffix;
4295 }
4296
4297 #if 0
4298 static char *get_element_class_token(int element)
4299 {
4300   char *element_class_name = element_info[element].class_name;
4301   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4302
4303   sprintf(element_class_token, "[%s]", element_class_name);
4304
4305   return element_class_token;
4306 }
4307
4308 static char *get_action_class_token(int action)
4309 {
4310   char *action_class_name = &element_action_info[action].suffix[1];
4311   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4312
4313   sprintf(action_class_token, "[%s]", action_class_name);
4314
4315   return action_class_token;
4316 }
4317 #endif
4318
4319 static void InitArtworkConfig()
4320 {
4321   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4322   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4323   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4324   static char *action_id_suffix[NUM_ACTIONS + 1];
4325   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4326   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4327   static char *level_id_suffix[MAX_LEVELS + 1];
4328   static char *dummy[1] = { NULL };
4329   static char *ignore_generic_tokens[] =
4330   {
4331     "name",
4332     "sort_priority",
4333     NULL
4334   };
4335   static char **ignore_image_tokens;
4336   static char **ignore_sound_tokens;
4337   static char **ignore_music_tokens;
4338   int num_ignore_generic_tokens;
4339   int num_ignore_image_tokens;
4340   int num_ignore_sound_tokens;
4341   int num_ignore_music_tokens;
4342   int i;
4343
4344   /* dynamically determine list of generic tokens to be ignored */
4345   num_ignore_generic_tokens = 0;
4346   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4347     num_ignore_generic_tokens++;
4348
4349   /* dynamically determine list of image tokens to be ignored */
4350   num_ignore_image_tokens = num_ignore_generic_tokens;
4351   for (i = 0; image_config_vars[i].token != NULL; i++)
4352     num_ignore_image_tokens++;
4353   ignore_image_tokens =
4354     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4355   for (i = 0; i < num_ignore_generic_tokens; i++)
4356     ignore_image_tokens[i] = ignore_generic_tokens[i];
4357   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4358     ignore_image_tokens[num_ignore_generic_tokens + i] =
4359       image_config_vars[i].token;
4360   ignore_image_tokens[num_ignore_image_tokens] = NULL;
4361
4362   /* dynamically determine list of sound tokens to be ignored */
4363   num_ignore_sound_tokens = num_ignore_generic_tokens;
4364   ignore_sound_tokens =
4365     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4366   for (i = 0; i < num_ignore_generic_tokens; i++)
4367     ignore_sound_tokens[i] = ignore_generic_tokens[i];
4368   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4369
4370   /* dynamically determine list of music tokens to be ignored */
4371   num_ignore_music_tokens = num_ignore_generic_tokens;
4372   ignore_music_tokens =
4373     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4374   for (i = 0; i < num_ignore_generic_tokens; i++)
4375     ignore_music_tokens[i] = ignore_generic_tokens[i];
4376   ignore_music_tokens[num_ignore_music_tokens] = NULL;
4377
4378   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4379     image_id_prefix[i] = element_info[i].token_name;
4380   for (i = 0; i < NUM_FONTS; i++)
4381     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4382   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4383
4384   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4385     sound_id_prefix[i] = element_info[i].token_name;
4386   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4387     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4388       get_string_in_brackets(element_info[i].class_name);
4389   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4390
4391   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4392     music_id_prefix[i] = music_prefix_info[i].prefix;
4393   music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4394
4395   for (i = 0; i < NUM_ACTIONS; i++)
4396     action_id_suffix[i] = element_action_info[i].suffix;
4397   action_id_suffix[NUM_ACTIONS] = NULL;
4398
4399   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4400     direction_id_suffix[i] = element_direction_info[i].suffix;
4401   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4402
4403   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4404     special_id_suffix[i] = special_suffix_info[i].suffix;
4405   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4406
4407   for (i = 0; i < MAX_LEVELS; i++)
4408     level_id_suffix[i] = get_level_id_suffix(i);
4409   level_id_suffix[MAX_LEVELS] = NULL;
4410
4411   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4412                 image_id_prefix, action_id_suffix, direction_id_suffix,
4413                 special_id_suffix, ignore_image_tokens);
4414   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4415                 sound_id_prefix, action_id_suffix, dummy,
4416                 special_id_suffix, ignore_sound_tokens);
4417   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4418                 music_id_prefix, special_id_suffix, level_id_suffix,
4419                 dummy, ignore_music_tokens);
4420 }
4421
4422 static void InitMixer()
4423 {
4424   OpenAudio();
4425   StartMixer();
4426 }
4427
4428 void InitGfx()
4429 {
4430   char *filename_font_initial = NULL;
4431   Bitmap *bitmap_font_initial = NULL;
4432   int font_height;
4433   int i, j;
4434
4435   /* determine settings for initial font (for displaying startup messages) */
4436   for (i = 0; image_config[i].token != NULL; i++)
4437   {
4438     for (j = 0; j < NUM_INITIAL_FONTS; j++)
4439     {
4440       char font_token[128];
4441       int len_font_token;
4442
4443       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4444       len_font_token = strlen(font_token);
4445
4446       if (strEqual(image_config[i].token, font_token))
4447         filename_font_initial = image_config[i].value;
4448       else if (strlen(image_config[i].token) > len_font_token &&
4449                strncmp(image_config[i].token, font_token, len_font_token) == 0)
4450       {
4451         if (strEqual(&image_config[i].token[len_font_token], ".x"))
4452           font_initial[j].src_x = atoi(image_config[i].value);
4453         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4454           font_initial[j].src_y = atoi(image_config[i].value);
4455         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4456           font_initial[j].width = atoi(image_config[i].value);
4457         else if (strEqual(&image_config[i].token[len_font_token],".height"))
4458           font_initial[j].height = atoi(image_config[i].value);
4459       }
4460     }
4461   }
4462
4463   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4464   {
4465     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4466     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4467   }
4468
4469   if (filename_font_initial == NULL)    /* should not happen */
4470     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4471
4472   /* create additional image buffers for double-buffering and cross-fading */
4473   bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4474   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4475   bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4476   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4477
4478   /* initialize screen properties */
4479   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4480                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4481                    bitmap_db_field);
4482   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4483   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4484   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4485
4486   bitmap_font_initial = LoadCustomImage(filename_font_initial);
4487
4488   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4489     font_initial[j].bitmap = bitmap_font_initial;
4490
4491   InitFontGraphicInfo();
4492
4493   font_height = getFontHeight(FC_RED);
4494
4495   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4496   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4497   DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4498
4499   DrawInitText("Loading graphics:", 120, FC_GREEN);
4500 }
4501
4502 void RedrawBackground()
4503 {
4504   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4505              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4506
4507   redraw_mask = REDRAW_ALL;
4508 }
4509
4510 void InitGfxBackground()
4511 {
4512   int x, y;
4513
4514   drawto = backbuffer;
4515   fieldbuffer = bitmap_db_field;
4516   SetDrawtoField(DRAW_BACKBUFFER);
4517
4518   RedrawBackground();
4519
4520   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4521   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4522
4523   for (x = 0; x < MAX_BUF_XSIZE; x++)
4524     for (y = 0; y < MAX_BUF_YSIZE; y++)
4525       redraw[x][y] = 0;
4526   redraw_tiles = 0;
4527   redraw_mask = REDRAW_ALL;
4528 }
4529
4530 static void InitLevelInfo()
4531 {
4532   LoadLevelInfo();                              /* global level info */
4533   LoadLevelSetup_LastSeries();                  /* last played series info */
4534   LoadLevelSetup_SeriesInfo();                  /* last played level info */
4535 }
4536
4537 void InitLevelArtworkInfo()
4538 {
4539   LoadLevelArtworkInfo();
4540 }
4541
4542 static void InitImages()
4543 {
4544   setLevelArtworkDir(artwork.gfx_first);
4545
4546 #if 0
4547   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4548          leveldir_current->identifier,
4549          artwork.gfx_current_identifier,
4550          artwork.gfx_current->identifier,
4551          leveldir_current->graphics_set,
4552          leveldir_current->graphics_path);
4553 #endif
4554
4555   ReloadCustomImages();
4556
4557   LoadCustomElementDescriptions();
4558   LoadSpecialMenuDesignSettings();
4559
4560   ReinitializeGraphics();
4561 }
4562
4563 static void InitSound(char *identifier)
4564 {
4565   if (identifier == NULL)
4566     identifier = artwork.snd_current->identifier;
4567
4568   /* set artwork path to send it to the sound server process */
4569   setLevelArtworkDir(artwork.snd_first);
4570
4571   InitReloadCustomSounds(identifier);
4572   ReinitializeSounds();
4573 }
4574
4575 static void InitMusic(char *identifier)
4576 {
4577   if (identifier == NULL)
4578     identifier = artwork.mus_current->identifier;
4579
4580   /* set artwork path to send it to the sound server process */
4581   setLevelArtworkDir(artwork.mus_first);
4582
4583   InitReloadCustomMusic(identifier);
4584   ReinitializeMusic();
4585 }
4586
4587 void InitNetworkServer()
4588 {
4589 #if defined(NETWORK_AVALIABLE)
4590   int nr_wanted;
4591 #endif
4592
4593   if (!options.network)
4594     return;
4595
4596 #if defined(NETWORK_AVALIABLE)
4597   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4598
4599   if (!ConnectToServer(options.server_host, options.server_port))
4600     Error(ERR_EXIT, "cannot connect to network game server");
4601
4602   SendToServer_PlayerName(setup.player_name);
4603   SendToServer_ProtocolVersion();
4604
4605   if (nr_wanted)
4606     SendToServer_NrWanted(nr_wanted);
4607 #endif
4608 }
4609
4610 static char *getNewArtworkIdentifier(int type)
4611 {
4612   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4613   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4614   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4615   static boolean initialized[3] = { FALSE, FALSE, FALSE };
4616   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4617   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4618   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4619   char *leveldir_identifier = leveldir_current->identifier;
4620 #if 1
4621   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4622   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4623 #else
4624   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4625 #endif
4626   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4627   char *artwork_current_identifier;
4628   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
4629
4630   /* leveldir_current may be invalid (level group, parent link) */
4631   if (!validLevelSeries(leveldir_current))
4632     return NULL;
4633
4634   /* 1st step: determine artwork set to be activated in descending order:
4635      --------------------------------------------------------------------
4636      1. setup artwork (when configured to override everything else)
4637      2. artwork set configured in "levelinfo.conf" of current level set
4638         (artwork in level directory will have priority when loading later)
4639      3. artwork in level directory (stored in artwork sub-directory)
4640      4. setup artwork (currently configured in setup menu) */
4641
4642   if (setup_override_artwork)
4643     artwork_current_identifier = setup_artwork_set;
4644   else if (leveldir_artwork_set != NULL)
4645     artwork_current_identifier = leveldir_artwork_set;
4646   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4647     artwork_current_identifier = leveldir_identifier;
4648   else
4649     artwork_current_identifier = setup_artwork_set;
4650
4651
4652   /* 2nd step: check if it is really needed to reload artwork set
4653      ------------------------------------------------------------ */
4654
4655 #if 0
4656   if (type == ARTWORK_TYPE_GRAPHICS)
4657     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4658            artwork_new_identifier,
4659            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4660            artwork_current_identifier,
4661            leveldir_current->graphics_set,
4662            leveldir_current->identifier);
4663 #endif
4664
4665   /* ---------- reload if level set and also artwork set has changed ------- */
4666   if (leveldir_current_identifier[type] != leveldir_identifier &&
4667       (last_has_level_artwork_set[type] || has_level_artwork_set))
4668     artwork_new_identifier = artwork_current_identifier;
4669
4670   leveldir_current_identifier[type] = leveldir_identifier;
4671   last_has_level_artwork_set[type] = has_level_artwork_set;
4672
4673 #if 0
4674   if (type == ARTWORK_TYPE_GRAPHICS)
4675     printf("::: 1: '%s'\n", artwork_new_identifier);
4676 #endif
4677
4678   /* ---------- reload if "override artwork" setting has changed ----------- */
4679   if (last_override_level_artwork[type] != setup_override_artwork)
4680     artwork_new_identifier = artwork_current_identifier;
4681
4682   last_override_level_artwork[type] = setup_override_artwork;
4683
4684 #if 0
4685   if (type == ARTWORK_TYPE_GRAPHICS)
4686     printf("::: 2: '%s'\n", artwork_new_identifier);
4687 #endif
4688
4689   /* ---------- reload if current artwork identifier has changed ----------- */
4690   if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4691                 artwork_current_identifier))
4692     artwork_new_identifier = artwork_current_identifier;
4693
4694   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4695
4696 #if 0
4697   if (type == ARTWORK_TYPE_GRAPHICS)
4698     printf("::: 3: '%s'\n", artwork_new_identifier);
4699 #endif
4700
4701   /* ---------- do not reload directly after starting ---------------------- */
4702   if (!initialized[type])
4703     artwork_new_identifier = NULL;
4704
4705   initialized[type] = TRUE;
4706
4707 #if 0
4708   if (type == ARTWORK_TYPE_GRAPHICS)
4709     printf("::: 4: '%s'\n", artwork_new_identifier);
4710 #endif
4711
4712 #if 0
4713   if (type == ARTWORK_TYPE_GRAPHICS)
4714     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4715            artwork.gfx_current_identifier, artwork_current_identifier,
4716            artwork.gfx_current->identifier, leveldir_current->graphics_set,
4717            artwork_new_identifier);
4718 #endif
4719
4720   return artwork_new_identifier;
4721 }
4722
4723 void ReloadCustomArtwork(int force_reload)
4724 {
4725   char *gfx_new_identifier;
4726   char *snd_new_identifier;
4727   char *mus_new_identifier;
4728   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4729   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4730   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4731   boolean redraw_screen = FALSE;
4732
4733   force_reload_gfx |= AdjustGraphicsForEMC();
4734
4735   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4736   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4737   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4738
4739   if (gfx_new_identifier != NULL || force_reload_gfx)
4740   {
4741 #if 0
4742     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4743            artwork.gfx_current_identifier,
4744            gfx_new_identifier,
4745            artwork.gfx_current->identifier,
4746            leveldir_current->graphics_set);
4747 #endif
4748
4749     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4750
4751     InitImages();
4752
4753     redraw_screen = TRUE;
4754   }
4755
4756   if (snd_new_identifier != NULL || force_reload_snd)
4757   {
4758     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4759
4760     InitSound(snd_new_identifier);
4761
4762     redraw_screen = TRUE;
4763   }
4764
4765   if (mus_new_identifier != NULL || force_reload_mus)
4766   {
4767     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4768
4769     InitMusic(mus_new_identifier);
4770
4771     redraw_screen = TRUE;
4772   }
4773
4774   if (redraw_screen)
4775   {
4776     RedrawBackground();
4777
4778     /* force redraw of (open or closed) door graphics */
4779     SetDoorState(DOOR_OPEN_ALL);
4780     CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4781   }
4782 }
4783
4784 void KeyboardAutoRepeatOffUnlessAutoplay()
4785 {
4786   if (global.autoplay_leveldir == NULL)
4787     KeyboardAutoRepeatOff();
4788 }
4789
4790
4791 /* ========================================================================= */
4792 /* OpenAll()                                                                 */
4793 /* ========================================================================= */
4794
4795 void OpenAll()
4796 {
4797   InitGlobal();                 /* initialize some global variables */
4798
4799   if (options.execute_command)
4800     Execute_Command(options.execute_command);
4801
4802   if (options.serveronly)
4803   {
4804 #if defined(PLATFORM_UNIX)
4805     NetworkServer(options.server_port, options.serveronly);
4806 #else
4807     Error(ERR_WARN, "networking only supported in Unix version");
4808 #endif
4809
4810     exit(0);                    /* never reached, server loops forever */
4811   }
4812
4813   InitSetup();
4814
4815   InitGameInfo();
4816   InitPlayerInfo();
4817   InitArtworkInfo();            /* needed before loading gfx, sound & music */
4818   InitArtworkConfig();          /* needed before forking sound child process */
4819   InitMixer();
4820
4821   InitCounter();
4822
4823   InitRND(NEW_RANDOMIZE);
4824   InitSimpleRandom(NEW_RANDOMIZE);
4825
4826   InitJoysticks();
4827
4828   InitVideoDisplay();
4829   InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4830                   setup.fullscreen);
4831
4832   InitEventFilter(FilterMouseMotionEvents);
4833
4834   InitElementPropertiesStatic();
4835   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4836
4837   InitGfx();
4838
4839   InitLevelInfo();
4840   InitLevelArtworkInfo();
4841
4842   InitImages();                 /* needs to know current level directory */
4843   InitSound(NULL);              /* needs to know current level directory */
4844   InitMusic(NULL);              /* needs to know current level directory */
4845
4846   InitGfxBackground();
4847
4848 #if 1
4849   em_open_all();
4850 #endif
4851
4852   if (global.autoplay_leveldir)
4853   {
4854     AutoPlayTape();
4855     return;
4856   }
4857   else if (global.convert_leveldir)
4858   {
4859     ConvertLevels();
4860     return;
4861   }
4862
4863   game_status = GAME_MODE_MAIN;
4864
4865   DrawMainMenu();
4866
4867   InitNetworkServer();
4868 }
4869
4870 void CloseAllAndExit(int exit_value)
4871 {
4872   StopSounds();
4873   FreeAllSounds();
4874   FreeAllMusic();
4875   CloseAudio();         /* called after freeing sounds (needed for SDL) */
4876
4877 #if 1
4878   em_close_all();
4879 #endif
4880
4881   FreeAllImages();
4882
4883 #if defined(TARGET_SDL)
4884   if (network_server)   /* terminate network server */
4885     SDL_KillThread(server_thread);
4886 #endif
4887
4888   CloseVideoDisplay();
4889   ClosePlatformDependentStuff();
4890
4891   if (exit_value != 0)
4892     NotifyUserAboutErrorFile();
4893
4894   exit(exit_value);
4895 }