166ee1d46288fd2d118e8a2999a8e0cc08407dca
[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       /* no sound for this specific action -- use default action sound */
1264       if (element_info[i].sound[act] == -1)
1265         element_info[i].sound[act] = default_action_sound;
1266     }
1267   }
1268 }
1269
1270 static void InitGameModeSoundInfo()
1271 {
1272   int i;
1273
1274   /* set values to -1 to identify later as "uninitialized" values */
1275   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1276     menu.sound[i] = -1;
1277
1278   /* initialize gamemode/sound mapping from static configuration */
1279   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1280   {
1281     int gamemode = gamemode_to_sound[i].gamemode;
1282     int sound    = gamemode_to_sound[i].sound;
1283
1284     if (gamemode < 0)
1285       gamemode = GAME_MODE_DEFAULT;
1286
1287     menu.sound[gamemode] = sound;
1288   }
1289
1290   /* now set all '-1' values to levelset specific default values */
1291   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1292     if (menu.sound[i] == -1)
1293       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1294
1295 #if 0
1296   /* TEST ONLY */
1297   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1298     if (menu.sound[i] != -1)
1299       printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1300 #endif
1301 }
1302
1303 static void set_sound_parameters(int sound, char **parameter_raw)
1304 {
1305   int parameter[NUM_SND_ARGS];
1306   int i;
1307
1308   /* get integer values from string parameters */
1309   for (i = 0; i < NUM_SND_ARGS; i++)
1310     parameter[i] =
1311       get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1312                           sound_config_suffix[i].type);
1313
1314   /* explicit loop mode setting in configuration overrides default value */
1315   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1316     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1317
1318   /* sound volume to change the original volume when loading the sound file */
1319   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1320
1321   /* sound priority to give certain sounds a higher or lower priority */
1322   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1323 }
1324
1325 static void InitSoundInfo()
1326 {
1327 #if 0
1328   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1329   int num_property_mappings = getSoundListPropertyMappingSize();
1330 #endif
1331   int *sound_effect_properties;
1332   int num_sounds = getSoundListSize();
1333   int i, j;
1334
1335   checked_free(sound_info);
1336
1337   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1338   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1339
1340   /* initialize sound effect for all elements to "no sound" */
1341   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1342     for (j = 0; j < NUM_ACTIONS; j++)
1343       element_info[i].sound[j] = SND_UNDEFINED;
1344
1345   for (i = 0; i < num_sounds; i++)
1346   {
1347     struct FileInfo *sound = getSoundListEntry(i);
1348     int len_effect_text = strlen(sound->token);
1349
1350     sound_effect_properties[i] = ACTION_OTHER;
1351     sound_info[i].loop = FALSE;         /* default: play sound only once */
1352
1353 #if 0
1354     printf("::: sound %d: '%s'\n", i, sound->token);
1355 #endif
1356
1357     /* determine all loop sounds and identify certain sound classes */
1358
1359     for (j = 0; element_action_info[j].suffix; j++)
1360     {
1361       int len_action_text = strlen(element_action_info[j].suffix);
1362
1363       if (len_action_text < len_effect_text &&
1364           strcmp(&sound->token[len_effect_text - len_action_text],
1365                  element_action_info[j].suffix) == 0)
1366       {
1367         sound_effect_properties[i] = element_action_info[j].value;
1368         sound_info[i].loop = element_action_info[j].is_loop_sound;
1369
1370         break;
1371       }
1372     }
1373
1374 #if 0
1375     if (strcmp(sound->token, "custom_42") == 0)
1376       printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1377 #endif
1378
1379     /* associate elements and some selected sound actions */
1380
1381     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1382     {
1383       if (element_info[j].class_name)
1384       {
1385         int len_class_text = strlen(element_info[j].class_name);
1386
1387         if (len_class_text + 1 < len_effect_text &&
1388             strncmp(sound->token,
1389                     element_info[j].class_name, len_class_text) == 0 &&
1390             sound->token[len_class_text] == '.')
1391         {
1392           int sound_action_value = sound_effect_properties[i];
1393
1394           element_info[j].sound[sound_action_value] = i;
1395         }
1396       }
1397     }
1398
1399     set_sound_parameters(i, sound->parameter);
1400   }
1401
1402   free(sound_effect_properties);
1403
1404 #if 0
1405   /* !!! now handled in InitElementSoundInfo() !!! */
1406   /* initialize element/sound mapping from dynamic configuration */
1407   for (i = 0; i < num_property_mappings; i++)
1408   {
1409     int element   = property_mapping[i].base_index;
1410     int action    = property_mapping[i].ext1_index;
1411     int sound     = property_mapping[i].artwork_index;
1412
1413     if (action < 0)
1414       action = ACTION_DEFAULT;
1415
1416     printf("::: %d: %d, %d, %d ['%s']\n",
1417            i, element, action, sound, element_info[element].token_name);
1418
1419     element_info[element].sound[action] = sound;
1420   }
1421 #endif
1422
1423 #if 0
1424   /* TEST ONLY */
1425   {
1426     int element = EL_CUSTOM_11;
1427     int j = 0;
1428
1429     while (element_action_info[j].suffix)
1430     {
1431       printf("element %d, sound action '%s'  == %d\n",
1432              element, element_action_info[j].suffix,
1433              element_info[element].sound[j]);
1434       j++;
1435     }
1436   }
1437
1438   PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1439 #endif
1440
1441 #if 0
1442   /* TEST ONLY */
1443   {
1444     int element = EL_SAND;
1445     int sound_action = ACTION_DIGGING;
1446     int j = 0;
1447
1448     while (element_action_info[j].suffix)
1449     {
1450       if (element_action_info[j].value == sound_action)
1451         printf("element %d, sound action '%s'  == %d\n",
1452                element, element_action_info[j].suffix,
1453                element_info[element].sound[sound_action]);
1454       j++;
1455     }
1456   }
1457 #endif
1458 }
1459
1460 static void InitGameModeMusicInfo()
1461 {
1462   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1463   int num_property_mappings = getMusicListPropertyMappingSize();
1464   int default_levelset_music = -1;
1465   int i;
1466
1467   /* set values to -1 to identify later as "uninitialized" values */
1468   for (i = 0; i < MAX_LEVELS; i++)
1469     levelset.music[i] = -1;
1470   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1471     menu.music[i] = -1;
1472
1473   /* initialize gamemode/music mapping from static configuration */
1474   for (i = 0; gamemode_to_music[i].music > -1; i++)
1475   {
1476     int gamemode = gamemode_to_music[i].gamemode;
1477     int music    = gamemode_to_music[i].music;
1478
1479 #if 0
1480     printf("::: gamemode == %d, music == %d\n", gamemode, music);
1481 #endif
1482
1483     if (gamemode < 0)
1484       gamemode = GAME_MODE_DEFAULT;
1485
1486     menu.music[gamemode] = music;
1487   }
1488
1489   /* initialize gamemode/music mapping from dynamic configuration */
1490   for (i = 0; i < num_property_mappings; i++)
1491   {
1492     int prefix   = property_mapping[i].base_index;
1493     int gamemode = property_mapping[i].ext1_index;
1494     int level    = property_mapping[i].ext2_index;
1495     int music    = property_mapping[i].artwork_index;
1496
1497 #if 0
1498     printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1499            prefix, gamemode, level, music);
1500 #endif
1501
1502     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1503       continue;
1504
1505     if (gamemode < 0)
1506       gamemode = GAME_MODE_DEFAULT;
1507
1508     /* level specific music only allowed for in-game music */
1509     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1510       gamemode = GAME_MODE_PLAYING;
1511
1512     if (level == -1)
1513     {
1514       level = 0;
1515       default_levelset_music = music;
1516     }
1517
1518     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1519       levelset.music[level] = music;
1520     if (gamemode != GAME_MODE_PLAYING)
1521       menu.music[gamemode] = music;
1522   }
1523
1524   /* now set all '-1' values to menu specific default values */
1525   /* (undefined values of "levelset.music[]" might stay at "-1" to
1526      allow dynamic selection of music files from music directory!) */
1527   for (i = 0; i < MAX_LEVELS; i++)
1528     if (levelset.music[i] == -1)
1529       levelset.music[i] = default_levelset_music;
1530   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1531     if (menu.music[i] == -1)
1532       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1533
1534 #if 0
1535   /* TEST ONLY */
1536   for (i = 0; i < MAX_LEVELS; i++)
1537     if (levelset.music[i] != -1)
1538       printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1539   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1540     if (menu.music[i] != -1)
1541       printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1542 #endif
1543 }
1544
1545 static void set_music_parameters(int music, char **parameter_raw)
1546 {
1547   int parameter[NUM_MUS_ARGS];
1548   int i;
1549
1550   /* get integer values from string parameters */
1551   for (i = 0; i < NUM_MUS_ARGS; i++)
1552     parameter[i] =
1553       get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1554                           music_config_suffix[i].type);
1555
1556   /* explicit loop mode setting in configuration overrides default value */
1557   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1558     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1559 }
1560
1561 static void InitMusicInfo()
1562 {
1563   int num_music = getMusicListSize();
1564   int i, j;
1565
1566   checked_free(music_info);
1567
1568   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1569
1570   for (i = 0; i < num_music; i++)
1571   {
1572     struct FileInfo *music = getMusicListEntry(i);
1573     int len_music_text = strlen(music->token);
1574
1575     music_info[i].loop = TRUE;          /* default: play music in loop mode */
1576
1577     /* determine all loop music */
1578
1579     for (j = 0; music_prefix_info[j].prefix; j++)
1580     {
1581       int len_prefix_text = strlen(music_prefix_info[j].prefix);
1582
1583       if (len_prefix_text < len_music_text &&
1584           strncmp(music->token,
1585                   music_prefix_info[j].prefix, len_prefix_text) == 0)
1586       {
1587         music_info[i].loop = music_prefix_info[j].is_loop_music;
1588
1589         break;
1590       }
1591     }
1592
1593     set_music_parameters(i, music->parameter);
1594   }
1595 }
1596
1597 static void ReinitializeGraphics()
1598 {
1599   InitGraphicInfo();                    /* graphic properties mapping */
1600   InitElementGraphicInfo();             /* element game graphic mapping */
1601   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
1602
1603   InitElementSmallImages();             /* scale images to all needed sizes */
1604   InitFontGraphicInfo();                /* initialize text drawing functions */
1605
1606   SetMainBackgroundImage(IMG_BACKGROUND);
1607   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1608
1609   InitGadgets();
1610   InitToons();
1611 }
1612
1613 static void ReinitializeSounds()
1614 {
1615   InitSoundInfo();              /* sound properties mapping */
1616   InitElementSoundInfo();       /* element game sound mapping */
1617   InitGameModeSoundInfo();      /* game mode sound mapping */
1618
1619   InitPlayLevelSound();         /* internal game sound settings */
1620 }
1621
1622 static void ReinitializeMusic()
1623 {
1624   InitMusicInfo();              /* music properties mapping */
1625   InitGameModeMusicInfo();      /* game mode music mapping */
1626 }
1627
1628 static int get_special_property_bit(int element, int property_bit_nr)
1629 {
1630   struct PropertyBitInfo
1631   {
1632     int element;
1633     int bit_nr;
1634   };
1635
1636   static struct PropertyBitInfo pb_can_move_into_acid[] =
1637   {
1638     /* the player may be able fall into acid when gravity is activated */
1639     { EL_PLAYER_1,              0       },
1640     { EL_PLAYER_2,              0       },
1641     { EL_PLAYER_3,              0       },
1642     { EL_PLAYER_4,              0       },
1643     { EL_SP_MURPHY,             0       },
1644     { EL_SOKOBAN_FIELD_PLAYER,  0       },
1645
1646     /* all element that can move may be able to also move into acid */
1647     { EL_BUG,                   1       },
1648     { EL_BUG_LEFT,              1       },
1649     { EL_BUG_RIGHT,             1       },
1650     { EL_BUG_UP,                1       },
1651     { EL_BUG_DOWN,              1       },
1652     { EL_SPACESHIP,             2       },
1653     { EL_SPACESHIP_LEFT,        2       },
1654     { EL_SPACESHIP_RIGHT,       2       },
1655     { EL_SPACESHIP_UP,          2       },
1656     { EL_SPACESHIP_DOWN,        2       },
1657     { EL_BD_BUTTERFLY,          3       },
1658     { EL_BD_BUTTERFLY_LEFT,     3       },
1659     { EL_BD_BUTTERFLY_RIGHT,    3       },
1660     { EL_BD_BUTTERFLY_UP,       3       },
1661     { EL_BD_BUTTERFLY_DOWN,     3       },
1662     { EL_BD_FIREFLY,            4       },
1663     { EL_BD_FIREFLY_LEFT,       4       },
1664     { EL_BD_FIREFLY_RIGHT,      4       },
1665     { EL_BD_FIREFLY_UP,         4       },
1666     { EL_BD_FIREFLY_DOWN,       4       },
1667     { EL_YAMYAM,                5       },
1668     { EL_DARK_YAMYAM,           6       },
1669     { EL_ROBOT,                 7       },
1670     { EL_PACMAN,                8       },
1671     { EL_PACMAN_LEFT,           8       },
1672     { EL_PACMAN_RIGHT,          8       },
1673     { EL_PACMAN_UP,             8       },
1674     { EL_PACMAN_DOWN,           8       },
1675     { EL_MOLE,                  9       },
1676     { EL_MOLE_LEFT,             9       },
1677     { EL_MOLE_RIGHT,            9       },
1678     { EL_MOLE_UP,               9       },
1679     { EL_MOLE_DOWN,             9       },
1680     { EL_PENGUIN,               10      },
1681     { EL_PIG,                   11      },
1682     { EL_DRAGON,                12      },
1683     { EL_SATELLITE,             13      },
1684     { EL_SP_SNIKSNAK,           14      },
1685     { EL_SP_ELECTRON,           15      },
1686     { EL_BALLOON,               16      },
1687     { EL_SPRING,                17      },
1688
1689     { -1,                       -1      },
1690   };
1691
1692   static struct PropertyBitInfo pb_dont_collide_with[] =
1693   {
1694     { EL_SP_SNIKSNAK,           0       },
1695     { EL_SP_ELECTRON,           1       },
1696
1697     { -1,                       -1      },
1698   };
1699
1700   static struct
1701   {
1702     int bit_nr;
1703     struct PropertyBitInfo *pb_info;
1704   } pb_definition[] =
1705   {
1706     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
1707     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
1708
1709     { -1,                       NULL                    },
1710   };
1711
1712   struct PropertyBitInfo *pb_info = NULL;
1713   int i;
1714
1715   for (i = 0; pb_definition[i].bit_nr != -1; i++)
1716     if (pb_definition[i].bit_nr == property_bit_nr)
1717       pb_info = pb_definition[i].pb_info;
1718
1719   if (pb_info == NULL)
1720     return -1;
1721
1722   for (i = 0; pb_info[i].element != -1; i++)
1723     if (pb_info[i].element == element)
1724       return pb_info[i].bit_nr;
1725
1726   return -1;
1727 }
1728
1729 #if 1
1730 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1731                          boolean property_value)
1732 {
1733   int bit_nr = get_special_property_bit(element, property_bit_nr);
1734
1735   if (bit_nr > -1)
1736   {
1737     if (property_value)
1738       *bitfield |=  (1 << bit_nr);
1739     else
1740       *bitfield &= ~(1 << bit_nr);
1741   }
1742 }
1743
1744 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1745 {
1746   int bit_nr = get_special_property_bit(element, property_bit_nr);
1747
1748   if (bit_nr > -1)
1749     return ((*bitfield & (1 << bit_nr)) != 0);
1750
1751   return FALSE;
1752 }
1753
1754 #else
1755
1756 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1757 {
1758   int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1759
1760   if (bit_nr > -1)
1761   {
1762     level->can_move_into_acid_bits &= ~(1 << bit_nr);
1763
1764     if (set)
1765       level->can_move_into_acid_bits |= (1 << bit_nr);
1766   }
1767 }
1768
1769 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1770 {
1771   int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1772
1773   if (bit_nr > -1)
1774     return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1775
1776   return FALSE;
1777 }
1778 #endif
1779
1780 void InitElementPropertiesStatic()
1781 {
1782   static int ep_diggable[] =
1783   {
1784     EL_SAND,
1785     EL_SP_BASE,
1786     EL_SP_BUGGY_BASE,
1787     EL_SP_BUGGY_BASE_ACTIVATING,
1788     EL_TRAP,
1789     EL_INVISIBLE_SAND,
1790     EL_INVISIBLE_SAND_ACTIVE,
1791
1792     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1793     /* (if amoeba can grow into anything diggable, maybe keep these out) */
1794 #if 0
1795     EL_LANDMINE,
1796     EL_TRAP_ACTIVE,
1797     EL_SP_BUGGY_BASE_ACTIVE,
1798 #endif
1799     -1
1800   };
1801
1802   static int ep_collectible_only[] =
1803   {
1804     EL_BD_DIAMOND,
1805     EL_EMERALD,
1806     EL_DIAMOND,
1807     EL_EMERALD_YELLOW,
1808     EL_EMERALD_RED,
1809     EL_EMERALD_PURPLE,
1810     EL_KEY_1,
1811     EL_KEY_2,
1812     EL_KEY_3,
1813     EL_KEY_4,
1814     EL_EM_KEY_1,
1815     EL_EM_KEY_2,
1816     EL_EM_KEY_3,
1817     EL_EM_KEY_4,
1818     EL_DYNAMITE,
1819     EL_DYNABOMB_INCREASE_NUMBER,
1820     EL_DYNABOMB_INCREASE_SIZE,
1821     EL_DYNABOMB_INCREASE_POWER,
1822     EL_SP_INFOTRON,
1823     EL_SP_DISK_RED,
1824     EL_PEARL,
1825     EL_CRYSTAL,
1826     EL_KEY_WHITE,
1827     EL_SHIELD_NORMAL,
1828     EL_SHIELD_DEADLY,
1829     EL_EXTRA_TIME,
1830     EL_ENVELOPE_1,
1831     EL_ENVELOPE_2,
1832     EL_ENVELOPE_3,
1833     EL_ENVELOPE_4,
1834     EL_SPEED_PILL,
1835     -1
1836   };
1837
1838   static int ep_dont_run_into[] =
1839   {
1840     /* same elements as in 'ep_dont_touch' */
1841     EL_BUG,
1842     EL_SPACESHIP,
1843     EL_BD_BUTTERFLY,
1844     EL_BD_FIREFLY,
1845
1846     /* same elements as in 'ep_dont_collide_with' */
1847     EL_YAMYAM,
1848     EL_DARK_YAMYAM,
1849     EL_ROBOT,
1850     EL_PACMAN,
1851     EL_SP_SNIKSNAK,
1852     EL_SP_ELECTRON,
1853
1854     /* new elements */
1855     EL_AMOEBA_DROP,
1856     EL_ACID,
1857
1858     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1859 #if 1
1860     EL_LANDMINE,
1861     EL_TRAP_ACTIVE,
1862     EL_SP_BUGGY_BASE_ACTIVE,
1863 #endif
1864     -1
1865   };
1866
1867   static int ep_dont_collide_with[] =
1868   {
1869     /* same elements as in 'ep_dont_touch' */
1870     EL_BUG,
1871     EL_SPACESHIP,
1872     EL_BD_BUTTERFLY,
1873     EL_BD_FIREFLY,
1874
1875     /* new elements */
1876     EL_YAMYAM,
1877     EL_DARK_YAMYAM,
1878     EL_ROBOT,
1879     EL_PACMAN,
1880     EL_SP_SNIKSNAK,
1881     EL_SP_ELECTRON,
1882     -1
1883   };
1884
1885   static int ep_dont_touch[] =
1886   {
1887     EL_BUG,
1888     EL_SPACESHIP,
1889     EL_BD_BUTTERFLY,
1890     EL_BD_FIREFLY,
1891     -1
1892   };
1893
1894   static int ep_indestructible[] =
1895   {
1896     EL_STEELWALL,
1897     EL_ACID,
1898     EL_ACID_POOL_TOPLEFT,
1899     EL_ACID_POOL_TOPRIGHT,
1900     EL_ACID_POOL_BOTTOMLEFT,
1901     EL_ACID_POOL_BOTTOM,
1902     EL_ACID_POOL_BOTTOMRIGHT,
1903     EL_SP_HARDWARE_GRAY,
1904     EL_SP_HARDWARE_GREEN,
1905     EL_SP_HARDWARE_BLUE,
1906     EL_SP_HARDWARE_RED,
1907     EL_SP_HARDWARE_YELLOW,
1908     EL_SP_HARDWARE_BASE_1,
1909     EL_SP_HARDWARE_BASE_2,
1910     EL_SP_HARDWARE_BASE_3,
1911     EL_SP_HARDWARE_BASE_4,
1912     EL_SP_HARDWARE_BASE_5,
1913     EL_SP_HARDWARE_BASE_6,
1914     EL_INVISIBLE_STEELWALL,
1915     EL_INVISIBLE_STEELWALL_ACTIVE,
1916     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1917     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1918     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1919     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1920     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1921     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1922     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1923     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1924     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1925     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1926     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1927     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1928     EL_LIGHT_SWITCH,
1929     EL_LIGHT_SWITCH_ACTIVE,
1930     EL_SIGN_EXCLAMATION,
1931     EL_SIGN_RADIOACTIVITY,
1932     EL_SIGN_STOP,
1933     EL_SIGN_WHEELCHAIR,
1934     EL_SIGN_PARKING,
1935     EL_SIGN_ONEWAY,
1936     EL_SIGN_HEART,
1937     EL_SIGN_TRIANGLE,
1938     EL_SIGN_ROUND,
1939     EL_SIGN_EXIT,
1940     EL_SIGN_YINYANG,
1941     EL_SIGN_OTHER,
1942     EL_STEELWALL_SLIPPERY,
1943     EL_EMC_STEELWALL_1,
1944     EL_EMC_STEELWALL_2,
1945     EL_EMC_STEELWALL_3,
1946     EL_EMC_STEELWALL_4,
1947     EL_CRYSTAL,
1948     EL_GATE_1,
1949     EL_GATE_2,
1950     EL_GATE_3,
1951     EL_GATE_4,
1952     EL_GATE_1_GRAY,
1953     EL_GATE_2_GRAY,
1954     EL_GATE_3_GRAY,
1955     EL_GATE_4_GRAY,
1956     EL_EM_GATE_1,
1957     EL_EM_GATE_2,
1958     EL_EM_GATE_3,
1959     EL_EM_GATE_4,
1960     EL_EM_GATE_1_GRAY,
1961     EL_EM_GATE_2_GRAY,
1962     EL_EM_GATE_3_GRAY,
1963     EL_EM_GATE_4_GRAY,
1964     EL_SWITCHGATE_OPEN,
1965     EL_SWITCHGATE_OPENING,
1966     EL_SWITCHGATE_CLOSED,
1967     EL_SWITCHGATE_CLOSING,
1968 #if 0
1969     EL_SWITCHGATE_SWITCH_UP,
1970     EL_SWITCHGATE_SWITCH_DOWN,
1971 #endif
1972     EL_TIMEGATE_OPEN,
1973     EL_TIMEGATE_OPENING,
1974     EL_TIMEGATE_CLOSED,
1975     EL_TIMEGATE_CLOSING,
1976 #if 0
1977     EL_TIMEGATE_SWITCH,
1978     EL_TIMEGATE_SWITCH_ACTIVE,
1979 #endif
1980     EL_TUBE_ANY,
1981     EL_TUBE_VERTICAL,
1982     EL_TUBE_HORIZONTAL,
1983     EL_TUBE_VERTICAL_LEFT,
1984     EL_TUBE_VERTICAL_RIGHT,
1985     EL_TUBE_HORIZONTAL_UP,
1986     EL_TUBE_HORIZONTAL_DOWN,
1987     EL_TUBE_LEFT_UP,
1988     EL_TUBE_LEFT_DOWN,
1989     EL_TUBE_RIGHT_UP,
1990     EL_TUBE_RIGHT_DOWN,
1991     -1
1992   };
1993
1994   static int ep_slippery[] =
1995   {
1996     EL_WALL_SLIPPERY,
1997     EL_BD_WALL,
1998     EL_ROCK,
1999     EL_BD_ROCK,
2000     EL_EMERALD,
2001     EL_BD_DIAMOND,
2002     EL_EMERALD_YELLOW,
2003     EL_EMERALD_RED,
2004     EL_EMERALD_PURPLE,
2005     EL_DIAMOND,
2006     EL_BOMB,
2007     EL_NUT,
2008     EL_ROBOT_WHEEL_ACTIVE,
2009     EL_ROBOT_WHEEL,
2010     EL_TIME_ORB_FULL,
2011     EL_TIME_ORB_EMPTY,
2012     EL_LAMP_ACTIVE,
2013     EL_LAMP,
2014     EL_ACID_POOL_TOPLEFT,
2015     EL_ACID_POOL_TOPRIGHT,
2016     EL_SATELLITE,
2017     EL_SP_ZONK,
2018     EL_SP_INFOTRON,
2019     EL_SP_CHIP_SINGLE,
2020     EL_SP_CHIP_LEFT,
2021     EL_SP_CHIP_RIGHT,
2022     EL_SP_CHIP_TOP,
2023     EL_SP_CHIP_BOTTOM,
2024     EL_SPEED_PILL,
2025     EL_STEELWALL_SLIPPERY,
2026     EL_PEARL,
2027     EL_CRYSTAL,
2028     -1
2029   };
2030
2031   static int ep_can_change[] =
2032   {
2033     -1
2034   };
2035
2036   static int ep_can_move[] =
2037   {
2038     /* same elements as in 'pb_can_move_into_acid' */
2039     EL_BUG,
2040     EL_SPACESHIP,
2041     EL_BD_BUTTERFLY,
2042     EL_BD_FIREFLY,
2043     EL_YAMYAM,
2044     EL_DARK_YAMYAM,
2045     EL_ROBOT,
2046     EL_PACMAN,
2047     EL_MOLE,
2048     EL_PENGUIN,
2049     EL_PIG,
2050     EL_DRAGON,
2051     EL_SATELLITE,
2052     EL_SP_SNIKSNAK,
2053     EL_SP_ELECTRON,
2054     EL_BALLOON,
2055     EL_SPRING,
2056     -1
2057   };
2058
2059   static int ep_can_fall[] =
2060   {
2061     EL_ROCK,
2062     EL_BD_ROCK,
2063     EL_EMERALD,
2064     EL_BD_DIAMOND,
2065     EL_EMERALD_YELLOW,
2066     EL_EMERALD_RED,
2067     EL_EMERALD_PURPLE,
2068     EL_DIAMOND,
2069     EL_BOMB,
2070     EL_NUT,
2071     EL_AMOEBA_DROP,
2072     EL_QUICKSAND_FULL,
2073     EL_MAGIC_WALL_FULL,
2074     EL_BD_MAGIC_WALL_FULL,
2075     EL_TIME_ORB_FULL,
2076     EL_TIME_ORB_EMPTY,
2077     EL_SP_ZONK,
2078     EL_SP_INFOTRON,
2079     EL_SP_DISK_ORANGE,
2080     EL_PEARL,
2081     EL_CRYSTAL,
2082     EL_SPRING,
2083     EL_DX_SUPABOMB,
2084     -1
2085   };
2086
2087   static int ep_can_smash_player[] =
2088   {
2089     EL_ROCK,
2090     EL_BD_ROCK,
2091     EL_EMERALD,
2092     EL_BD_DIAMOND,
2093     EL_EMERALD_YELLOW,
2094     EL_EMERALD_RED,
2095     EL_EMERALD_PURPLE,
2096     EL_DIAMOND,
2097     EL_BOMB,
2098     EL_NUT,
2099     EL_AMOEBA_DROP,
2100     EL_TIME_ORB_FULL,
2101     EL_TIME_ORB_EMPTY,
2102     EL_SP_ZONK,
2103     EL_SP_INFOTRON,
2104     EL_SP_DISK_ORANGE,
2105     EL_PEARL,
2106     EL_CRYSTAL,
2107     EL_SPRING,
2108     EL_DX_SUPABOMB,
2109     -1
2110   };
2111
2112   static int ep_can_smash_enemies[] =
2113   {
2114     EL_ROCK,
2115     EL_BD_ROCK,
2116     EL_SP_ZONK,
2117     -1
2118   };
2119
2120   static int ep_can_smash_everything[] =
2121   {
2122     EL_ROCK,
2123     EL_BD_ROCK,
2124     EL_SP_ZONK,
2125     -1
2126   };
2127
2128   static int ep_explodes_by_fire[] =
2129   {
2130     /* same elements as in 'ep_explodes_impact' */
2131     EL_BOMB,
2132     EL_SP_DISK_ORANGE,
2133     EL_DX_SUPABOMB,
2134
2135     /* same elements as in 'ep_explodes_smashed' */
2136     EL_SATELLITE,
2137     EL_PIG,
2138     EL_DRAGON,
2139     EL_MOLE,
2140
2141     /* new elements */
2142     EL_DYNAMITE_ACTIVE,
2143     EL_DYNAMITE,
2144     EL_DYNABOMB_PLAYER_1_ACTIVE,
2145     EL_DYNABOMB_PLAYER_2_ACTIVE,
2146     EL_DYNABOMB_PLAYER_3_ACTIVE,
2147     EL_DYNABOMB_PLAYER_4_ACTIVE,
2148     EL_DYNABOMB_INCREASE_NUMBER,
2149     EL_DYNABOMB_INCREASE_SIZE,
2150     EL_DYNABOMB_INCREASE_POWER,
2151     EL_SP_DISK_RED_ACTIVE,
2152     EL_BUG,
2153     EL_PENGUIN,
2154     EL_SP_DISK_RED,
2155     EL_SP_DISK_YELLOW,
2156     EL_SP_SNIKSNAK,
2157     EL_SP_ELECTRON,
2158 #if 0
2159     EL_BLACK_ORB,
2160 #endif
2161     -1
2162   };
2163
2164   static int ep_explodes_smashed[] =
2165   {
2166     /* same elements as in 'ep_explodes_impact' */
2167     EL_BOMB,
2168     EL_SP_DISK_ORANGE,
2169     EL_DX_SUPABOMB,
2170
2171     /* new elements */
2172     EL_SATELLITE,
2173     EL_PIG,
2174     EL_DRAGON,
2175     EL_MOLE,
2176     -1
2177   };
2178
2179   static int ep_explodes_impact[] =
2180   {
2181     EL_BOMB,
2182     EL_SP_DISK_ORANGE,
2183     EL_DX_SUPABOMB,
2184     -1
2185   };
2186
2187   static int ep_walkable_over[] =
2188   {
2189     EL_EMPTY_SPACE,
2190     EL_SP_EMPTY_SPACE,
2191     EL_SOKOBAN_FIELD_EMPTY,
2192     EL_EXIT_OPEN,
2193     EL_SP_EXIT_OPEN,
2194     EL_SP_EXIT_OPENING,
2195     EL_GATE_1,
2196     EL_GATE_2,
2197     EL_GATE_3,
2198     EL_GATE_4,
2199     EL_GATE_1_GRAY,
2200     EL_GATE_2_GRAY,
2201     EL_GATE_3_GRAY,
2202     EL_GATE_4_GRAY,
2203     EL_PENGUIN,
2204     EL_PIG,
2205     EL_DRAGON,
2206     -1
2207   };
2208
2209   static int ep_walkable_inside[] =
2210   {
2211     EL_TUBE_ANY,
2212     EL_TUBE_VERTICAL,
2213     EL_TUBE_HORIZONTAL,
2214     EL_TUBE_VERTICAL_LEFT,
2215     EL_TUBE_VERTICAL_RIGHT,
2216     EL_TUBE_HORIZONTAL_UP,
2217     EL_TUBE_HORIZONTAL_DOWN,
2218     EL_TUBE_LEFT_UP,
2219     EL_TUBE_LEFT_DOWN,
2220     EL_TUBE_RIGHT_UP,
2221     EL_TUBE_RIGHT_DOWN,
2222     -1
2223   };
2224
2225   static int ep_walkable_under[] =
2226   {
2227     -1
2228   };
2229
2230   static int ep_passable_over[] =
2231   {
2232     EL_EM_GATE_1,
2233     EL_EM_GATE_2,
2234     EL_EM_GATE_3,
2235     EL_EM_GATE_4,
2236     EL_EM_GATE_1_GRAY,
2237     EL_EM_GATE_2_GRAY,
2238     EL_EM_GATE_3_GRAY,
2239     EL_EM_GATE_4_GRAY,
2240     EL_SWITCHGATE_OPEN,
2241     EL_TIMEGATE_OPEN,
2242     -1
2243   };
2244
2245   static int ep_passable_inside[] =
2246   {
2247     EL_SP_PORT_LEFT,
2248     EL_SP_PORT_RIGHT,
2249     EL_SP_PORT_UP,
2250     EL_SP_PORT_DOWN,
2251     EL_SP_PORT_HORIZONTAL,
2252     EL_SP_PORT_VERTICAL,
2253     EL_SP_PORT_ANY,
2254     EL_SP_GRAVITY_PORT_LEFT,
2255     EL_SP_GRAVITY_PORT_RIGHT,
2256     EL_SP_GRAVITY_PORT_UP,
2257     EL_SP_GRAVITY_PORT_DOWN,
2258     EL_SP_GRAVITY_ON_PORT_LEFT,
2259     EL_SP_GRAVITY_ON_PORT_RIGHT,
2260     EL_SP_GRAVITY_ON_PORT_UP,
2261     EL_SP_GRAVITY_ON_PORT_DOWN,
2262     EL_SP_GRAVITY_OFF_PORT_LEFT,
2263     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2264     EL_SP_GRAVITY_OFF_PORT_UP,
2265     EL_SP_GRAVITY_OFF_PORT_DOWN,
2266     -1
2267   };
2268
2269   static int ep_passable_under[] =
2270   {
2271     -1
2272   };
2273
2274   static int ep_droppable[] =
2275   {
2276     -1
2277   };
2278
2279   static int ep_explodes_1x1_old[] =
2280   {
2281     -1
2282   };
2283
2284   static int ep_pushable[] =
2285   {
2286     EL_ROCK,
2287     EL_BOMB,
2288     EL_DX_SUPABOMB,
2289     EL_NUT,
2290     EL_TIME_ORB_EMPTY,
2291     EL_SP_ZONK,
2292     EL_SP_DISK_ORANGE,
2293     EL_SPRING,
2294     EL_BD_ROCK,
2295     EL_SOKOBAN_OBJECT,
2296     EL_SOKOBAN_FIELD_FULL,
2297     EL_SATELLITE,
2298     EL_SP_DISK_YELLOW,
2299     EL_BALLOON,
2300     -1
2301   };
2302
2303   static int ep_explodes_cross_old[] =
2304   {
2305     -1
2306   };
2307
2308   static int ep_protected[] =
2309   {
2310     /* same elements as in 'ep_walkable_inside' */
2311     EL_TUBE_ANY,
2312     EL_TUBE_VERTICAL,
2313     EL_TUBE_HORIZONTAL,
2314     EL_TUBE_VERTICAL_LEFT,
2315     EL_TUBE_VERTICAL_RIGHT,
2316     EL_TUBE_HORIZONTAL_UP,
2317     EL_TUBE_HORIZONTAL_DOWN,
2318     EL_TUBE_LEFT_UP,
2319     EL_TUBE_LEFT_DOWN,
2320     EL_TUBE_RIGHT_UP,
2321     EL_TUBE_RIGHT_DOWN,
2322
2323     /* same elements as in 'ep_passable_over' */
2324     EL_EM_GATE_1,
2325     EL_EM_GATE_2,
2326     EL_EM_GATE_3,
2327     EL_EM_GATE_4,
2328     EL_EM_GATE_1_GRAY,
2329     EL_EM_GATE_2_GRAY,
2330     EL_EM_GATE_3_GRAY,
2331     EL_EM_GATE_4_GRAY,
2332     EL_SWITCHGATE_OPEN,
2333     EL_TIMEGATE_OPEN,
2334
2335     /* same elements as in 'ep_passable_inside' */
2336     EL_SP_PORT_LEFT,
2337     EL_SP_PORT_RIGHT,
2338     EL_SP_PORT_UP,
2339     EL_SP_PORT_DOWN,
2340     EL_SP_PORT_HORIZONTAL,
2341     EL_SP_PORT_VERTICAL,
2342     EL_SP_PORT_ANY,
2343     EL_SP_GRAVITY_PORT_LEFT,
2344     EL_SP_GRAVITY_PORT_RIGHT,
2345     EL_SP_GRAVITY_PORT_UP,
2346     EL_SP_GRAVITY_PORT_DOWN,
2347     EL_SP_GRAVITY_ON_PORT_LEFT,
2348     EL_SP_GRAVITY_ON_PORT_RIGHT,
2349     EL_SP_GRAVITY_ON_PORT_UP,
2350     EL_SP_GRAVITY_ON_PORT_DOWN,
2351     EL_SP_GRAVITY_OFF_PORT_LEFT,
2352     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2353     EL_SP_GRAVITY_OFF_PORT_UP,
2354     EL_SP_GRAVITY_OFF_PORT_DOWN,
2355     -1
2356   };
2357
2358   static int ep_throwable[] =
2359   {
2360     -1
2361   };
2362
2363   static int ep_can_explode[] =
2364   {
2365     /* same elements as in 'ep_explodes_impact' */
2366     EL_BOMB,
2367     EL_SP_DISK_ORANGE,
2368     EL_DX_SUPABOMB,
2369
2370     /* same elements as in 'ep_explodes_smashed' */
2371     EL_SATELLITE,
2372     EL_PIG,
2373     EL_DRAGON,
2374     EL_MOLE,
2375
2376     /* elements that can explode by explosion or by dragonfire */
2377     EL_DYNAMITE_ACTIVE,
2378     EL_DYNAMITE,
2379     EL_DYNABOMB_PLAYER_1_ACTIVE,
2380     EL_DYNABOMB_PLAYER_2_ACTIVE,
2381     EL_DYNABOMB_PLAYER_3_ACTIVE,
2382     EL_DYNABOMB_PLAYER_4_ACTIVE,
2383     EL_DYNABOMB_INCREASE_NUMBER,
2384     EL_DYNABOMB_INCREASE_SIZE,
2385     EL_DYNABOMB_INCREASE_POWER,
2386     EL_SP_DISK_RED_ACTIVE,
2387     EL_BUG,
2388     EL_PENGUIN,
2389     EL_SP_DISK_RED,
2390     EL_SP_DISK_YELLOW,
2391     EL_SP_SNIKSNAK,
2392     EL_SP_ELECTRON,
2393
2394     /* elements that can explode only by explosion */
2395     EL_BLACK_ORB,
2396     -1
2397   };
2398
2399   static int ep_gravity_reachable[] =
2400   {
2401     EL_SAND,
2402     EL_SP_BASE,
2403     EL_TRAP,
2404     EL_INVISIBLE_SAND,
2405     EL_INVISIBLE_SAND_ACTIVE,
2406     EL_SP_PORT_LEFT,
2407     EL_SP_PORT_RIGHT,
2408     EL_SP_PORT_UP,
2409     EL_SP_PORT_DOWN,
2410     EL_SP_PORT_HORIZONTAL,
2411     EL_SP_PORT_VERTICAL,
2412     EL_SP_PORT_ANY,
2413     EL_SP_GRAVITY_PORT_LEFT,
2414     EL_SP_GRAVITY_PORT_RIGHT,
2415     EL_SP_GRAVITY_PORT_UP,
2416     EL_SP_GRAVITY_PORT_DOWN,
2417     EL_SP_GRAVITY_ON_PORT_LEFT,
2418     EL_SP_GRAVITY_ON_PORT_RIGHT,
2419     EL_SP_GRAVITY_ON_PORT_UP,
2420     EL_SP_GRAVITY_ON_PORT_DOWN,
2421     EL_SP_GRAVITY_OFF_PORT_LEFT,
2422     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2423     EL_SP_GRAVITY_OFF_PORT_UP,
2424     EL_SP_GRAVITY_OFF_PORT_DOWN,
2425     -1
2426   };
2427
2428   static int ep_player[] =
2429   {
2430     EL_PLAYER_1,
2431     EL_PLAYER_2,
2432     EL_PLAYER_3,
2433     EL_PLAYER_4,
2434     EL_SP_MURPHY,
2435     EL_SOKOBAN_FIELD_PLAYER,
2436     EL_TRIGGER_PLAYER,
2437     -1
2438   };
2439
2440   static int ep_can_pass_magic_wall[] =
2441   {
2442     EL_ROCK,
2443     EL_BD_ROCK,
2444     EL_EMERALD,
2445     EL_BD_DIAMOND,
2446     EL_EMERALD_YELLOW,
2447     EL_EMERALD_RED,
2448     EL_EMERALD_PURPLE,
2449     EL_DIAMOND,
2450     -1
2451   };
2452
2453   static int ep_switchable[] =
2454   {
2455     EL_ROBOT_WHEEL,
2456     EL_SP_TERMINAL,
2457     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2458     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2459     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2460     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2461     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2462     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2463     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2464     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2465     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2466     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2467     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2468     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2469     EL_SWITCHGATE_SWITCH_UP,
2470     EL_SWITCHGATE_SWITCH_DOWN,
2471     EL_LIGHT_SWITCH,
2472     EL_LIGHT_SWITCH_ACTIVE,
2473     EL_TIMEGATE_SWITCH,
2474     EL_BALLOON_SWITCH_LEFT,
2475     EL_BALLOON_SWITCH_RIGHT,
2476     EL_BALLOON_SWITCH_UP,
2477     EL_BALLOON_SWITCH_DOWN,
2478     EL_BALLOON_SWITCH_ANY,
2479     EL_LAMP,
2480     EL_TIME_ORB_FULL,
2481     -1
2482   };
2483
2484   static int ep_bd_element[] =
2485   {
2486     EL_EMPTY,
2487     EL_SAND,
2488     EL_WALL_SLIPPERY,
2489     EL_BD_WALL,
2490     EL_ROCK,
2491     EL_BD_ROCK,
2492     EL_BD_DIAMOND,
2493     EL_BD_MAGIC_WALL,
2494     EL_EXIT_CLOSED,
2495     EL_EXIT_OPEN,
2496     EL_STEELWALL,
2497     EL_PLAYER_1,
2498     EL_PLAYER_2,
2499     EL_PLAYER_3,
2500     EL_PLAYER_4,
2501     EL_BD_FIREFLY,
2502     EL_BD_FIREFLY_1,
2503     EL_BD_FIREFLY_2,
2504     EL_BD_FIREFLY_3,
2505     EL_BD_FIREFLY_4,
2506     EL_BD_BUTTERFLY,
2507     EL_BD_BUTTERFLY_1,
2508     EL_BD_BUTTERFLY_2,
2509     EL_BD_BUTTERFLY_3,
2510     EL_BD_BUTTERFLY_4,
2511     EL_BD_AMOEBA,
2512     EL_CHAR_QUESTION,
2513     EL_UNKNOWN,
2514     -1
2515   };
2516
2517   static int ep_sp_element[] =
2518   {
2519     /* should always be valid */
2520     EL_EMPTY,
2521
2522     /* standard classic Supaplex elements */
2523     EL_SP_EMPTY,
2524     EL_SP_ZONK,
2525     EL_SP_BASE,
2526     EL_SP_MURPHY,
2527     EL_SP_INFOTRON,
2528     EL_SP_CHIP_SINGLE,
2529     EL_SP_HARDWARE_GRAY,
2530     EL_SP_EXIT_CLOSED,
2531     EL_SP_EXIT_OPEN,
2532     EL_SP_DISK_ORANGE,
2533     EL_SP_PORT_RIGHT,
2534     EL_SP_PORT_DOWN,
2535     EL_SP_PORT_LEFT,
2536     EL_SP_PORT_UP,
2537     EL_SP_GRAVITY_PORT_RIGHT,
2538     EL_SP_GRAVITY_PORT_DOWN,
2539     EL_SP_GRAVITY_PORT_LEFT,
2540     EL_SP_GRAVITY_PORT_UP,
2541     EL_SP_SNIKSNAK,
2542     EL_SP_DISK_YELLOW,
2543     EL_SP_TERMINAL,
2544     EL_SP_DISK_RED,
2545     EL_SP_PORT_VERTICAL,
2546     EL_SP_PORT_HORIZONTAL,
2547     EL_SP_PORT_ANY,
2548     EL_SP_ELECTRON,
2549     EL_SP_BUGGY_BASE,
2550     EL_SP_CHIP_LEFT,
2551     EL_SP_CHIP_RIGHT,
2552     EL_SP_HARDWARE_BASE_1,
2553     EL_SP_HARDWARE_GREEN,
2554     EL_SP_HARDWARE_BLUE,
2555     EL_SP_HARDWARE_RED,
2556     EL_SP_HARDWARE_YELLOW,
2557     EL_SP_HARDWARE_BASE_2,
2558     EL_SP_HARDWARE_BASE_3,
2559     EL_SP_HARDWARE_BASE_4,
2560     EL_SP_HARDWARE_BASE_5,
2561     EL_SP_HARDWARE_BASE_6,
2562     EL_SP_CHIP_TOP,
2563     EL_SP_CHIP_BOTTOM,
2564
2565     /* additional elements that appeared in newer Supaplex levels */
2566     EL_INVISIBLE_WALL,
2567
2568     /* additional gravity port elements (not switching, but setting gravity) */
2569     EL_SP_GRAVITY_ON_PORT_LEFT,
2570     EL_SP_GRAVITY_ON_PORT_RIGHT,
2571     EL_SP_GRAVITY_ON_PORT_UP,
2572     EL_SP_GRAVITY_ON_PORT_DOWN,
2573     EL_SP_GRAVITY_OFF_PORT_LEFT,
2574     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2575     EL_SP_GRAVITY_OFF_PORT_UP,
2576     EL_SP_GRAVITY_OFF_PORT_DOWN,
2577
2578     /* more than one Murphy in a level results in an inactive clone */
2579     EL_SP_MURPHY_CLONE,
2580
2581     /* runtime Supaplex elements */
2582     EL_SP_DISK_RED_ACTIVE,
2583     EL_SP_TERMINAL_ACTIVE,
2584     EL_SP_BUGGY_BASE_ACTIVATING,
2585     EL_SP_BUGGY_BASE_ACTIVE,
2586     EL_SP_EXIT_OPENING,
2587     EL_SP_EXIT_CLOSING,
2588     -1
2589   };
2590
2591   static int ep_sb_element[] =
2592   {
2593     EL_EMPTY,
2594     EL_STEELWALL,
2595     EL_SOKOBAN_OBJECT,
2596     EL_SOKOBAN_FIELD_EMPTY,
2597     EL_SOKOBAN_FIELD_FULL,
2598     EL_SOKOBAN_FIELD_PLAYER,
2599     EL_PLAYER_1,
2600     EL_PLAYER_2,
2601     EL_PLAYER_3,
2602     EL_PLAYER_4,
2603     EL_INVISIBLE_STEELWALL,
2604     -1
2605   };
2606
2607   static int ep_gem[] =
2608   {
2609     EL_BD_DIAMOND,
2610     EL_EMERALD,
2611     EL_EMERALD_YELLOW,
2612     EL_EMERALD_RED,
2613     EL_EMERALD_PURPLE,
2614     EL_DIAMOND,
2615     -1
2616   };
2617
2618   static int ep_food_dark_yamyam[] =
2619   {
2620     EL_SAND,
2621     EL_BUG,
2622     EL_SPACESHIP,
2623     EL_BD_BUTTERFLY,
2624     EL_BD_FIREFLY,
2625     EL_YAMYAM,
2626     EL_ROBOT,
2627     EL_PACMAN,
2628     EL_AMOEBA_DROP,
2629     EL_AMOEBA_DEAD,
2630     EL_AMOEBA_WET,
2631     EL_AMOEBA_DRY,
2632     EL_AMOEBA_FULL,
2633     EL_BD_AMOEBA,
2634     EL_EMERALD,
2635     EL_BD_DIAMOND,
2636     EL_EMERALD_YELLOW,
2637     EL_EMERALD_RED,
2638     EL_EMERALD_PURPLE,
2639     EL_DIAMOND,
2640     EL_PEARL,
2641     EL_CRYSTAL,
2642     -1
2643   };
2644
2645   static int ep_food_penguin[] =
2646   {
2647     EL_EMERALD,
2648     EL_BD_DIAMOND,
2649     EL_EMERALD_YELLOW,
2650     EL_EMERALD_RED,
2651     EL_EMERALD_PURPLE,
2652     EL_DIAMOND,
2653     EL_PEARL,
2654     EL_CRYSTAL,
2655     -1
2656   };
2657
2658   static int ep_food_pig[] =
2659   {
2660     EL_EMERALD,
2661     EL_BD_DIAMOND,
2662     EL_EMERALD_YELLOW,
2663     EL_EMERALD_RED,
2664     EL_EMERALD_PURPLE,
2665     EL_DIAMOND,
2666     -1
2667   };
2668
2669   static int ep_historic_wall[] =
2670   {
2671     EL_STEELWALL,
2672     EL_GATE_1,
2673     EL_GATE_2,
2674     EL_GATE_3,
2675     EL_GATE_4,
2676     EL_GATE_1_GRAY,
2677     EL_GATE_2_GRAY,
2678     EL_GATE_3_GRAY,
2679     EL_GATE_4_GRAY,
2680     EL_EM_GATE_1,
2681     EL_EM_GATE_2,
2682     EL_EM_GATE_3,
2683     EL_EM_GATE_4,
2684     EL_EM_GATE_1_GRAY,
2685     EL_EM_GATE_2_GRAY,
2686     EL_EM_GATE_3_GRAY,
2687     EL_EM_GATE_4_GRAY,
2688     EL_EXIT_CLOSED,
2689     EL_EXIT_OPENING,
2690     EL_EXIT_OPEN,
2691     EL_WALL,
2692     EL_WALL_SLIPPERY,
2693     EL_EXPANDABLE_WALL,
2694     EL_EXPANDABLE_WALL_HORIZONTAL,
2695     EL_EXPANDABLE_WALL_VERTICAL,
2696     EL_EXPANDABLE_WALL_ANY,
2697     EL_EXPANDABLE_WALL_GROWING,
2698     EL_BD_WALL,
2699     EL_SP_CHIP_SINGLE,
2700     EL_SP_CHIP_LEFT,
2701     EL_SP_CHIP_RIGHT,
2702     EL_SP_CHIP_TOP,
2703     EL_SP_CHIP_BOTTOM,
2704     EL_SP_HARDWARE_GRAY,
2705     EL_SP_HARDWARE_GREEN,
2706     EL_SP_HARDWARE_BLUE,
2707     EL_SP_HARDWARE_RED,
2708     EL_SP_HARDWARE_YELLOW,
2709     EL_SP_HARDWARE_BASE_1,
2710     EL_SP_HARDWARE_BASE_2,
2711     EL_SP_HARDWARE_BASE_3,
2712     EL_SP_HARDWARE_BASE_4,
2713     EL_SP_HARDWARE_BASE_5,
2714     EL_SP_HARDWARE_BASE_6,
2715     EL_SP_TERMINAL,
2716     EL_SP_TERMINAL_ACTIVE,
2717     EL_SP_EXIT_CLOSED,
2718     EL_SP_EXIT_OPEN,
2719     EL_INVISIBLE_STEELWALL,
2720     EL_INVISIBLE_STEELWALL_ACTIVE,
2721     EL_INVISIBLE_WALL,
2722     EL_INVISIBLE_WALL_ACTIVE,
2723     EL_STEELWALL_SLIPPERY,
2724     EL_EMC_STEELWALL_1,
2725     EL_EMC_STEELWALL_2,
2726     EL_EMC_STEELWALL_3,
2727     EL_EMC_STEELWALL_4,
2728     EL_EMC_WALL_1,
2729     EL_EMC_WALL_2,
2730     EL_EMC_WALL_3,
2731     EL_EMC_WALL_4,
2732     EL_EMC_WALL_5,
2733     EL_EMC_WALL_6,
2734     EL_EMC_WALL_7,
2735     EL_EMC_WALL_8,
2736     -1
2737   };
2738
2739   static int ep_historic_solid[] =
2740   {
2741     EL_WALL,
2742     EL_EXPANDABLE_WALL,
2743     EL_EXPANDABLE_WALL_HORIZONTAL,
2744     EL_EXPANDABLE_WALL_VERTICAL,
2745     EL_EXPANDABLE_WALL_ANY,
2746     EL_BD_WALL,
2747     EL_WALL_SLIPPERY,
2748     EL_EXIT_CLOSED,
2749     EL_EXIT_OPENING,
2750     EL_EXIT_OPEN,
2751     EL_AMOEBA_DEAD,
2752     EL_AMOEBA_WET,
2753     EL_AMOEBA_DRY,
2754     EL_AMOEBA_FULL,
2755     EL_BD_AMOEBA,
2756     EL_QUICKSAND_EMPTY,
2757     EL_QUICKSAND_FULL,
2758     EL_QUICKSAND_FILLING,
2759     EL_QUICKSAND_EMPTYING,
2760     EL_MAGIC_WALL,
2761     EL_MAGIC_WALL_ACTIVE,
2762     EL_MAGIC_WALL_EMPTYING,
2763     EL_MAGIC_WALL_FILLING,
2764     EL_MAGIC_WALL_FULL,
2765     EL_MAGIC_WALL_DEAD,
2766     EL_BD_MAGIC_WALL,
2767     EL_BD_MAGIC_WALL_ACTIVE,
2768     EL_BD_MAGIC_WALL_EMPTYING,
2769     EL_BD_MAGIC_WALL_FULL,
2770     EL_BD_MAGIC_WALL_FILLING,
2771     EL_BD_MAGIC_WALL_DEAD,
2772     EL_GAME_OF_LIFE,
2773     EL_BIOMAZE,
2774     EL_SP_CHIP_SINGLE,
2775     EL_SP_CHIP_LEFT,
2776     EL_SP_CHIP_RIGHT,
2777     EL_SP_CHIP_TOP,
2778     EL_SP_CHIP_BOTTOM,
2779     EL_SP_TERMINAL,
2780     EL_SP_TERMINAL_ACTIVE,
2781     EL_SP_EXIT_CLOSED,
2782     EL_SP_EXIT_OPEN,
2783     EL_INVISIBLE_WALL,
2784     EL_INVISIBLE_WALL_ACTIVE,
2785     EL_SWITCHGATE_SWITCH_UP,
2786     EL_SWITCHGATE_SWITCH_DOWN,
2787     EL_TIMEGATE_SWITCH,
2788     EL_TIMEGATE_SWITCH_ACTIVE,
2789     EL_EMC_WALL_1,
2790     EL_EMC_WALL_2,
2791     EL_EMC_WALL_3,
2792     EL_EMC_WALL_4,
2793     EL_EMC_WALL_5,
2794     EL_EMC_WALL_6,
2795     EL_EMC_WALL_7,
2796     EL_EMC_WALL_8,
2797     EL_WALL_PEARL,
2798     EL_WALL_CRYSTAL,
2799
2800     /* the following elements are a direct copy of "indestructible" elements,
2801        except "EL_ACID", which is "indestructible", but not "solid"! */
2802 #if 0
2803     EL_ACID,
2804 #endif
2805     EL_STEELWALL,
2806     EL_ACID_POOL_TOPLEFT,
2807     EL_ACID_POOL_TOPRIGHT,
2808     EL_ACID_POOL_BOTTOMLEFT,
2809     EL_ACID_POOL_BOTTOM,
2810     EL_ACID_POOL_BOTTOMRIGHT,
2811     EL_SP_HARDWARE_GRAY,
2812     EL_SP_HARDWARE_GREEN,
2813     EL_SP_HARDWARE_BLUE,
2814     EL_SP_HARDWARE_RED,
2815     EL_SP_HARDWARE_YELLOW,
2816     EL_SP_HARDWARE_BASE_1,
2817     EL_SP_HARDWARE_BASE_2,
2818     EL_SP_HARDWARE_BASE_3,
2819     EL_SP_HARDWARE_BASE_4,
2820     EL_SP_HARDWARE_BASE_5,
2821     EL_SP_HARDWARE_BASE_6,
2822     EL_INVISIBLE_STEELWALL,
2823     EL_INVISIBLE_STEELWALL_ACTIVE,
2824     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2825     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2826     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2827     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2828     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2829     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2830     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2831     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2832     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2833     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2834     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2835     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2836     EL_LIGHT_SWITCH,
2837     EL_LIGHT_SWITCH_ACTIVE,
2838     EL_SIGN_EXCLAMATION,
2839     EL_SIGN_RADIOACTIVITY,
2840     EL_SIGN_STOP,
2841     EL_SIGN_WHEELCHAIR,
2842     EL_SIGN_PARKING,
2843     EL_SIGN_ONEWAY,
2844     EL_SIGN_HEART,
2845     EL_SIGN_TRIANGLE,
2846     EL_SIGN_ROUND,
2847     EL_SIGN_EXIT,
2848     EL_SIGN_YINYANG,
2849     EL_SIGN_OTHER,
2850     EL_STEELWALL_SLIPPERY,
2851     EL_EMC_STEELWALL_1,
2852     EL_EMC_STEELWALL_2,
2853     EL_EMC_STEELWALL_3,
2854     EL_EMC_STEELWALL_4,
2855     EL_CRYSTAL,
2856     EL_GATE_1,
2857     EL_GATE_2,
2858     EL_GATE_3,
2859     EL_GATE_4,
2860     EL_GATE_1_GRAY,
2861     EL_GATE_2_GRAY,
2862     EL_GATE_3_GRAY,
2863     EL_GATE_4_GRAY,
2864     EL_EM_GATE_1,
2865     EL_EM_GATE_2,
2866     EL_EM_GATE_3,
2867     EL_EM_GATE_4,
2868     EL_EM_GATE_1_GRAY,
2869     EL_EM_GATE_2_GRAY,
2870     EL_EM_GATE_3_GRAY,
2871     EL_EM_GATE_4_GRAY,
2872     EL_SWITCHGATE_OPEN,
2873     EL_SWITCHGATE_OPENING,
2874     EL_SWITCHGATE_CLOSED,
2875     EL_SWITCHGATE_CLOSING,
2876     EL_TIMEGATE_OPEN,
2877     EL_TIMEGATE_OPENING,
2878     EL_TIMEGATE_CLOSED,
2879     EL_TIMEGATE_CLOSING,
2880     EL_TUBE_ANY,
2881     EL_TUBE_VERTICAL,
2882     EL_TUBE_HORIZONTAL,
2883     EL_TUBE_VERTICAL_LEFT,
2884     EL_TUBE_VERTICAL_RIGHT,
2885     EL_TUBE_HORIZONTAL_UP,
2886     EL_TUBE_HORIZONTAL_DOWN,
2887     EL_TUBE_LEFT_UP,
2888     EL_TUBE_LEFT_DOWN,
2889     EL_TUBE_RIGHT_UP,
2890     EL_TUBE_RIGHT_DOWN,
2891     -1
2892   };
2893
2894   static int ep_classic_enemy[] =
2895   {
2896     EL_BUG,
2897     EL_SPACESHIP,
2898     EL_BD_BUTTERFLY,
2899     EL_BD_FIREFLY,
2900
2901     EL_YAMYAM,
2902     EL_DARK_YAMYAM,
2903     EL_ROBOT,
2904     EL_PACMAN,
2905     EL_SP_SNIKSNAK,
2906     EL_SP_ELECTRON,
2907     -1
2908   };
2909
2910   static int ep_belt[] =
2911   {
2912     EL_CONVEYOR_BELT_1_LEFT,
2913     EL_CONVEYOR_BELT_1_MIDDLE,
2914     EL_CONVEYOR_BELT_1_RIGHT,
2915     EL_CONVEYOR_BELT_2_LEFT,
2916     EL_CONVEYOR_BELT_2_MIDDLE,
2917     EL_CONVEYOR_BELT_2_RIGHT,
2918     EL_CONVEYOR_BELT_3_LEFT,
2919     EL_CONVEYOR_BELT_3_MIDDLE,
2920     EL_CONVEYOR_BELT_3_RIGHT,
2921     EL_CONVEYOR_BELT_4_LEFT,
2922     EL_CONVEYOR_BELT_4_MIDDLE,
2923     EL_CONVEYOR_BELT_4_RIGHT,
2924     -1
2925   };
2926
2927   static int ep_belt_active[] =
2928   {
2929     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2930     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2931     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2932     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2933     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2934     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2935     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2936     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2937     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2938     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2939     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2940     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2941     -1
2942   };
2943
2944   static int ep_belt_switch[] =
2945   {
2946     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2947     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2948     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2949     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2950     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2951     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2952     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2953     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2954     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2955     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2956     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2957     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2958     -1
2959   };
2960
2961   static int ep_tube[] =
2962   {
2963     EL_TUBE_LEFT_UP,
2964     EL_TUBE_LEFT_DOWN,
2965     EL_TUBE_RIGHT_UP,
2966     EL_TUBE_RIGHT_DOWN,
2967     EL_TUBE_HORIZONTAL,
2968     EL_TUBE_HORIZONTAL_UP,
2969     EL_TUBE_HORIZONTAL_DOWN,
2970     EL_TUBE_VERTICAL,
2971     EL_TUBE_VERTICAL_LEFT,
2972     EL_TUBE_VERTICAL_RIGHT,
2973     EL_TUBE_ANY,
2974     -1
2975   };
2976
2977   static int ep_keygate[] =
2978   {
2979     EL_GATE_1,
2980     EL_GATE_2,
2981     EL_GATE_3,
2982     EL_GATE_4,
2983     EL_GATE_1_GRAY,
2984     EL_GATE_2_GRAY,
2985     EL_GATE_3_GRAY,
2986     EL_GATE_4_GRAY,
2987     EL_EM_GATE_1,
2988     EL_EM_GATE_2,
2989     EL_EM_GATE_3,
2990     EL_EM_GATE_4,
2991     EL_EM_GATE_1_GRAY,
2992     EL_EM_GATE_2_GRAY,
2993     EL_EM_GATE_3_GRAY,
2994     EL_EM_GATE_4_GRAY,
2995     -1
2996   };
2997
2998   static int ep_amoeboid[] =
2999   {
3000     EL_AMOEBA_DEAD,
3001     EL_AMOEBA_WET,
3002     EL_AMOEBA_DRY,
3003     EL_AMOEBA_FULL,
3004     EL_BD_AMOEBA,
3005     -1
3006   };
3007
3008   static int ep_amoebalive[] =
3009   {
3010     EL_AMOEBA_WET,
3011     EL_AMOEBA_DRY,
3012     EL_AMOEBA_FULL,
3013     EL_BD_AMOEBA,
3014     -1
3015   };
3016
3017   static int ep_has_content[] =
3018   {
3019     EL_YAMYAM,
3020     EL_AMOEBA_WET,
3021     EL_AMOEBA_DRY,
3022     EL_AMOEBA_FULL,
3023     EL_BD_AMOEBA,
3024     -1
3025   };
3026
3027   static int ep_can_turn_each_move[] =
3028   {
3029     /* !!! do something with this one !!! */
3030     -1
3031   };
3032
3033   static int ep_can_grow[] =
3034   {
3035     EL_BD_AMOEBA,
3036     EL_AMOEBA_DROP,
3037     EL_AMOEBA_WET,
3038     EL_AMOEBA_DRY,
3039     EL_AMOEBA_FULL,
3040     EL_GAME_OF_LIFE,
3041     EL_BIOMAZE,
3042     -1
3043   };
3044
3045   static int ep_active_bomb[] =
3046   {
3047     EL_DYNAMITE_ACTIVE,
3048     EL_DYNABOMB_PLAYER_1_ACTIVE,
3049     EL_DYNABOMB_PLAYER_2_ACTIVE,
3050     EL_DYNABOMB_PLAYER_3_ACTIVE,
3051     EL_DYNABOMB_PLAYER_4_ACTIVE,
3052     EL_SP_DISK_RED_ACTIVE,
3053     -1
3054   };
3055
3056   static int ep_inactive[] =
3057   {
3058     EL_EMPTY,
3059     EL_SAND,
3060     EL_WALL,
3061     EL_BD_WALL,
3062     EL_WALL_SLIPPERY,
3063     EL_STEELWALL,
3064     EL_AMOEBA_DEAD,
3065     EL_QUICKSAND_EMPTY,
3066     EL_STONEBLOCK,
3067     EL_ROBOT_WHEEL,
3068     EL_KEY_1,
3069     EL_KEY_2,
3070     EL_KEY_3,
3071     EL_KEY_4,
3072     EL_EM_KEY_1,
3073     EL_EM_KEY_2,
3074     EL_EM_KEY_3,
3075     EL_EM_KEY_4,
3076     EL_GATE_1,
3077     EL_GATE_2,
3078     EL_GATE_3,
3079     EL_GATE_4,
3080     EL_GATE_1_GRAY,
3081     EL_GATE_2_GRAY,
3082     EL_GATE_3_GRAY,
3083     EL_GATE_4_GRAY,
3084     EL_EM_GATE_1,
3085     EL_EM_GATE_2,
3086     EL_EM_GATE_3,
3087     EL_EM_GATE_4,
3088     EL_EM_GATE_1_GRAY,
3089     EL_EM_GATE_2_GRAY,
3090     EL_EM_GATE_3_GRAY,
3091     EL_EM_GATE_4_GRAY,
3092     EL_DYNAMITE,
3093     EL_INVISIBLE_STEELWALL,
3094     EL_INVISIBLE_WALL,
3095     EL_INVISIBLE_SAND,
3096     EL_LAMP,
3097     EL_LAMP_ACTIVE,
3098     EL_WALL_EMERALD,
3099     EL_WALL_DIAMOND,
3100     EL_WALL_BD_DIAMOND,
3101     EL_WALL_EMERALD_YELLOW,
3102     EL_DYNABOMB_INCREASE_NUMBER,
3103     EL_DYNABOMB_INCREASE_SIZE,
3104     EL_DYNABOMB_INCREASE_POWER,
3105 #if 0
3106     EL_SOKOBAN_OBJECT,
3107 #endif
3108     EL_SOKOBAN_FIELD_EMPTY,
3109     EL_SOKOBAN_FIELD_FULL,
3110     EL_WALL_EMERALD_RED,
3111     EL_WALL_EMERALD_PURPLE,
3112     EL_ACID_POOL_TOPLEFT,
3113     EL_ACID_POOL_TOPRIGHT,
3114     EL_ACID_POOL_BOTTOMLEFT,
3115     EL_ACID_POOL_BOTTOM,
3116     EL_ACID_POOL_BOTTOMRIGHT,
3117     EL_MAGIC_WALL,
3118     EL_MAGIC_WALL_DEAD,
3119     EL_BD_MAGIC_WALL,
3120     EL_BD_MAGIC_WALL_DEAD,
3121     EL_AMOEBA_TO_DIAMOND,
3122     EL_BLOCKED,
3123     EL_SP_EMPTY,
3124     EL_SP_BASE,
3125     EL_SP_PORT_RIGHT,
3126     EL_SP_PORT_DOWN,
3127     EL_SP_PORT_LEFT,
3128     EL_SP_PORT_UP,
3129     EL_SP_GRAVITY_PORT_RIGHT,
3130     EL_SP_GRAVITY_PORT_DOWN,
3131     EL_SP_GRAVITY_PORT_LEFT,
3132     EL_SP_GRAVITY_PORT_UP,
3133     EL_SP_PORT_HORIZONTAL,
3134     EL_SP_PORT_VERTICAL,
3135     EL_SP_PORT_ANY,
3136     EL_SP_DISK_RED,
3137 #if 0
3138     EL_SP_DISK_YELLOW,
3139 #endif
3140     EL_SP_CHIP_SINGLE,
3141     EL_SP_CHIP_LEFT,
3142     EL_SP_CHIP_RIGHT,
3143     EL_SP_CHIP_TOP,
3144     EL_SP_CHIP_BOTTOM,
3145     EL_SP_HARDWARE_GRAY,
3146     EL_SP_HARDWARE_GREEN,
3147     EL_SP_HARDWARE_BLUE,
3148     EL_SP_HARDWARE_RED,
3149     EL_SP_HARDWARE_YELLOW,
3150     EL_SP_HARDWARE_BASE_1,
3151     EL_SP_HARDWARE_BASE_2,
3152     EL_SP_HARDWARE_BASE_3,
3153     EL_SP_HARDWARE_BASE_4,
3154     EL_SP_HARDWARE_BASE_5,
3155     EL_SP_HARDWARE_BASE_6,
3156     EL_SP_GRAVITY_ON_PORT_LEFT,
3157     EL_SP_GRAVITY_ON_PORT_RIGHT,
3158     EL_SP_GRAVITY_ON_PORT_UP,
3159     EL_SP_GRAVITY_ON_PORT_DOWN,
3160     EL_SP_GRAVITY_OFF_PORT_LEFT,
3161     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3162     EL_SP_GRAVITY_OFF_PORT_UP,
3163     EL_SP_GRAVITY_OFF_PORT_DOWN,
3164     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3165     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3166     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3167     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3168     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3169     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3170     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3171     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3172     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3173     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3174     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3175     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3176     EL_SIGN_EXCLAMATION,
3177     EL_SIGN_RADIOACTIVITY,
3178     EL_SIGN_STOP,
3179     EL_SIGN_WHEELCHAIR,
3180     EL_SIGN_PARKING,
3181     EL_SIGN_ONEWAY,
3182     EL_SIGN_HEART,
3183     EL_SIGN_TRIANGLE,
3184     EL_SIGN_ROUND,
3185     EL_SIGN_EXIT,
3186     EL_SIGN_YINYANG,
3187     EL_SIGN_OTHER,
3188     EL_STEELWALL_SLIPPERY,
3189     EL_EMC_STEELWALL_1,
3190     EL_EMC_STEELWALL_2,
3191     EL_EMC_STEELWALL_3,
3192     EL_EMC_STEELWALL_4,
3193     EL_EMC_WALL_1,
3194     EL_EMC_WALL_2,
3195     EL_EMC_WALL_3,
3196     EL_EMC_WALL_4,
3197     EL_EMC_WALL_5,
3198     EL_EMC_WALL_6,
3199     EL_EMC_WALL_7,
3200     EL_EMC_WALL_8,
3201     -1
3202   };
3203
3204   static int ep_em_slippery_wall[] =
3205   {
3206     -1
3207   };
3208
3209   static int ep_gfx_crumbled[] =
3210   {
3211     EL_SAND,
3212     EL_LANDMINE,
3213     EL_TRAP,
3214     EL_TRAP_ACTIVE,
3215     -1
3216   };
3217
3218   static struct
3219   {
3220     int *elements;
3221     int property;
3222   } element_properties[] =
3223   {
3224     { ep_diggable,              EP_DIGGABLE             },
3225     { ep_collectible_only,      EP_COLLECTIBLE_ONLY     },
3226     { ep_dont_run_into,         EP_DONT_RUN_INTO        },
3227     { ep_dont_collide_with,     EP_DONT_COLLIDE_WITH    },
3228     { ep_dont_touch,            EP_DONT_TOUCH           },
3229     { ep_indestructible,        EP_INDESTRUCTIBLE       },
3230     { ep_slippery,              EP_SLIPPERY             },
3231     { ep_can_change,            EP_CAN_CHANGE           },
3232     { ep_can_move,              EP_CAN_MOVE             },
3233     { ep_can_fall,              EP_CAN_FALL             },
3234     { ep_can_smash_player,      EP_CAN_SMASH_PLAYER     },
3235     { ep_can_smash_enemies,     EP_CAN_SMASH_ENEMIES    },
3236     { ep_can_smash_everything,  EP_CAN_SMASH_EVERYTHING },
3237     { ep_explodes_by_fire,      EP_EXPLODES_BY_FIRE     },
3238     { ep_explodes_smashed,      EP_EXPLODES_SMASHED     },
3239     { ep_explodes_impact,       EP_EXPLODES_IMPACT      },
3240     { ep_walkable_over,         EP_WALKABLE_OVER        },
3241     { ep_walkable_inside,       EP_WALKABLE_INSIDE      },
3242     { ep_walkable_under,        EP_WALKABLE_UNDER       },
3243     { ep_passable_over,         EP_PASSABLE_OVER        },
3244     { ep_passable_inside,       EP_PASSABLE_INSIDE      },
3245     { ep_passable_under,        EP_PASSABLE_UNDER       },
3246     { ep_droppable,             EP_DROPPABLE            },
3247     { ep_explodes_1x1_old,      EP_EXPLODES_1X1_OLD     },
3248     { ep_pushable,              EP_PUSHABLE             },
3249     { ep_explodes_cross_old,    EP_EXPLODES_CROSS_OLD   },
3250     { ep_protected,             EP_PROTECTED            },
3251     { ep_throwable,             EP_THROWABLE            },
3252     { ep_can_explode,           EP_CAN_EXPLODE          },
3253     { ep_gravity_reachable,     EP_GRAVITY_REACHABLE    },
3254
3255     { ep_player,                EP_PLAYER               },
3256     { ep_can_pass_magic_wall,   EP_CAN_PASS_MAGIC_WALL  },
3257     { ep_switchable,            EP_SWITCHABLE           },
3258     { ep_bd_element,            EP_BD_ELEMENT           },
3259     { ep_sp_element,            EP_SP_ELEMENT           },
3260     { ep_sb_element,            EP_SB_ELEMENT           },
3261     { ep_gem,                   EP_GEM                  },
3262     { ep_food_dark_yamyam,      EP_FOOD_DARK_YAMYAM     },
3263     { ep_food_penguin,          EP_FOOD_PENGUIN         },
3264     { ep_food_pig,              EP_FOOD_PIG             },
3265     { ep_historic_wall,         EP_HISTORIC_WALL        },
3266     { ep_historic_solid,        EP_HISTORIC_SOLID       },
3267     { ep_classic_enemy,         EP_CLASSIC_ENEMY        },
3268     { ep_belt,                  EP_BELT                 },
3269     { ep_belt_active,           EP_BELT_ACTIVE          },
3270     { ep_belt_switch,           EP_BELT_SWITCH          },
3271     { ep_tube,                  EP_TUBE                 },
3272     { ep_keygate,               EP_KEYGATE              },
3273     { ep_amoeboid,              EP_AMOEBOID             },
3274     { ep_amoebalive,            EP_AMOEBALIVE           },
3275     { ep_has_content,           EP_HAS_CONTENT          },
3276     { ep_can_turn_each_move,    EP_CAN_TURN_EACH_MOVE   },
3277     { ep_can_grow,              EP_CAN_GROW             },
3278     { ep_active_bomb,           EP_ACTIVE_BOMB          },
3279     { ep_inactive,              EP_INACTIVE             },
3280
3281     { ep_em_slippery_wall,      EP_EM_SLIPPERY_WALL     },
3282
3283     { ep_gfx_crumbled,          EP_GFX_CRUMBLED         },
3284
3285     { NULL,                     -1                      }
3286   };
3287
3288   static int copy_properties[][5] =
3289   {
3290     {
3291       EL_BUG,
3292       EL_BUG_LEFT,              EL_BUG_RIGHT,
3293       EL_BUG_UP,                EL_BUG_DOWN
3294     },
3295     {
3296       EL_SPACESHIP,
3297       EL_SPACESHIP_LEFT,        EL_SPACESHIP_RIGHT,
3298       EL_SPACESHIP_UP,          EL_SPACESHIP_DOWN
3299     },
3300     {
3301       EL_BD_BUTTERFLY,
3302       EL_BD_BUTTERFLY_LEFT,     EL_BD_BUTTERFLY_RIGHT,
3303       EL_BD_BUTTERFLY_UP,       EL_BD_BUTTERFLY_DOWN
3304     },
3305     {
3306       EL_BD_FIREFLY,
3307       EL_BD_FIREFLY_LEFT,       EL_BD_FIREFLY_RIGHT,
3308       EL_BD_FIREFLY_UP,         EL_BD_FIREFLY_DOWN
3309     },
3310     {
3311       EL_PACMAN,
3312       EL_PACMAN_LEFT,           EL_PACMAN_RIGHT,
3313       EL_PACMAN_UP,             EL_PACMAN_DOWN
3314     },
3315     {
3316       EL_MOLE,
3317       EL_MOLE_LEFT,             EL_MOLE_RIGHT,
3318       EL_MOLE_UP,               EL_MOLE_DOWN
3319     },
3320     {
3321       -1,
3322       -1, -1, -1, -1
3323     }
3324   };
3325
3326   int i, j, k;
3327
3328   /* always start with reliable default values (element has no properties) */
3329   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3330     for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3331       SET_PROPERTY(i, j, FALSE);
3332
3333   /* set all base element properties from above array definitions */
3334   for (i = 0; element_properties[i].elements != NULL; i++)
3335     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3336       SET_PROPERTY((element_properties[i].elements)[j],
3337                    element_properties[i].property, TRUE);
3338
3339   /* copy properties to some elements that are only stored in level file */
3340   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3341     for (j = 0; copy_properties[j][0] != -1; j++)
3342       if (HAS_PROPERTY(copy_properties[j][0], i))
3343         for (k = 1; k <= 4; k++)
3344           SET_PROPERTY(copy_properties[j][k], i, TRUE);
3345 }
3346
3347 void InitElementPropertiesEngine(int engine_version)
3348 {
3349 #if 0
3350   static int active_properties[] =
3351   {
3352     EP_AMOEBALIVE,
3353     EP_AMOEBOID,
3354     EP_PFORTE,
3355     EP_DONT_COLLIDE_WITH,
3356     EP_MAUER,
3357     EP_CAN_FALL,
3358     EP_CAN_SMASH,
3359     EP_CAN_PASS_MAGIC_WALL,
3360     EP_CAN_MOVE,
3361     EP_DONT_TOUCH,
3362     EP_DONT_RUN_INTO,
3363     EP_GEM,
3364     EP_EXPLODES_BY_FIRE,
3365     EP_PUSHABLE,
3366     EP_PLAYER,
3367     EP_HAS_CONTENT,
3368     EP_DIGGABLE,
3369     EP_PASSABLE_INSIDE,
3370     EP_OVER_PLAYER,
3371     EP_ACTIVE_BOMB,
3372
3373     EP_BELT,
3374     EP_BELT_ACTIVE,
3375     EP_BELT_SWITCH,
3376     EP_WALKABLE_UNDER,
3377     EP_EM_SLIPPERY_WALL,
3378   };
3379 #endif
3380
3381   static int no_wall_properties[] =
3382   {
3383     EP_DIGGABLE,
3384     EP_COLLECTIBLE_ONLY,
3385     EP_DONT_RUN_INTO,
3386     EP_DONT_COLLIDE_WITH,
3387     EP_CAN_MOVE,
3388     EP_CAN_FALL,
3389     EP_CAN_SMASH_PLAYER,
3390     EP_CAN_SMASH_ENEMIES,
3391     EP_CAN_SMASH_EVERYTHING,
3392     EP_PUSHABLE,
3393
3394     EP_PLAYER,
3395     EP_GEM,
3396     EP_FOOD_DARK_YAMYAM,
3397     EP_FOOD_PENGUIN,
3398     EP_BELT,
3399     EP_BELT_ACTIVE,
3400     EP_TUBE,
3401     EP_AMOEBOID,
3402     EP_AMOEBALIVE,
3403     EP_ACTIVE_BOMB,
3404
3405     EP_ACCESSIBLE,
3406
3407     -1
3408   };
3409
3410   int i, j;
3411
3412 #if 0
3413   InitElementPropertiesStatic();
3414 #endif
3415
3416   /* important: after initialization in InitElementPropertiesStatic(), the
3417      elements are not again initialized to a default value; therefore all
3418      changes have to make sure that they leave the element with a defined
3419      property (which means that conditional property changes must be set to
3420      a reliable default value before) */
3421
3422   /* set all special, combined or engine dependent element properties */
3423   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3424   {
3425 #if 0
3426     for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3427       SET_PROPERTY(i, j, FALSE);
3428 #endif
3429
3430     /* ---------- INACTIVE ------------------------------------------------- */
3431     SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3432
3433     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3434     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3435                                   IS_WALKABLE_INSIDE(i) ||
3436                                   IS_WALKABLE_UNDER(i)));
3437
3438     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3439                                   IS_PASSABLE_INSIDE(i) ||
3440                                   IS_PASSABLE_UNDER(i)));
3441
3442     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3443                                          IS_PASSABLE_OVER(i)));
3444
3445     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3446                                            IS_PASSABLE_INSIDE(i)));
3447
3448     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3449                                           IS_PASSABLE_UNDER(i)));
3450
3451     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3452                                     IS_PASSABLE(i)));
3453
3454     /* ---------- COLLECTIBLE ---------------------------------------------- */
3455     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3456                                      IS_DROPPABLE(i) ||
3457                                      IS_THROWABLE(i)));
3458
3459     /* ---------- SNAPPABLE ------------------------------------------------ */
3460     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3461                                    IS_COLLECTIBLE(i) ||
3462                                    IS_SWITCHABLE(i) ||
3463                                    i == EL_BD_ROCK));
3464
3465     /* ---------- WALL ----------------------------------------------------- */
3466     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
3467
3468     for (j = 0; no_wall_properties[j] != -1; j++)
3469       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3470           i >= EL_FIRST_RUNTIME_UNREAL)
3471         SET_PROPERTY(i, EP_WALL, FALSE);
3472
3473     if (IS_HISTORIC_WALL(i))
3474       SET_PROPERTY(i, EP_WALL, TRUE);
3475
3476     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3477     if (engine_version < VERSION_IDENT(2,2,0,0))
3478       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3479     else
3480       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3481                                              !IS_DIGGABLE(i) &&
3482                                              !IS_COLLECTIBLE(i)));
3483
3484 #if 0
3485     /* ---------- PROTECTED ------------------------------------------------ */
3486     if (IS_ACCESSIBLE_INSIDE(i))
3487       SET_PROPERTY(i, EP_PROTECTED, TRUE);
3488 #endif
3489
3490     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3491
3492     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3493       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3494     else
3495       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3496                                             IS_INDESTRUCTIBLE(i)));
3497
3498     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3499     if (i == EL_FLAMES)
3500       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3501     else if (engine_version < VERSION_IDENT(2,2,0,0))
3502       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3503     else
3504 #if 1
3505       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3506                                            (!IS_WALKABLE(i) ||
3507                                             IS_PROTECTED(i))));
3508 #else
3509 #if 1
3510       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3511                                            !IS_WALKABLE_OVER(i) &&
3512                                            !IS_WALKABLE_UNDER(i)));
3513 #else
3514       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3515                                            IS_PROTECTED(i)));
3516 #endif
3517 #endif
3518
3519     if (IS_CUSTOM_ELEMENT(i))
3520     {
3521       /* these are additional properties which are initially false when set */
3522
3523       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3524       if (DONT_TOUCH(i))
3525         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3526       if (DONT_COLLIDE_WITH(i))
3527         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3528
3529       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3530       if (CAN_SMASH_EVERYTHING(i))
3531         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3532       if (CAN_SMASH_ENEMIES(i))
3533         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3534     }
3535
3536     /* ---------- CAN_SMASH ------------------------------------------------ */
3537     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3538                                    CAN_SMASH_ENEMIES(i) ||
3539                                    CAN_SMASH_EVERYTHING(i)));
3540
3541 #if 0
3542     /* ---------- CAN_EXPLODE ---------------------------------------------- */
3543     SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3544                                      CAN_EXPLODE_SMASHED(i) ||
3545                                      CAN_EXPLODE_IMPACT(i)));
3546 #endif
3547
3548 #if 0
3549     /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3550 #if 0
3551     SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3552                                          !CAN_EXPLODE_CROSS(i)));
3553 #else
3554     SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3555                                          !CAN_EXPLODE_1X1(i) &&
3556                                          !CAN_EXPLODE_CROSS(i)));
3557 #endif
3558 #endif
3559
3560     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3561     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3562                                              EXPLODES_BY_FIRE(i)));
3563
3564     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3565     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3566                                              EXPLODES_SMASHED(i)));
3567
3568     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3569     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3570                                             EXPLODES_IMPACT(i)));
3571
3572     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3573     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3574
3575     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3576     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3577                                                   i == EL_BLACK_ORB));
3578
3579     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3580     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3581                                               CAN_MOVE(i) ||
3582                                               IS_CUSTOM_ELEMENT(i)));
3583
3584     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3585     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3586                                                  i == EL_SP_ELECTRON));
3587
3588     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3589     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3590       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3591                    getMoveIntoAcidProperty(&level, i));
3592
3593     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3594     if (MAYBE_DONT_COLLIDE_WITH(i))
3595       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3596                    getDontCollideWithProperty(&level, i));
3597
3598     /* ---------- SP_PORT -------------------------------------------------- */
3599     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3600                                  IS_PASSABLE_INSIDE(i)));
3601
3602     /* ---------- CAN_CHANGE ----------------------------------------------- */
3603     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
3604     for (j = 0; j < element_info[i].num_change_pages; j++)
3605       if (element_info[i].change_page[j].can_change)
3606         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3607
3608     /* ---------- GFX_CRUMBLED --------------------------------------------- */
3609     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3610                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3611   }
3612
3613 #if 0
3614   /* determine inactive elements (used for engine main loop optimization) */
3615   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3616   {
3617     boolean active = FALSE;
3618
3619     for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3620     {
3621       if (HAS_PROPERTY(i, j))
3622         active = TRUE;
3623     }
3624
3625 #if 0
3626     if (!active)
3627       SET_PROPERTY(i, EP_INACTIVE, TRUE);
3628 #endif
3629   }
3630 #endif
3631
3632   /* dynamically adjust element properties according to game engine version */
3633   {
3634     static int ep_em_slippery_wall[] =
3635     {
3636       EL_STEELWALL,
3637       EL_WALL,
3638       EL_EXPANDABLE_WALL,
3639       EL_EXPANDABLE_WALL_HORIZONTAL,
3640       EL_EXPANDABLE_WALL_VERTICAL,
3641       EL_EXPANDABLE_WALL_ANY,
3642       -1
3643     };
3644
3645     /* special EM style gems behaviour */
3646     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3647       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3648                    level.em_slippery_gems);
3649
3650     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3651     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3652                  (level.em_slippery_gems &&
3653                   engine_version > VERSION_IDENT(2,0,1,0)));
3654   }
3655
3656 #if 1
3657   /* set default push delay values (corrected since version 3.0.7-1) */
3658   if (engine_version < VERSION_IDENT(3,0,7,1))
3659   {
3660     game.default_push_delay_fixed = 2;
3661     game.default_push_delay_random = 8;
3662   }
3663   else
3664   {
3665     game.default_push_delay_fixed = 8;
3666     game.default_push_delay_random = 8;
3667   }
3668
3669   /* set uninitialized push delay values of custom elements in older levels */
3670   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3671   {
3672     int element = EL_CUSTOM_START + i;
3673
3674     if (element_info[element].push_delay_fixed == -1)
3675       element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3676     if (element_info[element].push_delay_random == -1)
3677       element_info[element].push_delay_random = game.default_push_delay_random;
3678   }
3679
3680   /* set some other uninitialized values of custom elements in older levels */
3681   if (engine_version < VERSION_IDENT(3,1,0,0))
3682   {
3683     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3684     {
3685       int element = EL_CUSTOM_START + i;
3686
3687       element_info[element].access_direction = MV_ALL_DIRECTIONS;
3688
3689       element_info[element].explosion_delay = 17;
3690       element_info[element].ignition_delay = 8;
3691     }
3692   }
3693
3694 #if 0
3695   /* set element properties that were handled incorrectly in older levels */
3696   if (engine_version < VERSION_IDENT(3,1,0,0))
3697   {
3698     SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3699     SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3700   }
3701 #endif
3702
3703 #endif
3704
3705   /* this is needed because some graphics depend on element properties */
3706   if (game_status == GAME_MODE_PLAYING)
3707     InitElementGraphicInfo();
3708 }
3709
3710 static void InitGlobal()
3711 {
3712   int i;
3713
3714   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3715   {
3716     /* check if element_name_info entry defined for each element in "main.h" */
3717     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3718       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3719
3720     element_info[i].token_name = element_name_info[i].token_name;
3721     element_info[i].class_name = element_name_info[i].class_name;
3722     element_info[i].editor_description=element_name_info[i].editor_description;
3723   }
3724
3725   global.autoplay_leveldir = NULL;
3726   global.convert_leveldir = NULL;
3727
3728   global.frames_per_second = 0;
3729   global.fps_slowdown = FALSE;
3730   global.fps_slowdown_factor = 1;
3731 }
3732
3733 void Execute_Command(char *command)
3734 {
3735   int i;
3736
3737   if (strcmp(command, "print graphicsinfo.conf") == 0)
3738   {
3739     printf("# You can configure additional/alternative image files here.\n");
3740     printf("# (The entries below are default and therefore commented out.)\n");
3741     printf("\n");
3742     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3743     printf("\n");
3744     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3745     printf("\n");
3746
3747     for (i = 0; image_config[i].token != NULL; i++)
3748       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3749                                               image_config[i].value));
3750
3751     exit(0);
3752   }
3753   else if (strcmp(command, "print soundsinfo.conf") == 0)
3754   {
3755     printf("# You can configure additional/alternative sound files here.\n");
3756     printf("# (The entries below are default and therefore commented out.)\n");
3757     printf("\n");
3758     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3759     printf("\n");
3760     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3761     printf("\n");
3762
3763     for (i = 0; sound_config[i].token != NULL; i++)
3764       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3765                                               sound_config[i].value));
3766
3767     exit(0);
3768   }
3769   else if (strcmp(command, "print musicinfo.conf") == 0)
3770   {
3771     printf("# You can configure additional/alternative music files here.\n");
3772     printf("# (The entries below are default and therefore commented out.)\n");
3773     printf("\n");
3774     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3775     printf("\n");
3776     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3777     printf("\n");
3778
3779     for (i = 0; music_config[i].token != NULL; i++)
3780       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3781                                               music_config[i].value));
3782
3783     exit(0);
3784   }
3785   else if (strcmp(command, "print editorsetup.conf") == 0)
3786   {
3787     printf("# You can configure your personal editor element list here.\n");
3788     printf("# (The entries below are default and therefore commented out.)\n");
3789     printf("\n");
3790
3791     PrintEditorElementList();
3792
3793     exit(0);
3794   }
3795   else if (strcmp(command, "print helpanim.conf") == 0)
3796   {
3797     printf("# You can configure different element help animations here.\n");
3798     printf("# (The entries below are default and therefore commented out.)\n");
3799     printf("\n");
3800
3801     for (i = 0; helpanim_config[i].token != NULL; i++)
3802     {
3803       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3804                                               helpanim_config[i].value));
3805
3806       if (strcmp(helpanim_config[i].token, "end") == 0)
3807         printf("#\n");
3808     }
3809
3810     exit(0);
3811   }
3812   else if (strcmp(command, "print helptext.conf") == 0)
3813   {
3814     printf("# You can configure different element help text here.\n");
3815     printf("# (The entries below are default and therefore commented out.)\n");
3816     printf("\n");
3817
3818     for (i = 0; helptext_config[i].token != NULL; i++)
3819       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3820                                               helptext_config[i].value));
3821
3822     exit(0);
3823   }
3824   else if (strncmp(command, "dump level ", 11) == 0)
3825   {
3826     char *filename = &command[11];
3827
3828     if (access(filename, F_OK) != 0)
3829       Error(ERR_EXIT, "cannot open file '%s'", filename);
3830
3831     LoadLevelFromFilename(&level, filename);
3832     DumpLevel(&level);
3833
3834     exit(0);
3835   }
3836   else if (strncmp(command, "dump tape ", 10) == 0)
3837   {
3838     char *filename = &command[10];
3839
3840     if (access(filename, F_OK) != 0)
3841       Error(ERR_EXIT, "cannot open file '%s'", filename);
3842
3843     LoadTapeFromFilename(filename);
3844     DumpTape(&tape);
3845
3846     exit(0);
3847   }
3848   else if (strncmp(command, "autoplay ", 9) == 0)
3849   {
3850     char *str_copy = getStringCopy(&command[9]);
3851     char *str_ptr = strchr(str_copy, ' ');
3852
3853     global.autoplay_leveldir = str_copy;
3854     global.autoplay_level_nr = -1;
3855
3856     if (str_ptr != NULL)
3857     {
3858       *str_ptr++ = '\0';                        /* terminate leveldir string */
3859       global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3860     }
3861   }
3862   else if (strncmp(command, "convert ", 8) == 0)
3863   {
3864     char *str_copy = getStringCopy(&command[8]);
3865     char *str_ptr = strchr(str_copy, ' ');
3866
3867     global.convert_leveldir = str_copy;
3868     global.convert_level_nr = -1;
3869
3870     if (str_ptr != NULL)
3871     {
3872       *str_ptr++ = '\0';                        /* terminate leveldir string */
3873       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
3874     }
3875   }
3876   else
3877   {
3878     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3879   }
3880 }
3881
3882 static void InitSetup()
3883 {
3884   LoadSetup();                                  /* global setup info */
3885
3886   /* set some options from setup file */
3887
3888   if (setup.options.verbose)
3889     options.verbose = TRUE;
3890 }
3891
3892 static void InitPlayerInfo()
3893 {
3894   int i;
3895
3896   /* choose default local player */
3897   local_player = &stored_player[0];
3898
3899   for (i = 0; i < MAX_PLAYERS; i++)
3900     stored_player[i].connected = FALSE;
3901
3902   local_player->connected = TRUE;
3903 }
3904
3905 static void InitArtworkInfo()
3906 {
3907   LoadArtworkInfo();
3908 }
3909
3910 static char *get_string_in_brackets(char *string)
3911 {
3912   char *string_in_brackets = checked_malloc(strlen(string) + 3);
3913
3914   sprintf(string_in_brackets, "[%s]", string);
3915
3916   return string_in_brackets;
3917 }
3918
3919 static char *get_level_id_suffix(int id_nr)
3920 {
3921   char *id_suffix = checked_malloc(1 + 3 + 1);
3922
3923   if (id_nr < 0 || id_nr > 999)
3924     id_nr = 0;
3925
3926   sprintf(id_suffix, ".%03d", id_nr);
3927
3928   return id_suffix;
3929 }
3930
3931 #if 0
3932 static char *get_element_class_token(int element)
3933 {
3934   char *element_class_name = element_info[element].class_name;
3935   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3936
3937   sprintf(element_class_token, "[%s]", element_class_name);
3938
3939   return element_class_token;
3940 }
3941
3942 static char *get_action_class_token(int action)
3943 {
3944   char *action_class_name = &element_action_info[action].suffix[1];
3945   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3946
3947   sprintf(action_class_token, "[%s]", action_class_name);
3948
3949   return action_class_token;
3950 }
3951 #endif
3952
3953 static void InitArtworkConfig()
3954 {
3955   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3956   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3957   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3958   static char *action_id_suffix[NUM_ACTIONS + 1];
3959   static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3960   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3961   static char *level_id_suffix[MAX_LEVELS + 1];
3962   static char *dummy[1] = { NULL };
3963   static char *ignore_generic_tokens[] =
3964   {
3965     "name",
3966     "sort_priority",
3967     NULL
3968   };
3969   static char **ignore_image_tokens;
3970   static char **ignore_sound_tokens;
3971   static char **ignore_music_tokens;
3972   int num_ignore_generic_tokens;
3973   int num_ignore_image_tokens;
3974   int num_ignore_sound_tokens;
3975   int num_ignore_music_tokens;
3976   int i;
3977
3978   /* dynamically determine list of generic tokens to be ignored */
3979   num_ignore_generic_tokens = 0;
3980   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3981     num_ignore_generic_tokens++;
3982
3983   /* dynamically determine list of image tokens to be ignored */
3984   num_ignore_image_tokens = num_ignore_generic_tokens;
3985   for (i = 0; image_config_vars[i].token != NULL; i++)
3986     num_ignore_image_tokens++;
3987   ignore_image_tokens =
3988     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3989   for (i = 0; i < num_ignore_generic_tokens; i++)
3990     ignore_image_tokens[i] = ignore_generic_tokens[i];
3991   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3992     ignore_image_tokens[num_ignore_generic_tokens + i] =
3993       image_config_vars[i].token;
3994   ignore_image_tokens[num_ignore_image_tokens] = NULL;
3995
3996   /* dynamically determine list of sound tokens to be ignored */
3997   num_ignore_sound_tokens = num_ignore_generic_tokens;
3998   ignore_sound_tokens =
3999     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4000   for (i = 0; i < num_ignore_generic_tokens; i++)
4001     ignore_sound_tokens[i] = ignore_generic_tokens[i];
4002   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4003
4004   /* dynamically determine list of music tokens to be ignored */
4005   num_ignore_music_tokens = num_ignore_generic_tokens;
4006   ignore_music_tokens =
4007     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4008   for (i = 0; i < num_ignore_generic_tokens; i++)
4009     ignore_music_tokens[i] = ignore_generic_tokens[i];
4010   ignore_music_tokens[num_ignore_music_tokens] = NULL;
4011
4012   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4013     image_id_prefix[i] = element_info[i].token_name;
4014   for (i = 0; i < NUM_FONTS; i++)
4015     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4016   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4017
4018   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4019     sound_id_prefix[i] = element_info[i].token_name;
4020   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4021     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4022       get_string_in_brackets(element_info[i].class_name);
4023   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4024
4025   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4026     music_id_prefix[i] = music_prefix_info[i].prefix;
4027   music_id_prefix[MAX_LEVELS] = NULL;
4028
4029   for (i = 0; i < NUM_ACTIONS; i++)
4030     action_id_suffix[i] = element_action_info[i].suffix;
4031   action_id_suffix[NUM_ACTIONS] = NULL;
4032
4033   for (i = 0; i < NUM_DIRECTIONS; i++)
4034     direction_id_suffix[i] = element_direction_info[i].suffix;
4035   direction_id_suffix[NUM_DIRECTIONS] = NULL;
4036
4037   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4038     special_id_suffix[i] = special_suffix_info[i].suffix;
4039   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4040
4041   for (i = 0; i < MAX_LEVELS; i++)
4042     level_id_suffix[i] = get_level_id_suffix(i);
4043   level_id_suffix[MAX_LEVELS] = NULL;
4044
4045   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4046                 image_id_prefix, action_id_suffix, direction_id_suffix,
4047                 special_id_suffix, ignore_image_tokens);
4048   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4049                 sound_id_prefix, action_id_suffix, dummy,
4050                 special_id_suffix, ignore_sound_tokens);
4051   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4052                 music_id_prefix, special_id_suffix, level_id_suffix,
4053                 dummy, ignore_music_tokens);
4054 }
4055
4056 static void InitMixer()
4057 {
4058   OpenAudio();
4059   StartMixer();
4060 }
4061
4062 void InitGfx()
4063 {
4064   char *filename_font_initial = NULL;
4065   Bitmap *bitmap_font_initial = NULL;
4066   int i, j;
4067
4068   /* determine settings for initial font (for displaying startup messages) */
4069   for (i = 0; image_config[i].token != NULL; i++)
4070   {
4071     for (j = 0; j < NUM_INITIAL_FONTS; j++)
4072     {
4073       char font_token[128];
4074       int len_font_token;
4075
4076       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4077       len_font_token = strlen(font_token);
4078
4079       if (strcmp(image_config[i].token, font_token) == 0)
4080         filename_font_initial = image_config[i].value;
4081       else if (strlen(image_config[i].token) > len_font_token &&
4082                strncmp(image_config[i].token, font_token, len_font_token) == 0)
4083       {
4084         if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4085           font_initial[j].src_x = atoi(image_config[i].value);
4086         else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4087           font_initial[j].src_y = atoi(image_config[i].value);
4088         else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4089           font_initial[j].width = atoi(image_config[i].value);
4090         else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4091           font_initial[j].height = atoi(image_config[i].value);
4092       }
4093     }
4094   }
4095
4096   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4097   {
4098     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4099     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4100   }
4101
4102   if (filename_font_initial == NULL)    /* should not happen */
4103     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4104
4105   /* create additional image buffers for double-buffering */
4106   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4107   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4108
4109   /* initialize screen properties */
4110   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4111                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4112                    bitmap_db_field);
4113   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4114   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4115   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4116
4117   bitmap_font_initial = LoadCustomImage(filename_font_initial);
4118
4119   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4120     font_initial[j].bitmap = bitmap_font_initial;
4121
4122   InitFontGraphicInfo();
4123
4124   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4125   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4126
4127   DrawInitText("Loading graphics:", 120, FC_GREEN);
4128
4129   InitTileClipmasks();
4130 }
4131
4132 void InitGfxBackground()
4133 {
4134   int x, y;
4135
4136   drawto = backbuffer;
4137   fieldbuffer = bitmap_db_field;
4138   SetDrawtoField(DRAW_BACKBUFFER);
4139
4140   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4141              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4142   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4143   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4144
4145   for (x = 0; x < MAX_BUF_XSIZE; x++)
4146     for (y = 0; y < MAX_BUF_YSIZE; y++)
4147       redraw[x][y] = 0;
4148   redraw_tiles = 0;
4149   redraw_mask = REDRAW_ALL;
4150 }
4151
4152 static void InitLevelInfo()
4153 {
4154   LoadLevelInfo();                              /* global level info */
4155   LoadLevelSetup_LastSeries();                  /* last played series info */
4156   LoadLevelSetup_SeriesInfo();                  /* last played level info */
4157 }
4158
4159 void InitLevelArtworkInfo()
4160 {
4161   LoadLevelArtworkInfo();
4162 }
4163
4164 static void InitImages()
4165 {
4166 #if 1
4167   setLevelArtworkDir(artwork.gfx_first);
4168 #endif
4169
4170 #if 0
4171   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4172          leveldir_current->identifier,
4173          artwork.gfx_current_identifier,
4174          artwork.gfx_current->identifier,
4175          leveldir_current->graphics_set,
4176          leveldir_current->graphics_path);
4177 #endif
4178
4179   ReloadCustomImages();
4180
4181   LoadCustomElementDescriptions();
4182   LoadSpecialMenuDesignSettings();
4183
4184   ReinitializeGraphics();
4185 }
4186
4187 static void InitSound(char *identifier)
4188 {
4189   if (identifier == NULL)
4190     identifier = artwork.snd_current->identifier;
4191
4192 #if 1
4193   /* set artwork path to send it to the sound server process */
4194   setLevelArtworkDir(artwork.snd_first);
4195 #endif
4196
4197   InitReloadCustomSounds(identifier);
4198   ReinitializeSounds();
4199 }
4200
4201 static void InitMusic(char *identifier)
4202 {
4203   if (identifier == NULL)
4204     identifier = artwork.mus_current->identifier;
4205
4206 #if 1
4207   /* set artwork path to send it to the sound server process */
4208   setLevelArtworkDir(artwork.mus_first);
4209 #endif
4210
4211   InitReloadCustomMusic(identifier);
4212   ReinitializeMusic();
4213 }
4214
4215 void InitNetworkServer()
4216 {
4217 #if defined(NETWORK_AVALIABLE)
4218   int nr_wanted;
4219 #endif
4220
4221   if (!options.network)
4222     return;
4223
4224 #if defined(NETWORK_AVALIABLE)
4225   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4226
4227   if (!ConnectToServer(options.server_host, options.server_port))
4228     Error(ERR_EXIT, "cannot connect to network game server");
4229
4230   SendToServer_PlayerName(setup.player_name);
4231   SendToServer_ProtocolVersion();
4232
4233   if (nr_wanted)
4234     SendToServer_NrWanted(nr_wanted);
4235 #endif
4236 }
4237
4238 static char *getNewArtworkIdentifier(int type)
4239 {
4240   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4241   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4242   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4243   static boolean initialized[3] = { FALSE, FALSE, FALSE };
4244   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4245   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4246   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4247   char *leveldir_identifier = leveldir_current->identifier;
4248 #if 1
4249   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4250   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4251 #else
4252   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4253 #endif
4254   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4255   char *artwork_current_identifier;
4256   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
4257
4258   /* leveldir_current may be invalid (level group, parent link) */
4259   if (!validLevelSeries(leveldir_current))
4260     return NULL;
4261
4262   /* 1st step: determine artwork set to be activated in descending order:
4263      --------------------------------------------------------------------
4264      1. setup artwork (when configured to override everything else)
4265      2. artwork set configured in "levelinfo.conf" of current level set
4266         (artwork in level directory will have priority when loading later)
4267      3. artwork in level directory (stored in artwork sub-directory)
4268      4. setup artwork (currently configured in setup menu) */
4269
4270   if (setup_override_artwork)
4271     artwork_current_identifier = setup_artwork_set;
4272   else if (leveldir_artwork_set != NULL)
4273     artwork_current_identifier = leveldir_artwork_set;
4274   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4275     artwork_current_identifier = leveldir_identifier;
4276   else
4277     artwork_current_identifier = setup_artwork_set;
4278
4279
4280   /* 2nd step: check if it is really needed to reload artwork set
4281      ------------------------------------------------------------ */
4282
4283 #if 0
4284   if (type == ARTWORK_TYPE_GRAPHICS)
4285     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4286            artwork_new_identifier,
4287            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4288            artwork_current_identifier,
4289            leveldir_current->graphics_set,
4290            leveldir_current->identifier);
4291 #endif
4292
4293   /* ---------- reload if level set and also artwork set has changed ------- */
4294   if (leveldir_current_identifier[type] != leveldir_identifier &&
4295       (last_has_level_artwork_set[type] || has_level_artwork_set))
4296     artwork_new_identifier = artwork_current_identifier;
4297
4298   leveldir_current_identifier[type] = leveldir_identifier;
4299   last_has_level_artwork_set[type] = has_level_artwork_set;
4300
4301 #if 0
4302   if (type == ARTWORK_TYPE_GRAPHICS)
4303     printf("::: 1: '%s'\n", artwork_new_identifier);
4304 #endif
4305
4306   /* ---------- reload if "override artwork" setting has changed ----------- */
4307   if (last_override_level_artwork[type] != setup_override_artwork)
4308     artwork_new_identifier = artwork_current_identifier;
4309
4310   last_override_level_artwork[type] = setup_override_artwork;
4311
4312 #if 0
4313   if (type == ARTWORK_TYPE_GRAPHICS)
4314     printf("::: 2: '%s'\n", artwork_new_identifier);
4315 #endif
4316
4317   /* ---------- reload if current artwork identifier has changed ----------- */
4318   if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4319              artwork_current_identifier) != 0)
4320     artwork_new_identifier = artwork_current_identifier;
4321
4322   *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4323
4324 #if 0
4325   if (type == ARTWORK_TYPE_GRAPHICS)
4326     printf("::: 3: '%s'\n", artwork_new_identifier);
4327 #endif
4328
4329   /* ---------- do not reload directly after starting ---------------------- */
4330   if (!initialized[type])
4331     artwork_new_identifier = NULL;
4332
4333   initialized[type] = TRUE;
4334
4335 #if 0
4336   if (type == ARTWORK_TYPE_GRAPHICS)
4337     printf("::: 4: '%s'\n", artwork_new_identifier);
4338 #endif
4339
4340 #if 0
4341   if (type == ARTWORK_TYPE_GRAPHICS)
4342     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4343            artwork.gfx_current_identifier, artwork_current_identifier,
4344            artwork.gfx_current->identifier, leveldir_current->graphics_set,
4345            artwork_new_identifier);
4346 #endif
4347
4348   return artwork_new_identifier;
4349 }
4350
4351 void ReloadCustomArtwork(int force_reload)
4352 {
4353   char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4354   char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4355   char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4356   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4357   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4358   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4359   boolean redraw_screen = FALSE;
4360
4361   if (gfx_new_identifier != NULL || force_reload_gfx)
4362   {
4363 #if 0
4364     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4365            artwork.gfx_current_identifier,
4366            gfx_new_identifier,
4367            artwork.gfx_current->identifier,
4368            leveldir_current->graphics_set);
4369 #endif
4370
4371     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4372
4373     InitImages();
4374
4375 #if 0
4376     printf("... '%s'\n",
4377            leveldir_current->graphics_set);
4378 #endif
4379
4380     FreeTileClipmasks();
4381     InitTileClipmasks();
4382
4383     redraw_screen = TRUE;
4384   }
4385
4386   if (snd_new_identifier != NULL || force_reload_snd)
4387   {
4388     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4389
4390     InitSound(snd_new_identifier);
4391
4392     redraw_screen = TRUE;
4393   }
4394
4395   if (mus_new_identifier != NULL || force_reload_mus)
4396   {
4397     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4398
4399     InitMusic(mus_new_identifier);
4400
4401     redraw_screen = TRUE;
4402   }
4403
4404   if (redraw_screen)
4405   {
4406     InitGfxBackground();
4407
4408     /* force redraw of (open or closed) door graphics */
4409     SetDoorState(DOOR_OPEN_ALL);
4410     CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4411   }
4412 }
4413
4414 void KeyboardAutoRepeatOffUnlessAutoplay()
4415 {
4416   if (global.autoplay_leveldir == NULL)
4417     KeyboardAutoRepeatOff();
4418 }
4419
4420
4421 /* ========================================================================= */
4422 /* OpenAll()                                                                 */
4423 /* ========================================================================= */
4424
4425 void OpenAll()
4426 {
4427   InitGlobal();         /* initialize some global variables */
4428
4429   if (options.execute_command)
4430     Execute_Command(options.execute_command);
4431
4432   if (options.serveronly)
4433   {
4434 #if defined(PLATFORM_UNIX)
4435     NetworkServer(options.server_port, options.serveronly);
4436 #else
4437     Error(ERR_WARN, "networking only supported in Unix version");
4438 #endif
4439     exit(0);    /* never reached */
4440   }
4441
4442   InitSetup();
4443
4444   InitPlayerInfo();
4445   InitArtworkInfo();            /* needed before loading gfx, sound & music */
4446   InitArtworkConfig();          /* needed before forking sound child process */
4447   InitMixer();
4448
4449   InitCounter();
4450
4451   InitRND(NEW_RANDOMIZE);
4452   InitSimpleRND(NEW_RANDOMIZE);
4453
4454   InitJoysticks();
4455
4456   InitVideoDisplay();
4457   InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4458                   setup.fullscreen);
4459
4460   InitEventFilter(FilterMouseMotionEvents);
4461
4462   InitElementPropertiesStatic();
4463   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4464
4465   InitGfx();
4466
4467   InitLevelInfo();
4468   InitLevelArtworkInfo();
4469
4470   InitImages();                 /* needs to know current level directory */
4471   InitSound(NULL);              /* needs to know current level directory */
4472   InitMusic(NULL);              /* needs to know current level directory */
4473
4474   InitGfxBackground();
4475
4476   if (global.autoplay_leveldir)
4477   {
4478     AutoPlayTape();
4479     return;
4480   }
4481   else if (global.convert_leveldir)
4482   {
4483     ConvertLevels();
4484     return;
4485   }
4486
4487   game_status = GAME_MODE_MAIN;
4488
4489 #if 1
4490   em_open_all();
4491 #endif
4492
4493   DrawMainMenu();
4494
4495   InitNetworkServer();
4496 }
4497
4498 void CloseAllAndExit(int exit_value)
4499 {
4500   StopSounds();
4501   FreeAllSounds();
4502   FreeAllMusic();
4503   CloseAudio();         /* called after freeing sounds (needed for SDL) */
4504
4505 #if 1
4506   em_close_all();
4507 #endif
4508
4509   FreeAllImages();
4510   FreeTileClipmasks();
4511
4512 #if defined(TARGET_SDL)
4513   if (network_server)   /* terminate network server */
4514     SDL_KillThread(server_thread);
4515 #endif
4516
4517   CloseVideoDisplay();
4518   ClosePlatformDependentStuff();
4519
4520   exit(exit_value);
4521 }