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