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