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