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