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