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