rnd-20040219-1-src
[rocksndiamonds.git] / src / init.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * init.c                                                   *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "init.h"
17 #include "events.h"
18 #include "screens.h"
19 #include "editor.h"
20 #include "game.h"
21 #include "tape.h"
22 #include "tools.h"
23 #include "files.h"
24 #include "network.h"
25 #include "netserv.h"
26 #include "cartoons.h"
27 #include "config.h"
28
29 #include "conf_e2g.c"   /* include auto-generated data structure definitions */
30 #include "conf_esg.c"   /* include auto-generated data structure definitions */
31 #include "conf_e2s.c"   /* include auto-generated data structure definitions */
32 #include "conf_fnt.c"   /* include auto-generated data structure definitions */
33 #include "conf_g2s.c"   /* include auto-generated data structure definitions */
34 #include "conf_g2m.c"   /* include auto-generated data structure definitions */
35
36
37 #define CONFIG_TOKEN_FONT_INITIAL               "font.initial"
38
39
40 struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41
42
43 static void InitTileClipmasks()
44 {
45 #if 0
46 #if defined(TARGET_X11)
47   XGCValues clip_gc_values;
48   unsigned long clip_gc_valuemask;
49
50 #if defined(TARGET_X11_NATIVE)
51
52 #if 0
53   GC copy_clipmask_gc;
54
55   static struct
56   {
57     int start;
58     int count;
59   }
60   tile_needs_clipping[] =
61   {
62     { GFX_SPIELER1_UP, 4 },
63     { GFX_SPIELER1_DOWN, 4 },
64     { GFX_SPIELER1_LEFT, 4 },
65     { GFX_SPIELER1_RIGHT, 4 },
66     { GFX_SPIELER1_PUSH_LEFT, 4 },
67     { GFX_SPIELER1_PUSH_RIGHT, 4 },
68     { GFX_SPIELER2_UP, 4 },
69     { GFX_SPIELER2_DOWN, 4 },
70     { GFX_SPIELER2_LEFT, 4 },
71     { GFX_SPIELER2_RIGHT, 4 },
72     { GFX_SPIELER2_PUSH_LEFT, 4 },
73     { GFX_SPIELER2_PUSH_RIGHT, 4 },
74     { GFX_SPIELER3_UP, 4 },
75     { GFX_SPIELER3_DOWN, 4 },
76     { GFX_SPIELER3_LEFT, 4 },
77     { GFX_SPIELER3_RIGHT, 4 },
78     { GFX_SPIELER3_PUSH_LEFT, 4 },
79     { GFX_SPIELER3_PUSH_RIGHT, 4 },
80     { GFX_SPIELER4_UP, 4 },
81     { GFX_SPIELER4_DOWN, 4 },
82     { GFX_SPIELER4_LEFT, 4 },
83     { GFX_SPIELER4_RIGHT, 4 },
84     { GFX_SPIELER4_PUSH_LEFT, 4 },
85     { GFX_SPIELER4_PUSH_RIGHT, 4 },
86     { GFX_SP_MURPHY, 1 },
87     { GFX_MURPHY_GO_LEFT, 3 },
88     { GFX_MURPHY_GO_RIGHT, 3 },
89     { GFX_MURPHY_SNAP_UP, 1 },
90     { GFX_MURPHY_SNAP_DOWN, 1 },
91     { GFX_MURPHY_SNAP_RIGHT, 1 },
92     { GFX_MURPHY_SNAP_LEFT, 1 },
93     { GFX_MURPHY_PUSH_RIGHT, 1 },
94     { GFX_MURPHY_PUSH_LEFT, 1 },
95     { GFX_GEBLUBBER, 4 },
96     { GFX_DYNAMIT, 7 },
97     { GFX_DYNABOMB, 4 },
98     { GFX_EXPLOSION, 8 },
99     { GFX_SOKOBAN_OBJEKT, 1 },
100     { GFX_FUNKELN_BLAU, 3 },
101     { GFX_FUNKELN_WEISS, 3 },
102     { GFX2_SHIELD_PASSIVE, 3 },
103     { GFX2_SHIELD_ACTIVE, 3 },
104     { -1, 0 }
105   };
106 #endif
107
108 #endif /* TARGET_X11_NATIVE */
109 #endif /* TARGET_X11 */
110
111   int i;
112
113   /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
114   for (i = 0; i < NUM_TILES; i++)
115     tile_clipmask[i] = None;
116
117 #if defined(TARGET_X11)
118   /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
119      often very slow when preparing a masked XCopyArea() for big Pixmaps.
120      To prevent this, create small (tile-sized) mask Pixmaps which will then
121      be set much faster with XSetClipOrigin() and speed things up a lot. */
122
123   clip_gc_values.graphics_exposures = False;
124   clip_gc_valuemask = GCGraphicsExposures;
125   tile_clip_gc = XCreateGC(display, window->drawable,
126                            clip_gc_valuemask, &clip_gc_values);
127
128 #if 0
129   for (i = 0; i < NUM_BITMAPS; i++)
130   {
131     if (pix[i]->clip_mask)
132     {
133       clip_gc_values.graphics_exposures = False;
134       clip_gc_values.clip_mask = pix[i]->clip_mask;
135       clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
136       pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
137                                          clip_gc_valuemask, &clip_gc_values);
138     }
139   }
140 #endif
141
142 #if defined(TARGET_X11_NATIVE)
143
144 #if 0
145   /* create graphic context structures needed for clipping */
146   clip_gc_values.graphics_exposures = False;
147   clip_gc_valuemask = GCGraphicsExposures;
148   copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
149                                clip_gc_valuemask, &clip_gc_values);
150
151   /* create only those clipping Pixmaps we really need */
152   for (i = 0; tile_needs_clipping[i].start >= 0; i++)
153   {
154     int j;
155
156     for (j = 0; j < tile_needs_clipping[i].count; j++)
157     {
158       int tile = tile_needs_clipping[i].start + j;
159       int graphic = tile;
160       int src_x, src_y;
161       Bitmap *src_bitmap;
162       Pixmap src_pixmap;
163
164       getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
165       src_pixmap = src_bitmap->clip_mask;
166
167       tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
168                                           TILEX, TILEY, 1);
169
170       XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
171                 src_x, src_y, TILEX, TILEY, 0, 0);
172     }
173   }
174
175   XFreeGC(display, copy_clipmask_gc);
176 #endif
177
178 #endif /* TARGET_X11_NATIVE */
179 #endif /* TARGET_X11 */
180 #endif
181 }
182
183 void FreeTileClipmasks()
184 {
185 #if 0
186 #if defined(TARGET_X11)
187   int i;
188
189   for (i = 0; i < NUM_TILES; i++)
190   {
191     if (tile_clipmask[i] != None)
192     {
193       XFreePixmap(display, tile_clipmask[i]);
194       tile_clipmask[i] = None;
195     }
196   }
197
198   if (tile_clip_gc)
199     XFreeGC(display, tile_clip_gc);
200   tile_clip_gc = None;
201
202 #if 0
203   for (i = 0; i < NUM_BITMAPS; i++)
204   {
205     if (pix[i] != NULL && pix[i]->stored_clip_gc)
206     {
207       XFreeGC(display, pix[i]->stored_clip_gc);
208       pix[i]->stored_clip_gc = None;
209     }
210   }
211 #endif
212
213 #endif /* TARGET_X11 */
214 #endif
215 }
216
217 void FreeGadgets()
218 {
219   FreeLevelEditorGadgets();
220   FreeGameButtons();
221   FreeTapeButtons();
222   FreeToolButtons();
223   FreeScreenGadgets();
224 }
225
226 void InitGadgets()
227 {
228   static boolean gadgets_initialized = FALSE;
229
230   if (gadgets_initialized)
231     FreeGadgets();
232
233   CreateLevelEditorGadgets();
234   CreateGameButtons();
235   CreateTapeButtons();
236   CreateToolButtons();
237   CreateScreenGadgets();
238
239   gadgets_initialized = TRUE;
240 }
241
242 void InitElementSmallImages()
243 {
244   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
245   int num_property_mappings = getImageListPropertyMappingSize();
246   int i;
247
248   /* initialize normal images from static configuration */
249   for (i = 0; element_to_graphic[i].element > -1; i++)
250     CreateImageWithSmallImages(element_to_graphic[i].graphic);
251
252   /* initialize special images from static configuration */
253   for (i = 0; element_to_special_graphic[i].element > -1; i++)
254     CreateImageWithSmallImages(element_to_special_graphic[i].graphic);
255
256   /* initialize images from dynamic configuration */
257   for (i = 0; i < num_property_mappings; i++)
258     if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
259       CreateImageWithSmallImages(property_mapping[i].artwork_index);
260 }
261
262 static int getFontBitmapID(int font_nr)
263 {
264   int special = -1;
265
266   if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
267     special = game_status;
268   else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
269     special = GFX_SPECIAL_ARG_MAIN;
270   else if (game_status == GAME_MODE_PLAYING)
271     special = GFX_SPECIAL_ARG_DOOR;
272
273   if (special != -1)
274     return font_info[font_nr].special_bitmap_id[special];
275   else
276     return font_nr;
277 }
278
279 void InitFontGraphicInfo()
280 {
281   static struct FontBitmapInfo *font_bitmap_info = NULL;
282   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
283   int num_property_mappings = getImageListPropertyMappingSize();
284   int num_font_bitmaps = NUM_FONTS;
285   int i, j;
286
287   if (graphic_info == NULL)             /* still at startup phase */
288   {
289     InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
290
291     return;
292   }
293
294   /* ---------- initialize font graphic definitions ---------- */
295
296   /* always start with reliable default values (normal font graphics) */
297 #if 1
298   for (i = 0; i < NUM_FONTS; i++)
299     font_info[i].graphic = IMG_FONT_INITIAL_1;
300 #else
301   for (i = 0; i < NUM_FONTS; i++)
302     font_info[i].graphic = FONT_INITIAL_1;
303 #endif
304
305   /* initialize normal font/graphic mapping from static configuration */
306   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
307   {
308     int font_nr = font_to_graphic[i].font_nr;
309     int special = font_to_graphic[i].special;
310     int graphic = font_to_graphic[i].graphic;
311
312     if (special != -1)
313       continue;
314
315     font_info[font_nr].graphic = graphic;
316   }
317
318   /* always start with reliable default values (special font graphics) */
319   for (i = 0; i < NUM_FONTS; i++)
320   {
321     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
322     {
323       font_info[i].special_graphic[j] = font_info[i].graphic;
324       font_info[i].special_bitmap_id[j] = i;
325     }
326   }
327
328   /* initialize special font/graphic mapping from static configuration */
329   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
330   {
331     int font_nr = font_to_graphic[i].font_nr;
332     int special = font_to_graphic[i].special;
333     int graphic = font_to_graphic[i].graphic;
334
335     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
336     {
337       font_info[font_nr].special_graphic[special] = graphic;
338       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
339       num_font_bitmaps++;
340     }
341   }
342
343   /* initialize special element/graphic mapping from dynamic configuration */
344   for (i = 0; i < num_property_mappings; i++)
345   {
346     int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
347     int special = property_mapping[i].ext3_index;
348     int graphic = property_mapping[i].artwork_index;
349
350     if (font_nr < 0)
351       continue;
352
353     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
354     {
355       font_info[font_nr].special_graphic[special] = graphic;
356       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
357       num_font_bitmaps++;
358     }
359   }
360
361   /* ---------- initialize font bitmap array ---------- */
362
363   if (font_bitmap_info != NULL)
364     FreeFontInfo(font_bitmap_info);
365
366   font_bitmap_info =
367     checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
368
369   /* ---------- initialize font bitmap definitions ---------- */
370
371   for (i = 0; i < NUM_FONTS; i++)
372   {
373     if (i < NUM_INITIAL_FONTS)
374     {
375       font_bitmap_info[i] = font_initial[i];
376       continue;
377     }
378
379     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
380     {
381       int font_bitmap_id = font_info[i].special_bitmap_id[j];
382       int graphic = font_info[i].special_graphic[j];
383
384       /* set 'graphic_info' for font entries, if uninitialized (guessed) */
385       if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
386       {
387         graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
388         graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
389       }
390
391       /* copy font relevant information from graphics information */
392       font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
393       font_bitmap_info[font_bitmap_id].src_x  = graphic_info[graphic].src_x;
394       font_bitmap_info[font_bitmap_id].src_y  = graphic_info[graphic].src_y;
395       font_bitmap_info[font_bitmap_id].width  = graphic_info[graphic].width;
396       font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
397       font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
398       font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
399
400       font_bitmap_info[font_bitmap_id].num_chars =
401         graphic_info[graphic].anim_frames;
402       font_bitmap_info[font_bitmap_id].num_chars_per_line =
403         graphic_info[graphic].anim_frames_per_line;
404     }
405   }
406
407   InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
408 }
409
410 void InitElementGraphicInfo()
411 {
412   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
413   int num_property_mappings = getImageListPropertyMappingSize();
414   int i, act, dir;
415
416   if (graphic_info == NULL)             /* still at startup phase */
417     return;
418
419   /* set values to -1 to identify later as "uninitialized" values */
420   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
421   {
422     for (act = 0; act < NUM_ACTIONS; act++)
423     {
424       element_info[i].graphic[act] = -1;
425       element_info[i].crumbled[act] = -1;
426
427       for (dir = 0; dir < NUM_DIRECTIONS; dir++)
428       {
429         element_info[i].direction_graphic[act][dir] = -1;
430         element_info[i].direction_crumbled[act][dir] = -1;
431       }
432     }
433   }
434
435   /* initialize normal element/graphic mapping from static configuration */
436   for (i = 0; element_to_graphic[i].element > -1; i++)
437   {
438     int element      = element_to_graphic[i].element;
439     int action       = element_to_graphic[i].action;
440     int direction    = element_to_graphic[i].direction;
441     boolean crumbled = element_to_graphic[i].crumbled;
442     int graphic      = element_to_graphic[i].graphic;
443
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 void InitElementPropertiesStatic()
1573 {
1574   static int ep_diggable[] =
1575   {
1576     EL_SAND,
1577     EL_SP_BASE,
1578     EL_SP_BUGGY_BASE,
1579     EL_SP_BUGGY_BASE_ACTIVATING,
1580     EL_TRAP,
1581     EL_INVISIBLE_SAND,
1582     EL_INVISIBLE_SAND_ACTIVE,
1583
1584     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1585 #if 0
1586     EL_LANDMINE,
1587     EL_TRAP_ACTIVE,
1588     EL_SP_BUGGY_BASE_ACTIVE,
1589 #endif
1590     -1
1591   };
1592
1593   static int ep_collectible_only[] =
1594   {
1595     EL_BD_DIAMOND,
1596     EL_EMERALD,
1597     EL_DIAMOND,
1598     EL_EMERALD_YELLOW,
1599     EL_EMERALD_RED,
1600     EL_EMERALD_PURPLE,
1601     EL_KEY_1,
1602     EL_KEY_2,
1603     EL_KEY_3,
1604     EL_KEY_4,
1605     EL_EM_KEY_1,
1606     EL_EM_KEY_2,
1607     EL_EM_KEY_3,
1608     EL_EM_KEY_4,
1609     EL_DYNAMITE,
1610     EL_DYNABOMB_INCREASE_NUMBER,
1611     EL_DYNABOMB_INCREASE_SIZE,
1612     EL_DYNABOMB_INCREASE_POWER,
1613     EL_SP_INFOTRON,
1614     EL_SP_DISK_RED,
1615     EL_PEARL,
1616     EL_CRYSTAL,
1617     EL_KEY_WHITE,
1618     EL_SHIELD_NORMAL,
1619     EL_SHIELD_DEADLY,
1620     EL_EXTRA_TIME,
1621     EL_ENVELOPE_1,
1622     EL_ENVELOPE_2,
1623     EL_ENVELOPE_3,
1624     EL_ENVELOPE_4,
1625     EL_SPEED_PILL,
1626     -1
1627   };
1628
1629   static int ep_dont_run_into[] =
1630   {
1631     /* same elements as in 'ep_dont_touch' */
1632     EL_BUG,
1633     EL_SPACESHIP,
1634     EL_BD_BUTTERFLY,
1635     EL_BD_FIREFLY,
1636
1637     /* same elements as in 'ep_dont_collide_with' */
1638     EL_YAMYAM,
1639     EL_DARK_YAMYAM,
1640     EL_ROBOT,
1641     EL_PACMAN,
1642     EL_SP_SNIKSNAK,
1643     EL_SP_ELECTRON,
1644
1645     /* new elements */
1646     EL_AMOEBA_DROP,
1647     EL_ACID,
1648
1649     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1650 #if 1
1651     EL_LANDMINE,
1652     EL_TRAP_ACTIVE,
1653     EL_SP_BUGGY_BASE_ACTIVE,
1654 #endif
1655     -1
1656   };
1657
1658   static int ep_dont_collide_with[] =
1659   {
1660     /* same elements as in 'ep_dont_touch' */
1661     EL_BUG,
1662     EL_SPACESHIP,
1663     EL_BD_BUTTERFLY,
1664     EL_BD_FIREFLY,
1665
1666     /* new elements */
1667     EL_YAMYAM,
1668     EL_DARK_YAMYAM,
1669     EL_ROBOT,
1670     EL_PACMAN,
1671     EL_SP_SNIKSNAK,
1672     EL_SP_ELECTRON,
1673     -1
1674   };
1675
1676   static int ep_dont_touch[] =
1677   {
1678     EL_BUG,
1679     EL_SPACESHIP,
1680     EL_BD_BUTTERFLY,
1681     EL_BD_FIREFLY,
1682     -1
1683   };
1684
1685   static int ep_indestructible[] =
1686   {
1687     EL_STEELWALL,
1688     EL_ACID,
1689     EL_ACID_POOL_TOPLEFT,
1690     EL_ACID_POOL_TOPRIGHT,
1691     EL_ACID_POOL_BOTTOMLEFT,
1692     EL_ACID_POOL_BOTTOM,
1693     EL_ACID_POOL_BOTTOMRIGHT,
1694     EL_SP_HARDWARE_GRAY,
1695     EL_SP_HARDWARE_GREEN,
1696     EL_SP_HARDWARE_BLUE,
1697     EL_SP_HARDWARE_RED,
1698     EL_SP_HARDWARE_YELLOW,
1699     EL_SP_HARDWARE_BASE_1,
1700     EL_SP_HARDWARE_BASE_2,
1701     EL_SP_HARDWARE_BASE_3,
1702     EL_SP_HARDWARE_BASE_4,
1703     EL_SP_HARDWARE_BASE_5,
1704     EL_SP_HARDWARE_BASE_6,
1705     EL_INVISIBLE_STEELWALL,
1706     EL_INVISIBLE_STEELWALL_ACTIVE,
1707     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1708     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1709     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1710     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1711     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1712     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1713     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1714     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1715     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1716     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1717     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1718     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1719     EL_LIGHT_SWITCH,
1720     EL_LIGHT_SWITCH_ACTIVE,
1721     EL_SIGN_EXCLAMATION,
1722     EL_SIGN_RADIOACTIVITY,
1723     EL_SIGN_STOP,
1724     EL_SIGN_WHEELCHAIR,
1725     EL_SIGN_PARKING,
1726     EL_SIGN_ONEWAY,
1727     EL_SIGN_HEART,
1728     EL_SIGN_TRIANGLE,
1729     EL_SIGN_ROUND,
1730     EL_SIGN_EXIT,
1731     EL_SIGN_YINYANG,
1732     EL_SIGN_OTHER,
1733     EL_STEELWALL_SLIPPERY,
1734     EL_EMC_STEELWALL_1,
1735     EL_EMC_STEELWALL_2,
1736     EL_EMC_STEELWALL_3,
1737     EL_EMC_STEELWALL_4,
1738     EL_CRYSTAL,
1739     EL_GATE_1,
1740     EL_GATE_2,
1741     EL_GATE_3,
1742     EL_GATE_4,
1743     EL_GATE_1_GRAY,
1744     EL_GATE_2_GRAY,
1745     EL_GATE_3_GRAY,
1746     EL_GATE_4_GRAY,
1747     EL_EM_GATE_1,
1748     EL_EM_GATE_2,
1749     EL_EM_GATE_3,
1750     EL_EM_GATE_4,
1751     EL_EM_GATE_1_GRAY,
1752     EL_EM_GATE_2_GRAY,
1753     EL_EM_GATE_3_GRAY,
1754     EL_EM_GATE_4_GRAY,
1755     EL_SWITCHGATE_OPEN,
1756     EL_SWITCHGATE_OPENING,
1757     EL_SWITCHGATE_CLOSED,
1758     EL_SWITCHGATE_CLOSING,
1759 #if 0
1760     EL_SWITCHGATE_SWITCH_UP,
1761     EL_SWITCHGATE_SWITCH_DOWN,
1762 #endif
1763     EL_TIMEGATE_OPEN,
1764     EL_TIMEGATE_OPENING,
1765     EL_TIMEGATE_CLOSED,
1766     EL_TIMEGATE_CLOSING,
1767 #if 0
1768     EL_TIMEGATE_SWITCH,
1769     EL_TIMEGATE_SWITCH_ACTIVE,
1770 #endif
1771     EL_TUBE_ANY,
1772     EL_TUBE_VERTICAL,
1773     EL_TUBE_HORIZONTAL,
1774     EL_TUBE_VERTICAL_LEFT,
1775     EL_TUBE_VERTICAL_RIGHT,
1776     EL_TUBE_HORIZONTAL_UP,
1777     EL_TUBE_HORIZONTAL_DOWN,
1778     EL_TUBE_LEFT_UP,
1779     EL_TUBE_LEFT_DOWN,
1780     EL_TUBE_RIGHT_UP,
1781     EL_TUBE_RIGHT_DOWN,
1782     -1
1783   };
1784
1785   static int ep_slippery[] =
1786   {
1787     EL_WALL_SLIPPERY,
1788     EL_BD_WALL,
1789     EL_ROCK,
1790     EL_BD_ROCK,
1791     EL_EMERALD,
1792     EL_BD_DIAMOND,
1793     EL_EMERALD_YELLOW,
1794     EL_EMERALD_RED,
1795     EL_EMERALD_PURPLE,
1796     EL_DIAMOND,
1797     EL_BOMB,
1798     EL_NUT,
1799     EL_ROBOT_WHEEL_ACTIVE,
1800     EL_ROBOT_WHEEL,
1801     EL_TIME_ORB_FULL,
1802     EL_TIME_ORB_EMPTY,
1803     EL_LAMP_ACTIVE,
1804     EL_LAMP,
1805     EL_ACID_POOL_TOPLEFT,
1806     EL_ACID_POOL_TOPRIGHT,
1807     EL_SATELLITE,
1808     EL_SP_ZONK,
1809     EL_SP_INFOTRON,
1810     EL_SP_CHIP_SINGLE,
1811     EL_SP_CHIP_LEFT,
1812     EL_SP_CHIP_RIGHT,
1813     EL_SP_CHIP_TOP,
1814     EL_SP_CHIP_BOTTOM,
1815     EL_SPEED_PILL,
1816     EL_STEELWALL_SLIPPERY,
1817     EL_PEARL,
1818     EL_CRYSTAL,
1819     -1
1820   };
1821
1822   static int ep_can_change[] =
1823   {
1824     -1
1825   };
1826
1827   static int ep_can_move[] =
1828   {
1829     EL_BUG,
1830     EL_SPACESHIP,
1831     EL_BD_BUTTERFLY,
1832     EL_BD_FIREFLY,
1833     EL_YAMYAM,
1834     EL_DARK_YAMYAM,
1835     EL_ROBOT,
1836     EL_PACMAN,
1837     EL_MOLE,
1838     EL_PENGUIN,
1839     EL_PIG,
1840     EL_DRAGON,
1841     EL_SATELLITE,
1842     EL_SP_SNIKSNAK,
1843     EL_SP_ELECTRON,
1844     EL_BALLOON,
1845     EL_SPRING,
1846     -1
1847   };
1848
1849   static int ep_can_fall[] =
1850   {
1851     EL_ROCK,
1852     EL_BD_ROCK,
1853     EL_EMERALD,
1854     EL_BD_DIAMOND,
1855     EL_EMERALD_YELLOW,
1856     EL_EMERALD_RED,
1857     EL_EMERALD_PURPLE,
1858     EL_DIAMOND,
1859     EL_BOMB,
1860     EL_NUT,
1861     EL_AMOEBA_DROP,
1862     EL_QUICKSAND_FULL,
1863     EL_MAGIC_WALL_FULL,
1864     EL_BD_MAGIC_WALL_FULL,
1865     EL_TIME_ORB_FULL,
1866     EL_TIME_ORB_EMPTY,
1867     EL_SP_ZONK,
1868     EL_SP_INFOTRON,
1869     EL_SP_DISK_ORANGE,
1870     EL_PEARL,
1871     EL_CRYSTAL,
1872     EL_SPRING,
1873     EL_DX_SUPABOMB,
1874     -1
1875   };
1876
1877   static int ep_can_smash_player[] =
1878   {
1879     EL_ROCK,
1880     EL_BD_ROCK,
1881     EL_EMERALD,
1882     EL_BD_DIAMOND,
1883     EL_EMERALD_YELLOW,
1884     EL_EMERALD_RED,
1885     EL_EMERALD_PURPLE,
1886     EL_DIAMOND,
1887     EL_BOMB,
1888     EL_NUT,
1889     EL_AMOEBA_DROP,
1890     EL_TIME_ORB_FULL,
1891     EL_TIME_ORB_EMPTY,
1892     EL_SP_ZONK,
1893     EL_SP_INFOTRON,
1894     EL_SP_DISK_ORANGE,
1895     EL_PEARL,
1896     EL_CRYSTAL,
1897     EL_SPRING,
1898     EL_DX_SUPABOMB,
1899     -1
1900   };
1901
1902   static int ep_can_smash_enemies[] =
1903   {
1904     EL_ROCK,
1905     EL_BD_ROCK,
1906     EL_SP_ZONK,
1907     -1
1908   };
1909
1910   static int ep_can_smash_everything[] =
1911   {
1912     EL_ROCK,
1913     EL_BD_ROCK,
1914     EL_SP_ZONK,
1915     -1
1916   };
1917
1918   static int ep_can_explode_by_fire[] =
1919   {
1920     /* same elements as in 'ep_can_explode_impact' */
1921     EL_BOMB,
1922     EL_SP_DISK_ORANGE,
1923     EL_DX_SUPABOMB,
1924
1925     /* same elements as in 'ep_can_explode_smashed' */
1926     EL_SATELLITE,
1927     EL_PIG,
1928     EL_DRAGON,
1929     EL_MOLE,
1930
1931     /* new elements */
1932     EL_DYNAMITE_ACTIVE,
1933     EL_DYNAMITE,
1934     EL_DYNABOMB_PLAYER_1_ACTIVE,
1935     EL_DYNABOMB_PLAYER_2_ACTIVE,
1936     EL_DYNABOMB_PLAYER_3_ACTIVE,
1937     EL_DYNABOMB_PLAYER_4_ACTIVE,
1938     EL_DYNABOMB_INCREASE_NUMBER,
1939     EL_DYNABOMB_INCREASE_SIZE,
1940     EL_DYNABOMB_INCREASE_POWER,
1941     EL_SP_DISK_RED_ACTIVE,
1942     EL_BUG,
1943     EL_PENGUIN,
1944     EL_SP_DISK_RED,
1945     EL_SP_DISK_YELLOW,
1946     EL_SP_SNIKSNAK,
1947     EL_SP_ELECTRON,
1948 #if 0
1949     EL_BLACK_ORB,
1950 #endif
1951     -1
1952   };
1953
1954   static int ep_can_explode_smashed[] =
1955   {
1956     /* same elements as in 'ep_can_explode_impact' */
1957     EL_BOMB,
1958     EL_SP_DISK_ORANGE,
1959     EL_DX_SUPABOMB,
1960
1961     /* new elements */
1962     EL_SATELLITE,
1963     EL_PIG,
1964     EL_DRAGON,
1965     EL_MOLE,
1966     -1
1967   };
1968
1969   static int ep_can_explode_impact[] =
1970   {
1971     EL_BOMB,
1972     EL_SP_DISK_ORANGE,
1973     EL_DX_SUPABOMB,
1974     -1
1975   };
1976
1977   static int ep_walkable_over[] =
1978   {
1979     EL_EMPTY_SPACE,
1980     EL_SP_EMPTY_SPACE,
1981     EL_SOKOBAN_FIELD_EMPTY,
1982     EL_EXIT_OPEN,
1983     EL_SP_EXIT_OPEN,
1984     EL_SP_EXIT_OPENING,
1985     EL_GATE_1,
1986     EL_GATE_2,
1987     EL_GATE_3,
1988     EL_GATE_4,
1989     EL_GATE_1_GRAY,
1990     EL_GATE_2_GRAY,
1991     EL_GATE_3_GRAY,
1992     EL_GATE_4_GRAY,
1993     EL_PENGUIN,
1994     EL_PIG,
1995     EL_DRAGON,
1996     -1
1997   };
1998
1999   static int ep_walkable_inside[] =
2000   {
2001     EL_TUBE_ANY,
2002     EL_TUBE_VERTICAL,
2003     EL_TUBE_HORIZONTAL,
2004     EL_TUBE_VERTICAL_LEFT,
2005     EL_TUBE_VERTICAL_RIGHT,
2006     EL_TUBE_HORIZONTAL_UP,
2007     EL_TUBE_HORIZONTAL_DOWN,
2008     EL_TUBE_LEFT_UP,
2009     EL_TUBE_LEFT_DOWN,
2010     EL_TUBE_RIGHT_UP,
2011     EL_TUBE_RIGHT_DOWN,
2012     -1
2013   };
2014
2015   static int ep_walkable_under[] =
2016   {
2017     -1
2018   };
2019
2020   static int ep_passable_over[] =
2021   {
2022     EL_EM_GATE_1,
2023     EL_EM_GATE_2,
2024     EL_EM_GATE_3,
2025     EL_EM_GATE_4,
2026     EL_EM_GATE_1_GRAY,
2027     EL_EM_GATE_2_GRAY,
2028     EL_EM_GATE_3_GRAY,
2029     EL_EM_GATE_4_GRAY,
2030     EL_SWITCHGATE_OPEN,
2031     EL_TIMEGATE_OPEN,
2032     -1
2033   };
2034
2035   static int ep_passable_inside[] =
2036   {
2037     EL_SP_PORT_LEFT,
2038     EL_SP_PORT_RIGHT,
2039     EL_SP_PORT_UP,
2040     EL_SP_PORT_DOWN,
2041     EL_SP_PORT_HORIZONTAL,
2042     EL_SP_PORT_VERTICAL,
2043     EL_SP_PORT_ANY,
2044     EL_SP_GRAVITY_PORT_LEFT,
2045     EL_SP_GRAVITY_PORT_RIGHT,
2046     EL_SP_GRAVITY_PORT_UP,
2047     EL_SP_GRAVITY_PORT_DOWN,
2048     -1
2049   };
2050
2051   static int ep_passable_under[] =
2052   {
2053     -1
2054   };
2055
2056   static int ep_droppable[] =
2057   {
2058     -1
2059   };
2060
2061   static int ep_can_explode_1x1[] =
2062   {
2063     -1
2064   };
2065
2066   static int ep_pushable[] =
2067   {
2068     EL_ROCK,
2069     EL_BOMB,
2070     EL_DX_SUPABOMB,
2071     EL_NUT,
2072     EL_TIME_ORB_EMPTY,
2073     EL_SP_ZONK,
2074     EL_SP_DISK_ORANGE,
2075     EL_SPRING,
2076     EL_BD_ROCK,
2077     EL_SOKOBAN_OBJECT,
2078     EL_SOKOBAN_FIELD_FULL,
2079     EL_SATELLITE,
2080     EL_SP_DISK_YELLOW,
2081     EL_BALLOON,
2082     -1
2083   };
2084
2085   static int ep_can_explode_dyna[] =
2086   {
2087     -1
2088   };
2089
2090   static int ep_protected[] =
2091   {
2092     EL_EM_GATE_1,
2093     EL_EM_GATE_2,
2094     EL_EM_GATE_3,
2095     EL_EM_GATE_4,
2096     EL_EM_GATE_1_GRAY,
2097     EL_EM_GATE_2_GRAY,
2098     EL_EM_GATE_3_GRAY,
2099     EL_EM_GATE_4_GRAY,
2100     EL_SWITCHGATE_OPEN,
2101     EL_TIMEGATE_OPEN,
2102     -1
2103   };
2104
2105   static int ep_player[] =
2106   {
2107     EL_PLAYER_1,
2108     EL_PLAYER_2,
2109     EL_PLAYER_3,
2110     EL_PLAYER_4,
2111     EL_SP_MURPHY,
2112     -1
2113   };
2114
2115   static int ep_can_pass_magic_wall[] =
2116   {
2117     EL_ROCK,
2118     EL_BD_ROCK,
2119     EL_EMERALD,
2120     EL_BD_DIAMOND,
2121     EL_EMERALD_YELLOW,
2122     EL_EMERALD_RED,
2123     EL_EMERALD_PURPLE,
2124     EL_DIAMOND,
2125     -1
2126   };
2127
2128   static int ep_switchable[] =
2129   {
2130     EL_ROBOT_WHEEL,
2131     EL_SP_TERMINAL,
2132     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2133     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2134     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2135     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2136     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2137     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2138     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2139     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2140     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2141     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2142     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2143     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2144     EL_SWITCHGATE_SWITCH_UP,
2145     EL_SWITCHGATE_SWITCH_DOWN,
2146     EL_LIGHT_SWITCH,
2147     EL_LIGHT_SWITCH_ACTIVE,
2148     EL_TIMEGATE_SWITCH,
2149     EL_BALLOON_SWITCH_LEFT,
2150     EL_BALLOON_SWITCH_RIGHT,
2151     EL_BALLOON_SWITCH_UP,
2152     EL_BALLOON_SWITCH_DOWN,
2153     EL_BALLOON_SWITCH_ANY,
2154     EL_LAMP,
2155     EL_TIME_ORB_FULL,
2156     -1
2157   };
2158
2159   static int ep_bd_element[] =
2160   {
2161     EL_EMPTY,
2162     EL_SAND,
2163     EL_WALL_SLIPPERY,
2164     EL_BD_WALL,
2165     EL_ROCK,
2166     EL_BD_ROCK,
2167     EL_BD_DIAMOND,
2168     EL_BD_MAGIC_WALL,
2169     EL_EXIT_CLOSED,
2170     EL_EXIT_OPEN,
2171     EL_STEELWALL,
2172     EL_PLAYER_1,
2173     EL_BD_FIREFLY,
2174     EL_BD_FIREFLY_1,
2175     EL_BD_FIREFLY_2,
2176     EL_BD_FIREFLY_3,
2177     EL_BD_FIREFLY_4,
2178     EL_BD_BUTTERFLY,
2179     EL_BD_BUTTERFLY_1,
2180     EL_BD_BUTTERFLY_2,
2181     EL_BD_BUTTERFLY_3,
2182     EL_BD_BUTTERFLY_4,
2183     EL_BD_AMOEBA,
2184     EL_CHAR_QUESTION,
2185     EL_UNKNOWN,
2186     -1
2187   };
2188
2189   static int ep_sp_element[] =
2190   {
2191     /* should always be valid */
2192     EL_EMPTY,
2193
2194     EL_SP_EMPTY,
2195     EL_SP_ZONK,
2196     EL_SP_BASE,
2197     EL_SP_MURPHY,
2198     EL_SP_INFOTRON,
2199     EL_SP_CHIP_SINGLE,
2200     EL_SP_HARDWARE_GRAY,
2201     EL_SP_EXIT_CLOSED,
2202     EL_SP_EXIT_OPEN,
2203     EL_SP_DISK_ORANGE,
2204     EL_SP_PORT_RIGHT,
2205     EL_SP_PORT_DOWN,
2206     EL_SP_PORT_LEFT,
2207     EL_SP_PORT_UP,
2208     EL_SP_GRAVITY_PORT_RIGHT,
2209     EL_SP_GRAVITY_PORT_DOWN,
2210     EL_SP_GRAVITY_PORT_LEFT,
2211     EL_SP_GRAVITY_PORT_UP,
2212     EL_SP_SNIKSNAK,
2213     EL_SP_DISK_YELLOW,
2214     EL_SP_TERMINAL,
2215     EL_SP_DISK_RED,
2216     EL_SP_PORT_VERTICAL,
2217     EL_SP_PORT_HORIZONTAL,
2218     EL_SP_PORT_ANY,
2219     EL_SP_ELECTRON,
2220     EL_SP_BUGGY_BASE,
2221     EL_SP_CHIP_LEFT,
2222     EL_SP_CHIP_RIGHT,
2223     EL_SP_HARDWARE_BASE_1,
2224     EL_SP_HARDWARE_GREEN,
2225     EL_SP_HARDWARE_BLUE,
2226     EL_SP_HARDWARE_RED,
2227     EL_SP_HARDWARE_YELLOW,
2228     EL_SP_HARDWARE_BASE_2,
2229     EL_SP_HARDWARE_BASE_3,
2230     EL_SP_HARDWARE_BASE_4,
2231     EL_SP_HARDWARE_BASE_5,
2232     EL_SP_HARDWARE_BASE_6,
2233     EL_SP_CHIP_TOP,
2234     EL_SP_CHIP_BOTTOM,
2235     /* additional elements that appeared in newer Supaplex levels */
2236     EL_INVISIBLE_WALL,
2237     /* more than one murphy in a level results in an inactive clone */
2238     EL_SP_MURPHY_CLONE,
2239     /* runtime elements*/
2240     EL_SP_DISK_RED_ACTIVE,
2241     EL_SP_TERMINAL_ACTIVE,
2242     EL_SP_BUGGY_BASE_ACTIVATING,
2243     EL_SP_BUGGY_BASE_ACTIVE,
2244     EL_SP_EXIT_OPENING,
2245     EL_SP_EXIT_CLOSING,
2246     -1
2247   };
2248
2249   static int ep_sb_element[] =
2250   {
2251     EL_EMPTY,
2252     EL_STEELWALL,
2253     EL_SOKOBAN_OBJECT,
2254     EL_SOKOBAN_FIELD_EMPTY,
2255     EL_SOKOBAN_FIELD_FULL,
2256     EL_PLAYER_1,
2257     EL_INVISIBLE_STEELWALL,
2258     -1
2259   };
2260
2261   static int ep_gem[] =
2262   {
2263     EL_BD_DIAMOND,
2264     EL_EMERALD,
2265     EL_EMERALD_YELLOW,
2266     EL_EMERALD_RED,
2267     EL_EMERALD_PURPLE,
2268     EL_DIAMOND,
2269     -1
2270   };
2271
2272   static int ep_food_dark_yamyam[] =
2273   {
2274     EL_SAND,
2275     EL_BUG,
2276     EL_SPACESHIP,
2277     EL_BD_BUTTERFLY,
2278     EL_BD_FIREFLY,
2279     EL_YAMYAM,
2280     EL_ROBOT,
2281     EL_PACMAN,
2282     EL_AMOEBA_DROP,
2283     EL_AMOEBA_DEAD,
2284     EL_AMOEBA_WET,
2285     EL_AMOEBA_DRY,
2286     EL_AMOEBA_FULL,
2287     EL_BD_AMOEBA,
2288     EL_EMERALD,
2289     EL_BD_DIAMOND,
2290     EL_EMERALD_YELLOW,
2291     EL_EMERALD_RED,
2292     EL_EMERALD_PURPLE,
2293     EL_DIAMOND,
2294     EL_PEARL,
2295     EL_CRYSTAL,
2296     -1
2297   };
2298
2299   static int ep_food_penguin[] =
2300   {
2301     EL_EMERALD,
2302     EL_BD_DIAMOND,
2303     EL_EMERALD_YELLOW,
2304     EL_EMERALD_RED,
2305     EL_EMERALD_PURPLE,
2306     EL_DIAMOND,
2307     EL_PEARL,
2308     EL_CRYSTAL,
2309     -1
2310   };
2311
2312   static int ep_food_pig[] =
2313   {
2314     EL_EMERALD,
2315     EL_BD_DIAMOND,
2316     EL_EMERALD_YELLOW,
2317     EL_EMERALD_RED,
2318     EL_EMERALD_PURPLE,
2319     EL_DIAMOND,
2320     -1
2321   };
2322
2323   static int ep_historic_wall[] =
2324   {
2325     EL_STEELWALL,
2326     EL_GATE_1,
2327     EL_GATE_2,
2328     EL_GATE_3,
2329     EL_GATE_4,
2330     EL_GATE_1_GRAY,
2331     EL_GATE_2_GRAY,
2332     EL_GATE_3_GRAY,
2333     EL_GATE_4_GRAY,
2334     EL_EM_GATE_1,
2335     EL_EM_GATE_2,
2336     EL_EM_GATE_3,
2337     EL_EM_GATE_4,
2338     EL_EM_GATE_1_GRAY,
2339     EL_EM_GATE_2_GRAY,
2340     EL_EM_GATE_3_GRAY,
2341     EL_EM_GATE_4_GRAY,
2342     EL_EXIT_CLOSED,
2343     EL_EXIT_OPENING,
2344     EL_EXIT_OPEN,
2345     EL_WALL,
2346     EL_WALL_SLIPPERY,
2347     EL_EXPANDABLE_WALL,
2348     EL_EXPANDABLE_WALL_HORIZONTAL,
2349     EL_EXPANDABLE_WALL_VERTICAL,
2350     EL_EXPANDABLE_WALL_ANY,
2351     EL_EXPANDABLE_WALL_GROWING,
2352     EL_BD_WALL,
2353     EL_SP_CHIP_SINGLE,
2354     EL_SP_CHIP_LEFT,
2355     EL_SP_CHIP_RIGHT,
2356     EL_SP_CHIP_TOP,
2357     EL_SP_CHIP_BOTTOM,
2358     EL_SP_HARDWARE_GRAY,
2359     EL_SP_HARDWARE_GREEN,
2360     EL_SP_HARDWARE_BLUE,
2361     EL_SP_HARDWARE_RED,
2362     EL_SP_HARDWARE_YELLOW,
2363     EL_SP_HARDWARE_BASE_1,
2364     EL_SP_HARDWARE_BASE_2,
2365     EL_SP_HARDWARE_BASE_3,
2366     EL_SP_HARDWARE_BASE_4,
2367     EL_SP_HARDWARE_BASE_5,
2368     EL_SP_HARDWARE_BASE_6,
2369     EL_SP_TERMINAL,
2370     EL_SP_TERMINAL_ACTIVE,
2371     EL_SP_EXIT_CLOSED,
2372     EL_SP_EXIT_OPEN,
2373     EL_INVISIBLE_STEELWALL,
2374     EL_INVISIBLE_STEELWALL_ACTIVE,
2375     EL_INVISIBLE_WALL,
2376     EL_INVISIBLE_WALL_ACTIVE,
2377     EL_STEELWALL_SLIPPERY,
2378     EL_EMC_STEELWALL_1,
2379     EL_EMC_STEELWALL_2,
2380     EL_EMC_STEELWALL_3,
2381     EL_EMC_STEELWALL_4,
2382     EL_EMC_WALL_1,
2383     EL_EMC_WALL_2,
2384     EL_EMC_WALL_3,
2385     EL_EMC_WALL_4,
2386     EL_EMC_WALL_5,
2387     EL_EMC_WALL_6,
2388     EL_EMC_WALL_7,
2389     EL_EMC_WALL_8,
2390     -1
2391   };
2392
2393   static int ep_historic_solid[] =
2394   {
2395     EL_WALL,
2396     EL_EXPANDABLE_WALL,
2397     EL_EXPANDABLE_WALL_HORIZONTAL,
2398     EL_EXPANDABLE_WALL_VERTICAL,
2399     EL_EXPANDABLE_WALL_ANY,
2400     EL_BD_WALL,
2401     EL_WALL_SLIPPERY,
2402     EL_EXIT_CLOSED,
2403     EL_EXIT_OPENING,
2404     EL_EXIT_OPEN,
2405     EL_AMOEBA_DEAD,
2406     EL_AMOEBA_WET,
2407     EL_AMOEBA_DRY,
2408     EL_AMOEBA_FULL,
2409     EL_BD_AMOEBA,
2410     EL_QUICKSAND_EMPTY,
2411     EL_QUICKSAND_FULL,
2412     EL_QUICKSAND_FILLING,
2413     EL_QUICKSAND_EMPTYING,
2414     EL_MAGIC_WALL,
2415     EL_MAGIC_WALL_ACTIVE,
2416     EL_MAGIC_WALL_EMPTYING,
2417     EL_MAGIC_WALL_FILLING,
2418     EL_MAGIC_WALL_FULL,
2419     EL_MAGIC_WALL_DEAD,
2420     EL_BD_MAGIC_WALL,
2421     EL_BD_MAGIC_WALL_ACTIVE,
2422     EL_BD_MAGIC_WALL_EMPTYING,
2423     EL_BD_MAGIC_WALL_FULL,
2424     EL_BD_MAGIC_WALL_FILLING,
2425     EL_BD_MAGIC_WALL_DEAD,
2426     EL_GAME_OF_LIFE,
2427     EL_BIOMAZE,
2428     EL_SP_CHIP_SINGLE,
2429     EL_SP_CHIP_LEFT,
2430     EL_SP_CHIP_RIGHT,
2431     EL_SP_CHIP_TOP,
2432     EL_SP_CHIP_BOTTOM,
2433     EL_SP_TERMINAL,
2434     EL_SP_TERMINAL_ACTIVE,
2435     EL_SP_EXIT_CLOSED,
2436     EL_SP_EXIT_OPEN,
2437     EL_INVISIBLE_WALL,
2438     EL_INVISIBLE_WALL_ACTIVE,
2439     EL_SWITCHGATE_SWITCH_UP,
2440     EL_SWITCHGATE_SWITCH_DOWN,
2441     EL_TIMEGATE_SWITCH,
2442     EL_TIMEGATE_SWITCH_ACTIVE,
2443     EL_EMC_WALL_1,
2444     EL_EMC_WALL_2,
2445     EL_EMC_WALL_3,
2446     EL_EMC_WALL_4,
2447     EL_EMC_WALL_5,
2448     EL_EMC_WALL_6,
2449     EL_EMC_WALL_7,
2450     EL_EMC_WALL_8,
2451     EL_WALL_PEARL,
2452     EL_WALL_CRYSTAL,
2453
2454     /* the following elements are a direct copy of "indestructible" elements,
2455        except "EL_ACID", which is "indestructible", but not "solid"! */
2456 #if 0
2457     EL_ACID,
2458 #endif
2459     EL_STEELWALL,
2460     EL_ACID_POOL_TOPLEFT,
2461     EL_ACID_POOL_TOPRIGHT,
2462     EL_ACID_POOL_BOTTOMLEFT,
2463     EL_ACID_POOL_BOTTOM,
2464     EL_ACID_POOL_BOTTOMRIGHT,
2465     EL_SP_HARDWARE_GRAY,
2466     EL_SP_HARDWARE_GREEN,
2467     EL_SP_HARDWARE_BLUE,
2468     EL_SP_HARDWARE_RED,
2469     EL_SP_HARDWARE_YELLOW,
2470     EL_SP_HARDWARE_BASE_1,
2471     EL_SP_HARDWARE_BASE_2,
2472     EL_SP_HARDWARE_BASE_3,
2473     EL_SP_HARDWARE_BASE_4,
2474     EL_SP_HARDWARE_BASE_5,
2475     EL_SP_HARDWARE_BASE_6,
2476     EL_INVISIBLE_STEELWALL,
2477     EL_INVISIBLE_STEELWALL_ACTIVE,
2478     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2479     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2480     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2481     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2482     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2483     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2484     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2485     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2486     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2487     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2488     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2489     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2490     EL_LIGHT_SWITCH,
2491     EL_LIGHT_SWITCH_ACTIVE,
2492     EL_SIGN_EXCLAMATION,
2493     EL_SIGN_RADIOACTIVITY,
2494     EL_SIGN_STOP,
2495     EL_SIGN_WHEELCHAIR,
2496     EL_SIGN_PARKING,
2497     EL_SIGN_ONEWAY,
2498     EL_SIGN_HEART,
2499     EL_SIGN_TRIANGLE,
2500     EL_SIGN_ROUND,
2501     EL_SIGN_EXIT,
2502     EL_SIGN_YINYANG,
2503     EL_SIGN_OTHER,
2504     EL_STEELWALL_SLIPPERY,
2505     EL_EMC_STEELWALL_1,
2506     EL_EMC_STEELWALL_2,
2507     EL_EMC_STEELWALL_3,
2508     EL_EMC_STEELWALL_4,
2509     EL_CRYSTAL,
2510     EL_GATE_1,
2511     EL_GATE_2,
2512     EL_GATE_3,
2513     EL_GATE_4,
2514     EL_GATE_1_GRAY,
2515     EL_GATE_2_GRAY,
2516     EL_GATE_3_GRAY,
2517     EL_GATE_4_GRAY,
2518     EL_EM_GATE_1,
2519     EL_EM_GATE_2,
2520     EL_EM_GATE_3,
2521     EL_EM_GATE_4,
2522     EL_EM_GATE_1_GRAY,
2523     EL_EM_GATE_2_GRAY,
2524     EL_EM_GATE_3_GRAY,
2525     EL_EM_GATE_4_GRAY,
2526     EL_SWITCHGATE_OPEN,
2527     EL_SWITCHGATE_OPENING,
2528     EL_SWITCHGATE_CLOSED,
2529     EL_SWITCHGATE_CLOSING,
2530     EL_TIMEGATE_OPEN,
2531     EL_TIMEGATE_OPENING,
2532     EL_TIMEGATE_CLOSED,
2533     EL_TIMEGATE_CLOSING,
2534     EL_TUBE_ANY,
2535     EL_TUBE_VERTICAL,
2536     EL_TUBE_HORIZONTAL,
2537     EL_TUBE_VERTICAL_LEFT,
2538     EL_TUBE_VERTICAL_RIGHT,
2539     EL_TUBE_HORIZONTAL_UP,
2540     EL_TUBE_HORIZONTAL_DOWN,
2541     EL_TUBE_LEFT_UP,
2542     EL_TUBE_LEFT_DOWN,
2543     EL_TUBE_RIGHT_UP,
2544     EL_TUBE_RIGHT_DOWN,
2545     -1
2546   };
2547
2548   static int ep_classic_enemy[] =
2549   {
2550     EL_BUG,
2551     EL_SPACESHIP,
2552     EL_BD_BUTTERFLY,
2553     EL_BD_FIREFLY,
2554
2555     EL_YAMYAM,
2556     EL_DARK_YAMYAM,
2557     EL_ROBOT,
2558     EL_PACMAN,
2559     EL_SP_SNIKSNAK,
2560     EL_SP_ELECTRON,
2561     -1
2562   };
2563
2564   static int ep_belt[] =
2565   {
2566     EL_CONVEYOR_BELT_1_LEFT,
2567     EL_CONVEYOR_BELT_1_MIDDLE,
2568     EL_CONVEYOR_BELT_1_RIGHT,
2569     EL_CONVEYOR_BELT_2_LEFT,
2570     EL_CONVEYOR_BELT_2_MIDDLE,
2571     EL_CONVEYOR_BELT_2_RIGHT,
2572     EL_CONVEYOR_BELT_3_LEFT,
2573     EL_CONVEYOR_BELT_3_MIDDLE,
2574     EL_CONVEYOR_BELT_3_RIGHT,
2575     EL_CONVEYOR_BELT_4_LEFT,
2576     EL_CONVEYOR_BELT_4_MIDDLE,
2577     EL_CONVEYOR_BELT_4_RIGHT,
2578     -1
2579   };
2580
2581   static int ep_belt_active[] =
2582   {
2583     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2584     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2585     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2586     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2587     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2588     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2589     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2590     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2591     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2592     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2593     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2594     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2595     -1
2596   };
2597
2598   static int ep_belt_switch[] =
2599   {
2600     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2601     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2602     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2603     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2604     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2605     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2606     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2607     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2608     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2609     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2610     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2611     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2612     -1
2613   };
2614
2615   static int ep_tube[] =
2616   {
2617     EL_TUBE_LEFT_UP,
2618     EL_TUBE_LEFT_DOWN,
2619     EL_TUBE_RIGHT_UP,
2620     EL_TUBE_RIGHT_DOWN,
2621     EL_TUBE_HORIZONTAL,
2622     EL_TUBE_HORIZONTAL_UP,
2623     EL_TUBE_HORIZONTAL_DOWN,
2624     EL_TUBE_VERTICAL,
2625     EL_TUBE_VERTICAL_LEFT,
2626     EL_TUBE_VERTICAL_RIGHT,
2627     EL_TUBE_ANY,
2628     -1
2629   };
2630
2631   static int ep_keygate[] =
2632   {
2633     EL_GATE_1,
2634     EL_GATE_2,
2635     EL_GATE_3,
2636     EL_GATE_4,
2637     EL_GATE_1_GRAY,
2638     EL_GATE_2_GRAY,
2639     EL_GATE_3_GRAY,
2640     EL_GATE_4_GRAY,
2641     EL_EM_GATE_1,
2642     EL_EM_GATE_2,
2643     EL_EM_GATE_3,
2644     EL_EM_GATE_4,
2645     EL_EM_GATE_1_GRAY,
2646     EL_EM_GATE_2_GRAY,
2647     EL_EM_GATE_3_GRAY,
2648     EL_EM_GATE_4_GRAY,
2649     -1
2650   };
2651
2652   static int ep_amoeboid[] =
2653   {
2654     EL_AMOEBA_DEAD,
2655     EL_AMOEBA_WET,
2656     EL_AMOEBA_DRY,
2657     EL_AMOEBA_FULL,
2658     EL_BD_AMOEBA,
2659     -1
2660   };
2661
2662   static int ep_amoebalive[] =
2663   {
2664     EL_AMOEBA_WET,
2665     EL_AMOEBA_DRY,
2666     EL_AMOEBA_FULL,
2667     EL_BD_AMOEBA,
2668     -1
2669   };
2670
2671   static int ep_has_content[] =
2672   {
2673     EL_YAMYAM,
2674     EL_AMOEBA_WET,
2675     EL_AMOEBA_DRY,
2676     EL_AMOEBA_FULL,
2677     EL_BD_AMOEBA,
2678     -1
2679   };
2680
2681   static int ep_active_bomb[] =
2682   {
2683     EL_DYNAMITE_ACTIVE,
2684     EL_DYNABOMB_PLAYER_1_ACTIVE,
2685     EL_DYNABOMB_PLAYER_2_ACTIVE,
2686     EL_DYNABOMB_PLAYER_3_ACTIVE,
2687     EL_DYNABOMB_PLAYER_4_ACTIVE,
2688     EL_SP_DISK_RED_ACTIVE,
2689     -1
2690   };
2691
2692   static int ep_inactive[] =
2693   {
2694     EL_EMPTY,
2695     EL_SAND,
2696     EL_WALL,
2697     EL_BD_WALL,
2698     EL_WALL_SLIPPERY,
2699     EL_STEELWALL,
2700     EL_AMOEBA_DEAD,
2701     EL_QUICKSAND_EMPTY,
2702     EL_STONEBLOCK,
2703     EL_ROBOT_WHEEL,
2704     EL_KEY_1,
2705     EL_KEY_2,
2706     EL_KEY_3,
2707     EL_KEY_4,
2708     EL_EM_KEY_1,
2709     EL_EM_KEY_2,
2710     EL_EM_KEY_3,
2711     EL_EM_KEY_4,
2712     EL_GATE_1,
2713     EL_GATE_2,
2714     EL_GATE_3,
2715     EL_GATE_4,
2716     EL_GATE_1_GRAY,
2717     EL_GATE_2_GRAY,
2718     EL_GATE_3_GRAY,
2719     EL_GATE_4_GRAY,
2720     EL_EM_GATE_1,
2721     EL_EM_GATE_2,
2722     EL_EM_GATE_3,
2723     EL_EM_GATE_4,
2724     EL_EM_GATE_1_GRAY,
2725     EL_EM_GATE_2_GRAY,
2726     EL_EM_GATE_3_GRAY,
2727     EL_EM_GATE_4_GRAY,
2728     EL_DYNAMITE,
2729     EL_INVISIBLE_STEELWALL,
2730     EL_INVISIBLE_WALL,
2731     EL_INVISIBLE_SAND,
2732     EL_LAMP,
2733     EL_LAMP_ACTIVE,
2734     EL_WALL_EMERALD,
2735     EL_WALL_DIAMOND,
2736     EL_WALL_BD_DIAMOND,
2737     EL_WALL_EMERALD_YELLOW,
2738     EL_DYNABOMB_INCREASE_NUMBER,
2739     EL_DYNABOMB_INCREASE_SIZE,
2740     EL_DYNABOMB_INCREASE_POWER,
2741 #if 0
2742     EL_SOKOBAN_OBJECT,
2743 #endif
2744     EL_SOKOBAN_FIELD_EMPTY,
2745     EL_SOKOBAN_FIELD_FULL,
2746     EL_WALL_EMERALD_RED,
2747     EL_WALL_EMERALD_PURPLE,
2748     EL_ACID_POOL_TOPLEFT,
2749     EL_ACID_POOL_TOPRIGHT,
2750     EL_ACID_POOL_BOTTOMLEFT,
2751     EL_ACID_POOL_BOTTOM,
2752     EL_ACID_POOL_BOTTOMRIGHT,
2753     EL_MAGIC_WALL,
2754     EL_MAGIC_WALL_DEAD,
2755     EL_BD_MAGIC_WALL,
2756     EL_BD_MAGIC_WALL_DEAD,
2757     EL_AMOEBA_TO_DIAMOND,
2758     EL_BLOCKED,
2759     EL_SP_EMPTY,
2760     EL_SP_BASE,
2761     EL_SP_PORT_RIGHT,
2762     EL_SP_PORT_DOWN,
2763     EL_SP_PORT_LEFT,
2764     EL_SP_PORT_UP,
2765     EL_SP_GRAVITY_PORT_RIGHT,
2766     EL_SP_GRAVITY_PORT_DOWN,
2767     EL_SP_GRAVITY_PORT_LEFT,
2768     EL_SP_GRAVITY_PORT_UP,
2769     EL_SP_PORT_HORIZONTAL,
2770     EL_SP_PORT_VERTICAL,
2771     EL_SP_PORT_ANY,
2772     EL_SP_DISK_RED,
2773 #if 0
2774     EL_SP_DISK_YELLOW,
2775 #endif
2776     EL_SP_CHIP_SINGLE,
2777     EL_SP_CHIP_LEFT,
2778     EL_SP_CHIP_RIGHT,
2779     EL_SP_CHIP_TOP,
2780     EL_SP_CHIP_BOTTOM,
2781     EL_SP_HARDWARE_GRAY,
2782     EL_SP_HARDWARE_GREEN,
2783     EL_SP_HARDWARE_BLUE,
2784     EL_SP_HARDWARE_RED,
2785     EL_SP_HARDWARE_YELLOW,
2786     EL_SP_HARDWARE_BASE_1,
2787     EL_SP_HARDWARE_BASE_2,
2788     EL_SP_HARDWARE_BASE_3,
2789     EL_SP_HARDWARE_BASE_4,
2790     EL_SP_HARDWARE_BASE_5,
2791     EL_SP_HARDWARE_BASE_6,
2792     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2793     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2794     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2795     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2796     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2797     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2798     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2799     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2800     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2801     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2802     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2803     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2804     EL_SIGN_EXCLAMATION,
2805     EL_SIGN_RADIOACTIVITY,
2806     EL_SIGN_STOP,
2807     EL_SIGN_WHEELCHAIR,
2808     EL_SIGN_PARKING,
2809     EL_SIGN_ONEWAY,
2810     EL_SIGN_HEART,
2811     EL_SIGN_TRIANGLE,
2812     EL_SIGN_ROUND,
2813     EL_SIGN_EXIT,
2814     EL_SIGN_YINYANG,
2815     EL_SIGN_OTHER,
2816     EL_STEELWALL_SLIPPERY,
2817     EL_EMC_STEELWALL_1,
2818     EL_EMC_STEELWALL_2,
2819     EL_EMC_STEELWALL_3,
2820     EL_EMC_STEELWALL_4,
2821     EL_EMC_WALL_1,
2822     EL_EMC_WALL_2,
2823     EL_EMC_WALL_3,
2824     EL_EMC_WALL_4,
2825     EL_EMC_WALL_5,
2826     EL_EMC_WALL_6,
2827     EL_EMC_WALL_7,
2828     EL_EMC_WALL_8,
2829     -1
2830   };
2831
2832   static int ep_em_slippery_wall[] =
2833   {
2834     -1
2835   };
2836
2837   static int ep_gfx_crumbled[] =
2838   {
2839     EL_SAND,
2840     EL_LANDMINE,
2841     EL_TRAP,
2842     EL_TRAP_ACTIVE,
2843     -1
2844   };
2845
2846   static struct
2847   {
2848     int *elements;
2849     int property;
2850   } element_properties[] =
2851   {
2852     { ep_diggable,              EP_DIGGABLE             },
2853     { ep_collectible_only,      EP_COLLECTIBLE_ONLY     },
2854     { ep_dont_run_into,         EP_DONT_RUN_INTO        },
2855     { ep_dont_collide_with,     EP_DONT_COLLIDE_WITH    },
2856     { ep_dont_touch,            EP_DONT_TOUCH           },
2857     { ep_indestructible,        EP_INDESTRUCTIBLE       },
2858     { ep_slippery,              EP_SLIPPERY             },
2859     { ep_can_change,            EP_CAN_CHANGE           },
2860     { ep_can_move,              EP_CAN_MOVE             },
2861     { ep_can_fall,              EP_CAN_FALL             },
2862     { ep_can_smash_player,      EP_CAN_SMASH_PLAYER     },
2863     { ep_can_smash_enemies,     EP_CAN_SMASH_ENEMIES    },
2864     { ep_can_smash_everything,  EP_CAN_SMASH_EVERYTHING },
2865     { ep_can_explode_by_fire,   EP_CAN_EXPLODE_BY_FIRE  },
2866     { ep_can_explode_smashed,   EP_CAN_EXPLODE_SMASHED  },
2867     { ep_can_explode_impact,    EP_CAN_EXPLODE_IMPACT   },
2868     { ep_walkable_over,         EP_WALKABLE_OVER        },
2869     { ep_walkable_inside,       EP_WALKABLE_INSIDE      },
2870     { ep_walkable_under,        EP_WALKABLE_UNDER       },
2871     { ep_passable_over,         EP_PASSABLE_OVER        },
2872     { ep_passable_inside,       EP_PASSABLE_INSIDE      },
2873     { ep_passable_under,        EP_PASSABLE_UNDER       },
2874     { ep_droppable,             EP_DROPPABLE            },
2875     { ep_can_explode_1x1,       EP_CAN_EXPLODE_1X1      },
2876     { ep_pushable,              EP_PUSHABLE             },
2877     { ep_can_explode_dyna,      EP_CAN_EXPLODE_DYNA     },
2878     { ep_protected,             EP_PROTECTED            },
2879
2880     { ep_player,                EP_PLAYER               },
2881     { ep_can_pass_magic_wall,   EP_CAN_PASS_MAGIC_WALL  },
2882     { ep_switchable,            EP_SWITCHABLE           },
2883     { ep_bd_element,            EP_BD_ELEMENT           },
2884     { ep_sp_element,            EP_SP_ELEMENT           },
2885     { ep_sb_element,            EP_SB_ELEMENT           },
2886     { ep_gem,                   EP_GEM                  },
2887     { ep_food_dark_yamyam,      EP_FOOD_DARK_YAMYAM     },
2888     { ep_food_penguin,          EP_FOOD_PENGUIN         },
2889     { ep_food_pig,              EP_FOOD_PIG             },
2890     { ep_historic_wall,         EP_HISTORIC_WALL        },
2891     { ep_historic_solid,        EP_HISTORIC_SOLID       },
2892     { ep_classic_enemy,         EP_CLASSIC_ENEMY        },
2893     { ep_belt,                  EP_BELT                 },
2894     { ep_belt_active,           EP_BELT_ACTIVE          },
2895     { ep_belt_switch,           EP_BELT_SWITCH          },
2896     { ep_tube,                  EP_TUBE                 },
2897     { ep_keygate,               EP_KEYGATE              },
2898     { ep_amoeboid,              EP_AMOEBOID             },
2899     { ep_amoebalive,            EP_AMOEBALIVE           },
2900     { ep_has_content,           EP_HAS_CONTENT          },
2901     { ep_active_bomb,           EP_ACTIVE_BOMB          },
2902     { ep_inactive,              EP_INACTIVE             },
2903
2904     { ep_em_slippery_wall,      EP_EM_SLIPPERY_WALL     },
2905
2906     { ep_gfx_crumbled,          EP_GFX_CRUMBLED         },
2907
2908     { NULL,                     -1                      }
2909   };
2910
2911   static int copy_properties[][5] =
2912   {
2913     {
2914       EL_BUG,
2915       EL_BUG_LEFT,              EL_BUG_RIGHT,
2916       EL_BUG_UP,                EL_BUG_DOWN
2917     },
2918     {
2919       EL_SPACESHIP,
2920       EL_SPACESHIP_LEFT,        EL_SPACESHIP_RIGHT,
2921       EL_SPACESHIP_UP,          EL_SPACESHIP_DOWN
2922     },
2923     {
2924       EL_BD_BUTTERFLY,
2925       EL_BD_BUTTERFLY_LEFT,     EL_BD_BUTTERFLY_RIGHT,
2926       EL_BD_BUTTERFLY_UP,       EL_BD_BUTTERFLY_DOWN
2927     },
2928     {
2929       EL_BD_FIREFLY,
2930       EL_BD_FIREFLY_LEFT,       EL_BD_FIREFLY_RIGHT,
2931       EL_BD_FIREFLY_UP,         EL_BD_FIREFLY_DOWN
2932     },
2933     {
2934       EL_PACMAN,
2935       EL_PACMAN_LEFT,           EL_PACMAN_RIGHT,
2936       EL_PACMAN_UP,             EL_PACMAN_DOWN
2937     },
2938     {
2939       -1,
2940       -1, -1, -1, -1
2941     }
2942   };
2943
2944   int i, j, k;
2945
2946   /* always start with reliable default values (element has no properties) */
2947   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2948     for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
2949       SET_PROPERTY(i, j, FALSE);
2950
2951   /* set all base element properties from above array definitions */
2952   for (i = 0; element_properties[i].elements != NULL; i++)
2953     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
2954       SET_PROPERTY((element_properties[i].elements)[j],
2955                    element_properties[i].property, TRUE);
2956
2957   /* copy properties to some elements that are only stored in level file */
2958   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
2959     for (j = 0; copy_properties[j][0] != -1; j++)
2960       if (HAS_PROPERTY(copy_properties[j][0], i))
2961         for (k = 1; k <= 4; k++)
2962           SET_PROPERTY(copy_properties[j][k], i, TRUE);
2963 }
2964
2965 void InitElementPropertiesEngine(int engine_version)
2966 {
2967 #if 0
2968   static int active_properties[] =
2969   {
2970     EP_AMOEBALIVE,
2971     EP_AMOEBOID,
2972     EP_PFORTE,
2973     EP_DONT_COLLIDE_WITH,
2974     EP_MAUER,
2975     EP_CAN_FALL,
2976     EP_CAN_SMASH,
2977     EP_CAN_PASS_MAGIC_WALL,
2978     EP_CAN_MOVE,
2979     EP_DONT_TOUCH,
2980     EP_DONT_RUN_INTO,
2981     EP_GEM,
2982     EP_CAN_EXPLODE_BY_FIRE,
2983     EP_PUSHABLE,
2984     EP_PLAYER,
2985     EP_HAS_CONTENT,
2986     EP_DIGGABLE,
2987     EP_PASSABLE_INSIDE,
2988     EP_OVER_PLAYER,
2989     EP_ACTIVE_BOMB,
2990
2991     EP_BELT,
2992     EP_BELT_ACTIVE,
2993     EP_BELT_SWITCH,
2994     EP_WALKABLE_UNDER,
2995     EP_EM_SLIPPERY_WALL,
2996   };
2997 #endif
2998
2999   static int no_wall_properties[] =
3000   {
3001     EP_DIGGABLE,
3002     EP_COLLECTIBLE_ONLY,
3003     EP_DONT_RUN_INTO,
3004     EP_DONT_COLLIDE_WITH,
3005     EP_CAN_MOVE,
3006     EP_CAN_FALL,
3007     EP_CAN_SMASH_PLAYER,
3008     EP_CAN_SMASH_ENEMIES,
3009     EP_CAN_SMASH_EVERYTHING,
3010     EP_PUSHABLE,
3011
3012     EP_PLAYER,
3013     EP_GEM,
3014     EP_FOOD_DARK_YAMYAM,
3015     EP_FOOD_PENGUIN,
3016     EP_BELT,
3017     EP_BELT_ACTIVE,
3018     EP_TUBE,
3019     EP_AMOEBOID,
3020     EP_AMOEBALIVE,
3021     EP_ACTIVE_BOMB,
3022
3023     EP_ACCESSIBLE,
3024     -1
3025   };
3026
3027   int i, j;
3028
3029 #if 0
3030   InitElementPropertiesStatic();
3031 #endif
3032
3033   /* set all special, combined or engine dependent element properties */
3034   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3035   {
3036 #if 0
3037     for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3038       SET_PROPERTY(i, j, FALSE);
3039 #endif
3040
3041     /* ---------- INACTIVE ------------------------------------------------- */
3042     if (i >= EL_CHAR_START && i <= EL_CHAR_END)
3043       SET_PROPERTY(i, EP_INACTIVE, TRUE);
3044
3045     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3046     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3047                                   IS_WALKABLE_INSIDE(i) ||
3048                                   IS_WALKABLE_UNDER(i)));
3049
3050     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3051                                   IS_PASSABLE_INSIDE(i) ||
3052                                   IS_PASSABLE_UNDER(i)));
3053
3054     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3055                                          IS_PASSABLE_OVER(i)));
3056
3057     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3058                                            IS_PASSABLE_INSIDE(i)));
3059
3060     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3061                                           IS_PASSABLE_UNDER(i)));
3062
3063     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3064                                     IS_PASSABLE(i)));
3065
3066     /* ---------- COLLECTIBLE ---------------------------------------------- */
3067     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3068                                      IS_DROPPABLE(i)));
3069
3070     /* ---------- SNAPPABLE ------------------------------------------------ */
3071     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3072                                    IS_COLLECTIBLE(i) ||
3073                                    IS_SWITCHABLE(i) ||
3074                                    i == EL_BD_ROCK));
3075
3076     /* ---------- WALL ----------------------------------------------------- */
3077     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
3078
3079     for (j = 0; no_wall_properties[j] != -1; j++)
3080       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3081           i >= EL_FIRST_RUNTIME_UNREAL)
3082         SET_PROPERTY(i, EP_WALL, FALSE);
3083
3084     if (IS_HISTORIC_WALL(i))
3085       SET_PROPERTY(i, EP_WALL, TRUE);
3086
3087     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3088     if (engine_version < VERSION_IDENT(2,2,0,0))
3089       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3090     else
3091       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3092                                              !IS_DIGGABLE(i) &&
3093                                              !IS_COLLECTIBLE(i)));
3094
3095     /* ---------- PROTECTED ------------------------------------------------ */
3096     if (IS_ACCESSIBLE_INSIDE(i))
3097       SET_PROPERTY(i, EP_PROTECTED, TRUE);
3098
3099     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3100
3101     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3102       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3103     else
3104       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3105                                             IS_INDESTRUCTIBLE(i)));
3106
3107     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3108     if (i == EL_FLAMES)
3109       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3110     else if (engine_version < VERSION_IDENT(2,2,0,0))
3111       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3112     else
3113 #if 1
3114       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3115                                            (!IS_WALKABLE(i) ||
3116                                             IS_PROTECTED(i))));
3117 #else
3118 #if 1
3119       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3120                                            !IS_WALKABLE_OVER(i) &&
3121                                            !IS_WALKABLE_UNDER(i)));
3122 #else
3123       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3124                                            IS_PROTECTED(i)));
3125 #endif
3126 #endif
3127
3128     if (IS_CUSTOM_ELEMENT(i))
3129     {
3130       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3131       if (DONT_TOUCH(i))
3132         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3133       if (DONT_COLLIDE_WITH(i))
3134         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3135
3136       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3137       if (CAN_SMASH_EVERYTHING(i))
3138         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3139       if (CAN_SMASH_ENEMIES(i))
3140         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3141     }
3142
3143     /* ---------- CAN_SMASH ------------------------------------------------ */
3144     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3145                                    CAN_SMASH_ENEMIES(i) ||
3146                                    CAN_SMASH_EVERYTHING(i)));
3147
3148     /* ---------- CAN_EXPLODE ---------------------------------------------- */
3149     SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3150                                      CAN_EXPLODE_SMASHED(i) ||
3151                                      CAN_EXPLODE_IMPACT(i)));
3152
3153     /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3154     SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3155                                          !CAN_EXPLODE_1X1(i) &&
3156                                          !CAN_EXPLODE_DYNA(i)));
3157
3158     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3159     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3160
3161     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3162     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3163                                                   i == EL_BLACK_ORB));
3164
3165     /* ---------- SP_PORT -------------------------------------------------- */
3166     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3167                                  IS_PASSABLE_INSIDE(i)));
3168
3169 #if 0
3170     if (i == EL_CUSTOM_START + 253)
3171       printf("::: %d, %d, %d -> %d\n",
3172              CAN_EXPLODE_1X1(i),
3173              CAN_EXPLODE_3X3(i),
3174              CAN_EXPLODE_DYNA(i),
3175              CAN_EXPLODE(i));
3176 #endif
3177
3178     /* ---------- CAN_CHANGE ----------------------------------------------- */
3179     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
3180     for (j = 0; j < element_info[i].num_change_pages; j++)
3181       if (element_info[i].change_page[j].can_change)
3182         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3183
3184     /* ---------- GFX_CRUMBLED --------------------------------------------- */
3185     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3186                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3187   }
3188
3189 #if 0
3190   /* determine inactive elements (used for engine main loop optimization) */
3191   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3192   {
3193     boolean active = FALSE;
3194
3195     for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3196     {
3197       if (HAS_PROPERTY(i, j))
3198         active = TRUE;
3199     }
3200
3201 #if 0
3202     if (!active)
3203       SET_PROPERTY(i, EP_INACTIVE, TRUE);
3204 #endif
3205   }
3206 #endif
3207
3208   /* dynamically adjust element properties according to game engine version */
3209   {
3210     static int ep_em_slippery_wall[] =
3211     {
3212       EL_STEELWALL,
3213       EL_WALL,
3214       EL_EXPANDABLE_WALL,
3215       EL_EXPANDABLE_WALL_HORIZONTAL,
3216       EL_EXPANDABLE_WALL_VERTICAL,
3217       EL_EXPANDABLE_WALL_ANY,
3218       -1
3219     };
3220
3221     /* special EM style gems behaviour */
3222     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3223       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3224                    level.em_slippery_gems);
3225
3226     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3227     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3228                  (level.em_slippery_gems &&
3229                   engine_version > VERSION_IDENT(2,0,1,0)));
3230   }
3231
3232 #if 1
3233   /* set default push delay values (corrected since version 3.0.7-1) */
3234   if (engine_version < VERSION_IDENT(3,0,7,1))
3235   {
3236     game.default_push_delay_fixed = 2;
3237     game.default_push_delay_random = 8;
3238   }
3239   else
3240   {
3241     game.default_push_delay_fixed = 8;
3242     game.default_push_delay_random = 8;
3243   }
3244
3245   /* set uninitialized push delay values of custom elements in older levels */
3246   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3247   {
3248     int element = EL_CUSTOM_START + i;
3249
3250     if (element_info[element].push_delay_fixed == -1)
3251       element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3252     if (element_info[element].push_delay_random == -1)
3253       element_info[element].push_delay_random = game.default_push_delay_random;
3254   }
3255
3256   /* set some other uninitialized values of custom elements in older levels */
3257   if (engine_version < VERSION_IDENT(3,0,9,0))
3258   {
3259     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3260     {
3261       int element = EL_CUSTOM_START + i;
3262
3263       element_info[element].access_direction = MV_ALL_DIRECTIONS;
3264
3265       element_info[element].explosion_delay = 18;
3266       element_info[element].ignition_delay = 8;
3267     }
3268   }
3269 #endif
3270
3271   /* this is needed because some graphics depend on element properties */
3272   if (game_status == GAME_MODE_PLAYING)
3273     InitElementGraphicInfo();
3274 }
3275
3276 static void InitGlobal()
3277 {
3278   global.autoplay_leveldir = NULL;
3279
3280   global.frames_per_second = 0;
3281   global.fps_slowdown = FALSE;
3282   global.fps_slowdown_factor = 1;
3283 }
3284
3285 void Execute_Command(char *command)
3286 {
3287   int i;
3288
3289   if (strcmp(command, "print graphicsinfo.conf") == 0)
3290   {
3291     printf("# You can configure additional/alternative image files here.\n");
3292     printf("# (The entries below are default and therefore commented out.)\n");
3293     printf("\n");
3294     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3295     printf("\n");
3296     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3297     printf("\n");
3298
3299     for (i = 0; image_config[i].token != NULL; i++)
3300       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3301                                               image_config[i].value));
3302
3303     exit(0);
3304   }
3305   else if (strcmp(command, "print soundsinfo.conf") == 0)
3306   {
3307     printf("# You can configure additional/alternative sound files here.\n");
3308     printf("# (The entries below are default and therefore commented out.)\n");
3309     printf("\n");
3310     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3311     printf("\n");
3312     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3313     printf("\n");
3314
3315     for (i = 0; sound_config[i].token != NULL; i++)
3316       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3317                                               sound_config[i].value));
3318
3319     exit(0);
3320   }
3321   else if (strcmp(command, "print musicinfo.conf") == 0)
3322   {
3323     printf("# You can configure additional/alternative music files here.\n");
3324     printf("# (The entries below are default and therefore commented out.)\n");
3325     printf("\n");
3326     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3327     printf("\n");
3328     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3329     printf("\n");
3330
3331     for (i = 0; music_config[i].token != NULL; i++)
3332       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3333                                               music_config[i].value));
3334
3335     exit(0);
3336   }
3337   else if (strcmp(command, "print editorsetup.conf") == 0)
3338   {
3339     printf("# You can configure your personal editor element list here.\n");
3340     printf("# (The entries below are default and therefore commented out.)\n");
3341     printf("\n");
3342
3343     PrintEditorElementList();
3344
3345     exit(0);
3346   }
3347   else if (strcmp(command, "print helpanim.conf") == 0)
3348   {
3349     printf("# You can configure different element help animations here.\n");
3350     printf("# (The entries below are default and therefore commented out.)\n");
3351     printf("\n");
3352
3353     for (i = 0; helpanim_config[i].token != NULL; i++)
3354     {
3355       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3356                                               helpanim_config[i].value));
3357
3358       if (strcmp(helpanim_config[i].token, "end") == 0)
3359         printf("#\n");
3360     }
3361
3362     exit(0);
3363   }
3364   else if (strcmp(command, "print helptext.conf") == 0)
3365   {
3366     printf("# You can configure different element help text here.\n");
3367     printf("# (The entries below are default and therefore commented out.)\n");
3368     printf("\n");
3369
3370     for (i = 0; helptext_config[i].token != NULL; i++)
3371       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3372                                               helptext_config[i].value));
3373
3374     exit(0);
3375   }
3376   else if (strncmp(command, "dump level ", 11) == 0)
3377   {
3378     char *filename = &command[11];
3379
3380     if (access(filename, F_OK) != 0)
3381       Error(ERR_EXIT, "cannot open file '%s'", filename);
3382
3383     LoadLevelFromFilename(&level, filename);
3384     DumpLevel(&level);
3385
3386     exit(0);
3387   }
3388   else if (strncmp(command, "dump tape ", 10) == 0)
3389   {
3390     char *filename = &command[10];
3391
3392     if (access(filename, F_OK) != 0)
3393       Error(ERR_EXIT, "cannot open file '%s'", filename);
3394
3395     LoadTapeFromFilename(filename);
3396     DumpTape(&tape);
3397
3398     exit(0);
3399   }
3400   else if (strncmp(command, "autoplay ", 9) == 0)
3401   {
3402     char *str_copy = getStringCopy(&command[9]);
3403     char *str_ptr = strchr(str_copy, ' ');
3404
3405     global.autoplay_leveldir = str_copy;
3406     global.autoplay_level_nr = -1;
3407
3408     if (str_ptr != NULL)
3409     {
3410       *str_ptr++ = '\0';                        /* terminate leveldir string */
3411       global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3412     }
3413   }
3414   else
3415   {
3416     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3417   }
3418 }
3419
3420 static void InitSetup()
3421 {
3422   LoadSetup();                                  /* global setup info */
3423
3424   /* set some options from setup file */
3425
3426   if (setup.options.verbose)
3427     options.verbose = TRUE;
3428 }
3429
3430 static void InitPlayerInfo()
3431 {
3432   int i;
3433
3434   /* choose default local player */
3435   local_player = &stored_player[0];
3436
3437   for (i = 0; i < MAX_PLAYERS; i++)
3438     stored_player[i].connected = FALSE;
3439
3440   local_player->connected = TRUE;
3441 }
3442
3443 static void InitArtworkInfo()
3444 {
3445   LoadArtworkInfo();
3446 }
3447
3448 static char *get_string_in_brackets(char *string)
3449 {
3450   char *string_in_brackets = checked_malloc(strlen(string) + 3);
3451
3452   sprintf(string_in_brackets, "[%s]", string);
3453
3454   return string_in_brackets;
3455 }
3456
3457 static char *get_level_id_suffix(int id_nr)
3458 {
3459   char *id_suffix = checked_malloc(1 + 3 + 1);
3460
3461   if (id_nr < 0 || id_nr > 999)
3462     id_nr = 0;
3463
3464   sprintf(id_suffix, ".%03d", id_nr);
3465
3466   return id_suffix;
3467 }
3468
3469 #if 0
3470 static char *get_element_class_token(int element)
3471 {
3472   char *element_class_name = element_info[element].class_name;
3473   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3474
3475   sprintf(element_class_token, "[%s]", element_class_name);
3476
3477   return element_class_token;
3478 }
3479
3480 static char *get_action_class_token(int action)
3481 {
3482   char *action_class_name = &element_action_info[action].suffix[1];
3483   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3484
3485   sprintf(action_class_token, "[%s]", action_class_name);
3486
3487   return action_class_token;
3488 }
3489 #endif
3490
3491 static void InitArtworkConfig()
3492 {
3493   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3494   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3495   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3496   static char *action_id_suffix[NUM_ACTIONS + 1];
3497   static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3498   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3499   static char *level_id_suffix[MAX_LEVELS + 1];
3500   static char *dummy[1] = { NULL };
3501   static char *ignore_generic_tokens[] =
3502   {
3503     "name",
3504     "sort_priority",
3505     NULL
3506   };
3507   static char **ignore_image_tokens;
3508   static char **ignore_sound_tokens;
3509   static char **ignore_music_tokens;
3510   int num_ignore_generic_tokens;
3511   int num_ignore_image_tokens;
3512   int num_ignore_sound_tokens;
3513   int num_ignore_music_tokens;
3514   int i;
3515
3516   /* dynamically determine list of generic tokens to be ignored */
3517   num_ignore_generic_tokens = 0;
3518   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3519     num_ignore_generic_tokens++;
3520
3521   /* dynamically determine list of image tokens to be ignored */
3522   num_ignore_image_tokens = num_ignore_generic_tokens;
3523   for (i = 0; image_config_vars[i].token != NULL; i++)
3524     num_ignore_image_tokens++;
3525   ignore_image_tokens =
3526     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3527   for (i = 0; i < num_ignore_generic_tokens; i++)
3528     ignore_image_tokens[i] = ignore_generic_tokens[i];
3529   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3530     ignore_image_tokens[num_ignore_generic_tokens + i] =
3531       image_config_vars[i].token;
3532   ignore_image_tokens[num_ignore_image_tokens] = NULL;
3533
3534   /* dynamically determine list of sound tokens to be ignored */
3535   num_ignore_sound_tokens = num_ignore_generic_tokens;
3536   ignore_sound_tokens =
3537     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3538   for (i = 0; i < num_ignore_generic_tokens; i++)
3539     ignore_sound_tokens[i] = ignore_generic_tokens[i];
3540   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3541
3542   /* dynamically determine list of music tokens to be ignored */
3543   num_ignore_music_tokens = num_ignore_generic_tokens;
3544   ignore_music_tokens =
3545     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3546   for (i = 0; i < num_ignore_generic_tokens; i++)
3547     ignore_music_tokens[i] = ignore_generic_tokens[i];
3548   ignore_music_tokens[num_ignore_music_tokens] = NULL;
3549
3550   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3551     image_id_prefix[i] = element_info[i].token_name;
3552   for (i = 0; i < NUM_FONTS; i++)
3553     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3554   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3555
3556   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3557     sound_id_prefix[i] = element_info[i].token_name;
3558   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3559     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3560       get_string_in_brackets(element_info[i].class_name);
3561   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3562
3563   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
3564     music_id_prefix[i] = music_prefix_info[i].prefix;
3565   music_id_prefix[MAX_LEVELS] = NULL;
3566
3567   for (i = 0; i < NUM_ACTIONS; i++)
3568     action_id_suffix[i] = element_action_info[i].suffix;
3569   action_id_suffix[NUM_ACTIONS] = NULL;
3570
3571   for (i = 0; i < NUM_DIRECTIONS; i++)
3572     direction_id_suffix[i] = element_direction_info[i].suffix;
3573   direction_id_suffix[NUM_DIRECTIONS] = NULL;
3574
3575   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
3576     special_id_suffix[i] = special_suffix_info[i].suffix;
3577   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
3578
3579   for (i = 0; i < MAX_LEVELS; i++)
3580     level_id_suffix[i] = get_level_id_suffix(i);
3581   level_id_suffix[MAX_LEVELS] = NULL;
3582
3583   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
3584                 image_id_prefix, action_id_suffix, direction_id_suffix,
3585                 special_id_suffix, ignore_image_tokens);
3586   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
3587                 sound_id_prefix, action_id_suffix, dummy,
3588                 special_id_suffix, ignore_sound_tokens);
3589   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
3590                 music_id_prefix, special_id_suffix, level_id_suffix,
3591                 dummy, ignore_music_tokens);
3592 }
3593
3594 static void InitMixer()
3595 {
3596   OpenAudio();
3597   StartMixer();
3598 }
3599
3600 void InitGfx()
3601 {
3602   char *filename_font_initial = NULL;
3603   Bitmap *bitmap_font_initial = NULL;
3604   int i, j;
3605
3606   /* determine settings for initial font (for displaying startup messages) */
3607   for (i = 0; image_config[i].token != NULL; i++)
3608   {
3609     for (j = 0; j < NUM_INITIAL_FONTS; j++)
3610     {
3611       char font_token[128];
3612       int len_font_token;
3613
3614       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
3615       len_font_token = strlen(font_token);
3616
3617       if (strcmp(image_config[i].token, font_token) == 0)
3618         filename_font_initial = image_config[i].value;
3619       else if (strlen(image_config[i].token) > len_font_token &&
3620                strncmp(image_config[i].token, font_token, len_font_token) == 0)
3621       {
3622         if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
3623           font_initial[j].src_x = atoi(image_config[i].value);
3624         else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
3625           font_initial[j].src_y = atoi(image_config[i].value);
3626         else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
3627           font_initial[j].width = atoi(image_config[i].value);
3628         else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
3629           font_initial[j].height = atoi(image_config[i].value);
3630       }
3631     }
3632   }
3633
3634   for (j = 0; j < NUM_INITIAL_FONTS; j++)
3635   {
3636     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
3637     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
3638   }
3639
3640   if (filename_font_initial == NULL)    /* should not happen */
3641     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
3642
3643   /* create additional image buffers for double-buffering */
3644   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
3645   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
3646
3647   /* initialize screen properties */
3648   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
3649                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
3650                    bitmap_db_field);
3651   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
3652   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
3653   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
3654
3655   bitmap_font_initial = LoadCustomImage(filename_font_initial);
3656
3657   for (j = 0; j < NUM_INITIAL_FONTS; j++)
3658     font_initial[j].bitmap = bitmap_font_initial;
3659
3660   InitFontGraphicInfo();
3661
3662   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
3663   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
3664
3665   DrawInitText("Loading graphics:", 120, FC_GREEN);
3666
3667   InitTileClipmasks();
3668 }
3669
3670 void InitGfxBackground()
3671 {
3672   int x, y;
3673
3674   drawto = backbuffer;
3675   fieldbuffer = bitmap_db_field;
3676   SetDrawtoField(DRAW_BACKBUFFER);
3677
3678   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3679              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3680   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3681   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3682
3683   for (x = 0; x < MAX_BUF_XSIZE; x++)
3684     for (y = 0; y < MAX_BUF_YSIZE; y++)
3685       redraw[x][y] = 0;
3686   redraw_tiles = 0;
3687   redraw_mask = REDRAW_ALL;
3688 }
3689
3690 static void InitLevelInfo()
3691 {
3692   LoadLevelInfo();                              /* global level info */
3693   LoadLevelSetup_LastSeries();                  /* last played series info */
3694   LoadLevelSetup_SeriesInfo();                  /* last played level info */
3695 }
3696
3697 void InitLevelArtworkInfo()
3698 {
3699   LoadLevelArtworkInfo();
3700 }
3701
3702 static void InitImages()
3703 {
3704 #if 1
3705   setLevelArtworkDir(artwork.gfx_first);
3706 #endif
3707
3708 #if 0
3709   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
3710          leveldir_current->identifier,
3711          artwork.gfx_current_identifier,
3712          artwork.gfx_current->identifier,
3713          leveldir_current->graphics_set,
3714          leveldir_current->graphics_path);
3715 #endif
3716
3717   ReloadCustomImages();
3718
3719   LoadCustomElementDescriptions();
3720   LoadSpecialMenuDesignSettings();
3721
3722   ReinitializeGraphics();
3723 }
3724
3725 static void InitSound(char *identifier)
3726 {
3727   if (identifier == NULL)
3728     identifier = artwork.snd_current->identifier;
3729
3730 #if 1
3731   /* set artwork path to send it to the sound server process */
3732   setLevelArtworkDir(artwork.snd_first);
3733 #endif
3734
3735   InitReloadCustomSounds(identifier);
3736   ReinitializeSounds();
3737 }
3738
3739 static void InitMusic(char *identifier)
3740 {
3741   if (identifier == NULL)
3742     identifier = artwork.mus_current->identifier;
3743
3744 #if 1
3745   /* set artwork path to send it to the sound server process */
3746   setLevelArtworkDir(artwork.mus_first);
3747 #endif
3748
3749   InitReloadCustomMusic(identifier);
3750   ReinitializeMusic();
3751 }
3752
3753 void InitNetworkServer()
3754 {
3755 #if defined(PLATFORM_UNIX)
3756   int nr_wanted;
3757 #endif
3758
3759   if (!options.network)
3760     return;
3761
3762 #if defined(PLATFORM_UNIX)
3763   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3764
3765   if (!ConnectToServer(options.server_host, options.server_port))
3766     Error(ERR_EXIT, "cannot connect to network game server");
3767
3768   SendToServer_PlayerName(setup.player_name);
3769   SendToServer_ProtocolVersion();
3770
3771   if (nr_wanted)
3772     SendToServer_NrWanted(nr_wanted);
3773 #endif
3774 }
3775
3776 static char *getNewArtworkIdentifier(int type)
3777 {
3778   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
3779   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
3780   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
3781   static boolean initialized[3] = { FALSE, FALSE, FALSE };
3782   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
3783   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
3784   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
3785   char *leveldir_identifier = leveldir_current->identifier;
3786 #if 1
3787   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
3788   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
3789 #else
3790   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
3791 #endif
3792   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
3793   char *artwork_current_identifier;
3794   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
3795
3796   /* leveldir_current may be invalid (level group, parent link) */
3797   if (!validLevelSeries(leveldir_current))
3798     return NULL;
3799
3800   /* 1st step: determine artwork set to be activated in descending order:
3801      --------------------------------------------------------------------
3802      1. setup artwork (when configured to override everything else)
3803      2. artwork set configured in "levelinfo.conf" of current level set
3804         (artwork in level directory will have priority when loading later)
3805      3. artwork in level directory (stored in artwork sub-directory)
3806      4. setup artwork (currently configured in setup menu) */
3807
3808   if (setup_override_artwork)
3809     artwork_current_identifier = setup_artwork_set;
3810   else if (leveldir_artwork_set != NULL)
3811     artwork_current_identifier = leveldir_artwork_set;
3812   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
3813     artwork_current_identifier = leveldir_identifier;
3814   else
3815     artwork_current_identifier = setup_artwork_set;
3816
3817
3818   /* 2nd step: check if it is really needed to reload artwork set
3819      ------------------------------------------------------------ */
3820
3821 #if 0
3822   if (type == ARTWORK_TYPE_GRAPHICS)
3823     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
3824            artwork_new_identifier,
3825            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3826            artwork_current_identifier,
3827            leveldir_current->graphics_set,
3828            leveldir_current->identifier);
3829 #endif
3830
3831   /* ---------- reload if level set and also artwork set has changed ------- */
3832   if (leveldir_current_identifier[type] != leveldir_identifier &&
3833       (last_has_level_artwork_set[type] || has_level_artwork_set))
3834     artwork_new_identifier = artwork_current_identifier;
3835
3836   leveldir_current_identifier[type] = leveldir_identifier;
3837   last_has_level_artwork_set[type] = has_level_artwork_set;
3838
3839 #if 0
3840   if (type == ARTWORK_TYPE_GRAPHICS)
3841     printf("::: 1: '%s'\n", artwork_new_identifier);
3842 #endif
3843
3844   /* ---------- reload if "override artwork" setting has changed ----------- */
3845   if (last_override_level_artwork[type] != setup_override_artwork)
3846     artwork_new_identifier = artwork_current_identifier;
3847
3848   last_override_level_artwork[type] = setup_override_artwork;
3849
3850 #if 0
3851   if (type == ARTWORK_TYPE_GRAPHICS)
3852     printf("::: 2: '%s'\n", artwork_new_identifier);
3853 #endif
3854
3855   /* ---------- reload if current artwork identifier has changed ----------- */
3856   if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
3857              artwork_current_identifier) != 0)
3858     artwork_new_identifier = artwork_current_identifier;
3859
3860   *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
3861
3862 #if 0
3863   if (type == ARTWORK_TYPE_GRAPHICS)
3864     printf("::: 3: '%s'\n", artwork_new_identifier);
3865 #endif
3866
3867   /* ---------- do not reload directly after starting ---------------------- */
3868   if (!initialized[type])
3869     artwork_new_identifier = NULL;
3870
3871   initialized[type] = TRUE;
3872
3873 #if 0
3874   if (type == ARTWORK_TYPE_GRAPHICS)
3875     printf("::: 4: '%s'\n", artwork_new_identifier);
3876 #endif
3877
3878 #if 0
3879   if (type == ARTWORK_TYPE_GRAPHICS)
3880     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
3881            artwork.gfx_current_identifier, artwork_current_identifier,
3882            artwork.gfx_current->identifier, leveldir_current->graphics_set,
3883            artwork_new_identifier);
3884 #endif
3885
3886   return artwork_new_identifier;
3887 }
3888
3889 void ReloadCustomArtwork(int force_reload)
3890 {
3891   char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
3892   char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
3893   char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
3894   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
3895   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
3896   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
3897   boolean redraw_screen = FALSE;
3898
3899   if (gfx_new_identifier != NULL || force_reload_gfx)
3900   {
3901 #if 0
3902     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
3903            artwork.gfx_current_identifier,
3904            gfx_new_identifier,
3905            artwork.gfx_current->identifier,
3906            leveldir_current->graphics_set);
3907 #endif
3908
3909     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3910
3911     InitImages();
3912
3913 #if 0
3914     printf("... '%s'\n",
3915            leveldir_current->graphics_set);
3916 #endif
3917
3918     FreeTileClipmasks();
3919     InitTileClipmasks();
3920
3921     redraw_screen = TRUE;
3922   }
3923
3924   if (snd_new_identifier != NULL || force_reload_snd)
3925   {
3926     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3927
3928     InitSound(snd_new_identifier);
3929
3930     redraw_screen = TRUE;
3931   }
3932
3933   if (mus_new_identifier != NULL || force_reload_mus)
3934   {
3935     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3936
3937     InitMusic(mus_new_identifier);
3938
3939     redraw_screen = TRUE;
3940   }
3941
3942   if (redraw_screen)
3943   {
3944     InitGfxBackground();
3945
3946     /* force redraw of (open or closed) door graphics */
3947     SetDoorState(DOOR_OPEN_ALL);
3948     CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3949   }
3950 }
3951
3952 void KeyboardAutoRepeatOffUnlessAutoplay()
3953 {
3954   if (global.autoplay_leveldir == NULL)
3955     KeyboardAutoRepeatOff();
3956 }
3957
3958
3959 /* ========================================================================= */
3960 /* OpenAll()                                                                 */
3961 /* ========================================================================= */
3962
3963 void OpenAll()
3964 {
3965   InitGlobal();         /* initialize some global variables */
3966
3967   if (options.execute_command)
3968     Execute_Command(options.execute_command);
3969
3970   if (options.serveronly)
3971   {
3972 #if defined(PLATFORM_UNIX)
3973     NetworkServer(options.server_port, options.serveronly);
3974 #else
3975     Error(ERR_WARN, "networking only supported in Unix version");
3976 #endif
3977     exit(0);    /* never reached */
3978   }
3979
3980   InitSetup();
3981
3982   InitPlayerInfo();
3983   InitArtworkInfo();            /* needed before loading gfx, sound & music */
3984   InitArtworkConfig();          /* needed before forking sound child process */
3985   InitMixer();
3986
3987   InitCounter();
3988
3989   InitRND(NEW_RANDOMIZE);
3990   InitSimpleRND(NEW_RANDOMIZE);
3991
3992   InitJoysticks();
3993
3994   InitVideoDisplay();
3995   InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3996                   setup.fullscreen);
3997
3998   InitEventFilter(FilterMouseMotionEvents);
3999
4000   InitElementPropertiesStatic();
4001   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4002
4003   InitGfx();
4004
4005   InitLevelInfo();
4006   InitLevelArtworkInfo();
4007
4008   InitImages();                 /* needs to know current level directory */
4009   InitSound(NULL);              /* needs to know current level directory */
4010   InitMusic(NULL);              /* needs to know current level directory */
4011
4012   InitGfxBackground();
4013
4014   if (global.autoplay_leveldir)
4015   {
4016     AutoPlayTape();
4017     return;
4018   }
4019
4020   game_status = GAME_MODE_MAIN;
4021
4022   DrawMainMenu();
4023
4024   InitNetworkServer();
4025 }
4026
4027 void CloseAllAndExit(int exit_value)
4028 {
4029   StopSounds();
4030   FreeAllSounds();
4031   FreeAllMusic();
4032   CloseAudio();         /* called after freeing sounds (needed for SDL) */
4033
4034   FreeAllImages();
4035   FreeTileClipmasks();
4036
4037   CloseVideoDisplay();
4038   ClosePlatformDependentStuff();
4039
4040   exit(exit_value);
4041 }