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