rnd-20030616-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 dependant 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     -1
1530   };
1531
1532   static int ep_walkable_inside[] =
1533   {
1534     EL_TUBE_ANY,
1535     EL_TUBE_VERTICAL,
1536     EL_TUBE_HORIZONTAL,
1537     EL_TUBE_VERTICAL_LEFT,
1538     EL_TUBE_VERTICAL_RIGHT,
1539     EL_TUBE_HORIZONTAL_UP,
1540     EL_TUBE_HORIZONTAL_DOWN,
1541     EL_TUBE_LEFT_UP,
1542     EL_TUBE_LEFT_DOWN,
1543     EL_TUBE_RIGHT_UP,
1544     EL_TUBE_RIGHT_DOWN,
1545     -1
1546   };
1547
1548   static int ep_walkable_under[] =
1549   {
1550     -1
1551   };
1552
1553   static int ep_passable_over[] =
1554   {
1555     EL_EM_GATE_1,
1556     EL_EM_GATE_2,
1557     EL_EM_GATE_3,
1558     EL_EM_GATE_4,
1559     EL_EM_GATE_1_GRAY,
1560     EL_EM_GATE_2_GRAY,
1561     EL_EM_GATE_3_GRAY,
1562     EL_EM_GATE_4_GRAY,
1563     EL_SWITCHGATE_OPEN,
1564     EL_TIMEGATE_OPEN,
1565     -1
1566   };
1567
1568   static int ep_passable_inside[] =
1569   {
1570     EL_SP_PORT_LEFT,
1571     EL_SP_PORT_RIGHT,
1572     EL_SP_PORT_UP,
1573     EL_SP_PORT_DOWN,
1574     EL_SP_PORT_HORIZONTAL,
1575     EL_SP_PORT_VERTICAL,
1576     EL_SP_PORT_ANY,
1577     EL_SP_GRAVITY_PORT_LEFT,
1578     EL_SP_GRAVITY_PORT_RIGHT,
1579     EL_SP_GRAVITY_PORT_UP,
1580     EL_SP_GRAVITY_PORT_DOWN,
1581     -1
1582   };
1583
1584   static int ep_passable_under[] =
1585   {
1586     -1
1587   };
1588
1589   static int ep_pushable[] =
1590   {
1591     EL_ROCK,
1592     EL_BOMB,
1593     EL_DX_SUPABOMB,
1594     EL_NUT,
1595     EL_TIME_ORB_EMPTY,
1596     EL_SP_ZONK,
1597     EL_SP_DISK_ORANGE,
1598     EL_SPRING,
1599     EL_BD_ROCK,
1600     EL_SOKOBAN_OBJECT,
1601     EL_SOKOBAN_FIELD_FULL,
1602     EL_SATELLITE,
1603     EL_SP_DISK_YELLOW,
1604     EL_BALLOON,
1605     -1
1606   };
1607
1608   static int ep_can_be_crumbled[] =
1609   {
1610     EL_SAND,
1611     EL_LANDMINE,
1612     EL_TRAP,
1613     EL_TRAP_ACTIVE,
1614     -1
1615   };
1616
1617   static int ep_player[] =
1618   {
1619     EL_PLAYER_1,
1620     EL_PLAYER_2,
1621     EL_PLAYER_3,
1622     EL_PLAYER_4,
1623     -1
1624   };
1625
1626   static int ep_can_pass_magic_wall[] =
1627   {
1628     EL_ROCK,
1629     EL_BD_ROCK,
1630     EL_EMERALD,
1631     EL_BD_DIAMOND,
1632     EL_EMERALD_YELLOW,
1633     EL_EMERALD_RED,
1634     EL_EMERALD_PURPLE,
1635     EL_DIAMOND,
1636     -1
1637   };
1638
1639   static int ep_switchable[] =
1640   {
1641     EL_ROBOT_WHEEL,
1642     EL_SP_TERMINAL,
1643     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1644     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1645     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1646     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1647     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1648     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1649     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1650     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1651     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1652     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1653     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1654     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1655     EL_SWITCHGATE_SWITCH_UP,
1656     EL_SWITCHGATE_SWITCH_DOWN,
1657     EL_LIGHT_SWITCH,
1658     EL_LIGHT_SWITCH_ACTIVE,
1659     EL_TIMEGATE_SWITCH,
1660     EL_BALLOON_SWITCH_LEFT,
1661     EL_BALLOON_SWITCH_RIGHT,
1662     EL_BALLOON_SWITCH_UP,
1663     EL_BALLOON_SWITCH_DOWN,
1664     EL_BALLOON_SWITCH_ANY,
1665     EL_LAMP,
1666     EL_TIME_ORB_FULL,
1667     -1
1668   };
1669
1670   static int ep_bd_element[] =
1671   {
1672     EL_EMPTY,
1673     EL_SAND,
1674     EL_WALL_CRUMBLED,
1675     EL_BD_WALL,
1676     EL_ROCK,
1677     EL_BD_ROCK,
1678     EL_BD_DIAMOND,
1679     EL_BD_MAGIC_WALL,
1680     EL_EXIT_CLOSED,
1681     EL_EXIT_OPEN,
1682     EL_STEELWALL,
1683     EL_PLAYER_1,
1684     EL_BD_FIREFLY,
1685     EL_BD_FIREFLY_1,
1686     EL_BD_FIREFLY_2,
1687     EL_BD_FIREFLY_3,
1688     EL_BD_FIREFLY_4,
1689     EL_BD_BUTTERFLY,
1690     EL_BD_BUTTERFLY_1,
1691     EL_BD_BUTTERFLY_2,
1692     EL_BD_BUTTERFLY_3,
1693     EL_BD_BUTTERFLY_4,
1694     EL_BD_AMOEBA,
1695     EL_CHAR_QUESTION,
1696     -1
1697   };
1698
1699   static int ep_sp_element[] =
1700   {
1701     EL_SP_EMPTY,
1702     EL_SP_ZONK,
1703     EL_SP_BASE,
1704     EL_SP_MURPHY,
1705     EL_SP_INFOTRON,
1706     EL_SP_CHIP_SINGLE,
1707     EL_SP_HARDWARE_GRAY,
1708     EL_SP_EXIT_CLOSED,
1709     EL_SP_EXIT_OPEN,
1710     EL_SP_DISK_ORANGE,
1711     EL_SP_PORT_RIGHT,
1712     EL_SP_PORT_DOWN,
1713     EL_SP_PORT_LEFT,
1714     EL_SP_PORT_UP,
1715     EL_SP_GRAVITY_PORT_RIGHT,
1716     EL_SP_GRAVITY_PORT_DOWN,
1717     EL_SP_GRAVITY_PORT_LEFT,
1718     EL_SP_GRAVITY_PORT_UP,
1719     EL_SP_SNIKSNAK,
1720     EL_SP_DISK_YELLOW,
1721     EL_SP_TERMINAL,
1722     EL_SP_DISK_RED,
1723     EL_SP_PORT_VERTICAL,
1724     EL_SP_PORT_HORIZONTAL,
1725     EL_SP_PORT_ANY,
1726     EL_SP_ELECTRON,
1727     EL_SP_BUGGY_BASE,
1728     EL_SP_CHIP_LEFT,
1729     EL_SP_CHIP_RIGHT,
1730     EL_SP_HARDWARE_BASE_1,
1731     EL_SP_HARDWARE_GREEN,
1732     EL_SP_HARDWARE_BLUE,
1733     EL_SP_HARDWARE_RED,
1734     EL_SP_HARDWARE_YELLOW,
1735     EL_SP_HARDWARE_BASE_2,
1736     EL_SP_HARDWARE_BASE_3,
1737     EL_SP_HARDWARE_BASE_4,
1738     EL_SP_HARDWARE_BASE_5,
1739     EL_SP_HARDWARE_BASE_6,
1740     EL_SP_CHIP_TOP,
1741     EL_SP_CHIP_BOTTOM,
1742     /* additional elements that appeared in newer Supaplex levels */
1743     EL_INVISIBLE_WALL,
1744     /* more than one murphy in a level results in an inactive clone */
1745     EL_SP_MURPHY_CLONE,
1746     /* runtime elements*/
1747     EL_SP_DISK_RED_ACTIVE,
1748     EL_SP_TERMINAL_ACTIVE,
1749     EL_SP_BUGGY_BASE_ACTIVATING,
1750     EL_SP_BUGGY_BASE_ACTIVE,
1751     -1
1752   };
1753
1754   static int ep_sb_element[] =
1755   {
1756     EL_EMPTY,
1757     EL_STEELWALL,
1758     EL_SOKOBAN_OBJECT,
1759     EL_SOKOBAN_FIELD_EMPTY,
1760     EL_SOKOBAN_FIELD_FULL,
1761     EL_PLAYER_1,
1762     EL_INVISIBLE_STEELWALL,
1763     -1
1764   };
1765
1766   static int ep_gem[] =
1767   {
1768     EL_BD_DIAMOND,
1769     EL_EMERALD,
1770     EL_EMERALD_YELLOW,
1771     EL_EMERALD_RED,
1772     EL_EMERALD_PURPLE,
1773     EL_DIAMOND,
1774     -1
1775   };
1776
1777   static int ep_food_dark_yamyam[] =
1778   {
1779     EL_SAND,
1780     EL_BUG,
1781     EL_SPACESHIP,
1782     EL_BD_BUTTERFLY,
1783     EL_BD_FIREFLY,
1784     EL_YAMYAM,
1785     EL_ROBOT,
1786     EL_PACMAN,
1787     EL_AMOEBA_DROP,
1788     EL_AMOEBA_DEAD,
1789     EL_AMOEBA_WET,
1790     EL_AMOEBA_DRY,
1791     EL_AMOEBA_FULL,
1792     EL_BD_AMOEBA,
1793     EL_EMERALD,
1794     EL_BD_DIAMOND,
1795     EL_EMERALD_YELLOW,
1796     EL_EMERALD_RED,
1797     EL_EMERALD_PURPLE,
1798     EL_DIAMOND,
1799     EL_PEARL,
1800     EL_CRYSTAL,
1801     -1
1802   };
1803
1804   static int ep_food_penguin[] =
1805   {
1806     EL_EMERALD,
1807     EL_BD_DIAMOND,
1808     EL_EMERALD_YELLOW,
1809     EL_EMERALD_RED,
1810     EL_EMERALD_PURPLE,
1811     EL_DIAMOND,
1812     EL_PEARL,
1813     EL_CRYSTAL,
1814     -1
1815   };
1816
1817   static int ep_food_pig[] =
1818   {
1819     EL_EMERALD,
1820     EL_BD_DIAMOND,
1821     EL_EMERALD_YELLOW,
1822     EL_EMERALD_RED,
1823     EL_EMERALD_PURPLE,
1824     EL_DIAMOND,
1825     -1
1826   };
1827
1828   static int ep_historic_wall[] =
1829   {
1830     EL_STEELWALL,
1831     EL_GATE_1,
1832     EL_GATE_2,
1833     EL_GATE_3,
1834     EL_GATE_4,
1835     EL_GATE_1_GRAY,
1836     EL_GATE_2_GRAY,
1837     EL_GATE_3_GRAY,
1838     EL_GATE_4_GRAY,
1839     EL_EM_GATE_1,
1840     EL_EM_GATE_2,
1841     EL_EM_GATE_3,
1842     EL_EM_GATE_4,
1843     EL_EM_GATE_1_GRAY,
1844     EL_EM_GATE_2_GRAY,
1845     EL_EM_GATE_3_GRAY,
1846     EL_EM_GATE_4_GRAY,
1847     EL_EXIT_CLOSED,
1848     EL_EXIT_OPENING,
1849     EL_EXIT_OPEN,
1850     EL_WALL,
1851     EL_WALL_CRUMBLED,
1852     EL_EXPANDABLE_WALL,
1853     EL_EXPANDABLE_WALL_HORIZONTAL,
1854     EL_EXPANDABLE_WALL_VERTICAL,
1855     EL_EXPANDABLE_WALL_ANY,
1856     EL_EXPANDABLE_WALL_GROWING,
1857     EL_BD_WALL,
1858     EL_SP_CHIP_SINGLE,
1859     EL_SP_CHIP_LEFT,
1860     EL_SP_CHIP_RIGHT,
1861     EL_SP_CHIP_TOP,
1862     EL_SP_CHIP_BOTTOM,
1863     EL_SP_HARDWARE_GRAY,
1864     EL_SP_HARDWARE_GREEN,
1865     EL_SP_HARDWARE_BLUE,
1866     EL_SP_HARDWARE_RED,
1867     EL_SP_HARDWARE_YELLOW,
1868     EL_SP_HARDWARE_BASE_1,
1869     EL_SP_HARDWARE_BASE_2,
1870     EL_SP_HARDWARE_BASE_3,
1871     EL_SP_HARDWARE_BASE_4,
1872     EL_SP_HARDWARE_BASE_5,
1873     EL_SP_HARDWARE_BASE_6,
1874     EL_SP_TERMINAL,
1875     EL_SP_TERMINAL_ACTIVE,
1876     EL_SP_EXIT_CLOSED,
1877     EL_SP_EXIT_OPEN,
1878     EL_INVISIBLE_STEELWALL,
1879     EL_INVISIBLE_STEELWALL_ACTIVE,
1880     EL_INVISIBLE_WALL,
1881     EL_INVISIBLE_WALL_ACTIVE,
1882     EL_STEELWALL_SLANTED,
1883     EL_EMC_STEELWALL_1,
1884     EL_EMC_STEELWALL_2,
1885     EL_EMC_STEELWALL_3,
1886     EL_EMC_STEELWALL_4,
1887     EL_EMC_WALL_1,
1888     EL_EMC_WALL_2,
1889     EL_EMC_WALL_3,
1890     EL_EMC_WALL_4,
1891     EL_EMC_WALL_5,
1892     EL_EMC_WALL_6,
1893     EL_EMC_WALL_7,
1894     EL_EMC_WALL_8,
1895     -1
1896   };
1897
1898   static int ep_historic_solid[] =
1899   {
1900     EL_WALL,
1901     EL_EXPANDABLE_WALL,
1902     EL_EXPANDABLE_WALL_HORIZONTAL,
1903     EL_EXPANDABLE_WALL_VERTICAL,
1904     EL_EXPANDABLE_WALL_ANY,
1905     EL_BD_WALL,
1906     EL_WALL_CRUMBLED,
1907     EL_EXIT_CLOSED,
1908     EL_EXIT_OPENING,
1909     EL_EXIT_OPEN,
1910     EL_AMOEBA_DEAD,
1911     EL_AMOEBA_WET,
1912     EL_AMOEBA_DRY,
1913     EL_AMOEBA_FULL,
1914     EL_BD_AMOEBA,
1915     EL_QUICKSAND_EMPTY,
1916     EL_QUICKSAND_FULL,
1917     EL_QUICKSAND_FILLING,
1918     EL_QUICKSAND_EMPTYING,
1919     EL_MAGIC_WALL,
1920     EL_MAGIC_WALL_ACTIVE,
1921     EL_MAGIC_WALL_EMPTYING,
1922     EL_MAGIC_WALL_FILLING,
1923     EL_MAGIC_WALL_FULL,
1924     EL_MAGIC_WALL_DEAD,
1925     EL_BD_MAGIC_WALL,
1926     EL_BD_MAGIC_WALL_ACTIVE,
1927     EL_BD_MAGIC_WALL_EMPTYING,
1928     EL_BD_MAGIC_WALL_FULL,
1929     EL_BD_MAGIC_WALL_FILLING,
1930     EL_BD_MAGIC_WALL_DEAD,
1931     EL_GAME_OF_LIFE,
1932     EL_BIOMAZE,
1933     EL_SP_CHIP_SINGLE,
1934     EL_SP_CHIP_LEFT,
1935     EL_SP_CHIP_RIGHT,
1936     EL_SP_CHIP_TOP,
1937     EL_SP_CHIP_BOTTOM,
1938     EL_SP_TERMINAL,
1939     EL_SP_TERMINAL_ACTIVE,
1940     EL_SP_EXIT_CLOSED,
1941     EL_SP_EXIT_OPEN,
1942     EL_INVISIBLE_WALL,
1943     EL_INVISIBLE_WALL_ACTIVE,
1944     EL_SWITCHGATE_SWITCH_UP,
1945     EL_SWITCHGATE_SWITCH_DOWN,
1946     EL_TIMEGATE_SWITCH,
1947     EL_TIMEGATE_SWITCH_ACTIVE,
1948     EL_EMC_WALL_1,
1949     EL_EMC_WALL_2,
1950     EL_EMC_WALL_3,
1951     EL_EMC_WALL_4,
1952     EL_EMC_WALL_5,
1953     EL_EMC_WALL_6,
1954     EL_EMC_WALL_7,
1955     EL_EMC_WALL_8,
1956     EL_WALL_PEARL,
1957     EL_WALL_CRYSTAL,
1958
1959     /* the following elements are a direct copy of "indestructible" elements,
1960        except "EL_ACID", which is "indestructible", but not "solid"! */
1961 #if 0
1962     EL_ACID,
1963 #endif
1964     EL_STEELWALL,
1965     EL_ACID_POOL_TOPLEFT,
1966     EL_ACID_POOL_TOPRIGHT,
1967     EL_ACID_POOL_BOTTOMLEFT,
1968     EL_ACID_POOL_BOTTOM,
1969     EL_ACID_POOL_BOTTOMRIGHT,
1970     EL_SP_HARDWARE_GRAY,
1971     EL_SP_HARDWARE_GREEN,
1972     EL_SP_HARDWARE_BLUE,
1973     EL_SP_HARDWARE_RED,
1974     EL_SP_HARDWARE_YELLOW,
1975     EL_SP_HARDWARE_BASE_1,
1976     EL_SP_HARDWARE_BASE_2,
1977     EL_SP_HARDWARE_BASE_3,
1978     EL_SP_HARDWARE_BASE_4,
1979     EL_SP_HARDWARE_BASE_5,
1980     EL_SP_HARDWARE_BASE_6,
1981     EL_INVISIBLE_STEELWALL,
1982     EL_INVISIBLE_STEELWALL_ACTIVE,
1983     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1984     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1985     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1986     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1987     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1988     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1989     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1990     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1991     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1992     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1993     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1994     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1995     EL_LIGHT_SWITCH,
1996     EL_LIGHT_SWITCH_ACTIVE,
1997     EL_SIGN_EXCLAMATION,
1998     EL_SIGN_RADIOACTIVITY,
1999     EL_SIGN_STOP,
2000     EL_SIGN_WHEELCHAIR,
2001     EL_SIGN_PARKING,
2002     EL_SIGN_ONEWAY,
2003     EL_SIGN_HEART,
2004     EL_SIGN_TRIANGLE,
2005     EL_SIGN_ROUND,
2006     EL_SIGN_EXIT,
2007     EL_SIGN_YINYANG,
2008     EL_SIGN_OTHER,
2009     EL_STEELWALL_SLANTED,
2010     EL_EMC_STEELWALL_1,
2011     EL_EMC_STEELWALL_2,
2012     EL_EMC_STEELWALL_3,
2013     EL_EMC_STEELWALL_4,
2014     EL_CRYSTAL,
2015     EL_GATE_1,
2016     EL_GATE_2,
2017     EL_GATE_3,
2018     EL_GATE_4,
2019     EL_GATE_1_GRAY,
2020     EL_GATE_2_GRAY,
2021     EL_GATE_3_GRAY,
2022     EL_GATE_4_GRAY,
2023     EL_EM_GATE_1,
2024     EL_EM_GATE_2,
2025     EL_EM_GATE_3,
2026     EL_EM_GATE_4,
2027     EL_EM_GATE_1_GRAY,
2028     EL_EM_GATE_2_GRAY,
2029     EL_EM_GATE_3_GRAY,
2030     EL_EM_GATE_4_GRAY,
2031     EL_SWITCHGATE_OPEN,
2032     EL_SWITCHGATE_OPENING,
2033     EL_SWITCHGATE_CLOSED,
2034     EL_SWITCHGATE_CLOSING,
2035     EL_TIMEGATE_OPEN,
2036     EL_TIMEGATE_OPENING,
2037     EL_TIMEGATE_CLOSED,
2038     EL_TIMEGATE_CLOSING,
2039     EL_TUBE_ANY,
2040     EL_TUBE_VERTICAL,
2041     EL_TUBE_HORIZONTAL,
2042     EL_TUBE_VERTICAL_LEFT,
2043     EL_TUBE_VERTICAL_RIGHT,
2044     EL_TUBE_HORIZONTAL_UP,
2045     EL_TUBE_HORIZONTAL_DOWN,
2046     EL_TUBE_LEFT_UP,
2047     EL_TUBE_LEFT_DOWN,
2048     EL_TUBE_RIGHT_UP,
2049     EL_TUBE_RIGHT_DOWN,
2050     -1
2051   };
2052
2053   static int ep_classic_enemy[] =
2054   {
2055     EL_BUG,
2056     EL_SPACESHIP,
2057     EL_BD_BUTTERFLY,
2058     EL_BD_FIREFLY,
2059
2060     EL_YAMYAM,
2061     EL_DARK_YAMYAM,
2062     EL_ROBOT,
2063     EL_PACMAN,
2064     EL_SP_SNIKSNAK,
2065     EL_SP_ELECTRON,
2066     -1
2067   };
2068
2069   static int ep_belt[] =
2070   {
2071     EL_CONVEYOR_BELT_1_LEFT,
2072     EL_CONVEYOR_BELT_1_MIDDLE,
2073     EL_CONVEYOR_BELT_1_RIGHT,
2074     EL_CONVEYOR_BELT_2_LEFT,
2075     EL_CONVEYOR_BELT_2_MIDDLE,
2076     EL_CONVEYOR_BELT_2_RIGHT,
2077     EL_CONVEYOR_BELT_3_LEFT,
2078     EL_CONVEYOR_BELT_3_MIDDLE,
2079     EL_CONVEYOR_BELT_3_RIGHT,
2080     EL_CONVEYOR_BELT_4_LEFT,
2081     EL_CONVEYOR_BELT_4_MIDDLE,
2082     EL_CONVEYOR_BELT_4_RIGHT,
2083     -1
2084   };
2085
2086   static int ep_belt_active[] =
2087   {
2088     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2089     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2090     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2091     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2092     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2093     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2094     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2095     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2096     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2097     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2098     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2099     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2100     -1
2101   };
2102
2103   static int ep_belt_switch[] =
2104   {
2105     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2106     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2107     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2108     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2109     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2110     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2111     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2112     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2113     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2114     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2115     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2116     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2117     -1
2118   };
2119
2120   static int ep_tube[] =
2121   {
2122     EL_TUBE_LEFT_UP,
2123     EL_TUBE_LEFT_DOWN,
2124     EL_TUBE_RIGHT_UP,
2125     EL_TUBE_RIGHT_DOWN,
2126     EL_TUBE_HORIZONTAL,
2127     EL_TUBE_HORIZONTAL_UP,
2128     EL_TUBE_HORIZONTAL_DOWN,
2129     EL_TUBE_VERTICAL,
2130     EL_TUBE_VERTICAL_LEFT,
2131     EL_TUBE_VERTICAL_RIGHT,
2132     EL_TUBE_ANY,
2133     -1
2134   };
2135
2136   static int ep_keygate[] =
2137   {
2138     EL_GATE_1,
2139     EL_GATE_2,
2140     EL_GATE_3,
2141     EL_GATE_4,
2142     EL_GATE_1_GRAY,
2143     EL_GATE_2_GRAY,
2144     EL_GATE_3_GRAY,
2145     EL_GATE_4_GRAY,
2146     EL_EM_GATE_1,
2147     EL_EM_GATE_2,
2148     EL_EM_GATE_3,
2149     EL_EM_GATE_4,
2150     EL_EM_GATE_1_GRAY,
2151     EL_EM_GATE_2_GRAY,
2152     EL_EM_GATE_3_GRAY,
2153     EL_EM_GATE_4_GRAY,
2154     -1
2155   };
2156
2157   static int ep_amoeboid[] =
2158   {
2159     EL_AMOEBA_DEAD,
2160     EL_AMOEBA_WET,
2161     EL_AMOEBA_DRY,
2162     EL_AMOEBA_FULL,
2163     EL_BD_AMOEBA,
2164     -1
2165   };
2166
2167   static int ep_amoebalive[] =
2168   {
2169     EL_AMOEBA_WET,
2170     EL_AMOEBA_DRY,
2171     EL_AMOEBA_FULL,
2172     EL_BD_AMOEBA,
2173     -1
2174   };
2175
2176   static int ep_has_content[] =
2177   {
2178     EL_YAMYAM,
2179     EL_AMOEBA_WET,
2180     EL_AMOEBA_DRY,
2181     EL_AMOEBA_FULL,
2182     EL_BD_AMOEBA,
2183     -1
2184   };
2185
2186   static int ep_active_bomb[] =
2187   {
2188     EL_DYNAMITE_ACTIVE,
2189     EL_DYNABOMB_PLAYER_1_ACTIVE,
2190     EL_DYNABOMB_PLAYER_2_ACTIVE,
2191     EL_DYNABOMB_PLAYER_3_ACTIVE,
2192     EL_DYNABOMB_PLAYER_4_ACTIVE,
2193     EL_SP_DISK_RED_ACTIVE,
2194     -1
2195   };
2196
2197   static int ep_inactive[] =
2198   {
2199     EL_EMPTY,
2200     EL_SAND,
2201     EL_WALL,
2202     EL_BD_WALL,
2203     EL_WALL_CRUMBLED,
2204     EL_STEELWALL,
2205     EL_AMOEBA_DEAD,
2206     EL_QUICKSAND_EMPTY,
2207     EL_STONEBLOCK,
2208     EL_ROBOT_WHEEL,
2209     EL_KEY_1,
2210     EL_KEY_2,
2211     EL_KEY_3,
2212     EL_KEY_4,
2213     EL_EM_KEY_1,
2214     EL_EM_KEY_2,
2215     EL_EM_KEY_3,
2216     EL_EM_KEY_4,
2217     EL_GATE_1,
2218     EL_GATE_2,
2219     EL_GATE_3,
2220     EL_GATE_4,
2221     EL_GATE_1_GRAY,
2222     EL_GATE_2_GRAY,
2223     EL_GATE_3_GRAY,
2224     EL_GATE_4_GRAY,
2225     EL_EM_GATE_1,
2226     EL_EM_GATE_2,
2227     EL_EM_GATE_3,
2228     EL_EM_GATE_4,
2229     EL_EM_GATE_1_GRAY,
2230     EL_EM_GATE_2_GRAY,
2231     EL_EM_GATE_3_GRAY,
2232     EL_EM_GATE_4_GRAY,
2233     EL_DYNAMITE,
2234     EL_INVISIBLE_STEELWALL,
2235     EL_INVISIBLE_WALL,
2236     EL_INVISIBLE_SAND,
2237     EL_LAMP,
2238     EL_LAMP_ACTIVE,
2239     EL_WALL_EMERALD,
2240     EL_WALL_DIAMOND,
2241     EL_WALL_BD_DIAMOND,
2242     EL_WALL_EMERALD_YELLOW,
2243     EL_DYNABOMB_INCREASE_NUMBER,
2244     EL_DYNABOMB_INCREASE_SIZE,
2245     EL_DYNABOMB_INCREASE_POWER,
2246     EL_SOKOBAN_OBJECT,
2247     EL_SOKOBAN_FIELD_EMPTY,
2248     EL_SOKOBAN_FIELD_FULL,
2249     EL_WALL_EMERALD_RED,
2250     EL_WALL_EMERALD_PURPLE,
2251     EL_ACID_POOL_TOPLEFT,
2252     EL_ACID_POOL_TOPRIGHT,
2253     EL_ACID_POOL_BOTTOMLEFT,
2254     EL_ACID_POOL_BOTTOM,
2255     EL_ACID_POOL_BOTTOMRIGHT,
2256     EL_MAGIC_WALL,
2257     EL_MAGIC_WALL_DEAD,
2258     EL_BD_MAGIC_WALL,
2259     EL_BD_MAGIC_WALL_DEAD,
2260     EL_AMOEBA_TO_DIAMOND,
2261     EL_BLOCKED,
2262     EL_SP_EMPTY,
2263     EL_SP_BASE,
2264     EL_SP_PORT_RIGHT,
2265     EL_SP_PORT_DOWN,
2266     EL_SP_PORT_LEFT,
2267     EL_SP_PORT_UP,
2268     EL_SP_GRAVITY_PORT_RIGHT,
2269     EL_SP_GRAVITY_PORT_DOWN,
2270     EL_SP_GRAVITY_PORT_LEFT,
2271     EL_SP_GRAVITY_PORT_UP,
2272     EL_SP_PORT_HORIZONTAL,
2273     EL_SP_PORT_VERTICAL,
2274     EL_SP_PORT_ANY,
2275     EL_SP_DISK_RED,
2276     EL_SP_DISK_YELLOW,
2277     EL_SP_CHIP_SINGLE,
2278     EL_SP_CHIP_LEFT,
2279     EL_SP_CHIP_RIGHT,
2280     EL_SP_CHIP_TOP,
2281     EL_SP_CHIP_BOTTOM,
2282     EL_SP_HARDWARE_GRAY,
2283     EL_SP_HARDWARE_GREEN,
2284     EL_SP_HARDWARE_BLUE,
2285     EL_SP_HARDWARE_RED,
2286     EL_SP_HARDWARE_YELLOW,
2287     EL_SP_HARDWARE_BASE_1,
2288     EL_SP_HARDWARE_BASE_2,
2289     EL_SP_HARDWARE_BASE_3,
2290     EL_SP_HARDWARE_BASE_4,
2291     EL_SP_HARDWARE_BASE_5,
2292     EL_SP_HARDWARE_BASE_6,
2293     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2294     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2295     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2296     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2297     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2298     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2299     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2300     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2301     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2302     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2303     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2304     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2305     EL_SIGN_EXCLAMATION,
2306     EL_SIGN_RADIOACTIVITY,
2307     EL_SIGN_STOP,
2308     EL_SIGN_WHEELCHAIR,
2309     EL_SIGN_PARKING,
2310     EL_SIGN_ONEWAY,
2311     EL_SIGN_HEART,
2312     EL_SIGN_TRIANGLE,
2313     EL_SIGN_ROUND,
2314     EL_SIGN_EXIT,
2315     EL_SIGN_YINYANG,
2316     EL_SIGN_OTHER,
2317     EL_STEELWALL_SLANTED,
2318     EL_EMC_STEELWALL_1,
2319     EL_EMC_STEELWALL_2,
2320     EL_EMC_STEELWALL_3,
2321     EL_EMC_STEELWALL_4,
2322     EL_EMC_WALL_1,
2323     EL_EMC_WALL_2,
2324     EL_EMC_WALL_3,
2325     EL_EMC_WALL_4,
2326     EL_EMC_WALL_5,
2327     EL_EMC_WALL_6,
2328     EL_EMC_WALL_7,
2329     EL_EMC_WALL_8,
2330     -1
2331   };
2332
2333   static struct
2334   {
2335     int *elements;
2336     int property;
2337   } element_properties[] =
2338   {
2339     { ep_diggable,              EP_DIGGABLE             },
2340     { ep_collectible,           EP_COLLECTIBLE          },
2341     { ep_dont_run_into,         EP_DONT_RUN_INTO        },
2342     { ep_dont_collide_with,     EP_DONT_COLLIDE_WITH    },
2343     { ep_dont_touch,            EP_DONT_TOUCH           },
2344     { ep_indestructible,        EP_INDESTRUCTIBLE       },
2345     { ep_slippery,              EP_SLIPPERY             },
2346     { ep_can_change,            EP_CAN_CHANGE           },
2347     { ep_can_move,              EP_CAN_MOVE             },
2348     { ep_can_fall,              EP_CAN_FALL             },
2349     { ep_can_smash_player,      EP_CAN_SMASH_PLAYER     },
2350     { ep_can_smash_enemies,     EP_CAN_SMASH_ENEMIES    },
2351     { ep_can_smash_everything,  EP_CAN_SMASH_EVERYTHING },
2352     { ep_can_explode_by_fire,   EP_CAN_EXPLODE_BY_FIRE  },
2353     { ep_can_explode_smashed,   EP_CAN_EXPLODE_SMASHED  },
2354     { ep_can_explode_impact,    EP_CAN_EXPLODE_IMPACT   },
2355     { ep_walkable_over,         EP_WALKABLE_OVER        },
2356     { ep_walkable_inside,       EP_WALKABLE_INSIDE      },
2357     { ep_walkable_under,        EP_WALKABLE_UNDER       },
2358     { ep_passable_over,         EP_PASSABLE_OVER        },
2359     { ep_passable_inside,       EP_PASSABLE_INSIDE      },
2360     { ep_passable_under,        EP_PASSABLE_UNDER       },
2361     { ep_pushable,              EP_PUSHABLE             },
2362
2363     { ep_can_be_crumbled,       EP_CAN_BE_CRUMBLED      },
2364
2365     { ep_player,                EP_PLAYER               },
2366     { ep_can_pass_magic_wall,   EP_CAN_PASS_MAGIC_WALL  },
2367     { ep_switchable,            EP_SWITCHABLE           },
2368     { ep_bd_element,            EP_BD_ELEMENT           },
2369     { ep_sp_element,            EP_SP_ELEMENT           },
2370     { ep_sb_element,            EP_SB_ELEMENT           },
2371     { ep_gem,                   EP_GEM                  },
2372     { ep_food_dark_yamyam,      EP_FOOD_DARK_YAMYAM     },
2373     { ep_food_penguin,          EP_FOOD_PENGUIN         },
2374     { ep_food_pig,              EP_FOOD_PIG             },
2375     { ep_historic_wall,         EP_HISTORIC_WALL        },
2376     { ep_historic_solid,        EP_HISTORIC_SOLID       },
2377     { ep_classic_enemy,         EP_CLASSIC_ENEMY        },
2378     { ep_belt,                  EP_BELT                 },
2379     { ep_belt_active,           EP_BELT_ACTIVE          },
2380     { ep_belt_switch,           EP_BELT_SWITCH          },
2381     { ep_tube,                  EP_TUBE                 },
2382     { ep_keygate,               EP_KEYGATE              },
2383     { ep_amoeboid,              EP_AMOEBOID             },
2384     { ep_amoebalive,            EP_AMOEBALIVE           },
2385     { ep_has_content,           EP_HAS_CONTENT          },
2386     { ep_active_bomb,           EP_ACTIVE_BOMB          },
2387     { ep_inactive,              EP_INACTIVE             },
2388
2389     { NULL,                     -1                      }
2390   };
2391
2392   static int copy_properties[][5] =
2393   {
2394     {
2395       EL_BUG,
2396       EL_BUG_LEFT,              EL_BUG_RIGHT,
2397       EL_BUG_UP,                EL_BUG_DOWN
2398     },
2399     {
2400       EL_SPACESHIP,
2401       EL_SPACESHIP_LEFT,        EL_SPACESHIP_RIGHT,
2402       EL_SPACESHIP_UP,          EL_SPACESHIP_DOWN
2403     },
2404     {
2405       EL_BD_BUTTERFLY,
2406       EL_BD_BUTTERFLY_LEFT,     EL_BD_BUTTERFLY_RIGHT,
2407       EL_BD_BUTTERFLY_UP,       EL_BD_BUTTERFLY_DOWN
2408     },
2409     {
2410       EL_BD_FIREFLY,
2411       EL_BD_FIREFLY_LEFT,       EL_BD_FIREFLY_RIGHT,
2412       EL_BD_FIREFLY_UP,         EL_BD_FIREFLY_DOWN
2413     },
2414     {
2415       EL_PACMAN,
2416       EL_PACMAN_LEFT,           EL_PACMAN_RIGHT,
2417       EL_PACMAN_UP,             EL_PACMAN_DOWN
2418     },
2419     {
2420       -1,
2421       -1, -1, -1, -1
2422     }
2423   };
2424
2425   int i, j, k;
2426
2427   /* always start with reliable default values (element has no properties) */
2428   for (i=0; i < MAX_NUM_ELEMENTS; i++)
2429     for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
2430       SET_PROPERTY(i, j, FALSE);
2431
2432   /* set all base element properties from above array definitions */
2433   for (i=0; element_properties[i].elements != NULL; i++)
2434     for (j=0; (element_properties[i].elements)[j] != -1; j++)
2435       SET_PROPERTY((element_properties[i].elements)[j],
2436                    element_properties[i].property, TRUE);
2437
2438   /* copy properties to some elements that are only stored in level file */
2439   for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
2440     for (j=0; copy_properties[j][0] != -1; j++)
2441       if (HAS_PROPERTY(copy_properties[j][0], i))
2442         for (k=1; k<=4; k++)
2443           SET_PROPERTY(copy_properties[j][k], i, TRUE);
2444 }
2445
2446 void InitElementPropertiesEngine(int engine_version)
2447 {
2448 #if 0
2449   static int active_properties[] =
2450   {
2451     EP_AMOEBALIVE,
2452     EP_AMOEBOID,
2453     EP_PFORTE,
2454     EP_DONT_COLLIDE_WITH,
2455     EP_MAUER,
2456     EP_CAN_FALL,
2457     EP_CAN_SMASH,
2458     EP_CAN_PASS_MAGIC_WALL,
2459     EP_CAN_MOVE,
2460     EP_DONT_TOUCH,
2461     EP_DONT_RUN_INTO,
2462     EP_GEM,
2463     EP_CAN_EXPLODE_BY_FIRE,
2464     EP_PUSHABLE,
2465     EP_PLAYER,
2466     EP_HAS_CONTENT,
2467     EP_DIGGABLE,
2468     EP_PASSABLE_INSIDE,
2469     EP_OVER_PLAYER,
2470     EP_ACTIVE_BOMB,
2471
2472     EP_BELT,
2473     EP_BELT_ACTIVE,
2474     EP_BELT_SWITCH,
2475     EP_WALKABLE_UNDER,
2476     EP_EM_SLIPPERY_WALL,
2477     EP_CAN_BE_CRUMBLED,
2478   };
2479 #endif
2480
2481   static int no_wall_properties[] =
2482   {
2483     EP_DIGGABLE,
2484     EP_COLLECTIBLE,
2485     EP_DONT_RUN_INTO,
2486     EP_DONT_COLLIDE_WITH,
2487     EP_CAN_MOVE,
2488     EP_CAN_FALL,
2489     EP_CAN_SMASH_PLAYER,
2490     EP_CAN_SMASH_ENEMIES,
2491     EP_CAN_SMASH_EVERYTHING,
2492     EP_PUSHABLE,
2493
2494     EP_CAN_BE_CRUMBLED,
2495
2496     EP_PLAYER,
2497     EP_GEM,
2498     EP_FOOD_DARK_YAMYAM,
2499     EP_FOOD_PENGUIN,
2500     EP_BELT,
2501     EP_BELT_ACTIVE,
2502     EP_TUBE,
2503     EP_AMOEBOID,
2504     EP_AMOEBALIVE,
2505     EP_ACTIVE_BOMB,
2506
2507     EP_ACCESSIBLE,
2508     -1
2509   };
2510
2511   int i, j;
2512
2513 #if 0
2514   InitElementPropertiesStatic();
2515 #endif
2516
2517   /* set all special, combined or engine dependant element properties */
2518   for (i=0; i < MAX_NUM_ELEMENTS; i++)
2519   {
2520 #if 0
2521     for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
2522       SET_PROPERTY(i, j, FALSE);
2523 #endif
2524
2525     /* ---------- INACTIVE ------------------------------------------------- */
2526     if (i >= EL_CHAR_START && i <= EL_CHAR_END)
2527       SET_PROPERTY(i, EP_INACTIVE, TRUE);
2528
2529     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
2530     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
2531                                   IS_WALKABLE_INSIDE(i) ||
2532                                   IS_WALKABLE_UNDER(i)));
2533
2534     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
2535                                   IS_PASSABLE_INSIDE(i) ||
2536                                   IS_PASSABLE_UNDER(i)));
2537
2538     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
2539                                          IS_PASSABLE_OVER(i)));
2540
2541     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
2542                                            IS_PASSABLE_INSIDE(i)));
2543
2544     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
2545                                           IS_PASSABLE_UNDER(i)));
2546
2547     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
2548                                     IS_PASSABLE(i)));
2549
2550     /* ---------- SNAPPABLE ------------------------------------------------ */
2551     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
2552                                    IS_COLLECTIBLE(i) ||
2553                                    IS_SWITCHABLE(i) ||
2554                                    i == EL_BD_ROCK));
2555
2556     /* ---------- WALL ----------------------------------------------------- */
2557     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
2558
2559     for (j=0; no_wall_properties[j] != -1; j++)
2560       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
2561           i >= EL_FIRST_RUNTIME_UNREAL)
2562         SET_PROPERTY(i, EP_WALL, FALSE);
2563
2564     if (IS_HISTORIC_WALL(i))
2565       SET_PROPERTY(i, EP_WALL, TRUE);
2566
2567     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
2568     if (engine_version < VERSION_IDENT(2,2,0))
2569       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
2570     else
2571       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
2572                                              !IS_DIGGABLE(i) &&
2573                                              !IS_COLLECTIBLE(i)));
2574
2575     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
2576
2577     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
2578       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
2579     else
2580       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
2581                                             IS_INDESTRUCTIBLE(i)));
2582
2583     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
2584     if (i == EL_FLAMES)
2585       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
2586     else if (engine_version < VERSION_IDENT(2,2,0))
2587       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
2588     else
2589       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
2590                                            !IS_WALKABLE_OVER(i) &&
2591                                            !IS_WALKABLE_UNDER(i)));
2592
2593     if (IS_CUSTOM_ELEMENT(i))
2594     {
2595       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
2596       if (DONT_TOUCH(i))
2597         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
2598       if (DONT_COLLIDE_WITH(i))
2599         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
2600
2601       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
2602       if (CAN_SMASH_EVERYTHING(i))
2603         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
2604       if (CAN_SMASH_ENEMIES(i))
2605         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
2606     }
2607
2608     /* ---------- CAN_SMASH ------------------------------------------------ */
2609     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
2610                                    CAN_SMASH_ENEMIES(i) ||
2611                                    CAN_SMASH_EVERYTHING(i)));
2612
2613     /* ---------- CAN_EXPLODE ---------------------------------------------- */
2614     SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
2615                                      CAN_EXPLODE_SMASHED(i) ||
2616                                      CAN_EXPLODE_BY_FIRE(i)));
2617   }
2618
2619 #if 0
2620   /* determine inactive elements (used for engine main loop optimization) */
2621   for (i=0; i < MAX_NUM_ELEMENTS; i++)
2622   {
2623     boolean active = FALSE;
2624
2625     for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
2626     {
2627       if (HAS_PROPERTY(i, j))
2628         active = TRUE;
2629     }
2630
2631 #if 0
2632     if (!active)
2633       SET_PROPERTY(i, EP_INACTIVE, TRUE);
2634 #endif
2635   }
2636 #endif
2637
2638   /* dynamically adjust element properties according to game engine version */
2639   {
2640     static int ep_em_slippery_wall[] =
2641     {
2642       EL_STEELWALL,
2643       EL_WALL,
2644       EL_EXPANDABLE_WALL,
2645       EL_EXPANDABLE_WALL_HORIZONTAL,
2646       EL_EXPANDABLE_WALL_VERTICAL,
2647       EL_EXPANDABLE_WALL_ANY,
2648       -1
2649     };
2650
2651     /* special EM style gems behaviour */
2652     for (i=0; ep_em_slippery_wall[i] != -1; i++)
2653       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
2654                    level.em_slippery_gems);
2655
2656     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
2657     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
2658                  (level.em_slippery_gems &&
2659                   engine_version > VERSION_IDENT(2,0,1)));
2660   }
2661
2662   /* dynamically adjust element properties according to game engine version */
2663 #if 0
2664   if (engine_version < RELEASE_IDENT(2,2,0,7))
2665 #endif
2666   {
2667     for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
2668     {
2669       int element = EL_CUSTOM_START + i;
2670
2671       element_info[element].push_delay_fixed = 2;
2672       element_info[element].push_delay_random = 8;
2673     }
2674   }
2675 }
2676
2677 static void InitGlobal()
2678 {
2679   global.autoplay_leveldir = NULL;
2680
2681   global.frames_per_second = 0;
2682   global.fps_slowdown = FALSE;
2683   global.fps_slowdown_factor = 1;
2684 }
2685
2686 void Execute_Command(char *command)
2687 {
2688   if (strcmp(command, "print graphicsinfo.conf") == 0)
2689   {
2690     int i;
2691
2692     printf("# You can configure additional/alternative image files here.\n");
2693     printf("# (The images below are default and therefore commented out.)\n");
2694     printf("\n");
2695     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2696     printf("\n");
2697     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2698     printf("\n");
2699
2700     for (i=0; image_config[i].token != NULL; i++)
2701       printf("# %s\n",
2702              getFormattedSetupEntry(image_config[i].token,
2703                                     image_config[i].value));
2704
2705     exit(0);
2706   }
2707   else if (strcmp(command, "print soundsinfo.conf") == 0)
2708   {
2709     int i;
2710
2711     printf("# You can configure additional/alternative sound files here.\n");
2712     printf("# (The sounds below are default and therefore commented out.)\n");
2713     printf("\n");
2714     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2715     printf("\n");
2716     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2717     printf("\n");
2718
2719     for (i=0; sound_config[i].token != NULL; i++)
2720       printf("# %s\n",
2721              getFormattedSetupEntry(sound_config[i].token,
2722                                     sound_config[i].value));
2723
2724     exit(0);
2725   }
2726   else if (strcmp(command, "print musicinfo.conf") == 0)
2727   {
2728     printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2729     printf("\n");
2730     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2731     printf("\n");
2732     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2733
2734     exit(0);
2735   }
2736   else if (strncmp(command, "dump level ", 11) == 0)
2737   {
2738     char *filename = &command[11];
2739
2740     if (access(filename, F_OK) != 0)
2741       Error(ERR_EXIT, "cannot open file '%s'", filename);
2742
2743     LoadLevelFromFilename(filename);
2744     DumpLevel(&level);
2745
2746     exit(0);
2747   }
2748   else if (strncmp(command, "dump tape ", 10) == 0)
2749   {
2750     char *filename = &command[10];
2751
2752     if (access(filename, F_OK) != 0)
2753       Error(ERR_EXIT, "cannot open file '%s'", filename);
2754
2755     LoadTapeFromFilename(filename);
2756     DumpTape(&tape);
2757
2758     exit(0);
2759   }
2760   else if (strncmp(command, "autoplay ", 9) == 0)
2761   {
2762     char *str_copy = getStringCopy(&command[9]);
2763     char *str_ptr = strchr(str_copy, ' ');
2764
2765     global.autoplay_leveldir = str_copy;
2766     global.autoplay_level_nr = -1;
2767
2768     if (str_ptr != NULL)
2769     {
2770       *str_ptr++ = '\0';                        /* terminate leveldir string */
2771       global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2772     }
2773   }
2774   else
2775   {
2776     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2777   }
2778 }
2779
2780 static void InitSetup()
2781 {
2782   LoadSetup();                                  /* global setup info */
2783
2784   /* set some options from setup file */
2785
2786   if (setup.options.verbose)
2787     options.verbose = TRUE;
2788 }
2789
2790 static void InitPlayerInfo()
2791 {
2792   int i;
2793
2794   /* choose default local player */
2795   local_player = &stored_player[0];
2796
2797   for (i=0; i<MAX_PLAYERS; i++)
2798     stored_player[i].connected = FALSE;
2799
2800   local_player->connected = TRUE;
2801 }
2802
2803 static void InitArtworkInfo()
2804 {
2805   LoadArtworkInfo();
2806 }
2807
2808 static char *get_string_in_brackets(char *string)
2809 {
2810   char *string_in_brackets = checked_malloc(strlen(string) + 3);
2811
2812   sprintf(string_in_brackets, "[%s]", string);
2813
2814   return string_in_brackets;
2815 }
2816
2817 #if 0
2818 static char *get_element_class_token(int element)
2819 {
2820   char *element_class_name = element_info[element].class_name;
2821   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2822
2823   sprintf(element_class_token, "[%s]", element_class_name);
2824
2825   return element_class_token;
2826 }
2827
2828 static char *get_action_class_token(int action)
2829 {
2830   char *action_class_name = &element_action_info[action].suffix[1];
2831   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
2832
2833   sprintf(action_class_token, "[%s]", action_class_name);
2834
2835   return action_class_token;
2836 }
2837 #endif
2838
2839 static void InitArtworkConfig()
2840 {
2841   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2842   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
2843   static char *action_id_suffix[NUM_ACTIONS + 1];
2844   static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2845   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2846   static char *dummy[1] = { NULL };
2847   static char *ignore_generic_tokens[] =
2848   {
2849     "name",
2850     "sort_priority",
2851     NULL
2852   };
2853   static char **ignore_image_tokens, **ignore_sound_tokens;
2854   int num_ignore_generic_tokens;
2855   int num_ignore_image_tokens, num_ignore_sound_tokens;
2856   int i;
2857
2858   /* dynamically determine list of generic tokens to be ignored */
2859   num_ignore_generic_tokens = 0;
2860   for (i=0; ignore_generic_tokens[i] != NULL; i++)
2861     num_ignore_generic_tokens++;
2862
2863   /* dynamically determine list of image tokens to be ignored */
2864   num_ignore_image_tokens = num_ignore_generic_tokens;
2865   for (i=0; image_config_vars[i].token != NULL; i++)
2866     num_ignore_image_tokens++;
2867   ignore_image_tokens =
2868     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
2869   for (i=0; i < num_ignore_generic_tokens; i++)
2870     ignore_image_tokens[i] = ignore_generic_tokens[i];
2871   for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
2872     ignore_image_tokens[num_ignore_generic_tokens + i] =
2873       image_config_vars[i].token;
2874   ignore_image_tokens[num_ignore_image_tokens] = NULL;
2875
2876   /* dynamically determine list of sound tokens to be ignored */
2877   num_ignore_sound_tokens = num_ignore_generic_tokens;
2878   ignore_sound_tokens =
2879     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
2880   for (i=0; i < num_ignore_generic_tokens; i++)
2881     ignore_sound_tokens[i] = ignore_generic_tokens[i];
2882   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
2883
2884   for (i=0; i<MAX_NUM_ELEMENTS; i++)
2885     image_id_prefix[i] = element_info[i].token_name;
2886   for (i=0; i<NUM_FONTS; i++)
2887     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2888   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2889
2890   for (i=0; i<MAX_NUM_ELEMENTS; i++)
2891     sound_id_prefix[i] = element_info[i].token_name;
2892   for (i=0; i<MAX_NUM_ELEMENTS; i++)
2893     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
2894       get_string_in_brackets(element_info[i].class_name);
2895   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
2896
2897   for (i=0; i<NUM_ACTIONS; i++)
2898     action_id_suffix[i] = element_action_info[i].suffix;
2899   action_id_suffix[NUM_ACTIONS] = NULL;
2900
2901   for (i=0; i<NUM_DIRECTIONS; i++)
2902     direction_id_suffix[i] = element_direction_info[i].suffix;
2903   direction_id_suffix[NUM_DIRECTIONS] = NULL;
2904
2905   for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2906     special_id_suffix[i] = special_suffix_info[i].suffix;
2907   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2908
2909   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2910                 image_id_prefix, action_id_suffix, direction_id_suffix,
2911                 special_id_suffix, ignore_image_tokens);
2912   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2913                 sound_id_prefix, action_id_suffix, dummy,
2914                 special_id_suffix, ignore_sound_tokens);
2915 }
2916
2917 static void InitMixer()
2918 {
2919   OpenAudio();
2920   StartMixer();
2921 }
2922
2923 void InitGfx()
2924 {
2925   char *filename_font_initial = NULL;
2926   Bitmap *bitmap_font_initial = NULL;
2927   int i, j;
2928
2929   /* determine settings for initial font (for displaying startup messages) */
2930   for (i=0; image_config[i].token != NULL; i++)
2931   {
2932     for (j=0; j < NUM_INITIAL_FONTS; j++)
2933     {
2934       char font_token[128];
2935       int len_font_token;
2936
2937       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2938       len_font_token = strlen(font_token);
2939
2940       if (strcmp(image_config[i].token, font_token) == 0)
2941         filename_font_initial = image_config[i].value;
2942       else if (strlen(image_config[i].token) > len_font_token &&
2943                strncmp(image_config[i].token, font_token, len_font_token) == 0)
2944       {
2945         if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2946           font_initial[j].src_x = atoi(image_config[i].value);
2947         else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2948           font_initial[j].src_y = atoi(image_config[i].value);
2949         else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2950           font_initial[j].width = atoi(image_config[i].value);
2951         else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2952           font_initial[j].height = atoi(image_config[i].value);
2953       }
2954     }
2955   }
2956
2957   for (j=0; j < NUM_INITIAL_FONTS; j++)
2958   {
2959     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
2960     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
2961   }
2962
2963   if (filename_font_initial == NULL)    /* should not happen */
2964     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
2965
2966   /* create additional image buffers for double-buffering */
2967   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
2968   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
2969
2970   /* initialize screen properties */
2971   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
2972                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
2973                    bitmap_db_field);
2974   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
2975   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
2976   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
2977
2978   bitmap_font_initial = LoadCustomImage(filename_font_initial);
2979
2980   for (j=0; j < NUM_INITIAL_FONTS; j++)
2981     font_initial[j].bitmap = bitmap_font_initial;
2982
2983   InitFontGraphicInfo();
2984
2985   DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
2986   DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
2987
2988   DrawInitText("Loading graphics:", 120, FC_GREEN);
2989
2990   InitTileClipmasks();
2991 }
2992
2993 void InitGfxBackground()
2994 {
2995   int x, y;
2996
2997   drawto = backbuffer;
2998   fieldbuffer = bitmap_db_field;
2999   SetDrawtoField(DRAW_BACKBUFFER);
3000
3001   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
3002              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3003   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
3004   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
3005
3006   for (x=0; x<MAX_BUF_XSIZE; x++)
3007     for (y=0; y<MAX_BUF_YSIZE; y++)
3008       redraw[x][y] = 0;
3009   redraw_tiles = 0;
3010   redraw_mask = REDRAW_ALL;
3011 }
3012
3013 static void InitLevelInfo()
3014 {
3015   LoadLevelInfo();                              /* global level info */
3016   LoadLevelSetup_LastSeries();                  /* last played series info */
3017   LoadLevelSetup_SeriesInfo();                  /* last played level info */
3018 }
3019
3020 void InitLevelArtworkInfo()
3021 {
3022   LoadLevelArtworkInfo();
3023 }
3024
3025 static void InitImages()
3026 {
3027   ReloadCustomImages();
3028
3029   LoadCustomElementDescriptions();
3030   LoadSpecialMenuDesignSettings();
3031
3032   ReinitializeGraphics();
3033 }
3034
3035 static void InitSound()
3036 {
3037   InitReloadCustomSounds(artwork.snd_current->identifier);
3038   ReinitializeSounds();
3039 }
3040
3041 static void InitMusic()
3042 {
3043   InitReloadCustomMusic(artwork.mus_current->identifier);
3044   ReinitializeMusic();
3045 }
3046
3047 void InitNetworkServer()
3048 {
3049 #if defined(PLATFORM_UNIX)
3050   int nr_wanted;
3051 #endif
3052
3053   if (!options.network)
3054     return;
3055
3056 #if defined(PLATFORM_UNIX)
3057   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
3058
3059   if (!ConnectToServer(options.server_host, options.server_port))
3060     Error(ERR_EXIT, "cannot connect to network game server");
3061
3062   SendToServer_PlayerName(setup.player_name);
3063   SendToServer_ProtocolVersion();
3064
3065   if (nr_wanted)
3066     SendToServer_NrWanted(nr_wanted);
3067 #endif
3068 }
3069
3070 void ReloadCustomArtwork()
3071 {
3072   static char *leveldir_current_identifier = NULL;
3073   static boolean last_override_level_graphics = FALSE;
3074   static boolean last_override_level_sounds = FALSE;
3075   static boolean last_override_level_music = FALSE;
3076   /* identifier for new artwork; default: artwork configured in setup */
3077   char *gfx_new_identifier = artwork.gfx_current->identifier;
3078   char *snd_new_identifier = artwork.snd_current->identifier;
3079   char *mus_new_identifier = artwork.mus_current->identifier;
3080   boolean redraw_screen = FALSE;
3081
3082   if (leveldir_current_identifier == NULL)
3083     leveldir_current_identifier = leveldir_current->identifier;
3084
3085 #if 0
3086   printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
3087          leveldir_current->graphics_set);
3088   printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
3089          leveldir_current->identifier);
3090 #endif
3091
3092 #if 0
3093   printf("graphics --> '%s' ('%s')\n",
3094          artwork.gfx_current_identifier, artwork.gfx_current->filename);
3095   printf("sounds   --> '%s' ('%s')\n",
3096          artwork.snd_current_identifier, artwork.snd_current->filename);
3097   printf("music    --> '%s' ('%s')\n",
3098          artwork.mus_current_identifier, artwork.mus_current->filename);
3099 #endif
3100
3101   /* leveldir_current may be invalid (level group, parent link) */
3102   if (!validLevelSeries(leveldir_current))
3103     return;
3104
3105   /* when a new level series was selected, check if there was a change
3106      in custom artwork stored in level series directory */
3107   if (leveldir_current_identifier != leveldir_current->identifier)
3108   {
3109     char *identifier_old = leveldir_current_identifier;
3110     char *identifier_new = leveldir_current->identifier;
3111
3112     if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
3113         getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
3114       gfx_new_identifier = identifier_new;
3115     if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
3116         getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
3117       snd_new_identifier = identifier_new;
3118     if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
3119         getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
3120       mus_new_identifier = identifier_new;
3121
3122     leveldir_current_identifier = leveldir_current->identifier;
3123   }
3124
3125   /* custom level artwork configured in level series configuration file
3126      always overrides custom level artwork stored in level series directory
3127      and (level independant) custom artwork configured in setup menue */
3128   if (leveldir_current->graphics_set != NULL)
3129     gfx_new_identifier = leveldir_current->graphics_set;
3130   if (leveldir_current->sounds_set != NULL)
3131     snd_new_identifier = leveldir_current->sounds_set;
3132   if (leveldir_current->music_set != NULL)
3133     mus_new_identifier = leveldir_current->music_set;
3134
3135   if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
3136       last_override_level_graphics != setup.override_level_graphics)
3137   {
3138 #if 0
3139     printf("RELOADING GRAPHICS '%s' -> '%s' ('%s')\n",
3140            artwork.gfx_current_identifier,
3141            artwork.gfx_current->identifier,
3142            gfx_new_identifier);
3143 #endif
3144
3145     setLevelArtworkDir(artwork.gfx_first);
3146
3147     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
3148
3149     InitImages();
3150
3151     FreeTileClipmasks();
3152     InitTileClipmasks();
3153
3154     artwork.gfx_current_identifier = artwork.gfx_current->identifier;
3155     last_override_level_graphics = setup.override_level_graphics;
3156
3157     redraw_screen = TRUE;
3158   }
3159
3160   if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
3161       last_override_level_sounds != setup.override_level_sounds)
3162   {
3163 #if 0
3164     printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
3165            artwork.snd_current_identifier,
3166            artwork.snd_current->identifier,
3167            snd_new_identifier);
3168 #endif
3169
3170     /* set artwork path to send it to the sound server process */
3171     setLevelArtworkDir(artwork.snd_first);
3172
3173     InitReloadCustomSounds(snd_new_identifier);
3174     ReinitializeSounds();
3175
3176     artwork.snd_current_identifier = artwork.snd_current->identifier;
3177     last_override_level_sounds = setup.override_level_sounds;
3178
3179     redraw_screen = TRUE;
3180   }
3181
3182   if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
3183       last_override_level_music != setup.override_level_music)
3184   {
3185     /* set artwork path to send it to the sound server process */
3186     setLevelArtworkDir(artwork.mus_first);
3187
3188     InitReloadCustomMusic(mus_new_identifier);
3189     ReinitializeMusic();
3190
3191     artwork.mus_current_identifier = artwork.mus_current->identifier;
3192     last_override_level_music = setup.override_level_music;
3193
3194     redraw_screen = TRUE;
3195   }
3196
3197   if (redraw_screen)
3198   {
3199     InitGfxBackground();
3200
3201     /* force redraw of (open or closed) door graphics */
3202     SetDoorState(DOOR_OPEN_ALL);
3203     CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
3204   }
3205 }
3206
3207 void KeyboardAutoRepeatOffUnlessAutoplay()
3208 {
3209   if (global.autoplay_leveldir == NULL)
3210     KeyboardAutoRepeatOff();
3211 }
3212
3213
3214 /* ========================================================================= */
3215 /* OpenAll()                                                                 */
3216 /* ========================================================================= */
3217
3218 void OpenAll()
3219 {
3220   InitGlobal();         /* initialize some global variables */
3221
3222   if (options.execute_command)
3223     Execute_Command(options.execute_command);
3224
3225   if (options.serveronly)
3226   {
3227 #if defined(PLATFORM_UNIX)
3228     NetworkServer(options.server_port, options.serveronly);
3229 #else
3230     Error(ERR_WARN, "networking only supported in Unix version");
3231 #endif
3232     exit(0);    /* never reached */
3233   }
3234
3235   InitSetup();
3236
3237   InitPlayerInfo();
3238   InitArtworkInfo();            /* needed before loading gfx, sound & music */
3239   InitArtworkConfig();          /* needed before forking sound child process */
3240   InitMixer();
3241
3242   InitCounter();
3243
3244   InitRND(NEW_RANDOMIZE);
3245   InitSimpleRND(NEW_RANDOMIZE);
3246
3247   InitJoysticks();
3248
3249   InitVideoDisplay();
3250   InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
3251                   setup.fullscreen);
3252
3253   InitEventFilter(FilterMouseMotionEvents);
3254
3255   InitElementPropertiesStatic();
3256
3257   InitGfx();
3258
3259   InitLevelInfo();
3260   InitLevelArtworkInfo();
3261
3262   InitImages();                 /* needs to know current level directory */
3263   InitSound();                  /* needs to know current level directory */
3264   InitMusic();                  /* needs to know current level directory */
3265
3266   InitGfxBackground();
3267
3268   if (global.autoplay_leveldir)
3269   {
3270     AutoPlayTape();
3271     return;
3272   }
3273
3274   game_status = GAME_MODE_MAIN;
3275
3276   DrawMainMenu();
3277
3278   InitNetworkServer();
3279 }
3280
3281 void CloseAllAndExit(int exit_value)
3282 {
3283   StopSounds();
3284   FreeAllSounds();
3285   FreeAllMusic();
3286   CloseAudio();         /* called after freeing sounds (needed for SDL) */
3287
3288   FreeAllImages();
3289   FreeTileClipmasks();
3290
3291   CloseVideoDisplay();
3292   ClosePlatformDependantStuff();
3293
3294   exit(exit_value);
3295 }