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