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