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