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