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