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