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