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