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