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