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