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