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