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