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