769d98fa411805999d3e75527cb0860c283aa54d
[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_EM_GATE_1,
1954     EL_EM_GATE_2,
1955     EL_EM_GATE_3,
1956     EL_EM_GATE_4,
1957     EL_EM_GATE_1_GRAY,
1958     EL_EM_GATE_2_GRAY,
1959     EL_EM_GATE_3_GRAY,
1960     EL_EM_GATE_4_GRAY,
1961     EL_EMC_GATE_5,
1962     EL_EMC_GATE_6,
1963     EL_EMC_GATE_7,
1964     EL_EMC_GATE_8,
1965     EL_EMC_GATE_5_GRAY,
1966     EL_EMC_GATE_6_GRAY,
1967     EL_EMC_GATE_7_GRAY,
1968     EL_EMC_GATE_8_GRAY,
1969     EL_SWITCHGATE_OPEN,
1970     EL_SWITCHGATE_OPENING,
1971     EL_SWITCHGATE_CLOSED,
1972     EL_SWITCHGATE_CLOSING,
1973 #if 0
1974     EL_SWITCHGATE_SWITCH_UP,
1975     EL_SWITCHGATE_SWITCH_DOWN,
1976 #endif
1977     EL_TIMEGATE_OPEN,
1978     EL_TIMEGATE_OPENING,
1979     EL_TIMEGATE_CLOSED,
1980     EL_TIMEGATE_CLOSING,
1981 #if 0
1982     EL_TIMEGATE_SWITCH,
1983     EL_TIMEGATE_SWITCH_ACTIVE,
1984 #endif
1985     EL_TUBE_ANY,
1986     EL_TUBE_VERTICAL,
1987     EL_TUBE_HORIZONTAL,
1988     EL_TUBE_VERTICAL_LEFT,
1989     EL_TUBE_VERTICAL_RIGHT,
1990     EL_TUBE_HORIZONTAL_UP,
1991     EL_TUBE_HORIZONTAL_DOWN,
1992     EL_TUBE_LEFT_UP,
1993     EL_TUBE_LEFT_DOWN,
1994     EL_TUBE_RIGHT_UP,
1995     EL_TUBE_RIGHT_DOWN,
1996     -1
1997   };
1998
1999   static int ep_slippery[] =
2000   {
2001     EL_WALL_SLIPPERY,
2002     EL_BD_WALL,
2003     EL_ROCK,
2004     EL_BD_ROCK,
2005     EL_EMERALD,
2006     EL_BD_DIAMOND,
2007     EL_EMERALD_YELLOW,
2008     EL_EMERALD_RED,
2009     EL_EMERALD_PURPLE,
2010     EL_DIAMOND,
2011     EL_BOMB,
2012     EL_NUT,
2013     EL_ROBOT_WHEEL_ACTIVE,
2014     EL_ROBOT_WHEEL,
2015     EL_TIME_ORB_FULL,
2016     EL_TIME_ORB_EMPTY,
2017     EL_LAMP_ACTIVE,
2018     EL_LAMP,
2019     EL_ACID_POOL_TOPLEFT,
2020     EL_ACID_POOL_TOPRIGHT,
2021     EL_SATELLITE,
2022     EL_SP_ZONK,
2023     EL_SP_INFOTRON,
2024     EL_SP_CHIP_SINGLE,
2025     EL_SP_CHIP_LEFT,
2026     EL_SP_CHIP_RIGHT,
2027     EL_SP_CHIP_TOP,
2028     EL_SP_CHIP_BOTTOM,
2029     EL_SPEED_PILL,
2030     EL_STEELWALL_SLIPPERY,
2031     EL_PEARL,
2032     EL_CRYSTAL,
2033     EL_EMC_WALL_SLIPPERY_1,
2034     EL_EMC_WALL_SLIPPERY_2,
2035     EL_EMC_WALL_SLIPPERY_3,
2036     EL_EMC_WALL_SLIPPERY_4,
2037     -1
2038   };
2039
2040   static int ep_can_change[] =
2041   {
2042     -1
2043   };
2044
2045   static int ep_can_move[] =
2046   {
2047     /* same elements as in 'pb_can_move_into_acid' */
2048     EL_BUG,
2049     EL_SPACESHIP,
2050     EL_BD_BUTTERFLY,
2051     EL_BD_FIREFLY,
2052     EL_YAMYAM,
2053     EL_DARK_YAMYAM,
2054     EL_ROBOT,
2055     EL_PACMAN,
2056     EL_MOLE,
2057     EL_PENGUIN,
2058     EL_PIG,
2059     EL_DRAGON,
2060     EL_SATELLITE,
2061     EL_SP_SNIKSNAK,
2062     EL_SP_ELECTRON,
2063     EL_BALLOON,
2064     EL_SPRING,
2065     EL_EMC_ANDROID,
2066     -1
2067   };
2068
2069   static int ep_can_fall[] =
2070   {
2071     EL_ROCK,
2072     EL_BD_ROCK,
2073     EL_EMERALD,
2074     EL_BD_DIAMOND,
2075     EL_EMERALD_YELLOW,
2076     EL_EMERALD_RED,
2077     EL_EMERALD_PURPLE,
2078     EL_DIAMOND,
2079     EL_BOMB,
2080     EL_NUT,
2081     EL_AMOEBA_DROP,
2082     EL_QUICKSAND_FULL,
2083     EL_MAGIC_WALL_FULL,
2084     EL_BD_MAGIC_WALL_FULL,
2085     EL_TIME_ORB_FULL,
2086     EL_TIME_ORB_EMPTY,
2087     EL_SP_ZONK,
2088     EL_SP_INFOTRON,
2089     EL_SP_DISK_ORANGE,
2090     EL_PEARL,
2091     EL_CRYSTAL,
2092     EL_SPRING,
2093     EL_DX_SUPABOMB,
2094     -1
2095   };
2096
2097   static int ep_can_smash_player[] =
2098   {
2099     EL_ROCK,
2100     EL_BD_ROCK,
2101     EL_EMERALD,
2102     EL_BD_DIAMOND,
2103     EL_EMERALD_YELLOW,
2104     EL_EMERALD_RED,
2105     EL_EMERALD_PURPLE,
2106     EL_DIAMOND,
2107     EL_BOMB,
2108     EL_NUT,
2109     EL_AMOEBA_DROP,
2110     EL_TIME_ORB_FULL,
2111     EL_TIME_ORB_EMPTY,
2112     EL_SP_ZONK,
2113     EL_SP_INFOTRON,
2114     EL_SP_DISK_ORANGE,
2115     EL_PEARL,
2116     EL_CRYSTAL,
2117     EL_SPRING,
2118     EL_DX_SUPABOMB,
2119     -1
2120   };
2121
2122   static int ep_can_smash_enemies[] =
2123   {
2124     EL_ROCK,
2125     EL_BD_ROCK,
2126     EL_SP_ZONK,
2127     -1
2128   };
2129
2130   static int ep_can_smash_everything[] =
2131   {
2132     EL_ROCK,
2133     EL_BD_ROCK,
2134     EL_SP_ZONK,
2135     -1
2136   };
2137
2138   static int ep_explodes_by_fire[] =
2139   {
2140     /* same elements as in 'ep_explodes_impact' */
2141     EL_BOMB,
2142     EL_SP_DISK_ORANGE,
2143     EL_DX_SUPABOMB,
2144
2145     /* same elements as in 'ep_explodes_smashed' */
2146     EL_SATELLITE,
2147     EL_PIG,
2148     EL_DRAGON,
2149     EL_MOLE,
2150
2151     /* new elements */
2152     EL_DYNAMITE_ACTIVE,
2153     EL_DYNAMITE,
2154     EL_DYNABOMB_PLAYER_1_ACTIVE,
2155     EL_DYNABOMB_PLAYER_2_ACTIVE,
2156     EL_DYNABOMB_PLAYER_3_ACTIVE,
2157     EL_DYNABOMB_PLAYER_4_ACTIVE,
2158     EL_DYNABOMB_INCREASE_NUMBER,
2159     EL_DYNABOMB_INCREASE_SIZE,
2160     EL_DYNABOMB_INCREASE_POWER,
2161     EL_SP_DISK_RED_ACTIVE,
2162     EL_BUG,
2163     EL_PENGUIN,
2164     EL_SP_DISK_RED,
2165     EL_SP_DISK_YELLOW,
2166     EL_SP_SNIKSNAK,
2167     EL_SP_ELECTRON,
2168 #if 0
2169     EL_BLACK_ORB,
2170 #endif
2171     -1
2172   };
2173
2174   static int ep_explodes_smashed[] =
2175   {
2176     /* same elements as in 'ep_explodes_impact' */
2177     EL_BOMB,
2178     EL_SP_DISK_ORANGE,
2179     EL_DX_SUPABOMB,
2180
2181     /* new elements */
2182     EL_SATELLITE,
2183     EL_PIG,
2184     EL_DRAGON,
2185     EL_MOLE,
2186     -1
2187   };
2188
2189   static int ep_explodes_impact[] =
2190   {
2191     EL_BOMB,
2192     EL_SP_DISK_ORANGE,
2193     EL_DX_SUPABOMB,
2194     -1
2195   };
2196
2197   static int ep_walkable_over[] =
2198   {
2199     EL_EMPTY_SPACE,
2200     EL_SP_EMPTY_SPACE,
2201     EL_SOKOBAN_FIELD_EMPTY,
2202     EL_EXIT_OPEN,
2203     EL_SP_EXIT_OPEN,
2204     EL_SP_EXIT_OPENING,
2205     EL_GATE_1,
2206     EL_GATE_2,
2207     EL_GATE_3,
2208     EL_GATE_4,
2209     EL_GATE_1_GRAY,
2210     EL_GATE_2_GRAY,
2211     EL_GATE_3_GRAY,
2212     EL_GATE_4_GRAY,
2213     EL_PENGUIN,
2214     EL_PIG,
2215     EL_DRAGON,
2216     -1
2217   };
2218
2219   static int ep_walkable_inside[] =
2220   {
2221     EL_TUBE_ANY,
2222     EL_TUBE_VERTICAL,
2223     EL_TUBE_HORIZONTAL,
2224     EL_TUBE_VERTICAL_LEFT,
2225     EL_TUBE_VERTICAL_RIGHT,
2226     EL_TUBE_HORIZONTAL_UP,
2227     EL_TUBE_HORIZONTAL_DOWN,
2228     EL_TUBE_LEFT_UP,
2229     EL_TUBE_LEFT_DOWN,
2230     EL_TUBE_RIGHT_UP,
2231     EL_TUBE_RIGHT_DOWN,
2232     -1
2233   };
2234
2235   static int ep_walkable_under[] =
2236   {
2237     -1
2238   };
2239
2240   static int ep_passable_over[] =
2241   {
2242     EL_EM_GATE_1,
2243     EL_EM_GATE_2,
2244     EL_EM_GATE_3,
2245     EL_EM_GATE_4,
2246     EL_EM_GATE_1_GRAY,
2247     EL_EM_GATE_2_GRAY,
2248     EL_EM_GATE_3_GRAY,
2249     EL_EM_GATE_4_GRAY,
2250     EL_EMC_GATE_5,
2251     EL_EMC_GATE_6,
2252     EL_EMC_GATE_7,
2253     EL_EMC_GATE_8,
2254     EL_EMC_GATE_5_GRAY,
2255     EL_EMC_GATE_6_GRAY,
2256     EL_EMC_GATE_7_GRAY,
2257     EL_EMC_GATE_8_GRAY,
2258     EL_SWITCHGATE_OPEN,
2259     EL_TIMEGATE_OPEN,
2260     -1
2261   };
2262
2263   static int ep_passable_inside[] =
2264   {
2265     EL_SP_PORT_LEFT,
2266     EL_SP_PORT_RIGHT,
2267     EL_SP_PORT_UP,
2268     EL_SP_PORT_DOWN,
2269     EL_SP_PORT_HORIZONTAL,
2270     EL_SP_PORT_VERTICAL,
2271     EL_SP_PORT_ANY,
2272     EL_SP_GRAVITY_PORT_LEFT,
2273     EL_SP_GRAVITY_PORT_RIGHT,
2274     EL_SP_GRAVITY_PORT_UP,
2275     EL_SP_GRAVITY_PORT_DOWN,
2276     EL_SP_GRAVITY_ON_PORT_LEFT,
2277     EL_SP_GRAVITY_ON_PORT_RIGHT,
2278     EL_SP_GRAVITY_ON_PORT_UP,
2279     EL_SP_GRAVITY_ON_PORT_DOWN,
2280     EL_SP_GRAVITY_OFF_PORT_LEFT,
2281     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2282     EL_SP_GRAVITY_OFF_PORT_UP,
2283     EL_SP_GRAVITY_OFF_PORT_DOWN,
2284     -1
2285   };
2286
2287   static int ep_passable_under[] =
2288   {
2289     -1
2290   };
2291
2292   static int ep_droppable[] =
2293   {
2294     -1
2295   };
2296
2297   static int ep_explodes_1x1_old[] =
2298   {
2299     -1
2300   };
2301
2302   static int ep_pushable[] =
2303   {
2304     EL_ROCK,
2305     EL_BOMB,
2306     EL_DX_SUPABOMB,
2307     EL_NUT,
2308     EL_TIME_ORB_EMPTY,
2309     EL_SP_ZONK,
2310     EL_SP_DISK_ORANGE,
2311     EL_SPRING,
2312     EL_BD_ROCK,
2313     EL_SOKOBAN_OBJECT,
2314     EL_SOKOBAN_FIELD_FULL,
2315     EL_SATELLITE,
2316     EL_SP_DISK_YELLOW,
2317     EL_BALLOON,
2318     EL_EMC_ANDROID,
2319     -1
2320   };
2321
2322   static int ep_explodes_cross_old[] =
2323   {
2324     -1
2325   };
2326
2327   static int ep_protected[] =
2328   {
2329     /* same elements as in 'ep_walkable_inside' */
2330     EL_TUBE_ANY,
2331     EL_TUBE_VERTICAL,
2332     EL_TUBE_HORIZONTAL,
2333     EL_TUBE_VERTICAL_LEFT,
2334     EL_TUBE_VERTICAL_RIGHT,
2335     EL_TUBE_HORIZONTAL_UP,
2336     EL_TUBE_HORIZONTAL_DOWN,
2337     EL_TUBE_LEFT_UP,
2338     EL_TUBE_LEFT_DOWN,
2339     EL_TUBE_RIGHT_UP,
2340     EL_TUBE_RIGHT_DOWN,
2341
2342     /* same elements as in 'ep_passable_over' */
2343     EL_EM_GATE_1,
2344     EL_EM_GATE_2,
2345     EL_EM_GATE_3,
2346     EL_EM_GATE_4,
2347     EL_EM_GATE_1_GRAY,
2348     EL_EM_GATE_2_GRAY,
2349     EL_EM_GATE_3_GRAY,
2350     EL_EM_GATE_4_GRAY,
2351     EL_EMC_GATE_5,
2352     EL_EMC_GATE_6,
2353     EL_EMC_GATE_7,
2354     EL_EMC_GATE_8,
2355     EL_EMC_GATE_5_GRAY,
2356     EL_EMC_GATE_6_GRAY,
2357     EL_EMC_GATE_7_GRAY,
2358     EL_EMC_GATE_8_GRAY,
2359     EL_SWITCHGATE_OPEN,
2360     EL_TIMEGATE_OPEN,
2361
2362     /* same elements as in 'ep_passable_inside' */
2363     EL_SP_PORT_LEFT,
2364     EL_SP_PORT_RIGHT,
2365     EL_SP_PORT_UP,
2366     EL_SP_PORT_DOWN,
2367     EL_SP_PORT_HORIZONTAL,
2368     EL_SP_PORT_VERTICAL,
2369     EL_SP_PORT_ANY,
2370     EL_SP_GRAVITY_PORT_LEFT,
2371     EL_SP_GRAVITY_PORT_RIGHT,
2372     EL_SP_GRAVITY_PORT_UP,
2373     EL_SP_GRAVITY_PORT_DOWN,
2374     EL_SP_GRAVITY_ON_PORT_LEFT,
2375     EL_SP_GRAVITY_ON_PORT_RIGHT,
2376     EL_SP_GRAVITY_ON_PORT_UP,
2377     EL_SP_GRAVITY_ON_PORT_DOWN,
2378     EL_SP_GRAVITY_OFF_PORT_LEFT,
2379     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2380     EL_SP_GRAVITY_OFF_PORT_UP,
2381     EL_SP_GRAVITY_OFF_PORT_DOWN,
2382     -1
2383   };
2384
2385   static int ep_throwable[] =
2386   {
2387     -1
2388   };
2389
2390   static int ep_can_explode[] =
2391   {
2392     /* same elements as in 'ep_explodes_impact' */
2393     EL_BOMB,
2394     EL_SP_DISK_ORANGE,
2395     EL_DX_SUPABOMB,
2396
2397     /* same elements as in 'ep_explodes_smashed' */
2398     EL_SATELLITE,
2399     EL_PIG,
2400     EL_DRAGON,
2401     EL_MOLE,
2402
2403     /* elements that can explode by explosion or by dragonfire */
2404     EL_DYNAMITE_ACTIVE,
2405     EL_DYNAMITE,
2406     EL_DYNABOMB_PLAYER_1_ACTIVE,
2407     EL_DYNABOMB_PLAYER_2_ACTIVE,
2408     EL_DYNABOMB_PLAYER_3_ACTIVE,
2409     EL_DYNABOMB_PLAYER_4_ACTIVE,
2410     EL_DYNABOMB_INCREASE_NUMBER,
2411     EL_DYNABOMB_INCREASE_SIZE,
2412     EL_DYNABOMB_INCREASE_POWER,
2413     EL_SP_DISK_RED_ACTIVE,
2414     EL_BUG,
2415     EL_PENGUIN,
2416     EL_SP_DISK_RED,
2417     EL_SP_DISK_YELLOW,
2418     EL_SP_SNIKSNAK,
2419     EL_SP_ELECTRON,
2420
2421     /* elements that can explode only by explosion */
2422     EL_BLACK_ORB,
2423     -1
2424   };
2425
2426   static int ep_gravity_reachable[] =
2427   {
2428     EL_SAND,
2429     EL_SP_BASE,
2430     EL_TRAP,
2431     EL_INVISIBLE_SAND,
2432     EL_INVISIBLE_SAND_ACTIVE,
2433     EL_SP_PORT_LEFT,
2434     EL_SP_PORT_RIGHT,
2435     EL_SP_PORT_UP,
2436     EL_SP_PORT_DOWN,
2437     EL_SP_PORT_HORIZONTAL,
2438     EL_SP_PORT_VERTICAL,
2439     EL_SP_PORT_ANY,
2440     EL_SP_GRAVITY_PORT_LEFT,
2441     EL_SP_GRAVITY_PORT_RIGHT,
2442     EL_SP_GRAVITY_PORT_UP,
2443     EL_SP_GRAVITY_PORT_DOWN,
2444     EL_SP_GRAVITY_ON_PORT_LEFT,
2445     EL_SP_GRAVITY_ON_PORT_RIGHT,
2446     EL_SP_GRAVITY_ON_PORT_UP,
2447     EL_SP_GRAVITY_ON_PORT_DOWN,
2448     EL_SP_GRAVITY_OFF_PORT_LEFT,
2449     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2450     EL_SP_GRAVITY_OFF_PORT_UP,
2451     EL_SP_GRAVITY_OFF_PORT_DOWN,
2452     EL_EMC_GRASS,
2453     -1
2454   };
2455
2456   static int ep_player[] =
2457   {
2458     EL_PLAYER_1,
2459     EL_PLAYER_2,
2460     EL_PLAYER_3,
2461     EL_PLAYER_4,
2462     EL_SP_MURPHY,
2463     EL_SOKOBAN_FIELD_PLAYER,
2464     EL_TRIGGER_PLAYER,
2465     -1
2466   };
2467
2468   static int ep_can_pass_magic_wall[] =
2469   {
2470     EL_ROCK,
2471     EL_BD_ROCK,
2472     EL_EMERALD,
2473     EL_BD_DIAMOND,
2474     EL_EMERALD_YELLOW,
2475     EL_EMERALD_RED,
2476     EL_EMERALD_PURPLE,
2477     EL_DIAMOND,
2478     -1
2479   };
2480
2481   static int ep_switchable[] =
2482   {
2483     EL_ROBOT_WHEEL,
2484     EL_SP_TERMINAL,
2485     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2486     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2487     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2488     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2489     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2490     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2491     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2492     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2493     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2494     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2495     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2496     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2497     EL_SWITCHGATE_SWITCH_UP,
2498     EL_SWITCHGATE_SWITCH_DOWN,
2499     EL_LIGHT_SWITCH,
2500     EL_LIGHT_SWITCH_ACTIVE,
2501     EL_TIMEGATE_SWITCH,
2502     EL_BALLOON_SWITCH_LEFT,
2503     EL_BALLOON_SWITCH_RIGHT,
2504     EL_BALLOON_SWITCH_UP,
2505     EL_BALLOON_SWITCH_DOWN,
2506     EL_BALLOON_SWITCH_ANY,
2507     EL_BALLOON_SWITCH_NONE,
2508     EL_LAMP,
2509     EL_TIME_ORB_FULL,
2510     EL_EMC_MAGIC_BALL_SWITCH,
2511     -1
2512   };
2513
2514   static int ep_bd_element[] =
2515   {
2516     EL_EMPTY,
2517     EL_SAND,
2518     EL_WALL_SLIPPERY,
2519     EL_BD_WALL,
2520     EL_ROCK,
2521     EL_BD_ROCK,
2522     EL_BD_DIAMOND,
2523     EL_BD_MAGIC_WALL,
2524     EL_EXIT_CLOSED,
2525     EL_EXIT_OPEN,
2526     EL_STEELWALL,
2527     EL_PLAYER_1,
2528     EL_PLAYER_2,
2529     EL_PLAYER_3,
2530     EL_PLAYER_4,
2531     EL_BD_FIREFLY,
2532     EL_BD_FIREFLY_1,
2533     EL_BD_FIREFLY_2,
2534     EL_BD_FIREFLY_3,
2535     EL_BD_FIREFLY_4,
2536     EL_BD_BUTTERFLY,
2537     EL_BD_BUTTERFLY_1,
2538     EL_BD_BUTTERFLY_2,
2539     EL_BD_BUTTERFLY_3,
2540     EL_BD_BUTTERFLY_4,
2541     EL_BD_AMOEBA,
2542     EL_CHAR_QUESTION,
2543     EL_UNKNOWN,
2544     -1
2545   };
2546
2547   static int ep_sp_element[] =
2548   {
2549     /* should always be valid */
2550     EL_EMPTY,
2551
2552     /* standard classic Supaplex elements */
2553     EL_SP_EMPTY,
2554     EL_SP_ZONK,
2555     EL_SP_BASE,
2556     EL_SP_MURPHY,
2557     EL_SP_INFOTRON,
2558     EL_SP_CHIP_SINGLE,
2559     EL_SP_HARDWARE_GRAY,
2560     EL_SP_EXIT_CLOSED,
2561     EL_SP_EXIT_OPEN,
2562     EL_SP_DISK_ORANGE,
2563     EL_SP_PORT_RIGHT,
2564     EL_SP_PORT_DOWN,
2565     EL_SP_PORT_LEFT,
2566     EL_SP_PORT_UP,
2567     EL_SP_GRAVITY_PORT_RIGHT,
2568     EL_SP_GRAVITY_PORT_DOWN,
2569     EL_SP_GRAVITY_PORT_LEFT,
2570     EL_SP_GRAVITY_PORT_UP,
2571     EL_SP_SNIKSNAK,
2572     EL_SP_DISK_YELLOW,
2573     EL_SP_TERMINAL,
2574     EL_SP_DISK_RED,
2575     EL_SP_PORT_VERTICAL,
2576     EL_SP_PORT_HORIZONTAL,
2577     EL_SP_PORT_ANY,
2578     EL_SP_ELECTRON,
2579     EL_SP_BUGGY_BASE,
2580     EL_SP_CHIP_LEFT,
2581     EL_SP_CHIP_RIGHT,
2582     EL_SP_HARDWARE_BASE_1,
2583     EL_SP_HARDWARE_GREEN,
2584     EL_SP_HARDWARE_BLUE,
2585     EL_SP_HARDWARE_RED,
2586     EL_SP_HARDWARE_YELLOW,
2587     EL_SP_HARDWARE_BASE_2,
2588     EL_SP_HARDWARE_BASE_3,
2589     EL_SP_HARDWARE_BASE_4,
2590     EL_SP_HARDWARE_BASE_5,
2591     EL_SP_HARDWARE_BASE_6,
2592     EL_SP_CHIP_TOP,
2593     EL_SP_CHIP_BOTTOM,
2594
2595     /* additional elements that appeared in newer Supaplex levels */
2596     EL_INVISIBLE_WALL,
2597
2598     /* additional gravity port elements (not switching, but setting gravity) */
2599     EL_SP_GRAVITY_ON_PORT_LEFT,
2600     EL_SP_GRAVITY_ON_PORT_RIGHT,
2601     EL_SP_GRAVITY_ON_PORT_UP,
2602     EL_SP_GRAVITY_ON_PORT_DOWN,
2603     EL_SP_GRAVITY_OFF_PORT_LEFT,
2604     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2605     EL_SP_GRAVITY_OFF_PORT_UP,
2606     EL_SP_GRAVITY_OFF_PORT_DOWN,
2607
2608     /* more than one Murphy in a level results in an inactive clone */
2609     EL_SP_MURPHY_CLONE,
2610
2611     /* runtime Supaplex elements */
2612     EL_SP_DISK_RED_ACTIVE,
2613     EL_SP_TERMINAL_ACTIVE,
2614     EL_SP_BUGGY_BASE_ACTIVATING,
2615     EL_SP_BUGGY_BASE_ACTIVE,
2616     EL_SP_EXIT_OPENING,
2617     EL_SP_EXIT_CLOSING,
2618     -1
2619   };
2620
2621   static int ep_sb_element[] =
2622   {
2623     EL_EMPTY,
2624     EL_STEELWALL,
2625     EL_SOKOBAN_OBJECT,
2626     EL_SOKOBAN_FIELD_EMPTY,
2627     EL_SOKOBAN_FIELD_FULL,
2628     EL_SOKOBAN_FIELD_PLAYER,
2629     EL_PLAYER_1,
2630     EL_PLAYER_2,
2631     EL_PLAYER_3,
2632     EL_PLAYER_4,
2633     EL_INVISIBLE_STEELWALL,
2634     -1
2635   };
2636
2637   static int ep_gem[] =
2638   {
2639     EL_BD_DIAMOND,
2640     EL_EMERALD,
2641     EL_EMERALD_YELLOW,
2642     EL_EMERALD_RED,
2643     EL_EMERALD_PURPLE,
2644     EL_DIAMOND,
2645     -1
2646   };
2647
2648   static int ep_food_dark_yamyam[] =
2649   {
2650     EL_SAND,
2651     EL_BUG,
2652     EL_SPACESHIP,
2653     EL_BD_BUTTERFLY,
2654     EL_BD_FIREFLY,
2655     EL_YAMYAM,
2656     EL_ROBOT,
2657     EL_PACMAN,
2658     EL_AMOEBA_DROP,
2659     EL_AMOEBA_DEAD,
2660     EL_AMOEBA_WET,
2661     EL_AMOEBA_DRY,
2662     EL_AMOEBA_FULL,
2663     EL_BD_AMOEBA,
2664     EL_EMERALD,
2665     EL_BD_DIAMOND,
2666     EL_EMERALD_YELLOW,
2667     EL_EMERALD_RED,
2668     EL_EMERALD_PURPLE,
2669     EL_DIAMOND,
2670     EL_PEARL,
2671     EL_CRYSTAL,
2672     -1
2673   };
2674
2675   static int ep_food_penguin[] =
2676   {
2677     EL_EMERALD,
2678     EL_BD_DIAMOND,
2679     EL_EMERALD_YELLOW,
2680     EL_EMERALD_RED,
2681     EL_EMERALD_PURPLE,
2682     EL_DIAMOND,
2683     EL_PEARL,
2684     EL_CRYSTAL,
2685     -1
2686   };
2687
2688   static int ep_food_pig[] =
2689   {
2690     EL_EMERALD,
2691     EL_BD_DIAMOND,
2692     EL_EMERALD_YELLOW,
2693     EL_EMERALD_RED,
2694     EL_EMERALD_PURPLE,
2695     EL_DIAMOND,
2696     -1
2697   };
2698
2699   static int ep_historic_wall[] =
2700   {
2701     EL_STEELWALL,
2702     EL_GATE_1,
2703     EL_GATE_2,
2704     EL_GATE_3,
2705     EL_GATE_4,
2706     EL_GATE_1_GRAY,
2707     EL_GATE_2_GRAY,
2708     EL_GATE_3_GRAY,
2709     EL_GATE_4_GRAY,
2710     EL_EM_GATE_1,
2711     EL_EM_GATE_2,
2712     EL_EM_GATE_3,
2713     EL_EM_GATE_4,
2714     EL_EM_GATE_1_GRAY,
2715     EL_EM_GATE_2_GRAY,
2716     EL_EM_GATE_3_GRAY,
2717     EL_EM_GATE_4_GRAY,
2718     EL_EXIT_CLOSED,
2719     EL_EXIT_OPENING,
2720     EL_EXIT_OPEN,
2721     EL_WALL,
2722     EL_WALL_SLIPPERY,
2723     EL_EXPANDABLE_WALL,
2724     EL_EXPANDABLE_WALL_HORIZONTAL,
2725     EL_EXPANDABLE_WALL_VERTICAL,
2726     EL_EXPANDABLE_WALL_ANY,
2727     EL_EXPANDABLE_WALL_GROWING,
2728     EL_BD_WALL,
2729     EL_SP_CHIP_SINGLE,
2730     EL_SP_CHIP_LEFT,
2731     EL_SP_CHIP_RIGHT,
2732     EL_SP_CHIP_TOP,
2733     EL_SP_CHIP_BOTTOM,
2734     EL_SP_HARDWARE_GRAY,
2735     EL_SP_HARDWARE_GREEN,
2736     EL_SP_HARDWARE_BLUE,
2737     EL_SP_HARDWARE_RED,
2738     EL_SP_HARDWARE_YELLOW,
2739     EL_SP_HARDWARE_BASE_1,
2740     EL_SP_HARDWARE_BASE_2,
2741     EL_SP_HARDWARE_BASE_3,
2742     EL_SP_HARDWARE_BASE_4,
2743     EL_SP_HARDWARE_BASE_5,
2744     EL_SP_HARDWARE_BASE_6,
2745     EL_SP_TERMINAL,
2746     EL_SP_TERMINAL_ACTIVE,
2747     EL_SP_EXIT_CLOSED,
2748     EL_SP_EXIT_OPEN,
2749     EL_INVISIBLE_STEELWALL,
2750     EL_INVISIBLE_STEELWALL_ACTIVE,
2751     EL_INVISIBLE_WALL,
2752     EL_INVISIBLE_WALL_ACTIVE,
2753     EL_STEELWALL_SLIPPERY,
2754     EL_EMC_STEELWALL_1,
2755     EL_EMC_STEELWALL_2,
2756     EL_EMC_STEELWALL_3,
2757     EL_EMC_STEELWALL_4,
2758     EL_EMC_WALL_1,
2759     EL_EMC_WALL_2,
2760     EL_EMC_WALL_3,
2761     EL_EMC_WALL_4,
2762     EL_EMC_WALL_5,
2763     EL_EMC_WALL_6,
2764     EL_EMC_WALL_7,
2765     EL_EMC_WALL_8,
2766     -1
2767   };
2768
2769   static int ep_historic_solid[] =
2770   {
2771     EL_WALL,
2772     EL_EXPANDABLE_WALL,
2773     EL_EXPANDABLE_WALL_HORIZONTAL,
2774     EL_EXPANDABLE_WALL_VERTICAL,
2775     EL_EXPANDABLE_WALL_ANY,
2776     EL_BD_WALL,
2777     EL_WALL_SLIPPERY,
2778     EL_EXIT_CLOSED,
2779     EL_EXIT_OPENING,
2780     EL_EXIT_OPEN,
2781     EL_AMOEBA_DEAD,
2782     EL_AMOEBA_WET,
2783     EL_AMOEBA_DRY,
2784     EL_AMOEBA_FULL,
2785     EL_BD_AMOEBA,
2786     EL_QUICKSAND_EMPTY,
2787     EL_QUICKSAND_FULL,
2788     EL_QUICKSAND_FILLING,
2789     EL_QUICKSAND_EMPTYING,
2790     EL_MAGIC_WALL,
2791     EL_MAGIC_WALL_ACTIVE,
2792     EL_MAGIC_WALL_EMPTYING,
2793     EL_MAGIC_WALL_FILLING,
2794     EL_MAGIC_WALL_FULL,
2795     EL_MAGIC_WALL_DEAD,
2796     EL_BD_MAGIC_WALL,
2797     EL_BD_MAGIC_WALL_ACTIVE,
2798     EL_BD_MAGIC_WALL_EMPTYING,
2799     EL_BD_MAGIC_WALL_FULL,
2800     EL_BD_MAGIC_WALL_FILLING,
2801     EL_BD_MAGIC_WALL_DEAD,
2802     EL_GAME_OF_LIFE,
2803     EL_BIOMAZE,
2804     EL_SP_CHIP_SINGLE,
2805     EL_SP_CHIP_LEFT,
2806     EL_SP_CHIP_RIGHT,
2807     EL_SP_CHIP_TOP,
2808     EL_SP_CHIP_BOTTOM,
2809     EL_SP_TERMINAL,
2810     EL_SP_TERMINAL_ACTIVE,
2811     EL_SP_EXIT_CLOSED,
2812     EL_SP_EXIT_OPEN,
2813     EL_INVISIBLE_WALL,
2814     EL_INVISIBLE_WALL_ACTIVE,
2815     EL_SWITCHGATE_SWITCH_UP,
2816     EL_SWITCHGATE_SWITCH_DOWN,
2817     EL_TIMEGATE_SWITCH,
2818     EL_TIMEGATE_SWITCH_ACTIVE,
2819     EL_EMC_WALL_1,
2820     EL_EMC_WALL_2,
2821     EL_EMC_WALL_3,
2822     EL_EMC_WALL_4,
2823     EL_EMC_WALL_5,
2824     EL_EMC_WALL_6,
2825     EL_EMC_WALL_7,
2826     EL_EMC_WALL_8,
2827     EL_WALL_PEARL,
2828     EL_WALL_CRYSTAL,
2829
2830     /* the following elements are a direct copy of "indestructible" elements,
2831        except "EL_ACID", which is "indestructible", but not "solid"! */
2832 #if 0
2833     EL_ACID,
2834 #endif
2835     EL_STEELWALL,
2836     EL_ACID_POOL_TOPLEFT,
2837     EL_ACID_POOL_TOPRIGHT,
2838     EL_ACID_POOL_BOTTOMLEFT,
2839     EL_ACID_POOL_BOTTOM,
2840     EL_ACID_POOL_BOTTOMRIGHT,
2841     EL_SP_HARDWARE_GRAY,
2842     EL_SP_HARDWARE_GREEN,
2843     EL_SP_HARDWARE_BLUE,
2844     EL_SP_HARDWARE_RED,
2845     EL_SP_HARDWARE_YELLOW,
2846     EL_SP_HARDWARE_BASE_1,
2847     EL_SP_HARDWARE_BASE_2,
2848     EL_SP_HARDWARE_BASE_3,
2849     EL_SP_HARDWARE_BASE_4,
2850     EL_SP_HARDWARE_BASE_5,
2851     EL_SP_HARDWARE_BASE_6,
2852     EL_INVISIBLE_STEELWALL,
2853     EL_INVISIBLE_STEELWALL_ACTIVE,
2854     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2855     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2856     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2857     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2858     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2859     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2860     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2861     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2862     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2863     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2864     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2865     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2866     EL_LIGHT_SWITCH,
2867     EL_LIGHT_SWITCH_ACTIVE,
2868     EL_SIGN_EXCLAMATION,
2869     EL_SIGN_RADIOACTIVITY,
2870     EL_SIGN_STOP,
2871     EL_SIGN_WHEELCHAIR,
2872     EL_SIGN_PARKING,
2873     EL_SIGN_ONEWAY,
2874     EL_SIGN_HEART,
2875     EL_SIGN_TRIANGLE,
2876     EL_SIGN_ROUND,
2877     EL_SIGN_EXIT,
2878     EL_SIGN_YINYANG,
2879     EL_SIGN_OTHER,
2880     EL_STEELWALL_SLIPPERY,
2881     EL_EMC_STEELWALL_1,
2882     EL_EMC_STEELWALL_2,
2883     EL_EMC_STEELWALL_3,
2884     EL_EMC_STEELWALL_4,
2885     EL_CRYSTAL,
2886     EL_GATE_1,
2887     EL_GATE_2,
2888     EL_GATE_3,
2889     EL_GATE_4,
2890     EL_GATE_1_GRAY,
2891     EL_GATE_2_GRAY,
2892     EL_GATE_3_GRAY,
2893     EL_GATE_4_GRAY,
2894     EL_EM_GATE_1,
2895     EL_EM_GATE_2,
2896     EL_EM_GATE_3,
2897     EL_EM_GATE_4,
2898     EL_EM_GATE_1_GRAY,
2899     EL_EM_GATE_2_GRAY,
2900     EL_EM_GATE_3_GRAY,
2901     EL_EM_GATE_4_GRAY,
2902     EL_SWITCHGATE_OPEN,
2903     EL_SWITCHGATE_OPENING,
2904     EL_SWITCHGATE_CLOSED,
2905     EL_SWITCHGATE_CLOSING,
2906     EL_TIMEGATE_OPEN,
2907     EL_TIMEGATE_OPENING,
2908     EL_TIMEGATE_CLOSED,
2909     EL_TIMEGATE_CLOSING,
2910     EL_TUBE_ANY,
2911     EL_TUBE_VERTICAL,
2912     EL_TUBE_HORIZONTAL,
2913     EL_TUBE_VERTICAL_LEFT,
2914     EL_TUBE_VERTICAL_RIGHT,
2915     EL_TUBE_HORIZONTAL_UP,
2916     EL_TUBE_HORIZONTAL_DOWN,
2917     EL_TUBE_LEFT_UP,
2918     EL_TUBE_LEFT_DOWN,
2919     EL_TUBE_RIGHT_UP,
2920     EL_TUBE_RIGHT_DOWN,
2921     -1
2922   };
2923
2924   static int ep_classic_enemy[] =
2925   {
2926     EL_BUG,
2927     EL_SPACESHIP,
2928     EL_BD_BUTTERFLY,
2929     EL_BD_FIREFLY,
2930
2931     EL_YAMYAM,
2932     EL_DARK_YAMYAM,
2933     EL_ROBOT,
2934     EL_PACMAN,
2935     EL_SP_SNIKSNAK,
2936     EL_SP_ELECTRON,
2937     -1
2938   };
2939
2940   static int ep_belt[] =
2941   {
2942     EL_CONVEYOR_BELT_1_LEFT,
2943     EL_CONVEYOR_BELT_1_MIDDLE,
2944     EL_CONVEYOR_BELT_1_RIGHT,
2945     EL_CONVEYOR_BELT_2_LEFT,
2946     EL_CONVEYOR_BELT_2_MIDDLE,
2947     EL_CONVEYOR_BELT_2_RIGHT,
2948     EL_CONVEYOR_BELT_3_LEFT,
2949     EL_CONVEYOR_BELT_3_MIDDLE,
2950     EL_CONVEYOR_BELT_3_RIGHT,
2951     EL_CONVEYOR_BELT_4_LEFT,
2952     EL_CONVEYOR_BELT_4_MIDDLE,
2953     EL_CONVEYOR_BELT_4_RIGHT,
2954     -1
2955   };
2956
2957   static int ep_belt_active[] =
2958   {
2959     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2960     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2961     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2962     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2963     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2964     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2965     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2966     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2967     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2968     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2969     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2970     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2971     -1
2972   };
2973
2974   static int ep_belt_switch[] =
2975   {
2976     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2977     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2978     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2979     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2980     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2981     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2982     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2983     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2984     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2985     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2986     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2987     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2988     -1
2989   };
2990
2991   static int ep_tube[] =
2992   {
2993     EL_TUBE_LEFT_UP,
2994     EL_TUBE_LEFT_DOWN,
2995     EL_TUBE_RIGHT_UP,
2996     EL_TUBE_RIGHT_DOWN,
2997     EL_TUBE_HORIZONTAL,
2998     EL_TUBE_HORIZONTAL_UP,
2999     EL_TUBE_HORIZONTAL_DOWN,
3000     EL_TUBE_VERTICAL,
3001     EL_TUBE_VERTICAL_LEFT,
3002     EL_TUBE_VERTICAL_RIGHT,
3003     EL_TUBE_ANY,
3004     -1
3005   };
3006
3007   static int ep_keygate[] =
3008   {
3009     EL_GATE_1,
3010     EL_GATE_2,
3011     EL_GATE_3,
3012     EL_GATE_4,
3013     EL_GATE_1_GRAY,
3014     EL_GATE_2_GRAY,
3015     EL_GATE_3_GRAY,
3016     EL_GATE_4_GRAY,
3017     EL_EM_GATE_1,
3018     EL_EM_GATE_2,
3019     EL_EM_GATE_3,
3020     EL_EM_GATE_4,
3021     EL_EM_GATE_1_GRAY,
3022     EL_EM_GATE_2_GRAY,
3023     EL_EM_GATE_3_GRAY,
3024     EL_EM_GATE_4_GRAY,
3025     EL_EMC_GATE_5,
3026     EL_EMC_GATE_6,
3027     EL_EMC_GATE_7,
3028     EL_EMC_GATE_8,
3029     EL_EMC_GATE_5_GRAY,
3030     EL_EMC_GATE_6_GRAY,
3031     EL_EMC_GATE_7_GRAY,
3032     EL_EMC_GATE_8_GRAY,
3033     -1
3034   };
3035
3036   static int ep_amoeboid[] =
3037   {
3038     EL_AMOEBA_DEAD,
3039     EL_AMOEBA_WET,
3040     EL_AMOEBA_DRY,
3041     EL_AMOEBA_FULL,
3042     EL_BD_AMOEBA,
3043     -1
3044   };
3045
3046   static int ep_amoebalive[] =
3047   {
3048     EL_AMOEBA_WET,
3049     EL_AMOEBA_DRY,
3050     EL_AMOEBA_FULL,
3051     EL_BD_AMOEBA,
3052     -1
3053   };
3054
3055   static int ep_has_content[] =
3056   {
3057     EL_YAMYAM,
3058     EL_AMOEBA_WET,
3059     EL_AMOEBA_DRY,
3060     EL_AMOEBA_FULL,
3061     EL_BD_AMOEBA,
3062     -1
3063   };
3064
3065   static int ep_can_turn_each_move[] =
3066   {
3067     /* !!! do something with this one !!! */
3068     -1
3069   };
3070
3071   static int ep_can_grow[] =
3072   {
3073     EL_BD_AMOEBA,
3074     EL_AMOEBA_DROP,
3075     EL_AMOEBA_WET,
3076     EL_AMOEBA_DRY,
3077     EL_AMOEBA_FULL,
3078     EL_GAME_OF_LIFE,
3079     EL_BIOMAZE,
3080     -1
3081   };
3082
3083   static int ep_active_bomb[] =
3084   {
3085     EL_DYNAMITE_ACTIVE,
3086     EL_DYNABOMB_PLAYER_1_ACTIVE,
3087     EL_DYNABOMB_PLAYER_2_ACTIVE,
3088     EL_DYNABOMB_PLAYER_3_ACTIVE,
3089     EL_DYNABOMB_PLAYER_4_ACTIVE,
3090     EL_SP_DISK_RED_ACTIVE,
3091     -1
3092   };
3093
3094   static int ep_inactive[] =
3095   {
3096     EL_EMPTY,
3097     EL_SAND,
3098     EL_WALL,
3099     EL_BD_WALL,
3100     EL_WALL_SLIPPERY,
3101     EL_STEELWALL,
3102     EL_AMOEBA_DEAD,
3103     EL_QUICKSAND_EMPTY,
3104     EL_STONEBLOCK,
3105     EL_ROBOT_WHEEL,
3106     EL_KEY_1,
3107     EL_KEY_2,
3108     EL_KEY_3,
3109     EL_KEY_4,
3110     EL_EM_KEY_1,
3111     EL_EM_KEY_2,
3112     EL_EM_KEY_3,
3113     EL_EM_KEY_4,
3114     EL_EMC_KEY_5,
3115     EL_EMC_KEY_6,
3116     EL_EMC_KEY_7,
3117     EL_EMC_KEY_8,
3118     EL_GATE_1,
3119     EL_GATE_2,
3120     EL_GATE_3,
3121     EL_GATE_4,
3122     EL_GATE_1_GRAY,
3123     EL_GATE_2_GRAY,
3124     EL_GATE_3_GRAY,
3125     EL_GATE_4_GRAY,
3126     EL_EM_GATE_1,
3127     EL_EM_GATE_2,
3128     EL_EM_GATE_3,
3129     EL_EM_GATE_4,
3130     EL_EM_GATE_1_GRAY,
3131     EL_EM_GATE_2_GRAY,
3132     EL_EM_GATE_3_GRAY,
3133     EL_EM_GATE_4_GRAY,
3134     EL_EMC_GATE_5,
3135     EL_EMC_GATE_6,
3136     EL_EMC_GATE_7,
3137     EL_EMC_GATE_8,
3138     EL_EMC_GATE_5_GRAY,
3139     EL_EMC_GATE_6_GRAY,
3140     EL_EMC_GATE_7_GRAY,
3141     EL_EMC_GATE_8_GRAY,
3142     EL_DYNAMITE,
3143     EL_INVISIBLE_STEELWALL,
3144     EL_INVISIBLE_WALL,
3145     EL_INVISIBLE_SAND,
3146     EL_LAMP,
3147     EL_LAMP_ACTIVE,
3148     EL_WALL_EMERALD,
3149     EL_WALL_DIAMOND,
3150     EL_WALL_BD_DIAMOND,
3151     EL_WALL_EMERALD_YELLOW,
3152     EL_DYNABOMB_INCREASE_NUMBER,
3153     EL_DYNABOMB_INCREASE_SIZE,
3154     EL_DYNABOMB_INCREASE_POWER,
3155 #if 0
3156     EL_SOKOBAN_OBJECT,
3157 #endif
3158     EL_SOKOBAN_FIELD_EMPTY,
3159     EL_SOKOBAN_FIELD_FULL,
3160     EL_WALL_EMERALD_RED,
3161     EL_WALL_EMERALD_PURPLE,
3162     EL_ACID_POOL_TOPLEFT,
3163     EL_ACID_POOL_TOPRIGHT,
3164     EL_ACID_POOL_BOTTOMLEFT,
3165     EL_ACID_POOL_BOTTOM,
3166     EL_ACID_POOL_BOTTOMRIGHT,
3167     EL_MAGIC_WALL,
3168     EL_MAGIC_WALL_DEAD,
3169     EL_BD_MAGIC_WALL,
3170     EL_BD_MAGIC_WALL_DEAD,
3171     EL_AMOEBA_TO_DIAMOND,
3172     EL_BLOCKED,
3173     EL_SP_EMPTY,
3174     EL_SP_BASE,
3175     EL_SP_PORT_RIGHT,
3176     EL_SP_PORT_DOWN,
3177     EL_SP_PORT_LEFT,
3178     EL_SP_PORT_UP,
3179     EL_SP_GRAVITY_PORT_RIGHT,
3180     EL_SP_GRAVITY_PORT_DOWN,
3181     EL_SP_GRAVITY_PORT_LEFT,
3182     EL_SP_GRAVITY_PORT_UP,
3183     EL_SP_PORT_HORIZONTAL,
3184     EL_SP_PORT_VERTICAL,
3185     EL_SP_PORT_ANY,
3186     EL_SP_DISK_RED,
3187 #if 0
3188     EL_SP_DISK_YELLOW,
3189 #endif
3190     EL_SP_CHIP_SINGLE,
3191     EL_SP_CHIP_LEFT,
3192     EL_SP_CHIP_RIGHT,
3193     EL_SP_CHIP_TOP,
3194     EL_SP_CHIP_BOTTOM,
3195     EL_SP_HARDWARE_GRAY,
3196     EL_SP_HARDWARE_GREEN,
3197     EL_SP_HARDWARE_BLUE,
3198     EL_SP_HARDWARE_RED,
3199     EL_SP_HARDWARE_YELLOW,
3200     EL_SP_HARDWARE_BASE_1,
3201     EL_SP_HARDWARE_BASE_2,
3202     EL_SP_HARDWARE_BASE_3,
3203     EL_SP_HARDWARE_BASE_4,
3204     EL_SP_HARDWARE_BASE_5,
3205     EL_SP_HARDWARE_BASE_6,
3206     EL_SP_GRAVITY_ON_PORT_LEFT,
3207     EL_SP_GRAVITY_ON_PORT_RIGHT,
3208     EL_SP_GRAVITY_ON_PORT_UP,
3209     EL_SP_GRAVITY_ON_PORT_DOWN,
3210     EL_SP_GRAVITY_OFF_PORT_LEFT,
3211     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3212     EL_SP_GRAVITY_OFF_PORT_UP,
3213     EL_SP_GRAVITY_OFF_PORT_DOWN,
3214     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3215     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3216     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3217     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3218     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3219     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3220     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3221     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3222     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3223     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3224     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3225     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3226     EL_SIGN_EXCLAMATION,
3227     EL_SIGN_RADIOACTIVITY,
3228     EL_SIGN_STOP,
3229     EL_SIGN_WHEELCHAIR,
3230     EL_SIGN_PARKING,
3231     EL_SIGN_ONEWAY,
3232     EL_SIGN_HEART,
3233     EL_SIGN_TRIANGLE,
3234     EL_SIGN_ROUND,
3235     EL_SIGN_EXIT,
3236     EL_SIGN_YINYANG,
3237     EL_SIGN_OTHER,
3238     EL_STEELWALL_SLIPPERY,
3239     EL_EMC_STEELWALL_1,
3240     EL_EMC_STEELWALL_2,
3241     EL_EMC_STEELWALL_3,
3242     EL_EMC_STEELWALL_4,
3243     EL_EMC_WALL_SLIPPERY_1,
3244     EL_EMC_WALL_SLIPPERY_2,
3245     EL_EMC_WALL_SLIPPERY_3,
3246     EL_EMC_WALL_SLIPPERY_4,
3247     EL_EMC_WALL_1,
3248     EL_EMC_WALL_2,
3249     EL_EMC_WALL_3,
3250     EL_EMC_WALL_4,
3251     EL_EMC_WALL_5,
3252     EL_EMC_WALL_6,
3253     EL_EMC_WALL_7,
3254     EL_EMC_WALL_8,
3255     EL_EMC_WALL_9,
3256     EL_EMC_WALL_10,
3257     EL_EMC_WALL_11,
3258     EL_EMC_WALL_12,
3259     EL_EMC_WALL_13,
3260     EL_EMC_WALL_14,
3261     EL_EMC_WALL_15,
3262     EL_EMC_WALL_16,
3263     -1
3264   };
3265
3266   static int ep_em_slippery_wall[] =
3267   {
3268     -1
3269   };
3270
3271   static int ep_gfx_crumbled[] =
3272   {
3273     EL_SAND,
3274     EL_LANDMINE,
3275     EL_TRAP,
3276     EL_TRAP_ACTIVE,
3277     -1
3278   };
3279
3280   static struct
3281   {
3282     int *elements;
3283     int property;
3284   } element_properties[] =
3285   {
3286     { ep_diggable,              EP_DIGGABLE             },
3287     { ep_collectible_only,      EP_COLLECTIBLE_ONLY     },
3288     { ep_dont_run_into,         EP_DONT_RUN_INTO        },
3289     { ep_dont_collide_with,     EP_DONT_COLLIDE_WITH    },
3290     { ep_dont_touch,            EP_DONT_TOUCH           },
3291     { ep_indestructible,        EP_INDESTRUCTIBLE       },
3292     { ep_slippery,              EP_SLIPPERY             },
3293     { ep_can_change,            EP_CAN_CHANGE           },
3294     { ep_can_move,              EP_CAN_MOVE             },
3295     { ep_can_fall,              EP_CAN_FALL             },
3296     { ep_can_smash_player,      EP_CAN_SMASH_PLAYER     },
3297     { ep_can_smash_enemies,     EP_CAN_SMASH_ENEMIES    },
3298     { ep_can_smash_everything,  EP_CAN_SMASH_EVERYTHING },
3299     { ep_explodes_by_fire,      EP_EXPLODES_BY_FIRE     },
3300     { ep_explodes_smashed,      EP_EXPLODES_SMASHED     },
3301     { ep_explodes_impact,       EP_EXPLODES_IMPACT      },
3302     { ep_walkable_over,         EP_WALKABLE_OVER        },
3303     { ep_walkable_inside,       EP_WALKABLE_INSIDE      },
3304     { ep_walkable_under,        EP_WALKABLE_UNDER       },
3305     { ep_passable_over,         EP_PASSABLE_OVER        },
3306     { ep_passable_inside,       EP_PASSABLE_INSIDE      },
3307     { ep_passable_under,        EP_PASSABLE_UNDER       },
3308     { ep_droppable,             EP_DROPPABLE            },
3309     { ep_explodes_1x1_old,      EP_EXPLODES_1X1_OLD     },
3310     { ep_pushable,              EP_PUSHABLE             },
3311     { ep_explodes_cross_old,    EP_EXPLODES_CROSS_OLD   },
3312     { ep_protected,             EP_PROTECTED            },
3313     { ep_throwable,             EP_THROWABLE            },
3314     { ep_can_explode,           EP_CAN_EXPLODE          },
3315     { ep_gravity_reachable,     EP_GRAVITY_REACHABLE    },
3316
3317     { ep_player,                EP_PLAYER               },
3318     { ep_can_pass_magic_wall,   EP_CAN_PASS_MAGIC_WALL  },
3319     { ep_switchable,            EP_SWITCHABLE           },
3320     { ep_bd_element,            EP_BD_ELEMENT           },
3321     { ep_sp_element,            EP_SP_ELEMENT           },
3322     { ep_sb_element,            EP_SB_ELEMENT           },
3323     { ep_gem,                   EP_GEM                  },
3324     { ep_food_dark_yamyam,      EP_FOOD_DARK_YAMYAM     },
3325     { ep_food_penguin,          EP_FOOD_PENGUIN         },
3326     { ep_food_pig,              EP_FOOD_PIG             },
3327     { ep_historic_wall,         EP_HISTORIC_WALL        },
3328     { ep_historic_solid,        EP_HISTORIC_SOLID       },
3329     { ep_classic_enemy,         EP_CLASSIC_ENEMY        },
3330     { ep_belt,                  EP_BELT                 },
3331     { ep_belt_active,           EP_BELT_ACTIVE          },
3332     { ep_belt_switch,           EP_BELT_SWITCH          },
3333     { ep_tube,                  EP_TUBE                 },
3334     { ep_keygate,               EP_KEYGATE              },
3335     { ep_amoeboid,              EP_AMOEBOID             },
3336     { ep_amoebalive,            EP_AMOEBALIVE           },
3337     { ep_has_content,           EP_HAS_CONTENT          },
3338     { ep_can_turn_each_move,    EP_CAN_TURN_EACH_MOVE   },
3339     { ep_can_grow,              EP_CAN_GROW             },
3340     { ep_active_bomb,           EP_ACTIVE_BOMB          },
3341     { ep_inactive,              EP_INACTIVE             },
3342
3343     { ep_em_slippery_wall,      EP_EM_SLIPPERY_WALL     },
3344
3345     { ep_gfx_crumbled,          EP_GFX_CRUMBLED         },
3346
3347     { NULL,                     -1                      }
3348   };
3349
3350   int i, j, k;
3351
3352   /* always start with reliable default values (element has no properties) */
3353   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3354     for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3355       SET_PROPERTY(i, j, FALSE);
3356
3357   /* set all base element properties from above array definitions */
3358   for (i = 0; element_properties[i].elements != NULL; i++)
3359     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3360       SET_PROPERTY((element_properties[i].elements)[j],
3361                    element_properties[i].property, TRUE);
3362
3363   /* copy properties to some elements that are only stored in level file */
3364   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3365     for (j = 0; copy_properties[j][0] != -1; j++)
3366       if (HAS_PROPERTY(copy_properties[j][0], i))
3367         for (k = 1; k <= 4; k++)
3368           SET_PROPERTY(copy_properties[j][k], i, TRUE);
3369 }
3370
3371 void InitElementPropertiesEngine(int engine_version)
3372 {
3373   static int no_wall_properties[] =
3374   {
3375     EP_DIGGABLE,
3376     EP_COLLECTIBLE_ONLY,
3377     EP_DONT_RUN_INTO,
3378     EP_DONT_COLLIDE_WITH,
3379     EP_CAN_MOVE,
3380     EP_CAN_FALL,
3381     EP_CAN_SMASH_PLAYER,
3382     EP_CAN_SMASH_ENEMIES,
3383     EP_CAN_SMASH_EVERYTHING,
3384     EP_PUSHABLE,
3385
3386     EP_PLAYER,
3387     EP_GEM,
3388     EP_FOOD_DARK_YAMYAM,
3389     EP_FOOD_PENGUIN,
3390     EP_BELT,
3391     EP_BELT_ACTIVE,
3392     EP_TUBE,
3393     EP_AMOEBOID,
3394     EP_AMOEBALIVE,
3395     EP_ACTIVE_BOMB,
3396
3397     EP_ACCESSIBLE,
3398
3399     -1
3400   };
3401
3402   int i, j;
3403
3404   /* important: after initialization in InitElementPropertiesStatic(), the
3405      elements are not again initialized to a default value; therefore all
3406      changes have to make sure that they leave the element with a defined
3407      property (which means that conditional property changes must be set to
3408      a reliable default value before) */
3409
3410   /* set all special, combined or engine dependent element properties */
3411   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3412   {
3413     /* ---------- INACTIVE ------------------------------------------------- */
3414     SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3415
3416     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3417     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3418                                   IS_WALKABLE_INSIDE(i) ||
3419                                   IS_WALKABLE_UNDER(i)));
3420
3421     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3422                                   IS_PASSABLE_INSIDE(i) ||
3423                                   IS_PASSABLE_UNDER(i)));
3424
3425     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3426                                          IS_PASSABLE_OVER(i)));
3427
3428     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3429                                            IS_PASSABLE_INSIDE(i)));
3430
3431     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3432                                           IS_PASSABLE_UNDER(i)));
3433
3434     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3435                                     IS_PASSABLE(i)));
3436
3437     /* ---------- COLLECTIBLE ---------------------------------------------- */
3438     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3439                                      IS_DROPPABLE(i) ||
3440                                      IS_THROWABLE(i)));
3441
3442     /* ---------- SNAPPABLE ------------------------------------------------ */
3443     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3444                                    IS_COLLECTIBLE(i) ||
3445                                    IS_SWITCHABLE(i) ||
3446                                    i == EL_BD_ROCK));
3447
3448     /* ---------- WALL ----------------------------------------------------- */
3449     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
3450
3451     for (j = 0; no_wall_properties[j] != -1; j++)
3452       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3453           i >= EL_FIRST_RUNTIME_UNREAL)
3454         SET_PROPERTY(i, EP_WALL, FALSE);
3455
3456     if (IS_HISTORIC_WALL(i))
3457       SET_PROPERTY(i, EP_WALL, TRUE);
3458
3459     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3460     if (engine_version < VERSION_IDENT(2,2,0,0))
3461       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3462     else
3463       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3464                                              !IS_DIGGABLE(i) &&
3465                                              !IS_COLLECTIBLE(i)));
3466
3467     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3468
3469     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3470       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3471     else
3472       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3473                                             IS_INDESTRUCTIBLE(i)));
3474
3475     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3476     if (i == EL_FLAMES)
3477       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3478     else if (engine_version < VERSION_IDENT(2,2,0,0))
3479       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3480     else
3481       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3482                                            (!IS_WALKABLE(i) ||
3483                                             IS_PROTECTED(i))));
3484
3485     if (IS_CUSTOM_ELEMENT(i))
3486     {
3487       /* these are additional properties which are initially false when set */
3488
3489       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3490       if (DONT_TOUCH(i))
3491         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3492       if (DONT_COLLIDE_WITH(i))
3493         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3494
3495       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3496       if (CAN_SMASH_EVERYTHING(i))
3497         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3498       if (CAN_SMASH_ENEMIES(i))
3499         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3500     }
3501
3502     /* ---------- CAN_SMASH ------------------------------------------------ */
3503     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3504                                    CAN_SMASH_ENEMIES(i) ||
3505                                    CAN_SMASH_EVERYTHING(i)));
3506
3507     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3508     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3509                                              EXPLODES_BY_FIRE(i)));
3510
3511     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3512     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3513                                              EXPLODES_SMASHED(i)));
3514
3515     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3516     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3517                                             EXPLODES_IMPACT(i)));
3518
3519     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3520     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3521
3522     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3523     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3524                                                   i == EL_BLACK_ORB));
3525
3526     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3527     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3528                                               CAN_MOVE(i) ||
3529                                               IS_CUSTOM_ELEMENT(i)));
3530
3531     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3532     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3533                                                  i == EL_SP_ELECTRON));
3534
3535     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3536     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3537       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3538                    getMoveIntoAcidProperty(&level, i));
3539
3540     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3541     if (MAYBE_DONT_COLLIDE_WITH(i))
3542       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3543                    getDontCollideWithProperty(&level, i));
3544
3545     /* ---------- SP_PORT -------------------------------------------------- */
3546     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3547                                  IS_PASSABLE_INSIDE(i)));
3548
3549     /* ---------- CAN_CHANGE ----------------------------------------------- */
3550     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
3551     for (j = 0; j < element_info[i].num_change_pages; j++)
3552       if (element_info[i].change_page[j].can_change)
3553         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3554
3555     /* ---------- HAS_ACTION ----------------------------------------------- */
3556     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      /* default: has no action */
3557     for (j = 0; j < element_info[i].num_change_pages; j++)
3558       if (element_info[i].change_page[j].has_action)
3559         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3560
3561     /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3562     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3563                                                   HAS_ACTION(i)));
3564
3565     /* ---------- GFX_CRUMBLED --------------------------------------------- */
3566 #if 1
3567     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3568                  element_info[i].crumbled[ACTION_DEFAULT] !=
3569                  element_info[i].graphic[ACTION_DEFAULT]);
3570 #else
3571     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3572     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3573                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3574 #endif
3575   }
3576
3577   /* dynamically adjust element properties according to game engine version */
3578   {
3579     static int ep_em_slippery_wall[] =
3580     {
3581       EL_STEELWALL,
3582       EL_WALL,
3583       EL_EXPANDABLE_WALL,
3584       EL_EXPANDABLE_WALL_HORIZONTAL,
3585       EL_EXPANDABLE_WALL_VERTICAL,
3586       EL_EXPANDABLE_WALL_ANY,
3587       -1
3588     };
3589
3590     /* special EM style gems behaviour */
3591     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3592       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3593                    level.em_slippery_gems);
3594
3595     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3596     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3597                  (level.em_slippery_gems &&
3598                   engine_version > VERSION_IDENT(2,0,1,0)));
3599   }
3600
3601   /* set default push delay values (corrected since version 3.0.7-1) */
3602   if (engine_version < VERSION_IDENT(3,0,7,1))
3603   {
3604     game.default_push_delay_fixed = 2;
3605     game.default_push_delay_random = 8;
3606   }
3607   else
3608   {
3609     game.default_push_delay_fixed = 8;
3610     game.default_push_delay_random = 8;
3611   }
3612
3613   /* set uninitialized push delay values of custom elements in older levels */
3614   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3615   {
3616     int element = EL_CUSTOM_START + i;
3617
3618     if (element_info[element].push_delay_fixed == -1)
3619       element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3620     if (element_info[element].push_delay_random == -1)
3621       element_info[element].push_delay_random = game.default_push_delay_random;
3622   }
3623
3624   /* set some other uninitialized values of custom elements in older levels */
3625   if (engine_version < VERSION_IDENT(3,1,0,0))
3626   {
3627     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3628     {
3629       int element = EL_CUSTOM_START + i;
3630
3631       element_info[element].access_direction = MV_ALL_DIRECTIONS;
3632
3633       element_info[element].explosion_delay = 17;
3634       element_info[element].ignition_delay = 8;
3635     }
3636   }
3637
3638 #if 0
3639   /* set element properties that were handled incorrectly in older levels */
3640   if (engine_version < VERSION_IDENT(3,1,0,0))
3641   {
3642     SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3643     SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3644   }
3645 #endif
3646
3647   /* this is needed because some graphics depend on element properties */
3648   if (game_status == GAME_MODE_PLAYING)
3649     InitElementGraphicInfo();
3650 }
3651
3652 static void InitGlobal()
3653 {
3654   int i;
3655
3656   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3657   {
3658     /* check if element_name_info entry defined for each element in "main.h" */
3659     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3660       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3661
3662     element_info[i].token_name = element_name_info[i].token_name;
3663     element_info[i].class_name = element_name_info[i].class_name;
3664     element_info[i].editor_description=element_name_info[i].editor_description;
3665   }
3666
3667   global.autoplay_leveldir = NULL;
3668   global.convert_leveldir = NULL;
3669
3670   global.frames_per_second = 0;
3671   global.fps_slowdown = FALSE;
3672   global.fps_slowdown_factor = 1;
3673 }
3674
3675 void Execute_Command(char *command)
3676 {
3677   int i;
3678
3679   if (strcmp(command, "print graphicsinfo.conf") == 0)
3680   {
3681     printf("# You can configure additional/alternative image files here.\n");
3682     printf("# (The entries below are default and therefore commented out.)\n");
3683     printf("\n");
3684     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3685     printf("\n");
3686     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3687     printf("\n");
3688
3689     for (i = 0; image_config[i].token != NULL; i++)
3690       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3691                                               image_config[i].value));
3692
3693     exit(0);
3694   }
3695   else if (strcmp(command, "print soundsinfo.conf") == 0)
3696   {
3697     printf("# You can configure additional/alternative sound files here.\n");
3698     printf("# (The entries below are default and therefore commented out.)\n");
3699     printf("\n");
3700     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3701     printf("\n");
3702     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3703     printf("\n");
3704
3705     for (i = 0; sound_config[i].token != NULL; i++)
3706       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3707                                               sound_config[i].value));
3708
3709     exit(0);
3710   }
3711   else if (strcmp(command, "print musicinfo.conf") == 0)
3712   {
3713     printf("# You can configure additional/alternative music files here.\n");
3714     printf("# (The entries below are default and therefore commented out.)\n");
3715     printf("\n");
3716     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3717     printf("\n");
3718     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3719     printf("\n");
3720
3721     for (i = 0; music_config[i].token != NULL; i++)
3722       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3723                                               music_config[i].value));
3724
3725     exit(0);
3726   }
3727   else if (strcmp(command, "print editorsetup.conf") == 0)
3728   {
3729     printf("# You can configure your personal editor element list here.\n");
3730     printf("# (The entries below are default and therefore commented out.)\n");
3731     printf("\n");
3732
3733     PrintEditorElementList();
3734
3735     exit(0);
3736   }
3737   else if (strcmp(command, "print helpanim.conf") == 0)
3738   {
3739     printf("# You can configure different element help animations here.\n");
3740     printf("# (The entries below are default and therefore commented out.)\n");
3741     printf("\n");
3742
3743     for (i = 0; helpanim_config[i].token != NULL; i++)
3744     {
3745       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3746                                               helpanim_config[i].value));
3747
3748       if (strcmp(helpanim_config[i].token, "end") == 0)
3749         printf("#\n");
3750     }
3751
3752     exit(0);
3753   }
3754   else if (strcmp(command, "print helptext.conf") == 0)
3755   {
3756     printf("# You can configure different element help text here.\n");
3757     printf("# (The entries below are default and therefore commented out.)\n");
3758     printf("\n");
3759
3760     for (i = 0; helptext_config[i].token != NULL; i++)
3761       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3762                                               helptext_config[i].value));
3763
3764     exit(0);
3765   }
3766   else if (strncmp(command, "dump level ", 11) == 0)
3767   {
3768     char *filename = &command[11];
3769
3770     if (!fileExists(filename))
3771       Error(ERR_EXIT, "cannot open file '%s'", filename);
3772
3773     LoadLevelFromFilename(&level, filename);
3774     DumpLevel(&level);
3775
3776     exit(0);
3777   }
3778   else if (strncmp(command, "dump tape ", 10) == 0)
3779   {
3780     char *filename = &command[10];
3781
3782     if (!fileExists(filename))
3783       Error(ERR_EXIT, "cannot open file '%s'", filename);
3784
3785     LoadTapeFromFilename(filename);
3786     DumpTape(&tape);
3787
3788     exit(0);
3789   }
3790   else if (strncmp(command, "autoplay ", 9) == 0)
3791   {
3792     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
3793
3794     while (*str_ptr != '\0')                    /* continue parsing string */
3795     {
3796       /* cut leading whitespace from string, replace it by string terminator */
3797       while (*str_ptr == ' ' || *str_ptr == '\t')
3798         *str_ptr++ = '\0';
3799
3800       if (*str_ptr == '\0')                     /* end of string reached */
3801         break;
3802
3803       if (global.autoplay_leveldir == NULL)     /* read level set string */
3804       {
3805         global.autoplay_leveldir = str_ptr;
3806         global.autoplay_all = TRUE;             /* default: play all tapes */
3807
3808         for (i = 0; i < MAX_TAPES_PER_SET; i++)
3809           global.autoplay_level[i] = FALSE;
3810       }
3811       else                                      /* read level number string */
3812       {
3813         int level_nr = atoi(str_ptr);           /* get level_nr value */
3814
3815         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
3816           global.autoplay_level[level_nr] = TRUE;
3817
3818         global.autoplay_all = FALSE;
3819       }
3820
3821       /* advance string pointer to the next whitespace (or end of string) */
3822       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
3823         str_ptr++;
3824     }
3825   }
3826   else if (strncmp(command, "convert ", 8) == 0)
3827   {
3828     char *str_copy = getStringCopy(&command[8]);
3829     char *str_ptr = strchr(str_copy, ' ');
3830
3831     global.convert_leveldir = str_copy;
3832     global.convert_level_nr = -1;
3833
3834     if (str_ptr != NULL)                        /* level number follows */
3835     {
3836       *str_ptr++ = '\0';                        /* terminate leveldir string */
3837       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
3838     }
3839   }
3840   else
3841   {
3842     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3843   }
3844 }
3845
3846 static void InitSetup()
3847 {
3848   LoadSetup();                                  /* global setup info */
3849
3850   /* set some options from setup file */
3851
3852   if (setup.options.verbose)
3853     options.verbose = TRUE;
3854 }
3855
3856 static void InitGameInfo()
3857 {
3858   game.restart_level = FALSE;
3859 }
3860
3861 static void InitPlayerInfo()
3862 {
3863   int i;
3864
3865   /* choose default local player */
3866   local_player = &stored_player[0];
3867
3868   for (i = 0; i < MAX_PLAYERS; i++)
3869     stored_player[i].connected = FALSE;
3870
3871   local_player->connected = TRUE;
3872 }
3873
3874 static void InitArtworkInfo()
3875 {
3876   LoadArtworkInfo();
3877 }
3878
3879 static char *get_string_in_brackets(char *string)
3880 {
3881   char *string_in_brackets = checked_malloc(strlen(string) + 3);
3882
3883   sprintf(string_in_brackets, "[%s]", string);
3884
3885   return string_in_brackets;
3886 }
3887
3888 static char *get_level_id_suffix(int id_nr)
3889 {
3890   char *id_suffix = checked_malloc(1 + 3 + 1);
3891
3892   if (id_nr < 0 || id_nr > 999)
3893     id_nr = 0;
3894
3895   sprintf(id_suffix, ".%03d", id_nr);
3896
3897   return id_suffix;
3898 }
3899
3900 #if 0
3901 static char *get_element_class_token(int element)
3902 {
3903   char *element_class_name = element_info[element].class_name;
3904   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3905
3906   sprintf(element_class_token, "[%s]", element_class_name);
3907
3908   return element_class_token;
3909 }
3910
3911 static char *get_action_class_token(int action)
3912 {
3913   char *action_class_name = &element_action_info[action].suffix[1];
3914   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3915
3916   sprintf(action_class_token, "[%s]", action_class_name);
3917
3918   return action_class_token;
3919 }
3920 #endif
3921
3922 static void InitArtworkConfig()
3923 {
3924   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3925   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3926   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3927   static char *action_id_suffix[NUM_ACTIONS + 1];
3928   static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3929   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3930   static char *level_id_suffix[MAX_LEVELS + 1];
3931   static char *dummy[1] = { NULL };
3932   static char *ignore_generic_tokens[] =
3933   {
3934     "name",
3935     "sort_priority",
3936     NULL
3937   };
3938   static char **ignore_image_tokens;
3939   static char **ignore_sound_tokens;
3940   static char **ignore_music_tokens;
3941   int num_ignore_generic_tokens;
3942   int num_ignore_image_tokens;
3943   int num_ignore_sound_tokens;
3944   int num_ignore_music_tokens;
3945   int i;
3946
3947   /* dynamically determine list of generic tokens to be ignored */
3948   num_ignore_generic_tokens = 0;
3949   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3950     num_ignore_generic_tokens++;
3951
3952   /* dynamically determine list of image tokens to be ignored */
3953   num_ignore_image_tokens = num_ignore_generic_tokens;
3954   for (i = 0; image_config_vars[i].token != NULL; i++)
3955     num_ignore_image_tokens++;
3956   ignore_image_tokens =
3957     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3958   for (i = 0; i < num_ignore_generic_tokens; i++)
3959     ignore_image_tokens[i] = ignore_generic_tokens[i];
3960   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3961     ignore_image_tokens[num_ignore_generic_tokens + i] =
3962       image_config_vars[i].token;
3963   ignore_image_tokens[num_ignore_image_tokens] = NULL;
3964
3965   /* dynamically determine list of sound tokens to be ignored */
3966   num_ignore_sound_tokens = num_ignore_generic_tokens;
3967   ignore_sound_tokens =
3968     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3969   for (i = 0; i < num_ignore_generic_tokens; i++)
3970     ignore_sound_tokens[i] = ignore_generic_tokens[i];
3971   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3972
3973   /* dynamically determine list of music tokens to be ignored */
3974   num_ignore_music_tokens = num_ignore_generic_tokens;
3975   ignore_music_tokens =
3976     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3977   for (i = 0; i < num_ignore_generic_tokens; i++)
3978     ignore_music_tokens[i] = ignore_generic_tokens[i];
3979   ignore_music_tokens[num_ignore_music_tokens] = NULL;
3980
3981   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3982     image_id_prefix[i] = element_info[i].token_name;
3983   for (i = 0; i < NUM_FONTS; i++)
3984     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3985   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3986
3987   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3988     sound_id_prefix[i] = element_info[i].token_name;
3989   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3990     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3991       get_string_in_brackets(element_info[i].class_name);
3992   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3993
3994   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
3995     music_id_prefix[i] = music_prefix_info[i].prefix;
3996   music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
3997
3998   for (i = 0; i < NUM_ACTIONS; i++)
3999     action_id_suffix[i] = element_action_info[i].suffix;
4000   action_id_suffix[NUM_ACTIONS] = NULL;
4001
4002   for (i = 0; i < NUM_DIRECTIONS; i++)
4003     direction_id_suffix[i] = element_direction_info[i].suffix;
4004   direction_id_suffix[NUM_DIRECTIONS] = NULL;
4005
4006   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4007     special_id_suffix[i] = special_suffix_info[i].suffix;
4008   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4009
4010   for (i = 0; i < MAX_LEVELS; i++)
4011     level_id_suffix[i] = get_level_id_suffix(i);
4012   level_id_suffix[MAX_LEVELS] = NULL;
4013
4014   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4015                 image_id_prefix, action_id_suffix, direction_id_suffix,
4016                 special_id_suffix, ignore_image_tokens);
4017   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4018                 sound_id_prefix, action_id_suffix, dummy,
4019                 special_id_suffix, ignore_sound_tokens);
4020   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4021                 music_id_prefix, special_id_suffix, level_id_suffix,
4022                 dummy, ignore_music_tokens);
4023 }
4024
4025 static void InitMixer()
4026 {
4027   OpenAudio();
4028   StartMixer();
4029 }
4030
4031 void InitGfx()
4032 {
4033   char *filename_font_initial = NULL;
4034   Bitmap *bitmap_font_initial = NULL;
4035   int i, j;
4036
4037   /* determine settings for initial font (for displaying startup messages) */
4038   for (i = 0; image_config[i].token != NULL; i++)
4039   {
4040     for (j = 0; j < NUM_INITIAL_FONTS; j++)
4041     {
4042       char font_token[128];
4043       int len_font_token;
4044
4045       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4046       len_font_token = strlen(font_token);
4047
4048       if (strcmp(image_config[i].token, font_token) == 0)
4049         filename_font_initial = image_config[i].value;
4050       else if (strlen(image_config[i].token) > len_font_token &&
4051                strncmp(image_config[i].token, font_token, len_font_token) == 0)
4052       {
4053         if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4054           font_initial[j].src_x = atoi(image_config[i].value);
4055         else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4056           font_initial[j].src_y = atoi(image_config[i].value);
4057         else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4058           font_initial[j].width = atoi(image_config[i].value);
4059         else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4060           font_initial[j].height = atoi(image_config[i].value);
4061       }
4062     }
4063   }
4064
4065   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4066   {
4067     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4068     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4069   }
4070
4071   if (filename_font_initial == NULL)    /* should not happen */
4072     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4073
4074   /* create additional image buffers for double-buffering */
4075   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4076   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4077
4078   /* initialize screen properties */
4079   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4080                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4081                    bitmap_db_field);
4082   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4083   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4084   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4085
4086   bitmap_font_initial = LoadCustomImage(filename_font_initial);
4087
4088   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4089     font_initial[j].bitmap = bitmap_font_initial;
4090
4091   InitFontGraphicInfo();
4092
4093   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4094   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4095
4096   DrawInitText("Loading graphics:", 120, FC_GREEN);
4097 }
4098
4099 void InitGfxBackground()
4100 {
4101   int x, y;
4102
4103   drawto = backbuffer;
4104   fieldbuffer = bitmap_db_field;
4105   SetDrawtoField(DRAW_BACKBUFFER);
4106
4107   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4108              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4109   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4110   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4111
4112   for (x = 0; x < MAX_BUF_XSIZE; x++)
4113     for (y = 0; y < MAX_BUF_YSIZE; y++)
4114       redraw[x][y] = 0;
4115   redraw_tiles = 0;
4116   redraw_mask = REDRAW_ALL;
4117 }
4118
4119 static void InitLevelInfo()
4120 {
4121   LoadLevelInfo();                              /* global level info */
4122   LoadLevelSetup_LastSeries();                  /* last played series info */
4123   LoadLevelSetup_SeriesInfo();                  /* last played level info */
4124 }
4125
4126 void InitLevelArtworkInfo()
4127 {
4128   LoadLevelArtworkInfo();
4129 }
4130
4131 static void InitImages()
4132 {
4133   setLevelArtworkDir(artwork.gfx_first);
4134
4135 #if 0
4136   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4137          leveldir_current->identifier,
4138          artwork.gfx_current_identifier,
4139          artwork.gfx_current->identifier,
4140          leveldir_current->graphics_set,
4141          leveldir_current->graphics_path);
4142 #endif
4143
4144   ReloadCustomImages();
4145
4146   LoadCustomElementDescriptions();
4147   LoadSpecialMenuDesignSettings();
4148
4149   ReinitializeGraphics();
4150 }
4151
4152 static void InitSound(char *identifier)
4153 {
4154   if (identifier == NULL)
4155     identifier = artwork.snd_current->identifier;
4156
4157   /* set artwork path to send it to the sound server process */
4158   setLevelArtworkDir(artwork.snd_first);
4159
4160   InitReloadCustomSounds(identifier);
4161   ReinitializeSounds();
4162 }
4163
4164 static void InitMusic(char *identifier)
4165 {
4166   if (identifier == NULL)
4167     identifier = artwork.mus_current->identifier;
4168
4169   /* set artwork path to send it to the sound server process */
4170   setLevelArtworkDir(artwork.mus_first);
4171
4172   InitReloadCustomMusic(identifier);
4173   ReinitializeMusic();
4174 }
4175
4176 void InitNetworkServer()
4177 {
4178 #if defined(NETWORK_AVALIABLE)
4179   int nr_wanted;
4180 #endif
4181
4182   if (!options.network)
4183     return;
4184
4185 #if defined(NETWORK_AVALIABLE)
4186   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4187
4188   if (!ConnectToServer(options.server_host, options.server_port))
4189     Error(ERR_EXIT, "cannot connect to network game server");
4190
4191   SendToServer_PlayerName(setup.player_name);
4192   SendToServer_ProtocolVersion();
4193
4194   if (nr_wanted)
4195     SendToServer_NrWanted(nr_wanted);
4196 #endif
4197 }
4198
4199 static char *getNewArtworkIdentifier(int type)
4200 {
4201   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4202   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4203   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4204   static boolean initialized[3] = { FALSE, FALSE, FALSE };
4205   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4206   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4207   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4208   char *leveldir_identifier = leveldir_current->identifier;
4209 #if 1
4210   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4211   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4212 #else
4213   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4214 #endif
4215   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4216   char *artwork_current_identifier;
4217   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
4218
4219   /* leveldir_current may be invalid (level group, parent link) */
4220   if (!validLevelSeries(leveldir_current))
4221     return NULL;
4222
4223   /* 1st step: determine artwork set to be activated in descending order:
4224      --------------------------------------------------------------------
4225      1. setup artwork (when configured to override everything else)
4226      2. artwork set configured in "levelinfo.conf" of current level set
4227         (artwork in level directory will have priority when loading later)
4228      3. artwork in level directory (stored in artwork sub-directory)
4229      4. setup artwork (currently configured in setup menu) */
4230
4231   if (setup_override_artwork)
4232     artwork_current_identifier = setup_artwork_set;
4233   else if (leveldir_artwork_set != NULL)
4234     artwork_current_identifier = leveldir_artwork_set;
4235   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4236     artwork_current_identifier = leveldir_identifier;
4237   else
4238     artwork_current_identifier = setup_artwork_set;
4239
4240
4241   /* 2nd step: check if it is really needed to reload artwork set
4242      ------------------------------------------------------------ */
4243
4244 #if 0
4245   if (type == ARTWORK_TYPE_GRAPHICS)
4246     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4247            artwork_new_identifier,
4248            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4249            artwork_current_identifier,
4250            leveldir_current->graphics_set,
4251            leveldir_current->identifier);
4252 #endif
4253
4254   /* ---------- reload if level set and also artwork set has changed ------- */
4255   if (leveldir_current_identifier[type] != leveldir_identifier &&
4256       (last_has_level_artwork_set[type] || has_level_artwork_set))
4257     artwork_new_identifier = artwork_current_identifier;
4258
4259   leveldir_current_identifier[type] = leveldir_identifier;
4260   last_has_level_artwork_set[type] = has_level_artwork_set;
4261
4262 #if 0
4263   if (type == ARTWORK_TYPE_GRAPHICS)
4264     printf("::: 1: '%s'\n", artwork_new_identifier);
4265 #endif
4266
4267   /* ---------- reload if "override artwork" setting has changed ----------- */
4268   if (last_override_level_artwork[type] != setup_override_artwork)
4269     artwork_new_identifier = artwork_current_identifier;
4270
4271   last_override_level_artwork[type] = setup_override_artwork;
4272
4273 #if 0
4274   if (type == ARTWORK_TYPE_GRAPHICS)
4275     printf("::: 2: '%s'\n", artwork_new_identifier);
4276 #endif
4277
4278   /* ---------- reload if current artwork identifier has changed ----------- */
4279   if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4280              artwork_current_identifier) != 0)
4281     artwork_new_identifier = artwork_current_identifier;
4282
4283   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4284
4285 #if 0
4286   if (type == ARTWORK_TYPE_GRAPHICS)
4287     printf("::: 3: '%s'\n", artwork_new_identifier);
4288 #endif
4289
4290   /* ---------- do not reload directly after starting ---------------------- */
4291   if (!initialized[type])
4292     artwork_new_identifier = NULL;
4293
4294   initialized[type] = TRUE;
4295
4296 #if 0
4297   if (type == ARTWORK_TYPE_GRAPHICS)
4298     printf("::: 4: '%s'\n", artwork_new_identifier);
4299 #endif
4300
4301 #if 0
4302   if (type == ARTWORK_TYPE_GRAPHICS)
4303     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4304            artwork.gfx_current_identifier, artwork_current_identifier,
4305            artwork.gfx_current->identifier, leveldir_current->graphics_set,
4306            artwork_new_identifier);
4307 #endif
4308
4309   return artwork_new_identifier;
4310 }
4311
4312 void ReloadCustomArtwork(int force_reload)
4313 {
4314   char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4315   char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4316   char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4317   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4318   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4319   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4320   boolean redraw_screen = FALSE;
4321
4322   if (gfx_new_identifier != NULL || force_reload_gfx)
4323   {
4324 #if 0
4325     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4326            artwork.gfx_current_identifier,
4327            gfx_new_identifier,
4328            artwork.gfx_current->identifier,
4329            leveldir_current->graphics_set);
4330 #endif
4331
4332     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4333
4334     InitImages();
4335
4336     redraw_screen = TRUE;
4337   }
4338
4339   if (snd_new_identifier != NULL || force_reload_snd)
4340   {
4341     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4342
4343     InitSound(snd_new_identifier);
4344
4345     redraw_screen = TRUE;
4346   }
4347
4348   if (mus_new_identifier != NULL || force_reload_mus)
4349   {
4350     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4351
4352     InitMusic(mus_new_identifier);
4353
4354     redraw_screen = TRUE;
4355   }
4356
4357   if (redraw_screen)
4358   {
4359     InitGfxBackground();
4360
4361     /* force redraw of (open or closed) door graphics */
4362     SetDoorState(DOOR_OPEN_ALL);
4363     CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4364   }
4365 }
4366
4367 void KeyboardAutoRepeatOffUnlessAutoplay()
4368 {
4369   if (global.autoplay_leveldir == NULL)
4370     KeyboardAutoRepeatOff();
4371 }
4372
4373
4374 /* ========================================================================= */
4375 /* OpenAll()                                                                 */
4376 /* ========================================================================= */
4377
4378 void OpenAll()
4379 {
4380   InitGlobal();                 /* initialize some global variables */
4381
4382   if (options.execute_command)
4383     Execute_Command(options.execute_command);
4384
4385   if (options.serveronly)
4386   {
4387 #if defined(PLATFORM_UNIX)
4388     NetworkServer(options.server_port, options.serveronly);
4389 #else
4390     Error(ERR_WARN, "networking only supported in Unix version");
4391 #endif
4392
4393     exit(0);                    /* never reached, server loops forever */
4394   }
4395
4396   InitSetup();
4397
4398   InitGameInfo();
4399   InitPlayerInfo();
4400   InitArtworkInfo();            /* needed before loading gfx, sound & music */
4401   InitArtworkConfig();          /* needed before forking sound child process */
4402   InitMixer();
4403
4404   InitCounter();
4405
4406   InitRND(NEW_RANDOMIZE);
4407   InitSimpleRND(NEW_RANDOMIZE);
4408
4409   InitJoysticks();
4410
4411   InitVideoDisplay();
4412   InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4413                   setup.fullscreen);
4414
4415   InitEventFilter(FilterMouseMotionEvents);
4416
4417   InitElementPropertiesStatic();
4418   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4419
4420   InitGfx();
4421
4422   InitLevelInfo();
4423   InitLevelArtworkInfo();
4424
4425   InitImages();                 /* needs to know current level directory */
4426   InitSound(NULL);              /* needs to know current level directory */
4427   InitMusic(NULL);              /* needs to know current level directory */
4428
4429   InitGfxBackground();
4430
4431   if (global.autoplay_leveldir)
4432   {
4433     AutoPlayTape();
4434     return;
4435   }
4436   else if (global.convert_leveldir)
4437   {
4438     ConvertLevels();
4439     return;
4440   }
4441
4442   game_status = GAME_MODE_MAIN;
4443
4444 #if 1
4445   em_open_all();
4446 #endif
4447
4448   DrawMainMenu();
4449
4450   InitNetworkServer();
4451 }
4452
4453 void CloseAllAndExit(int exit_value)
4454 {
4455   StopSounds();
4456   FreeAllSounds();
4457   FreeAllMusic();
4458   CloseAudio();         /* called after freeing sounds (needed for SDL) */
4459
4460 #if 1
4461   em_close_all();
4462 #endif
4463
4464   FreeAllImages();
4465
4466 #if defined(TARGET_SDL)
4467   if (network_server)   /* terminate network server */
4468     SDL_KillThread(server_thread);
4469 #endif
4470
4471   CloseVideoDisplay();
4472   ClosePlatformDependentStuff();
4473
4474   exit(exit_value);
4475 }