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