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