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