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