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