175c063ac52e3c2d1bd23d26b50e6c4df77267ab
[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 #include "config.h"
28
29 #include "conf_e2g.c"   /* include auto-generated data structure definitions */
30 #include "conf_esg.c"   /* include auto-generated data structure definitions */
31 #include "conf_e2s.c"   /* include auto-generated data structure definitions */
32 #include "conf_fnt.c"   /* include auto-generated data structure definitions */
33 #include "conf_g2s.c"   /* include auto-generated data structure definitions */
34 #include "conf_g2m.c"   /* include auto-generated data structure definitions */
35
36
37 #define CONFIG_TOKEN_FONT_INITIAL               "font.initial"
38
39
40 struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41
42
43 static void InitTileClipmasks()
44 {
45 #if 0
46 #if defined(TARGET_X11)
47   XGCValues clip_gc_values;
48   unsigned long clip_gc_valuemask;
49
50 #if defined(TARGET_X11_NATIVE)
51
52 #if 0
53   GC copy_clipmask_gc;
54
55   static struct
56   {
57     int start;
58     int count;
59   }
60   tile_needs_clipping[] =
61   {
62     { GFX_SPIELER1_UP, 4 },
63     { GFX_SPIELER1_DOWN, 4 },
64     { GFX_SPIELER1_LEFT, 4 },
65     { GFX_SPIELER1_RIGHT, 4 },
66     { GFX_SPIELER1_PUSH_LEFT, 4 },
67     { GFX_SPIELER1_PUSH_RIGHT, 4 },
68     { GFX_SPIELER2_UP, 4 },
69     { GFX_SPIELER2_DOWN, 4 },
70     { GFX_SPIELER2_LEFT, 4 },
71     { GFX_SPIELER2_RIGHT, 4 },
72     { GFX_SPIELER2_PUSH_LEFT, 4 },
73     { GFX_SPIELER2_PUSH_RIGHT, 4 },
74     { GFX_SPIELER3_UP, 4 },
75     { GFX_SPIELER3_DOWN, 4 },
76     { GFX_SPIELER3_LEFT, 4 },
77     { GFX_SPIELER3_RIGHT, 4 },
78     { GFX_SPIELER3_PUSH_LEFT, 4 },
79     { GFX_SPIELER3_PUSH_RIGHT, 4 },
80     { GFX_SPIELER4_UP, 4 },
81     { GFX_SPIELER4_DOWN, 4 },
82     { GFX_SPIELER4_LEFT, 4 },
83     { GFX_SPIELER4_RIGHT, 4 },
84     { GFX_SPIELER4_PUSH_LEFT, 4 },
85     { GFX_SPIELER4_PUSH_RIGHT, 4 },
86     { GFX_SP_MURPHY, 1 },
87     { GFX_MURPHY_GO_LEFT, 3 },
88     { GFX_MURPHY_GO_RIGHT, 3 },
89     { GFX_MURPHY_SNAP_UP, 1 },
90     { GFX_MURPHY_SNAP_DOWN, 1 },
91     { GFX_MURPHY_SNAP_RIGHT, 1 },
92     { GFX_MURPHY_SNAP_LEFT, 1 },
93     { GFX_MURPHY_PUSH_RIGHT, 1 },
94     { GFX_MURPHY_PUSH_LEFT, 1 },
95     { GFX_GEBLUBBER, 4 },
96     { GFX_DYNAMIT, 7 },
97     { GFX_DYNABOMB, 4 },
98     { GFX_EXPLOSION, 8 },
99     { GFX_SOKOBAN_OBJEKT, 1 },
100     { GFX_FUNKELN_BLAU, 3 },
101     { GFX_FUNKELN_WEISS, 3 },
102     { GFX2_SHIELD_PASSIVE, 3 },
103     { GFX2_SHIELD_ACTIVE, 3 },
104     { -1, 0 }
105   };
106 #endif
107
108 #endif /* TARGET_X11_NATIVE */
109 #endif /* TARGET_X11 */
110
111   int i;
112
113   /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
114   for (i = 0; i < NUM_TILES; i++)
115     tile_clipmask[i] = None;
116
117 #if defined(TARGET_X11)
118   /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
119      often very slow when preparing a masked XCopyArea() for big Pixmaps.
120      To prevent this, create small (tile-sized) mask Pixmaps which will then
121      be set much faster with XSetClipOrigin() and speed things up a lot. */
122
123   clip_gc_values.graphics_exposures = False;
124   clip_gc_valuemask = GCGraphicsExposures;
125   tile_clip_gc = XCreateGC(display, window->drawable,
126                            clip_gc_valuemask, &clip_gc_values);
127
128 #if 0
129   for (i = 0; i < NUM_BITMAPS; i++)
130   {
131     if (pix[i]->clip_mask)
132     {
133       clip_gc_values.graphics_exposures = False;
134       clip_gc_values.clip_mask = pix[i]->clip_mask;
135       clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
136       pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
137                                          clip_gc_valuemask, &clip_gc_values);
138     }
139   }
140 #endif
141
142 #if defined(TARGET_X11_NATIVE)
143
144 #if 0
145   /* create graphic context structures needed for clipping */
146   clip_gc_values.graphics_exposures = False;
147   clip_gc_valuemask = GCGraphicsExposures;
148   copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
149                                clip_gc_valuemask, &clip_gc_values);
150
151   /* create only those clipping Pixmaps we really need */
152   for (i = 0; tile_needs_clipping[i].start >= 0; i++)
153   {
154     int j;
155
156     for (j = 0; j < tile_needs_clipping[i].count; j++)
157     {
158       int tile = tile_needs_clipping[i].start + j;
159       int graphic = tile;
160       int src_x, src_y;
161       Bitmap *src_bitmap;
162       Pixmap src_pixmap;
163
164       getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
165       src_pixmap = src_bitmap->clip_mask;
166
167       tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
168                                           TILEX, TILEY, 1);
169
170       XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
171                 src_x, src_y, TILEX, TILEY, 0, 0);
172     }
173   }
174
175   XFreeGC(display, copy_clipmask_gc);
176 #endif
177
178 #endif /* TARGET_X11_NATIVE */
179 #endif /* TARGET_X11 */
180 #endif
181 }
182
183 void FreeTileClipmasks()
184 {
185 #if 0
186 #if defined(TARGET_X11)
187   int i;
188
189   for (i = 0; i < NUM_TILES; i++)
190   {
191     if (tile_clipmask[i] != None)
192     {
193       XFreePixmap(display, tile_clipmask[i]);
194       tile_clipmask[i] = None;
195     }
196   }
197
198   if (tile_clip_gc)
199     XFreeGC(display, tile_clip_gc);
200   tile_clip_gc = None;
201
202 #if 0
203   for (i = 0; i < NUM_BITMAPS; i++)
204   {
205     if (pix[i] != NULL && pix[i]->stored_clip_gc)
206     {
207       XFreeGC(display, pix[i]->stored_clip_gc);
208       pix[i]->stored_clip_gc = None;
209     }
210   }
211 #endif
212
213 #endif /* TARGET_X11 */
214 #endif
215 }
216
217 void FreeGadgets()
218 {
219   FreeLevelEditorGadgets();
220   FreeGameButtons();
221   FreeTapeButtons();
222   FreeToolButtons();
223   FreeScreenGadgets();
224 }
225
226 void InitGadgets()
227 {
228   static boolean gadgets_initialized = FALSE;
229
230   if (gadgets_initialized)
231     FreeGadgets();
232
233   CreateLevelEditorGadgets();
234   CreateGameButtons();
235   CreateTapeButtons();
236   CreateToolButtons();
237   CreateScreenGadgets();
238
239   gadgets_initialized = TRUE;
240 }
241
242 inline void InitElementSmallImagesScaledUp(int graphic)
243 {
244   CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
245 }
246
247 void InitElementSmallImages()
248 {
249   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
250   int num_property_mappings = getImageListPropertyMappingSize();
251   int i;
252
253   /* initialize normal images from static configuration */
254   for (i = 0; element_to_graphic[i].element > -1; i++)
255     InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
256
257   /* initialize special images from static configuration */
258   for (i = 0; element_to_special_graphic[i].element > -1; i++)
259     InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
260
261   /* initialize images from dynamic configuration */
262   for (i = 0; i < num_property_mappings; i++)
263     if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
264       InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
265
266 #if 1
267   /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
268   for (i = IMG_EMC_OBJECT; i <= IMG_EMC_SPRITE; i++)
269     InitElementSmallImagesScaledUp(i);
270 #endif
271 }
272
273 #if 1
274 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
275 void SetBitmaps_EM(Bitmap **em_bitmap)
276 {
277   em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
278   em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
279 }
280 #endif
281
282 static int getFontBitmapID(int font_nr)
283 {
284   int special = -1;
285
286   if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
287     special = game_status;
288   else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
289     special = GFX_SPECIAL_ARG_MAIN;
290   else if (game_status == GAME_MODE_PLAYING)
291     special = GFX_SPECIAL_ARG_DOOR;
292
293   if (special != -1)
294     return font_info[font_nr].special_bitmap_id[special];
295   else
296     return font_nr;
297 }
298
299 void InitFontGraphicInfo()
300 {
301   static struct FontBitmapInfo *font_bitmap_info = NULL;
302   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
303   int num_property_mappings = getImageListPropertyMappingSize();
304   int num_font_bitmaps = NUM_FONTS;
305   int i, j;
306
307   if (graphic_info == NULL)             /* still at startup phase */
308   {
309     InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
310
311     return;
312   }
313
314   /* ---------- initialize font graphic definitions ---------- */
315
316   /* always start with reliable default values (normal font graphics) */
317 #if 1
318   for (i = 0; i < NUM_FONTS; i++)
319     font_info[i].graphic = IMG_FONT_INITIAL_1;
320 #else
321   for (i = 0; i < NUM_FONTS; i++)
322     font_info[i].graphic = FONT_INITIAL_1;
323 #endif
324
325   /* initialize normal font/graphic mapping from static configuration */
326   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
327   {
328     int font_nr = font_to_graphic[i].font_nr;
329     int special = font_to_graphic[i].special;
330     int graphic = font_to_graphic[i].graphic;
331
332     if (special != -1)
333       continue;
334
335     font_info[font_nr].graphic = graphic;
336   }
337
338   /* always start with reliable default values (special font graphics) */
339   for (i = 0; i < NUM_FONTS; i++)
340   {
341     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
342     {
343       font_info[i].special_graphic[j] = font_info[i].graphic;
344       font_info[i].special_bitmap_id[j] = i;
345     }
346   }
347
348   /* initialize special font/graphic mapping from static configuration */
349   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
350   {
351     int font_nr = font_to_graphic[i].font_nr;
352     int special = font_to_graphic[i].special;
353     int graphic = font_to_graphic[i].graphic;
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 special element/graphic mapping from dynamic configuration */
364   for (i = 0; i < num_property_mappings; i++)
365   {
366     int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
367     int special = property_mapping[i].ext3_index;
368     int graphic = property_mapping[i].artwork_index;
369
370     if (font_nr < 0)
371       continue;
372
373     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
374     {
375       font_info[font_nr].special_graphic[special] = graphic;
376       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
377       num_font_bitmaps++;
378     }
379   }
380
381   /* ---------- initialize font bitmap array ---------- */
382
383   if (font_bitmap_info != NULL)
384     FreeFontInfo(font_bitmap_info);
385
386   font_bitmap_info =
387     checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
388
389   /* ---------- initialize font bitmap definitions ---------- */
390
391   for (i = 0; i < NUM_FONTS; i++)
392   {
393     if (i < NUM_INITIAL_FONTS)
394     {
395       font_bitmap_info[i] = font_initial[i];
396       continue;
397     }
398
399     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
400     {
401       int font_bitmap_id = font_info[i].special_bitmap_id[j];
402       int graphic = font_info[i].special_graphic[j];
403
404       /* set 'graphic_info' for font entries, if uninitialized (guessed) */
405       if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
406       {
407         graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
408         graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
409       }
410
411       /* copy font relevant information from graphics information */
412       font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
413       font_bitmap_info[font_bitmap_id].src_x  = graphic_info[graphic].src_x;
414       font_bitmap_info[font_bitmap_id].src_y  = graphic_info[graphic].src_y;
415       font_bitmap_info[font_bitmap_id].width  = graphic_info[graphic].width;
416       font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
417       font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
418       font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
419
420       font_bitmap_info[font_bitmap_id].num_chars =
421         graphic_info[graphic].anim_frames;
422       font_bitmap_info[font_bitmap_id].num_chars_per_line =
423         graphic_info[graphic].anim_frames_per_line;
424     }
425   }
426
427   InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
428 }
429
430 void InitElementGraphicInfo()
431 {
432   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
433   int num_property_mappings = getImageListPropertyMappingSize();
434   int i, act, dir;
435
436   if (graphic_info == NULL)             /* still at startup phase */
437     return;
438
439   /* set values to -1 to identify later as "uninitialized" values */
440   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
441   {
442     for (act = 0; act < NUM_ACTIONS; act++)
443     {
444       element_info[i].graphic[act] = -1;
445       element_info[i].crumbled[act] = -1;
446
447       for (dir = 0; dir < NUM_DIRECTIONS; dir++)
448       {
449         element_info[i].direction_graphic[act][dir] = -1;
450         element_info[i].direction_crumbled[act][dir] = -1;
451       }
452     }
453   }
454
455   /* initialize normal element/graphic mapping from static configuration */
456   for (i = 0; element_to_graphic[i].element > -1; i++)
457   {
458     int element      = element_to_graphic[i].element;
459     int action       = element_to_graphic[i].action;
460     int direction    = element_to_graphic[i].direction;
461     boolean crumbled = element_to_graphic[i].crumbled;
462     int graphic      = element_to_graphic[i].graphic;
463     int base_graphic = el2baseimg(element);
464
465     if (graphic_info[graphic].bitmap == NULL)
466       continue;
467
468     if ((action > -1 || direction > -1 || crumbled == TRUE) &&
469         base_graphic != -1)
470     {
471       boolean base_redefined = getImageListEntry(base_graphic)->redefined;
472       boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
473
474       /* if the base graphic ("emerald", for example) has been redefined,
475          but not the action graphic ("emerald.falling", for example), do not
476          use an existing (in this case considered obsolete) action graphic
477          anymore, but use the automatically determined default graphic */
478       if (base_redefined && !act_dir_redefined)
479         continue;
480     }
481
482     if (action < 0)
483       action = ACTION_DEFAULT;
484
485     if (crumbled)
486     {
487       if (direction > -1)
488         element_info[element].direction_crumbled[action][direction] = graphic;
489       else
490         element_info[element].crumbled[action] = graphic;
491     }
492     else
493     {
494       if (direction > -1)
495         element_info[element].direction_graphic[action][direction] = graphic;
496       else
497         element_info[element].graphic[action] = graphic;
498     }
499   }
500
501   /* initialize normal element/graphic mapping from dynamic configuration */
502   for (i = 0; i < num_property_mappings; i++)
503   {
504     int element   = property_mapping[i].base_index;
505     int action    = property_mapping[i].ext1_index;
506     int direction = property_mapping[i].ext2_index;
507     int special   = property_mapping[i].ext3_index;
508     int graphic   = property_mapping[i].artwork_index;
509     boolean crumbled = FALSE;
510
511     if (special == GFX_SPECIAL_ARG_CRUMBLED)
512     {
513       special = -1;
514       crumbled = TRUE;
515     }
516
517     if (graphic_info[graphic].bitmap == NULL)
518       continue;
519
520     if (element >= MAX_NUM_ELEMENTS || special != -1)
521       continue;
522
523     if (action < 0)
524       action = ACTION_DEFAULT;
525
526     if (crumbled)
527     {
528       if (direction < 0)
529         for (dir = 0; dir < NUM_DIRECTIONS; dir++)
530           element_info[element].direction_crumbled[action][dir] = -1;
531
532       if (direction > -1)
533         element_info[element].direction_crumbled[action][direction] = graphic;
534       else
535         element_info[element].crumbled[action] = graphic;
536     }
537     else
538     {
539       if (direction < 0)
540         for (dir = 0; dir < NUM_DIRECTIONS; dir++)
541           element_info[element].direction_graphic[action][dir] = -1;
542
543       if (direction > -1)
544         element_info[element].direction_graphic[action][direction] = graphic;
545       else
546         element_info[element].graphic[action] = graphic;
547     }
548   }
549
550   /* now copy all graphics that are defined to be cloned from other graphics */
551   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
552   {
553     int graphic = element_info[i].graphic[ACTION_DEFAULT];
554     int crumbled_like, diggable_like;
555
556     if (graphic == -1)
557       continue;
558
559     crumbled_like = graphic_info[graphic].crumbled_like;
560     diggable_like = graphic_info[graphic].diggable_like;
561
562     if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
563     {
564       for (act = 0; act < NUM_ACTIONS; act++)
565         element_info[i].crumbled[act] =
566           element_info[crumbled_like].crumbled[act];
567       for (act = 0; act < NUM_ACTIONS; act++)
568         for (dir = 0; dir < NUM_DIRECTIONS; dir++)
569           element_info[i].direction_crumbled[act][dir] =
570             element_info[crumbled_like].direction_crumbled[act][dir];
571     }
572
573     if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
574     {
575       element_info[i].graphic[ACTION_DIGGING] =
576         element_info[diggable_like].graphic[ACTION_DIGGING];
577       for (dir = 0; dir < NUM_DIRECTIONS; dir++)
578         element_info[i].direction_graphic[ACTION_DIGGING][dir] =
579           element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
580     }
581   }
582
583 #if 1
584   /* set hardcoded definitions for some runtime elements without graphic */
585   element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
586 #endif
587
588 #if 1
589   /* now set all undefined/invalid graphics to -1 to set to default after it */
590   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
591   {
592     for (act = 0; act < NUM_ACTIONS; act++)
593     {
594       int graphic;
595
596       graphic = element_info[i].graphic[act];
597       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
598         element_info[i].graphic[act] = -1;
599
600       graphic = element_info[i].crumbled[act];
601       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
602         element_info[i].crumbled[act] = -1;
603
604       for (dir = 0; dir < NUM_DIRECTIONS; dir++)
605       {
606         graphic = element_info[i].direction_graphic[act][dir];
607         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
608           element_info[i].direction_graphic[act][dir] = -1;
609
610         graphic = element_info[i].direction_crumbled[act][dir];
611         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
612           element_info[i].direction_crumbled[act][dir] = -1;
613       }
614     }
615   }
616 #endif
617
618   /* now set all '-1' values to element specific default values */
619   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
620   {
621     int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
622     int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
623     int default_direction_graphic[NUM_DIRECTIONS];
624     int default_direction_crumbled[NUM_DIRECTIONS];
625
626     if (default_graphic == -1)
627       default_graphic = IMG_UNKNOWN;
628     if (default_crumbled == -1)
629       default_crumbled = IMG_EMPTY;
630
631     for (dir = 0; dir < NUM_DIRECTIONS; dir++)
632     {
633       default_direction_graphic[dir] =
634         element_info[i].direction_graphic[ACTION_DEFAULT][dir];
635       default_direction_crumbled[dir] =
636         element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
637
638       if (default_direction_graphic[dir] == -1)
639         default_direction_graphic[dir] = default_graphic;
640       if (default_direction_crumbled[dir] == -1)
641         default_direction_crumbled[dir] = default_crumbled;
642     }
643
644     for (act = 0; act < NUM_ACTIONS; act++)
645     {
646       boolean act_remove = ((IS_DIGGABLE(i)    && act == ACTION_DIGGING)  ||
647                             (IS_SNAPPABLE(i)   && act == ACTION_SNAPPING) ||
648                             (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
649       boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
650                              act == ACTION_TURNING_FROM_RIGHT ||
651                              act == ACTION_TURNING_FROM_UP ||
652                              act == ACTION_TURNING_FROM_DOWN);
653
654       /* generic default action graphic (defined by "[default]" directive) */
655       int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
656       int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
657
658       /* look for special default action graphic (classic game specific) */
659       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
660         default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
661       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
662         default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
663       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
664         default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
665
666       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
667         default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
668       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
669         default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
670       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
671         default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
672
673 #if 1
674       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
675       /* !!! make this better !!! */
676       if (i == EL_EMPTY_SPACE)
677       {
678         default_action_graphic = element_info[EL_DEFAULT].graphic[act];
679         default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
680       }
681 #endif
682
683       if (default_action_graphic == -1)
684         default_action_graphic = default_graphic;
685       if (default_action_crumbled == -1)
686         default_action_crumbled = default_crumbled;
687
688       for (dir = 0; dir < NUM_DIRECTIONS; dir++)
689       {
690         int default_action_direction_graphic = element_info[i].graphic[act];
691         int default_action_direction_crumbled = element_info[i].crumbled[act];
692
693         /* no graphic for current action -- use default direction graphic */
694         if (default_action_direction_graphic == -1)
695           default_action_direction_graphic =
696             (act_remove ? IMG_EMPTY :
697              act_turning ?
698              element_info[i].direction_graphic[ACTION_TURNING][dir] :
699              default_direction_graphic[dir]);
700         if (default_action_direction_crumbled == -1)
701           default_action_direction_crumbled =
702             (act_remove ? IMG_EMPTY :
703              act_turning ?
704              element_info[i].direction_crumbled[ACTION_TURNING][dir] :
705              default_direction_crumbled[dir]);
706
707         if (element_info[i].direction_graphic[act][dir] == -1)
708           element_info[i].direction_graphic[act][dir] =
709             default_action_direction_graphic;
710         if (element_info[i].direction_crumbled[act][dir] == -1)
711           element_info[i].direction_crumbled[act][dir] =
712             default_action_direction_crumbled;
713       }
714
715       /* no graphic for this specific action -- use default action graphic */
716       if (element_info[i].graphic[act] == -1)
717         element_info[i].graphic[act] =
718           (act_remove ? IMG_EMPTY :
719            act_turning ? element_info[i].graphic[ACTION_TURNING] :
720            default_action_graphic);
721       if (element_info[i].crumbled[act] == -1)
722         element_info[i].crumbled[act] =
723           (act_remove ? IMG_EMPTY :
724            act_turning ? element_info[i].crumbled[ACTION_TURNING] :
725            default_action_crumbled);
726     }
727   }
728
729 #if 1
730   /* set animation mode to "none" for each graphic with only 1 frame */
731   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
732   {
733     for (act = 0; act < NUM_ACTIONS; act++)
734     {
735       int graphic = element_info[i].graphic[act];
736       int crumbled = element_info[i].crumbled[act];
737
738       if (graphic_info[graphic].anim_frames == 1)
739         graphic_info[graphic].anim_mode = ANIM_NONE;
740       if (graphic_info[crumbled].anim_frames == 1)
741         graphic_info[crumbled].anim_mode = ANIM_NONE;
742
743       for (dir = 0; dir < NUM_DIRECTIONS; dir++)
744       {
745         graphic = element_info[i].direction_graphic[act][dir];
746         crumbled = element_info[i].direction_crumbled[act][dir];
747
748         if (graphic_info[graphic].anim_frames == 1)
749           graphic_info[graphic].anim_mode = ANIM_NONE;
750         if (graphic_info[crumbled].anim_frames == 1)
751           graphic_info[crumbled].anim_mode = ANIM_NONE;
752       }
753     }
754   }
755 #endif
756
757 #if 0
758 #if DEBUG
759   if (options.verbose)
760   {
761     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
762       if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
763           i != EL_UNKNOWN)
764         Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
765               element_info[i].token_name, i);
766   }
767 #endif
768 #endif
769 }
770
771 void InitElementSpecialGraphicInfo()
772 {
773   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
774   int num_property_mappings = getImageListPropertyMappingSize();
775   int i, j;
776
777   /* always start with reliable default values */
778   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
779     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
780       element_info[i].special_graphic[j] =
781         element_info[i].graphic[ACTION_DEFAULT];
782
783   /* initialize special element/graphic mapping from static configuration */
784   for (i = 0; element_to_special_graphic[i].element > -1; i++)
785   {
786     int element = element_to_special_graphic[i].element;
787     int special = element_to_special_graphic[i].special;
788     int graphic = element_to_special_graphic[i].graphic;
789     int base_graphic = el2baseimg(element);
790     boolean base_redefined = getImageListEntry(base_graphic)->redefined;
791     boolean special_redefined = getImageListEntry(graphic)->redefined;
792
793     /* if the base graphic ("emerald", for example) has been redefined,
794        but not the special graphic ("emerald.EDITOR", for example), do not
795        use an existing (in this case considered obsolete) special graphic
796        anymore, but use the automatically created (down-scaled) graphic */
797     if (base_redefined && !special_redefined)
798       continue;
799
800     element_info[element].special_graphic[special] = graphic;
801   }
802
803   /* initialize special element/graphic mapping from dynamic configuration */
804   for (i = 0; i < num_property_mappings; i++)
805   {
806     int element = property_mapping[i].base_index;
807     int special = property_mapping[i].ext3_index;
808     int graphic = property_mapping[i].artwork_index;
809
810     if (element >= MAX_NUM_ELEMENTS)
811       continue;
812
813     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
814       element_info[element].special_graphic[special] = graphic;
815   }
816
817 #if 1
818   /* now set all undefined/invalid graphics to default */
819   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
820     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
821       if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
822         element_info[i].special_graphic[j] =
823           element_info[i].graphic[ACTION_DEFAULT];
824 #endif
825 }
826
827 static int get_element_from_token(char *token)
828 {
829   int i;
830
831   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
832     if (strcmp(element_info[i].token_name, token) == 0)
833       return i;
834
835   return -1;
836 }
837
838 static void set_graphic_parameters(int graphic, char **parameter_raw)
839 {
840   Bitmap *src_bitmap = getBitmapFromImageID(graphic);
841   int parameter[NUM_GFX_ARGS];
842   int anim_frames_per_row = 1, anim_frames_per_col = 1;
843   int anim_frames_per_line = 1;
844   int i;
845
846   /* get integer values from string parameters */
847   for (i = 0; i < NUM_GFX_ARGS; i++)
848   {
849     parameter[i] =
850       get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
851                           image_config_suffix[i].type);
852
853     if (image_config_suffix[i].type == TYPE_TOKEN)
854       parameter[i] = get_element_from_token(parameter_raw[i]);
855   }
856
857   graphic_info[graphic].bitmap = src_bitmap;
858
859   /* start with reliable default values */
860   graphic_info[graphic].src_x = 0;
861   graphic_info[graphic].src_y = 0;
862   graphic_info[graphic].width = TILEX;
863   graphic_info[graphic].height = TILEY;
864   graphic_info[graphic].offset_x = 0;   /* one or both of these values ... */
865   graphic_info[graphic].offset_y = 0;   /* ... will be corrected later */
866   graphic_info[graphic].crumbled_like = -1;     /* do not use clone element */
867   graphic_info[graphic].diggable_like = -1;     /* do not use clone element */
868   graphic_info[graphic].border_size = TILEX / 8;  /* "CRUMBLED" border size */
869   graphic_info[graphic].scale_up_factor = 1;    /* default: no scaling up */
870   graphic_info[graphic].anim_delay_fixed = 0;
871   graphic_info[graphic].anim_delay_random = 0;
872   graphic_info[graphic].post_delay_fixed = 0;
873   graphic_info[graphic].post_delay_random = 0;
874
875   /* optional x and y tile position of animation frame sequence */
876   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
877     graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
878   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
879     graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
880
881   /* optional x and y pixel position of animation frame sequence */
882   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
883     graphic_info[graphic].src_x = parameter[GFX_ARG_X];
884   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
885     graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
886
887   /* optional width and height of each animation frame */
888   if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
889     graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
890   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
891     graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
892
893   if (src_bitmap)
894   {
895     anim_frames_per_row = src_bitmap->width  / graphic_info[graphic].width;
896     anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
897   }
898
899   /* correct x or y offset dependent of vertical or horizontal frame order */
900   if (parameter[GFX_ARG_VERTICAL])      /* frames are ordered vertically */
901   {
902     graphic_info[graphic].offset_y =
903       (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
904        parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
905     anim_frames_per_line = anim_frames_per_col;
906   }
907   else                                  /* frames are ordered horizontally */
908   {
909     graphic_info[graphic].offset_x =
910       (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
911        parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
912     anim_frames_per_line = anim_frames_per_row;
913   }
914
915   /* optionally, the x and y offset of frames can be specified directly */
916   if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
917     graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
918   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
919     graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
920
921   /* automatically determine correct number of frames, if not defined */
922   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
923     graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
924   else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
925     graphic_info[graphic].anim_frames = anim_frames_per_row;
926   else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
927     graphic_info[graphic].anim_frames = anim_frames_per_col;
928   else
929     graphic_info[graphic].anim_frames = 1;
930
931   graphic_info[graphic].anim_frames_per_line =
932     (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
933      parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
934
935   graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
936   if (graphic_info[graphic].anim_delay == 0)    /* delay must be at least 1 */
937     graphic_info[graphic].anim_delay = 1;
938
939   graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
940 #if 0
941   if (graphic_info[graphic].anim_frames == 1)
942     graphic_info[graphic].anim_mode = ANIM_NONE;
943 #endif
944
945   /* automatically determine correct start frame, if not defined */
946   if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
947     graphic_info[graphic].anim_start_frame = 0;
948   else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
949     graphic_info[graphic].anim_start_frame =
950       graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
951   else
952     graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
953
954   /* animation synchronized with global frame counter, not move position */
955   graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
956
957   /* optional element for cloning crumble graphics */
958   if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
959     graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
960
961   /* optional element for cloning digging graphics */
962   if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
963     graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
964
965   /* optional border size for "crumbling" diggable graphics */
966   if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
967     graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
968
969   /* optional zoom factor for scaling up the image to a larger size */
970   if (parameter[GFX_ARG_SCALE_UP] != ARG_UNDEFINED_VALUE)
971     graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP];
972   if (graphic_info[graphic].scale_up_factor < 1)
973     graphic_info[graphic].scale_up_factor = 1;          /* no scaling */
974
975   /* this is only used for player "boring" and "sleeping" actions */
976   if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
977     graphic_info[graphic].anim_delay_fixed =
978       parameter[GFX_ARG_ANIM_DELAY_FIXED];
979   if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
980     graphic_info[graphic].anim_delay_random =
981       parameter[GFX_ARG_ANIM_DELAY_RANDOM];
982   if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
983     graphic_info[graphic].post_delay_fixed =
984       parameter[GFX_ARG_POST_DELAY_FIXED];
985   if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
986     graphic_info[graphic].post_delay_random =
987       parameter[GFX_ARG_POST_DELAY_RANDOM];
988
989   /* this is only used for toon animations */
990   graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
991   graphic_info[graphic].step_delay  = parameter[GFX_ARG_STEP_DELAY];
992
993   /* this is only used for drawing font characters */
994   graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
995   graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
996
997   /* this is only used for drawing envelope graphics */
998   graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
999 }
1000
1001 static void InitGraphicInfo()
1002 {
1003   int fallback_graphic = IMG_CHAR_EXCLAM;
1004   struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
1005   Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
1006   int num_images = getImageListSize();
1007   int i;
1008
1009 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1010   static boolean clipmasks_initialized = FALSE;
1011   Pixmap src_pixmap;
1012   XGCValues clip_gc_values;
1013   unsigned long clip_gc_valuemask;
1014   GC copy_clipmask_gc = None;
1015 #endif
1016
1017   checked_free(graphic_info);
1018
1019   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1020
1021 #if 0
1022   printf("::: graphic_info: %d entries\n", num_images);
1023 #endif
1024
1025 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1026   if (clipmasks_initialized)
1027   {
1028     for (i = 0; i < num_images; i++)
1029     {
1030       if (graphic_info[i].clip_mask)
1031         XFreePixmap(display, graphic_info[i].clip_mask);
1032       if (graphic_info[i].clip_gc)
1033         XFreeGC(display, graphic_info[i].clip_gc);
1034
1035       graphic_info[i].clip_mask = None;
1036       graphic_info[i].clip_gc = None;
1037     }
1038   }
1039 #endif
1040
1041   for (i = 0; i < num_images; i++)
1042   {
1043     struct FileInfo *image = getImageListEntry(i);
1044     Bitmap *src_bitmap;
1045     int src_x, src_y;
1046     int first_frame, last_frame;
1047
1048 #if 0
1049     printf("::: image: '%s' [%d]\n", image->token, i);
1050 #endif
1051
1052 #if 0
1053     printf("::: image # %d: '%s' ['%s']\n",
1054            i, image->token,
1055            getTokenFromImageID(i));
1056 #endif
1057
1058     set_graphic_parameters(i, image->parameter);
1059
1060     /* now check if no animation frames are outside of the loaded image */
1061
1062     if (graphic_info[i].bitmap == NULL)
1063       continue;         /* skip check for optional images that are undefined */
1064
1065     first_frame = 0;
1066     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1067     if (src_x < 0 || src_y < 0 ||
1068         src_x + TILEX > src_bitmap->width ||
1069         src_y + TILEY > src_bitmap->height)
1070     {
1071       Error(ERR_RETURN_LINE, "-");
1072       Error(ERR_RETURN, "warning: error found in config file:");
1073       Error(ERR_RETURN, "- config file: '%s'",
1074             getImageConfigFilename());
1075       Error(ERR_RETURN, "- config token: '%s'",
1076             getTokenFromImageID(i));
1077       Error(ERR_RETURN, "- image file: '%s'",
1078             src_bitmap->source_filename);
1079       Error(ERR_RETURN,
1080             "error: first animation frame out of bounds (%d, %d)",
1081             src_x, src_y);
1082       Error(ERR_RETURN, "custom graphic rejected for this element/action");
1083
1084       if (i == fallback_graphic)
1085         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1086
1087       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1088       Error(ERR_RETURN_LINE, "-");
1089
1090       set_graphic_parameters(i, fallback_image->default_parameter);
1091       graphic_info[i].bitmap = fallback_bitmap;
1092     }
1093
1094     last_frame = graphic_info[i].anim_frames - 1;
1095     getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1096     if (src_x < 0 || src_y < 0 ||
1097         src_x + TILEX > src_bitmap->width ||
1098         src_y + TILEY > src_bitmap->height)
1099     {
1100       Error(ERR_RETURN_LINE, "-");
1101       Error(ERR_RETURN, "warning: error found in config file:");
1102       Error(ERR_RETURN, "- config file: '%s'",
1103             getImageConfigFilename());
1104       Error(ERR_RETURN, "- config token: '%s'",
1105             getTokenFromImageID(i));
1106       Error(ERR_RETURN, "- image file: '%s'",
1107             src_bitmap->source_filename);
1108       Error(ERR_RETURN,
1109             "error: last animation frame (%d) out of bounds (%d, %d)",
1110             last_frame, src_x, src_y);
1111       Error(ERR_RETURN, "custom graphic rejected for this element/action");
1112
1113       if (i == fallback_graphic)
1114         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1115
1116       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1117       Error(ERR_RETURN_LINE, "-");
1118
1119       set_graphic_parameters(i, fallback_image->default_parameter);
1120       graphic_info[i].bitmap = fallback_bitmap;
1121     }
1122
1123 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1124     /* currently we need only a tile clip mask from the first frame */
1125     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1126
1127     if (copy_clipmask_gc == None)
1128     {
1129       clip_gc_values.graphics_exposures = False;
1130       clip_gc_valuemask = GCGraphicsExposures;
1131       copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1132                                    clip_gc_valuemask, &clip_gc_values);
1133     }
1134
1135     graphic_info[i].clip_mask =
1136       XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1137
1138     src_pixmap = src_bitmap->clip_mask;
1139     XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1140               copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1141
1142     clip_gc_values.graphics_exposures = False;
1143     clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1144     clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1145
1146     graphic_info[i].clip_gc =
1147       XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1148 #endif
1149   }
1150
1151 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1152   if (copy_clipmask_gc)
1153     XFreeGC(display, copy_clipmask_gc);
1154
1155   clipmasks_initialized = TRUE;
1156 #endif
1157 }
1158
1159 static void InitElementSoundInfo()
1160 {
1161   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1162   int num_property_mappings = getSoundListPropertyMappingSize();
1163   int i, j, act;
1164
1165   /* set values to -1 to identify later as "uninitialized" values */
1166   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1167     for (act = 0; act < NUM_ACTIONS; act++)
1168       element_info[i].sound[act] = -1;
1169
1170   /* initialize element/sound mapping from static configuration */
1171   for (i = 0; element_to_sound[i].element > -1; i++)
1172   {
1173     int element      = element_to_sound[i].element;
1174     int action       = element_to_sound[i].action;
1175     int sound        = element_to_sound[i].sound;
1176     boolean is_class = element_to_sound[i].is_class;
1177
1178     if (action < 0)
1179       action = ACTION_DEFAULT;
1180
1181     if (!is_class)
1182       element_info[element].sound[action] = sound;
1183     else
1184       for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1185         if (strcmp(element_info[j].class_name,
1186                    element_info[element].class_name) == 0)
1187           element_info[j].sound[action] = sound;
1188   }
1189
1190   /* initialize element class/sound mapping from dynamic configuration */
1191   for (i = 0; i < num_property_mappings; i++)
1192   {
1193     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1194     int action        = property_mapping[i].ext1_index;
1195     int sound         = property_mapping[i].artwork_index;
1196
1197     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1198       continue;
1199
1200     if (action < 0)
1201       action = ACTION_DEFAULT;
1202
1203     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1204       if (strcmp(element_info[j].class_name,
1205                  element_info[element_class].class_name) == 0)
1206         element_info[j].sound[action] = sound;
1207   }
1208
1209   /* initialize element/sound mapping from dynamic configuration */
1210   for (i = 0; i < num_property_mappings; i++)
1211   {
1212     int element = property_mapping[i].base_index;
1213     int action  = property_mapping[i].ext1_index;
1214     int sound   = property_mapping[i].artwork_index;
1215
1216     if (element >= MAX_NUM_ELEMENTS)
1217       continue;
1218
1219     if (action < 0)
1220       action = ACTION_DEFAULT;
1221
1222     element_info[element].sound[action] = sound;
1223   }
1224
1225   /* now set all '-1' values to element specific default values */
1226   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1227   {
1228     for (act = 0; act < NUM_ACTIONS; act++)
1229     {
1230       /* generic default action sound (defined by "[default]" directive) */
1231       int default_action_sound = element_info[EL_DEFAULT].sound[act];
1232
1233       /* look for special default action sound (classic game specific) */
1234       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1235         default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1236       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1237         default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1238       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1239         default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1240
1241       /* !!! there's no such thing as a "default action sound" !!! */
1242 #if 0
1243       /* look for element specific default sound (independent from action) */
1244       if (element_info[i].sound[ACTION_DEFAULT] != -1)
1245         default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1246 #endif
1247
1248       /* no sound for this specific action -- use default action sound */
1249       if (element_info[i].sound[act] == -1)
1250         element_info[i].sound[act] = default_action_sound;
1251     }
1252   }
1253 }
1254
1255 static void InitGameModeSoundInfo()
1256 {
1257   int i;
1258
1259   /* set values to -1 to identify later as "uninitialized" values */
1260   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1261     menu.sound[i] = -1;
1262
1263   /* initialize gamemode/sound mapping from static configuration */
1264   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1265   {
1266     int gamemode = gamemode_to_sound[i].gamemode;
1267     int sound    = gamemode_to_sound[i].sound;
1268
1269     if (gamemode < 0)
1270       gamemode = GAME_MODE_DEFAULT;
1271
1272     menu.sound[gamemode] = sound;
1273   }
1274
1275   /* now set all '-1' values to levelset specific default values */
1276   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1277     if (menu.sound[i] == -1)
1278       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1279
1280 #if 0
1281   /* TEST ONLY */
1282   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1283     if (menu.sound[i] != -1)
1284       printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1285 #endif
1286 }
1287
1288 static void set_sound_parameters(int sound, char **parameter_raw)
1289 {
1290   int parameter[NUM_SND_ARGS];
1291   int i;
1292
1293   /* get integer values from string parameters */
1294   for (i = 0; i < NUM_SND_ARGS; i++)
1295     parameter[i] =
1296       get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1297                           sound_config_suffix[i].type);
1298
1299   /* explicit loop mode setting in configuration overrides default value */
1300   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1301     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1302 }
1303
1304 static void InitSoundInfo()
1305 {
1306 #if 0
1307   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1308   int num_property_mappings = getSoundListPropertyMappingSize();
1309 #endif
1310   int *sound_effect_properties;
1311   int num_sounds = getSoundListSize();
1312   int i, j;
1313
1314   checked_free(sound_info);
1315
1316   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1317   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1318
1319   /* initialize sound effect for all elements to "no sound" */
1320   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1321     for (j = 0; j < NUM_ACTIONS; j++)
1322       element_info[i].sound[j] = SND_UNDEFINED;
1323
1324   for (i = 0; i < num_sounds; i++)
1325   {
1326     struct FileInfo *sound = getSoundListEntry(i);
1327     int len_effect_text = strlen(sound->token);
1328
1329     sound_effect_properties[i] = ACTION_OTHER;
1330     sound_info[i].loop = FALSE;         /* default: play sound only once */
1331
1332 #if 0
1333     printf("::: sound %d: '%s'\n", i, sound->token);
1334 #endif
1335
1336     /* determine all loop sounds and identify certain sound classes */
1337
1338     for (j = 0; element_action_info[j].suffix; j++)
1339     {
1340       int len_action_text = strlen(element_action_info[j].suffix);
1341
1342       if (len_action_text < len_effect_text &&
1343           strcmp(&sound->token[len_effect_text - len_action_text],
1344                  element_action_info[j].suffix) == 0)
1345       {
1346         sound_effect_properties[i] = element_action_info[j].value;
1347         sound_info[i].loop = element_action_info[j].is_loop_sound;
1348
1349         break;
1350       }
1351     }
1352
1353 #if 0
1354     if (strcmp(sound->token, "custom_42") == 0)
1355       printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
1356 #endif
1357
1358     /* associate elements and some selected sound actions */
1359
1360     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1361     {
1362       if (element_info[j].class_name)
1363       {
1364         int len_class_text = strlen(element_info[j].class_name);
1365
1366         if (len_class_text + 1 < len_effect_text &&
1367             strncmp(sound->token,
1368                     element_info[j].class_name, len_class_text) == 0 &&
1369             sound->token[len_class_text] == '.')
1370         {
1371           int sound_action_value = sound_effect_properties[i];
1372
1373           element_info[j].sound[sound_action_value] = i;
1374         }
1375       }
1376     }
1377
1378     set_sound_parameters(i, sound->parameter);
1379   }
1380
1381   free(sound_effect_properties);
1382
1383 #if 0
1384   /* !!! now handled in InitElementSoundInfo() !!! */
1385   /* initialize element/sound mapping from dynamic configuration */
1386   for (i = 0; i < num_property_mappings; i++)
1387   {
1388     int element   = property_mapping[i].base_index;
1389     int action    = property_mapping[i].ext1_index;
1390     int sound     = property_mapping[i].artwork_index;
1391
1392     if (action < 0)
1393       action = ACTION_DEFAULT;
1394
1395     printf("::: %d: %d, %d, %d ['%s']\n",
1396            i, element, action, sound, element_info[element].token_name);
1397
1398     element_info[element].sound[action] = sound;
1399   }
1400 #endif
1401
1402 #if 0
1403   /* TEST ONLY */
1404   {
1405     int element = EL_CUSTOM_11;
1406     int j = 0;
1407
1408     while (element_action_info[j].suffix)
1409     {
1410       printf("element %d, sound action '%s'  == %d\n",
1411              element, element_action_info[j].suffix,
1412              element_info[element].sound[j]);
1413       j++;
1414     }
1415   }
1416
1417   PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1418 #endif
1419
1420 #if 0
1421   /* TEST ONLY */
1422   {
1423     int element = EL_SAND;
1424     int sound_action = ACTION_DIGGING;
1425     int j = 0;
1426
1427     while (element_action_info[j].suffix)
1428     {
1429       if (element_action_info[j].value == sound_action)
1430         printf("element %d, sound action '%s'  == %d\n",
1431                element, element_action_info[j].suffix,
1432                element_info[element].sound[sound_action]);
1433       j++;
1434     }
1435   }
1436 #endif
1437 }
1438
1439 static void InitGameModeMusicInfo()
1440 {
1441   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1442   int num_property_mappings = getMusicListPropertyMappingSize();
1443   int default_levelset_music = -1;
1444   int i;
1445
1446   /* set values to -1 to identify later as "uninitialized" values */
1447   for (i = 0; i < MAX_LEVELS; i++)
1448     levelset.music[i] = -1;
1449   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1450     menu.music[i] = -1;
1451
1452   /* initialize gamemode/music mapping from static configuration */
1453   for (i = 0; gamemode_to_music[i].music > -1; i++)
1454   {
1455     int gamemode = gamemode_to_music[i].gamemode;
1456     int music    = gamemode_to_music[i].music;
1457
1458 #if 0
1459     printf("::: gamemode == %d, music == %d\n", gamemode, music);
1460 #endif
1461
1462     if (gamemode < 0)
1463       gamemode = GAME_MODE_DEFAULT;
1464
1465     menu.music[gamemode] = music;
1466   }
1467
1468   /* initialize gamemode/music mapping from dynamic configuration */
1469   for (i = 0; i < num_property_mappings; i++)
1470   {
1471     int prefix   = property_mapping[i].base_index;
1472     int gamemode = property_mapping[i].ext1_index;
1473     int level    = property_mapping[i].ext2_index;
1474     int music    = property_mapping[i].artwork_index;
1475
1476 #if 0
1477     printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1478            prefix, gamemode, level, music);
1479 #endif
1480
1481     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1482       continue;
1483
1484     if (gamemode < 0)
1485       gamemode = GAME_MODE_DEFAULT;
1486
1487     /* level specific music only allowed for in-game music */
1488     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1489       gamemode = GAME_MODE_PLAYING;
1490
1491     if (level == -1)
1492     {
1493       level = 0;
1494       default_levelset_music = music;
1495     }
1496
1497     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1498       levelset.music[level] = music;
1499     if (gamemode != GAME_MODE_PLAYING)
1500       menu.music[gamemode] = music;
1501   }
1502
1503   /* now set all '-1' values to menu specific default values */
1504   /* (undefined values of "levelset.music[]" might stay at "-1" to
1505      allow dynamic selection of music files from music directory!) */
1506   for (i = 0; i < MAX_LEVELS; i++)
1507     if (levelset.music[i] == -1)
1508       levelset.music[i] = default_levelset_music;
1509   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1510     if (menu.music[i] == -1)
1511       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1512
1513 #if 0
1514   /* TEST ONLY */
1515   for (i = 0; i < MAX_LEVELS; i++)
1516     if (levelset.music[i] != -1)
1517       printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1518   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1519     if (menu.music[i] != -1)
1520       printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1521 #endif
1522 }
1523
1524 static void set_music_parameters(int music, char **parameter_raw)
1525 {
1526   int parameter[NUM_MUS_ARGS];
1527   int i;
1528
1529   /* get integer values from string parameters */
1530   for (i = 0; i < NUM_MUS_ARGS; i++)
1531     parameter[i] =
1532       get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1533                           music_config_suffix[i].type);
1534
1535   /* explicit loop mode setting in configuration overrides default value */
1536   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1537     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1538 }
1539
1540 static void InitMusicInfo()
1541 {
1542   int num_music = getMusicListSize();
1543   int i, j;
1544
1545   checked_free(music_info);
1546
1547   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1548
1549   for (i = 0; i < num_music; i++)
1550   {
1551     struct FileInfo *music = getMusicListEntry(i);
1552     int len_music_text = strlen(music->token);
1553
1554     music_info[i].loop = TRUE;          /* default: play music in loop mode */
1555
1556     /* determine all loop music */
1557
1558     for (j = 0; music_prefix_info[j].prefix; j++)
1559     {
1560       int len_prefix_text = strlen(music_prefix_info[j].prefix);
1561
1562       if (len_prefix_text < len_music_text &&
1563           strncmp(music->token,
1564                   music_prefix_info[j].prefix, len_prefix_text) == 0)
1565       {
1566         music_info[i].loop = music_prefix_info[j].is_loop_music;
1567
1568         break;
1569       }
1570     }
1571
1572     set_music_parameters(i, music->parameter);
1573   }
1574 }
1575
1576 static void ReinitializeGraphics()
1577 {
1578   InitGraphicInfo();                    /* graphic properties mapping */
1579   InitElementGraphicInfo();             /* element game graphic mapping */
1580   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
1581
1582   InitElementSmallImages();             /* create editor and preview images */
1583   InitFontGraphicInfo();                /* initialize text drawing functions */
1584
1585   SetMainBackgroundImage(IMG_BACKGROUND);
1586   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1587
1588   InitGadgets();
1589   InitToons();
1590 }
1591
1592 static void ReinitializeSounds()
1593 {
1594   InitSoundInfo();              /* sound properties mapping */
1595   InitElementSoundInfo();       /* element game sound mapping */
1596   InitGameModeSoundInfo();      /* game mode sound mapping */
1597
1598   InitPlayLevelSound();         /* internal game sound settings */
1599 }
1600
1601 static void ReinitializeMusic()
1602 {
1603   InitMusicInfo();              /* music properties mapping */
1604   InitGameModeMusicInfo();      /* game mode music mapping */
1605 }
1606
1607 static int get_special_property_bit(int element, int property_bit_nr)
1608 {
1609   struct PropertyBitInfo
1610   {
1611     int element;
1612     int bit_nr;
1613   };
1614
1615   static struct PropertyBitInfo pb_can_move_into_acid[] =
1616   {
1617     /* the player may be able fall into acid when gravity is activated */
1618     { EL_PLAYER_1,              0       },
1619     { EL_PLAYER_2,              0       },
1620     { EL_PLAYER_3,              0       },
1621     { EL_PLAYER_4,              0       },
1622     { EL_SP_MURPHY,             0       },
1623     { EL_SOKOBAN_FIELD_PLAYER,  0       },
1624
1625     /* all element that can move may be able to also move into acid */
1626     { EL_BUG,                   1       },
1627     { EL_BUG_LEFT,              1       },
1628     { EL_BUG_RIGHT,             1       },
1629     { EL_BUG_UP,                1       },
1630     { EL_BUG_DOWN,              1       },
1631     { EL_SPACESHIP,             2       },
1632     { EL_SPACESHIP_LEFT,        2       },
1633     { EL_SPACESHIP_RIGHT,       2       },
1634     { EL_SPACESHIP_UP,          2       },
1635     { EL_SPACESHIP_DOWN,        2       },
1636     { EL_BD_BUTTERFLY,          3       },
1637     { EL_BD_BUTTERFLY_LEFT,     3       },
1638     { EL_BD_BUTTERFLY_RIGHT,    3       },
1639     { EL_BD_BUTTERFLY_UP,       3       },
1640     { EL_BD_BUTTERFLY_DOWN,     3       },
1641     { EL_BD_FIREFLY,            4       },
1642     { EL_BD_FIREFLY_LEFT,       4       },
1643     { EL_BD_FIREFLY_RIGHT,      4       },
1644     { EL_BD_FIREFLY_UP,         4       },
1645     { EL_BD_FIREFLY_DOWN,       4       },
1646     { EL_YAMYAM,                5       },
1647     { EL_DARK_YAMYAM,           6       },
1648     { EL_ROBOT,                 7       },
1649     { EL_PACMAN,                8       },
1650     { EL_PACMAN_LEFT,           8       },
1651     { EL_PACMAN_RIGHT,          8       },
1652     { EL_PACMAN_UP,             8       },
1653     { EL_PACMAN_DOWN,           8       },
1654     { EL_MOLE,                  9       },
1655     { EL_MOLE_LEFT,             9       },
1656     { EL_MOLE_RIGHT,            9       },
1657     { EL_MOLE_UP,               9       },
1658     { EL_MOLE_DOWN,             9       },
1659     { EL_PENGUIN,               10      },
1660     { EL_PIG,                   11      },
1661     { EL_DRAGON,                12      },
1662     { EL_SATELLITE,             13      },
1663     { EL_SP_SNIKSNAK,           14      },
1664     { EL_SP_ELECTRON,           15      },
1665     { EL_BALLOON,               16      },
1666     { EL_SPRING,                17      },
1667
1668     { -1,                       -1      },
1669   };
1670
1671   static struct PropertyBitInfo pb_dont_collide_with[] =
1672   {
1673     { EL_SP_SNIKSNAK,           0       },
1674     { EL_SP_ELECTRON,           1       },
1675
1676     { -1,                       -1      },
1677   };
1678
1679   static struct
1680   {
1681     int bit_nr;
1682     struct PropertyBitInfo *pb_info;
1683   } pb_definition[] =
1684   {
1685     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
1686     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
1687
1688     { -1,                       NULL                    },
1689   };
1690
1691   struct PropertyBitInfo *pb_info = NULL;
1692   int i;
1693
1694   for (i = 0; pb_definition[i].bit_nr != -1; i++)
1695     if (pb_definition[i].bit_nr == property_bit_nr)
1696       pb_info = pb_definition[i].pb_info;
1697
1698   if (pb_info == NULL)
1699     return -1;
1700
1701   for (i = 0; pb_info[i].element != -1; i++)
1702     if (pb_info[i].element == element)
1703       return pb_info[i].bit_nr;
1704
1705   return -1;
1706 }
1707
1708 #if 1
1709 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1710                          boolean property_value)
1711 {
1712   int bit_nr = get_special_property_bit(element, property_bit_nr);
1713
1714   if (bit_nr > -1)
1715   {
1716     if (property_value)
1717       *bitfield |=  (1 << bit_nr);
1718     else
1719       *bitfield &= ~(1 << bit_nr);
1720   }
1721 }
1722
1723 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1724 {
1725   int bit_nr = get_special_property_bit(element, property_bit_nr);
1726
1727   if (bit_nr > -1)
1728     return ((*bitfield & (1 << bit_nr)) != 0);
1729
1730   return FALSE;
1731 }
1732
1733 #else
1734
1735 void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
1736 {
1737   int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1738
1739   if (bit_nr > -1)
1740   {
1741     level->can_move_into_acid_bits &= ~(1 << bit_nr);
1742
1743     if (set)
1744       level->can_move_into_acid_bits |= (1 << bit_nr);
1745   }
1746 }
1747
1748 boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
1749 {
1750   int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
1751
1752   if (bit_nr > -1)
1753     return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
1754
1755   return FALSE;
1756 }
1757 #endif
1758
1759 void InitElementPropertiesStatic()
1760 {
1761   static int ep_diggable[] =
1762   {
1763     EL_SAND,
1764     EL_SP_BASE,
1765     EL_SP_BUGGY_BASE,
1766     EL_SP_BUGGY_BASE_ACTIVATING,
1767     EL_TRAP,
1768     EL_INVISIBLE_SAND,
1769     EL_INVISIBLE_SAND_ACTIVE,
1770
1771     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1772     /* (if amoeba can grow into anything diggable, maybe keep these out) */
1773 #if 0
1774     EL_LANDMINE,
1775     EL_TRAP_ACTIVE,
1776     EL_SP_BUGGY_BASE_ACTIVE,
1777 #endif
1778     -1
1779   };
1780
1781   static int ep_collectible_only[] =
1782   {
1783     EL_BD_DIAMOND,
1784     EL_EMERALD,
1785     EL_DIAMOND,
1786     EL_EMERALD_YELLOW,
1787     EL_EMERALD_RED,
1788     EL_EMERALD_PURPLE,
1789     EL_KEY_1,
1790     EL_KEY_2,
1791     EL_KEY_3,
1792     EL_KEY_4,
1793     EL_EM_KEY_1,
1794     EL_EM_KEY_2,
1795     EL_EM_KEY_3,
1796     EL_EM_KEY_4,
1797     EL_DYNAMITE,
1798     EL_DYNABOMB_INCREASE_NUMBER,
1799     EL_DYNABOMB_INCREASE_SIZE,
1800     EL_DYNABOMB_INCREASE_POWER,
1801     EL_SP_INFOTRON,
1802     EL_SP_DISK_RED,
1803     EL_PEARL,
1804     EL_CRYSTAL,
1805     EL_KEY_WHITE,
1806     EL_SHIELD_NORMAL,
1807     EL_SHIELD_DEADLY,
1808     EL_EXTRA_TIME,
1809     EL_ENVELOPE_1,
1810     EL_ENVELOPE_2,
1811     EL_ENVELOPE_3,
1812     EL_ENVELOPE_4,
1813     EL_SPEED_PILL,
1814     -1
1815   };
1816
1817   static int ep_dont_run_into[] =
1818   {
1819     /* same elements as in 'ep_dont_touch' */
1820     EL_BUG,
1821     EL_SPACESHIP,
1822     EL_BD_BUTTERFLY,
1823     EL_BD_FIREFLY,
1824
1825     /* same elements as in 'ep_dont_collide_with' */
1826     EL_YAMYAM,
1827     EL_DARK_YAMYAM,
1828     EL_ROBOT,
1829     EL_PACMAN,
1830     EL_SP_SNIKSNAK,
1831     EL_SP_ELECTRON,
1832
1833     /* new elements */
1834     EL_AMOEBA_DROP,
1835     EL_ACID,
1836
1837     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1838 #if 1
1839     EL_LANDMINE,
1840     EL_TRAP_ACTIVE,
1841     EL_SP_BUGGY_BASE_ACTIVE,
1842 #endif
1843     -1
1844   };
1845
1846   static int ep_dont_collide_with[] =
1847   {
1848     /* same elements as in 'ep_dont_touch' */
1849     EL_BUG,
1850     EL_SPACESHIP,
1851     EL_BD_BUTTERFLY,
1852     EL_BD_FIREFLY,
1853
1854     /* new elements */
1855     EL_YAMYAM,
1856     EL_DARK_YAMYAM,
1857     EL_ROBOT,
1858     EL_PACMAN,
1859     EL_SP_SNIKSNAK,
1860     EL_SP_ELECTRON,
1861     -1
1862   };
1863
1864   static int ep_dont_touch[] =
1865   {
1866     EL_BUG,
1867     EL_SPACESHIP,
1868     EL_BD_BUTTERFLY,
1869     EL_BD_FIREFLY,
1870     -1
1871   };
1872
1873   static int ep_indestructible[] =
1874   {
1875     EL_STEELWALL,
1876     EL_ACID,
1877     EL_ACID_POOL_TOPLEFT,
1878     EL_ACID_POOL_TOPRIGHT,
1879     EL_ACID_POOL_BOTTOMLEFT,
1880     EL_ACID_POOL_BOTTOM,
1881     EL_ACID_POOL_BOTTOMRIGHT,
1882     EL_SP_HARDWARE_GRAY,
1883     EL_SP_HARDWARE_GREEN,
1884     EL_SP_HARDWARE_BLUE,
1885     EL_SP_HARDWARE_RED,
1886     EL_SP_HARDWARE_YELLOW,
1887     EL_SP_HARDWARE_BASE_1,
1888     EL_SP_HARDWARE_BASE_2,
1889     EL_SP_HARDWARE_BASE_3,
1890     EL_SP_HARDWARE_BASE_4,
1891     EL_SP_HARDWARE_BASE_5,
1892     EL_SP_HARDWARE_BASE_6,
1893     EL_INVISIBLE_STEELWALL,
1894     EL_INVISIBLE_STEELWALL_ACTIVE,
1895     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1896     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1897     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1898     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1899     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1900     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1901     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1902     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1903     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1904     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1905     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1906     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1907     EL_LIGHT_SWITCH,
1908     EL_LIGHT_SWITCH_ACTIVE,
1909     EL_SIGN_EXCLAMATION,
1910     EL_SIGN_RADIOACTIVITY,
1911     EL_SIGN_STOP,
1912     EL_SIGN_WHEELCHAIR,
1913     EL_SIGN_PARKING,
1914     EL_SIGN_ONEWAY,
1915     EL_SIGN_HEART,
1916     EL_SIGN_TRIANGLE,
1917     EL_SIGN_ROUND,
1918     EL_SIGN_EXIT,
1919     EL_SIGN_YINYANG,
1920     EL_SIGN_OTHER,
1921     EL_STEELWALL_SLIPPERY,
1922     EL_EMC_STEELWALL_1,
1923     EL_EMC_STEELWALL_2,
1924     EL_EMC_STEELWALL_3,
1925     EL_EMC_STEELWALL_4,
1926     EL_CRYSTAL,
1927     EL_GATE_1,
1928     EL_GATE_2,
1929     EL_GATE_3,
1930     EL_GATE_4,
1931     EL_GATE_1_GRAY,
1932     EL_GATE_2_GRAY,
1933     EL_GATE_3_GRAY,
1934     EL_GATE_4_GRAY,
1935     EL_EM_GATE_1,
1936     EL_EM_GATE_2,
1937     EL_EM_GATE_3,
1938     EL_EM_GATE_4,
1939     EL_EM_GATE_1_GRAY,
1940     EL_EM_GATE_2_GRAY,
1941     EL_EM_GATE_3_GRAY,
1942     EL_EM_GATE_4_GRAY,
1943     EL_SWITCHGATE_OPEN,
1944     EL_SWITCHGATE_OPENING,
1945     EL_SWITCHGATE_CLOSED,
1946     EL_SWITCHGATE_CLOSING,
1947 #if 0
1948     EL_SWITCHGATE_SWITCH_UP,
1949     EL_SWITCHGATE_SWITCH_DOWN,
1950 #endif
1951     EL_TIMEGATE_OPEN,
1952     EL_TIMEGATE_OPENING,
1953     EL_TIMEGATE_CLOSED,
1954     EL_TIMEGATE_CLOSING,
1955 #if 0
1956     EL_TIMEGATE_SWITCH,
1957     EL_TIMEGATE_SWITCH_ACTIVE,
1958 #endif
1959     EL_TUBE_ANY,
1960     EL_TUBE_VERTICAL,
1961     EL_TUBE_HORIZONTAL,
1962     EL_TUBE_VERTICAL_LEFT,
1963     EL_TUBE_VERTICAL_RIGHT,
1964     EL_TUBE_HORIZONTAL_UP,
1965     EL_TUBE_HORIZONTAL_DOWN,
1966     EL_TUBE_LEFT_UP,
1967     EL_TUBE_LEFT_DOWN,
1968     EL_TUBE_RIGHT_UP,
1969     EL_TUBE_RIGHT_DOWN,
1970     -1
1971   };
1972
1973   static int ep_slippery[] =
1974   {
1975     EL_WALL_SLIPPERY,
1976     EL_BD_WALL,
1977     EL_ROCK,
1978     EL_BD_ROCK,
1979     EL_EMERALD,
1980     EL_BD_DIAMOND,
1981     EL_EMERALD_YELLOW,
1982     EL_EMERALD_RED,
1983     EL_EMERALD_PURPLE,
1984     EL_DIAMOND,
1985     EL_BOMB,
1986     EL_NUT,
1987     EL_ROBOT_WHEEL_ACTIVE,
1988     EL_ROBOT_WHEEL,
1989     EL_TIME_ORB_FULL,
1990     EL_TIME_ORB_EMPTY,
1991     EL_LAMP_ACTIVE,
1992     EL_LAMP,
1993     EL_ACID_POOL_TOPLEFT,
1994     EL_ACID_POOL_TOPRIGHT,
1995     EL_SATELLITE,
1996     EL_SP_ZONK,
1997     EL_SP_INFOTRON,
1998     EL_SP_CHIP_SINGLE,
1999     EL_SP_CHIP_LEFT,
2000     EL_SP_CHIP_RIGHT,
2001     EL_SP_CHIP_TOP,
2002     EL_SP_CHIP_BOTTOM,
2003     EL_SPEED_PILL,
2004     EL_STEELWALL_SLIPPERY,
2005     EL_PEARL,
2006     EL_CRYSTAL,
2007     -1
2008   };
2009
2010   static int ep_can_change[] =
2011   {
2012     -1
2013   };
2014
2015   static int ep_can_move[] =
2016   {
2017     /* same elements as in 'pb_can_move_into_acid' */
2018     EL_BUG,
2019     EL_SPACESHIP,
2020     EL_BD_BUTTERFLY,
2021     EL_BD_FIREFLY,
2022     EL_YAMYAM,
2023     EL_DARK_YAMYAM,
2024     EL_ROBOT,
2025     EL_PACMAN,
2026     EL_MOLE,
2027     EL_PENGUIN,
2028     EL_PIG,
2029     EL_DRAGON,
2030     EL_SATELLITE,
2031     EL_SP_SNIKSNAK,
2032     EL_SP_ELECTRON,
2033     EL_BALLOON,
2034     EL_SPRING,
2035     -1
2036   };
2037
2038   static int ep_can_fall[] =
2039   {
2040     EL_ROCK,
2041     EL_BD_ROCK,
2042     EL_EMERALD,
2043     EL_BD_DIAMOND,
2044     EL_EMERALD_YELLOW,
2045     EL_EMERALD_RED,
2046     EL_EMERALD_PURPLE,
2047     EL_DIAMOND,
2048     EL_BOMB,
2049     EL_NUT,
2050     EL_AMOEBA_DROP,
2051     EL_QUICKSAND_FULL,
2052     EL_MAGIC_WALL_FULL,
2053     EL_BD_MAGIC_WALL_FULL,
2054     EL_TIME_ORB_FULL,
2055     EL_TIME_ORB_EMPTY,
2056     EL_SP_ZONK,
2057     EL_SP_INFOTRON,
2058     EL_SP_DISK_ORANGE,
2059     EL_PEARL,
2060     EL_CRYSTAL,
2061     EL_SPRING,
2062     EL_DX_SUPABOMB,
2063     -1
2064   };
2065
2066   static int ep_can_smash_player[] =
2067   {
2068     EL_ROCK,
2069     EL_BD_ROCK,
2070     EL_EMERALD,
2071     EL_BD_DIAMOND,
2072     EL_EMERALD_YELLOW,
2073     EL_EMERALD_RED,
2074     EL_EMERALD_PURPLE,
2075     EL_DIAMOND,
2076     EL_BOMB,
2077     EL_NUT,
2078     EL_AMOEBA_DROP,
2079     EL_TIME_ORB_FULL,
2080     EL_TIME_ORB_EMPTY,
2081     EL_SP_ZONK,
2082     EL_SP_INFOTRON,
2083     EL_SP_DISK_ORANGE,
2084     EL_PEARL,
2085     EL_CRYSTAL,
2086     EL_SPRING,
2087     EL_DX_SUPABOMB,
2088     -1
2089   };
2090
2091   static int ep_can_smash_enemies[] =
2092   {
2093     EL_ROCK,
2094     EL_BD_ROCK,
2095     EL_SP_ZONK,
2096     -1
2097   };
2098
2099   static int ep_can_smash_everything[] =
2100   {
2101     EL_ROCK,
2102     EL_BD_ROCK,
2103     EL_SP_ZONK,
2104     -1
2105   };
2106
2107   static int ep_explodes_by_fire[] =
2108   {
2109     /* same elements as in 'ep_explodes_impact' */
2110     EL_BOMB,
2111     EL_SP_DISK_ORANGE,
2112     EL_DX_SUPABOMB,
2113
2114     /* same elements as in 'ep_explodes_smashed' */
2115     EL_SATELLITE,
2116     EL_PIG,
2117     EL_DRAGON,
2118     EL_MOLE,
2119
2120     /* new elements */
2121     EL_DYNAMITE_ACTIVE,
2122     EL_DYNAMITE,
2123     EL_DYNABOMB_PLAYER_1_ACTIVE,
2124     EL_DYNABOMB_PLAYER_2_ACTIVE,
2125     EL_DYNABOMB_PLAYER_3_ACTIVE,
2126     EL_DYNABOMB_PLAYER_4_ACTIVE,
2127     EL_DYNABOMB_INCREASE_NUMBER,
2128     EL_DYNABOMB_INCREASE_SIZE,
2129     EL_DYNABOMB_INCREASE_POWER,
2130     EL_SP_DISK_RED_ACTIVE,
2131     EL_BUG,
2132     EL_PENGUIN,
2133     EL_SP_DISK_RED,
2134     EL_SP_DISK_YELLOW,
2135     EL_SP_SNIKSNAK,
2136     EL_SP_ELECTRON,
2137 #if 0
2138     EL_BLACK_ORB,
2139 #endif
2140     -1
2141   };
2142
2143   static int ep_explodes_smashed[] =
2144   {
2145     /* same elements as in 'ep_explodes_impact' */
2146     EL_BOMB,
2147     EL_SP_DISK_ORANGE,
2148     EL_DX_SUPABOMB,
2149
2150     /* new elements */
2151     EL_SATELLITE,
2152     EL_PIG,
2153     EL_DRAGON,
2154     EL_MOLE,
2155     -1
2156   };
2157
2158   static int ep_explodes_impact[] =
2159   {
2160     EL_BOMB,
2161     EL_SP_DISK_ORANGE,
2162     EL_DX_SUPABOMB,
2163     -1
2164   };
2165
2166   static int ep_walkable_over[] =
2167   {
2168     EL_EMPTY_SPACE,
2169     EL_SP_EMPTY_SPACE,
2170     EL_SOKOBAN_FIELD_EMPTY,
2171     EL_EXIT_OPEN,
2172     EL_SP_EXIT_OPEN,
2173     EL_SP_EXIT_OPENING,
2174     EL_GATE_1,
2175     EL_GATE_2,
2176     EL_GATE_3,
2177     EL_GATE_4,
2178     EL_GATE_1_GRAY,
2179     EL_GATE_2_GRAY,
2180     EL_GATE_3_GRAY,
2181     EL_GATE_4_GRAY,
2182     EL_PENGUIN,
2183     EL_PIG,
2184     EL_DRAGON,
2185     -1
2186   };
2187
2188   static int ep_walkable_inside[] =
2189   {
2190     EL_TUBE_ANY,
2191     EL_TUBE_VERTICAL,
2192     EL_TUBE_HORIZONTAL,
2193     EL_TUBE_VERTICAL_LEFT,
2194     EL_TUBE_VERTICAL_RIGHT,
2195     EL_TUBE_HORIZONTAL_UP,
2196     EL_TUBE_HORIZONTAL_DOWN,
2197     EL_TUBE_LEFT_UP,
2198     EL_TUBE_LEFT_DOWN,
2199     EL_TUBE_RIGHT_UP,
2200     EL_TUBE_RIGHT_DOWN,
2201     -1
2202   };
2203
2204   static int ep_walkable_under[] =
2205   {
2206     -1
2207   };
2208
2209   static int ep_passable_over[] =
2210   {
2211     EL_EM_GATE_1,
2212     EL_EM_GATE_2,
2213     EL_EM_GATE_3,
2214     EL_EM_GATE_4,
2215     EL_EM_GATE_1_GRAY,
2216     EL_EM_GATE_2_GRAY,
2217     EL_EM_GATE_3_GRAY,
2218     EL_EM_GATE_4_GRAY,
2219     EL_SWITCHGATE_OPEN,
2220     EL_TIMEGATE_OPEN,
2221     -1
2222   };
2223
2224   static int ep_passable_inside[] =
2225   {
2226     EL_SP_PORT_LEFT,
2227     EL_SP_PORT_RIGHT,
2228     EL_SP_PORT_UP,
2229     EL_SP_PORT_DOWN,
2230     EL_SP_PORT_HORIZONTAL,
2231     EL_SP_PORT_VERTICAL,
2232     EL_SP_PORT_ANY,
2233     EL_SP_GRAVITY_PORT_LEFT,
2234     EL_SP_GRAVITY_PORT_RIGHT,
2235     EL_SP_GRAVITY_PORT_UP,
2236     EL_SP_GRAVITY_PORT_DOWN,
2237     EL_SP_GRAVITY_ON_PORT_LEFT,
2238     EL_SP_GRAVITY_ON_PORT_RIGHT,
2239     EL_SP_GRAVITY_ON_PORT_UP,
2240     EL_SP_GRAVITY_ON_PORT_DOWN,
2241     EL_SP_GRAVITY_OFF_PORT_LEFT,
2242     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2243     EL_SP_GRAVITY_OFF_PORT_UP,
2244     EL_SP_GRAVITY_OFF_PORT_DOWN,
2245     -1
2246   };
2247
2248   static int ep_passable_under[] =
2249   {
2250     -1
2251   };
2252
2253   static int ep_droppable[] =
2254   {
2255     -1
2256   };
2257
2258   static int ep_explodes_1x1_old[] =
2259   {
2260     -1
2261   };
2262
2263   static int ep_pushable[] =
2264   {
2265     EL_ROCK,
2266     EL_BOMB,
2267     EL_DX_SUPABOMB,
2268     EL_NUT,
2269     EL_TIME_ORB_EMPTY,
2270     EL_SP_ZONK,
2271     EL_SP_DISK_ORANGE,
2272     EL_SPRING,
2273     EL_BD_ROCK,
2274     EL_SOKOBAN_OBJECT,
2275     EL_SOKOBAN_FIELD_FULL,
2276     EL_SATELLITE,
2277     EL_SP_DISK_YELLOW,
2278     EL_BALLOON,
2279     -1
2280   };
2281
2282   static int ep_explodes_cross_old[] =
2283   {
2284     -1
2285   };
2286
2287   static int ep_protected[] =
2288   {
2289     /* same elements as in 'ep_walkable_inside' */
2290     EL_TUBE_ANY,
2291     EL_TUBE_VERTICAL,
2292     EL_TUBE_HORIZONTAL,
2293     EL_TUBE_VERTICAL_LEFT,
2294     EL_TUBE_VERTICAL_RIGHT,
2295     EL_TUBE_HORIZONTAL_UP,
2296     EL_TUBE_HORIZONTAL_DOWN,
2297     EL_TUBE_LEFT_UP,
2298     EL_TUBE_LEFT_DOWN,
2299     EL_TUBE_RIGHT_UP,
2300     EL_TUBE_RIGHT_DOWN,
2301
2302     /* same elements as in 'ep_passable_over' */
2303     EL_EM_GATE_1,
2304     EL_EM_GATE_2,
2305     EL_EM_GATE_3,
2306     EL_EM_GATE_4,
2307     EL_EM_GATE_1_GRAY,
2308     EL_EM_GATE_2_GRAY,
2309     EL_EM_GATE_3_GRAY,
2310     EL_EM_GATE_4_GRAY,
2311     EL_SWITCHGATE_OPEN,
2312     EL_TIMEGATE_OPEN,
2313
2314     /* same elements as in 'ep_passable_inside' */
2315     EL_SP_PORT_LEFT,
2316     EL_SP_PORT_RIGHT,
2317     EL_SP_PORT_UP,
2318     EL_SP_PORT_DOWN,
2319     EL_SP_PORT_HORIZONTAL,
2320     EL_SP_PORT_VERTICAL,
2321     EL_SP_PORT_ANY,
2322     EL_SP_GRAVITY_PORT_LEFT,
2323     EL_SP_GRAVITY_PORT_RIGHT,
2324     EL_SP_GRAVITY_PORT_UP,
2325     EL_SP_GRAVITY_PORT_DOWN,
2326     EL_SP_GRAVITY_ON_PORT_LEFT,
2327     EL_SP_GRAVITY_ON_PORT_RIGHT,
2328     EL_SP_GRAVITY_ON_PORT_UP,
2329     EL_SP_GRAVITY_ON_PORT_DOWN,
2330     EL_SP_GRAVITY_OFF_PORT_LEFT,
2331     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2332     EL_SP_GRAVITY_OFF_PORT_UP,
2333     EL_SP_GRAVITY_OFF_PORT_DOWN,
2334     -1
2335   };
2336
2337   static int ep_throwable[] =
2338   {
2339     -1
2340   };
2341
2342   static int ep_can_explode[] =
2343   {
2344     /* same elements as in 'ep_explodes_impact' */
2345     EL_BOMB,
2346     EL_SP_DISK_ORANGE,
2347     EL_DX_SUPABOMB,
2348
2349     /* same elements as in 'ep_explodes_smashed' */
2350     EL_SATELLITE,
2351     EL_PIG,
2352     EL_DRAGON,
2353     EL_MOLE,
2354
2355     /* elements that can explode by explosion or by dragonfire */
2356     EL_DYNAMITE_ACTIVE,
2357     EL_DYNAMITE,
2358     EL_DYNABOMB_PLAYER_1_ACTIVE,
2359     EL_DYNABOMB_PLAYER_2_ACTIVE,
2360     EL_DYNABOMB_PLAYER_3_ACTIVE,
2361     EL_DYNABOMB_PLAYER_4_ACTIVE,
2362     EL_DYNABOMB_INCREASE_NUMBER,
2363     EL_DYNABOMB_INCREASE_SIZE,
2364     EL_DYNABOMB_INCREASE_POWER,
2365     EL_SP_DISK_RED_ACTIVE,
2366     EL_BUG,
2367     EL_PENGUIN,
2368     EL_SP_DISK_RED,
2369     EL_SP_DISK_YELLOW,
2370     EL_SP_SNIKSNAK,
2371     EL_SP_ELECTRON,
2372
2373     /* elements that can explode only by explosion */
2374     EL_BLACK_ORB,
2375     -1
2376   };
2377
2378   static int ep_gravity_reachable[] =
2379   {
2380     EL_SAND,
2381     EL_SP_BASE,
2382     EL_TRAP,
2383     EL_INVISIBLE_SAND,
2384     EL_INVISIBLE_SAND_ACTIVE,
2385     EL_SP_PORT_LEFT,
2386     EL_SP_PORT_RIGHT,
2387     EL_SP_PORT_UP,
2388     EL_SP_PORT_DOWN,
2389     EL_SP_PORT_HORIZONTAL,
2390     EL_SP_PORT_VERTICAL,
2391     EL_SP_PORT_ANY,
2392     EL_SP_GRAVITY_PORT_LEFT,
2393     EL_SP_GRAVITY_PORT_RIGHT,
2394     EL_SP_GRAVITY_PORT_UP,
2395     EL_SP_GRAVITY_PORT_DOWN,
2396     EL_SP_GRAVITY_ON_PORT_LEFT,
2397     EL_SP_GRAVITY_ON_PORT_RIGHT,
2398     EL_SP_GRAVITY_ON_PORT_UP,
2399     EL_SP_GRAVITY_ON_PORT_DOWN,
2400     EL_SP_GRAVITY_OFF_PORT_LEFT,
2401     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2402     EL_SP_GRAVITY_OFF_PORT_UP,
2403     EL_SP_GRAVITY_OFF_PORT_DOWN,
2404     -1
2405   };
2406
2407   static int ep_player[] =
2408   {
2409     EL_PLAYER_1,
2410     EL_PLAYER_2,
2411     EL_PLAYER_3,
2412     EL_PLAYER_4,
2413     EL_SP_MURPHY,
2414     EL_SOKOBAN_FIELD_PLAYER,
2415     EL_TRIGGER_PLAYER,
2416     -1
2417   };
2418
2419   static int ep_can_pass_magic_wall[] =
2420   {
2421     EL_ROCK,
2422     EL_BD_ROCK,
2423     EL_EMERALD,
2424     EL_BD_DIAMOND,
2425     EL_EMERALD_YELLOW,
2426     EL_EMERALD_RED,
2427     EL_EMERALD_PURPLE,
2428     EL_DIAMOND,
2429     -1
2430   };
2431
2432   static int ep_switchable[] =
2433   {
2434     EL_ROBOT_WHEEL,
2435     EL_SP_TERMINAL,
2436     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2437     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2438     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2439     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2440     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2441     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2442     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2443     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2444     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2445     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2446     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2447     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2448     EL_SWITCHGATE_SWITCH_UP,
2449     EL_SWITCHGATE_SWITCH_DOWN,
2450     EL_LIGHT_SWITCH,
2451     EL_LIGHT_SWITCH_ACTIVE,
2452     EL_TIMEGATE_SWITCH,
2453     EL_BALLOON_SWITCH_LEFT,
2454     EL_BALLOON_SWITCH_RIGHT,
2455     EL_BALLOON_SWITCH_UP,
2456     EL_BALLOON_SWITCH_DOWN,
2457     EL_BALLOON_SWITCH_ANY,
2458     EL_LAMP,
2459     EL_TIME_ORB_FULL,
2460     -1
2461   };
2462
2463   static int ep_bd_element[] =
2464   {
2465     EL_EMPTY,
2466     EL_SAND,
2467     EL_WALL_SLIPPERY,
2468     EL_BD_WALL,
2469     EL_ROCK,
2470     EL_BD_ROCK,
2471     EL_BD_DIAMOND,
2472     EL_BD_MAGIC_WALL,
2473     EL_EXIT_CLOSED,
2474     EL_EXIT_OPEN,
2475     EL_STEELWALL,
2476     EL_PLAYER_1,
2477     EL_PLAYER_2,
2478     EL_PLAYER_3,
2479     EL_PLAYER_4,
2480     EL_BD_FIREFLY,
2481     EL_BD_FIREFLY_1,
2482     EL_BD_FIREFLY_2,
2483     EL_BD_FIREFLY_3,
2484     EL_BD_FIREFLY_4,
2485     EL_BD_BUTTERFLY,
2486     EL_BD_BUTTERFLY_1,
2487     EL_BD_BUTTERFLY_2,
2488     EL_BD_BUTTERFLY_3,
2489     EL_BD_BUTTERFLY_4,
2490     EL_BD_AMOEBA,
2491     EL_CHAR_QUESTION,
2492     EL_UNKNOWN,
2493     -1
2494   };
2495
2496   static int ep_sp_element[] =
2497   {
2498     /* should always be valid */
2499     EL_EMPTY,
2500
2501     /* standard classic Supaplex elements */
2502     EL_SP_EMPTY,
2503     EL_SP_ZONK,
2504     EL_SP_BASE,
2505     EL_SP_MURPHY,
2506     EL_SP_INFOTRON,
2507     EL_SP_CHIP_SINGLE,
2508     EL_SP_HARDWARE_GRAY,
2509     EL_SP_EXIT_CLOSED,
2510     EL_SP_EXIT_OPEN,
2511     EL_SP_DISK_ORANGE,
2512     EL_SP_PORT_RIGHT,
2513     EL_SP_PORT_DOWN,
2514     EL_SP_PORT_LEFT,
2515     EL_SP_PORT_UP,
2516     EL_SP_GRAVITY_PORT_RIGHT,
2517     EL_SP_GRAVITY_PORT_DOWN,
2518     EL_SP_GRAVITY_PORT_LEFT,
2519     EL_SP_GRAVITY_PORT_UP,
2520     EL_SP_SNIKSNAK,
2521     EL_SP_DISK_YELLOW,
2522     EL_SP_TERMINAL,
2523     EL_SP_DISK_RED,
2524     EL_SP_PORT_VERTICAL,
2525     EL_SP_PORT_HORIZONTAL,
2526     EL_SP_PORT_ANY,
2527     EL_SP_ELECTRON,
2528     EL_SP_BUGGY_BASE,
2529     EL_SP_CHIP_LEFT,
2530     EL_SP_CHIP_RIGHT,
2531     EL_SP_HARDWARE_BASE_1,
2532     EL_SP_HARDWARE_GREEN,
2533     EL_SP_HARDWARE_BLUE,
2534     EL_SP_HARDWARE_RED,
2535     EL_SP_HARDWARE_YELLOW,
2536     EL_SP_HARDWARE_BASE_2,
2537     EL_SP_HARDWARE_BASE_3,
2538     EL_SP_HARDWARE_BASE_4,
2539     EL_SP_HARDWARE_BASE_5,
2540     EL_SP_HARDWARE_BASE_6,
2541     EL_SP_CHIP_TOP,
2542     EL_SP_CHIP_BOTTOM,
2543
2544     /* additional elements that appeared in newer Supaplex levels */
2545     EL_INVISIBLE_WALL,
2546
2547     /* additional gravity port elements (not switching, but setting gravity) */
2548     EL_SP_GRAVITY_ON_PORT_LEFT,
2549     EL_SP_GRAVITY_ON_PORT_RIGHT,
2550     EL_SP_GRAVITY_ON_PORT_UP,
2551     EL_SP_GRAVITY_ON_PORT_DOWN,
2552     EL_SP_GRAVITY_OFF_PORT_LEFT,
2553     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2554     EL_SP_GRAVITY_OFF_PORT_UP,
2555     EL_SP_GRAVITY_OFF_PORT_DOWN,
2556
2557     /* more than one Murphy in a level results in an inactive clone */
2558     EL_SP_MURPHY_CLONE,
2559
2560     /* runtime Supaplex elements */
2561     EL_SP_DISK_RED_ACTIVE,
2562     EL_SP_TERMINAL_ACTIVE,
2563     EL_SP_BUGGY_BASE_ACTIVATING,
2564     EL_SP_BUGGY_BASE_ACTIVE,
2565     EL_SP_EXIT_OPENING,
2566     EL_SP_EXIT_CLOSING,
2567     -1
2568   };
2569
2570   static int ep_sb_element[] =
2571   {
2572     EL_EMPTY,
2573     EL_STEELWALL,
2574     EL_SOKOBAN_OBJECT,
2575     EL_SOKOBAN_FIELD_EMPTY,
2576     EL_SOKOBAN_FIELD_FULL,
2577     EL_SOKOBAN_FIELD_PLAYER,
2578     EL_PLAYER_1,
2579     EL_PLAYER_2,
2580     EL_PLAYER_3,
2581     EL_PLAYER_4,
2582     EL_INVISIBLE_STEELWALL,
2583     -1
2584   };
2585
2586   static int ep_gem[] =
2587   {
2588     EL_BD_DIAMOND,
2589     EL_EMERALD,
2590     EL_EMERALD_YELLOW,
2591     EL_EMERALD_RED,
2592     EL_EMERALD_PURPLE,
2593     EL_DIAMOND,
2594     -1
2595   };
2596
2597   static int ep_food_dark_yamyam[] =
2598   {
2599     EL_SAND,
2600     EL_BUG,
2601     EL_SPACESHIP,
2602     EL_BD_BUTTERFLY,
2603     EL_BD_FIREFLY,
2604     EL_YAMYAM,
2605     EL_ROBOT,
2606     EL_PACMAN,
2607     EL_AMOEBA_DROP,
2608     EL_AMOEBA_DEAD,
2609     EL_AMOEBA_WET,
2610     EL_AMOEBA_DRY,
2611     EL_AMOEBA_FULL,
2612     EL_BD_AMOEBA,
2613     EL_EMERALD,
2614     EL_BD_DIAMOND,
2615     EL_EMERALD_YELLOW,
2616     EL_EMERALD_RED,
2617     EL_EMERALD_PURPLE,
2618     EL_DIAMOND,
2619     EL_PEARL,
2620     EL_CRYSTAL,
2621     -1
2622   };
2623
2624   static int ep_food_penguin[] =
2625   {
2626     EL_EMERALD,
2627     EL_BD_DIAMOND,
2628     EL_EMERALD_YELLOW,
2629     EL_EMERALD_RED,
2630     EL_EMERALD_PURPLE,
2631     EL_DIAMOND,
2632     EL_PEARL,
2633     EL_CRYSTAL,
2634     -1
2635   };
2636
2637   static int ep_food_pig[] =
2638   {
2639     EL_EMERALD,
2640     EL_BD_DIAMOND,
2641     EL_EMERALD_YELLOW,
2642     EL_EMERALD_RED,
2643     EL_EMERALD_PURPLE,
2644     EL_DIAMOND,
2645     -1
2646   };
2647
2648   static int ep_historic_wall[] =
2649   {
2650     EL_STEELWALL,
2651     EL_GATE_1,
2652     EL_GATE_2,
2653     EL_GATE_3,
2654     EL_GATE_4,
2655     EL_GATE_1_GRAY,
2656     EL_GATE_2_GRAY,
2657     EL_GATE_3_GRAY,
2658     EL_GATE_4_GRAY,
2659     EL_EM_GATE_1,
2660     EL_EM_GATE_2,
2661     EL_EM_GATE_3,
2662     EL_EM_GATE_4,
2663     EL_EM_GATE_1_GRAY,
2664     EL_EM_GATE_2_GRAY,
2665     EL_EM_GATE_3_GRAY,
2666     EL_EM_GATE_4_GRAY,
2667     EL_EXIT_CLOSED,
2668     EL_EXIT_OPENING,
2669     EL_EXIT_OPEN,
2670     EL_WALL,
2671     EL_WALL_SLIPPERY,
2672     EL_EXPANDABLE_WALL,
2673     EL_EXPANDABLE_WALL_HORIZONTAL,
2674     EL_EXPANDABLE_WALL_VERTICAL,
2675     EL_EXPANDABLE_WALL_ANY,
2676     EL_EXPANDABLE_WALL_GROWING,
2677     EL_BD_WALL,
2678     EL_SP_CHIP_SINGLE,
2679     EL_SP_CHIP_LEFT,
2680     EL_SP_CHIP_RIGHT,
2681     EL_SP_CHIP_TOP,
2682     EL_SP_CHIP_BOTTOM,
2683     EL_SP_HARDWARE_GRAY,
2684     EL_SP_HARDWARE_GREEN,
2685     EL_SP_HARDWARE_BLUE,
2686     EL_SP_HARDWARE_RED,
2687     EL_SP_HARDWARE_YELLOW,
2688     EL_SP_HARDWARE_BASE_1,
2689     EL_SP_HARDWARE_BASE_2,
2690     EL_SP_HARDWARE_BASE_3,
2691     EL_SP_HARDWARE_BASE_4,
2692     EL_SP_HARDWARE_BASE_5,
2693     EL_SP_HARDWARE_BASE_6,
2694     EL_SP_TERMINAL,
2695     EL_SP_TERMINAL_ACTIVE,
2696     EL_SP_EXIT_CLOSED,
2697     EL_SP_EXIT_OPEN,
2698     EL_INVISIBLE_STEELWALL,
2699     EL_INVISIBLE_STEELWALL_ACTIVE,
2700     EL_INVISIBLE_WALL,
2701     EL_INVISIBLE_WALL_ACTIVE,
2702     EL_STEELWALL_SLIPPERY,
2703     EL_EMC_STEELWALL_1,
2704     EL_EMC_STEELWALL_2,
2705     EL_EMC_STEELWALL_3,
2706     EL_EMC_STEELWALL_4,
2707     EL_EMC_WALL_1,
2708     EL_EMC_WALL_2,
2709     EL_EMC_WALL_3,
2710     EL_EMC_WALL_4,
2711     EL_EMC_WALL_5,
2712     EL_EMC_WALL_6,
2713     EL_EMC_WALL_7,
2714     EL_EMC_WALL_8,
2715     -1
2716   };
2717
2718   static int ep_historic_solid[] =
2719   {
2720     EL_WALL,
2721     EL_EXPANDABLE_WALL,
2722     EL_EXPANDABLE_WALL_HORIZONTAL,
2723     EL_EXPANDABLE_WALL_VERTICAL,
2724     EL_EXPANDABLE_WALL_ANY,
2725     EL_BD_WALL,
2726     EL_WALL_SLIPPERY,
2727     EL_EXIT_CLOSED,
2728     EL_EXIT_OPENING,
2729     EL_EXIT_OPEN,
2730     EL_AMOEBA_DEAD,
2731     EL_AMOEBA_WET,
2732     EL_AMOEBA_DRY,
2733     EL_AMOEBA_FULL,
2734     EL_BD_AMOEBA,
2735     EL_QUICKSAND_EMPTY,
2736     EL_QUICKSAND_FULL,
2737     EL_QUICKSAND_FILLING,
2738     EL_QUICKSAND_EMPTYING,
2739     EL_MAGIC_WALL,
2740     EL_MAGIC_WALL_ACTIVE,
2741     EL_MAGIC_WALL_EMPTYING,
2742     EL_MAGIC_WALL_FILLING,
2743     EL_MAGIC_WALL_FULL,
2744     EL_MAGIC_WALL_DEAD,
2745     EL_BD_MAGIC_WALL,
2746     EL_BD_MAGIC_WALL_ACTIVE,
2747     EL_BD_MAGIC_WALL_EMPTYING,
2748     EL_BD_MAGIC_WALL_FULL,
2749     EL_BD_MAGIC_WALL_FILLING,
2750     EL_BD_MAGIC_WALL_DEAD,
2751     EL_GAME_OF_LIFE,
2752     EL_BIOMAZE,
2753     EL_SP_CHIP_SINGLE,
2754     EL_SP_CHIP_LEFT,
2755     EL_SP_CHIP_RIGHT,
2756     EL_SP_CHIP_TOP,
2757     EL_SP_CHIP_BOTTOM,
2758     EL_SP_TERMINAL,
2759     EL_SP_TERMINAL_ACTIVE,
2760     EL_SP_EXIT_CLOSED,
2761     EL_SP_EXIT_OPEN,
2762     EL_INVISIBLE_WALL,
2763     EL_INVISIBLE_WALL_ACTIVE,
2764     EL_SWITCHGATE_SWITCH_UP,
2765     EL_SWITCHGATE_SWITCH_DOWN,
2766     EL_TIMEGATE_SWITCH,
2767     EL_TIMEGATE_SWITCH_ACTIVE,
2768     EL_EMC_WALL_1,
2769     EL_EMC_WALL_2,
2770     EL_EMC_WALL_3,
2771     EL_EMC_WALL_4,
2772     EL_EMC_WALL_5,
2773     EL_EMC_WALL_6,
2774     EL_EMC_WALL_7,
2775     EL_EMC_WALL_8,
2776     EL_WALL_PEARL,
2777     EL_WALL_CRYSTAL,
2778
2779     /* the following elements are a direct copy of "indestructible" elements,
2780        except "EL_ACID", which is "indestructible", but not "solid"! */
2781 #if 0
2782     EL_ACID,
2783 #endif
2784     EL_STEELWALL,
2785     EL_ACID_POOL_TOPLEFT,
2786     EL_ACID_POOL_TOPRIGHT,
2787     EL_ACID_POOL_BOTTOMLEFT,
2788     EL_ACID_POOL_BOTTOM,
2789     EL_ACID_POOL_BOTTOMRIGHT,
2790     EL_SP_HARDWARE_GRAY,
2791     EL_SP_HARDWARE_GREEN,
2792     EL_SP_HARDWARE_BLUE,
2793     EL_SP_HARDWARE_RED,
2794     EL_SP_HARDWARE_YELLOW,
2795     EL_SP_HARDWARE_BASE_1,
2796     EL_SP_HARDWARE_BASE_2,
2797     EL_SP_HARDWARE_BASE_3,
2798     EL_SP_HARDWARE_BASE_4,
2799     EL_SP_HARDWARE_BASE_5,
2800     EL_SP_HARDWARE_BASE_6,
2801     EL_INVISIBLE_STEELWALL,
2802     EL_INVISIBLE_STEELWALL_ACTIVE,
2803     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2804     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2805     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2806     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2807     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2808     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2809     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2810     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2811     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2812     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2813     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2814     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2815     EL_LIGHT_SWITCH,
2816     EL_LIGHT_SWITCH_ACTIVE,
2817     EL_SIGN_EXCLAMATION,
2818     EL_SIGN_RADIOACTIVITY,
2819     EL_SIGN_STOP,
2820     EL_SIGN_WHEELCHAIR,
2821     EL_SIGN_PARKING,
2822     EL_SIGN_ONEWAY,
2823     EL_SIGN_HEART,
2824     EL_SIGN_TRIANGLE,
2825     EL_SIGN_ROUND,
2826     EL_SIGN_EXIT,
2827     EL_SIGN_YINYANG,
2828     EL_SIGN_OTHER,
2829     EL_STEELWALL_SLIPPERY,
2830     EL_EMC_STEELWALL_1,
2831     EL_EMC_STEELWALL_2,
2832     EL_EMC_STEELWALL_3,
2833     EL_EMC_STEELWALL_4,
2834     EL_CRYSTAL,
2835     EL_GATE_1,
2836     EL_GATE_2,
2837     EL_GATE_3,
2838     EL_GATE_4,
2839     EL_GATE_1_GRAY,
2840     EL_GATE_2_GRAY,
2841     EL_GATE_3_GRAY,
2842     EL_GATE_4_GRAY,
2843     EL_EM_GATE_1,
2844     EL_EM_GATE_2,
2845     EL_EM_GATE_3,
2846     EL_EM_GATE_4,
2847     EL_EM_GATE_1_GRAY,
2848     EL_EM_GATE_2_GRAY,
2849     EL_EM_GATE_3_GRAY,
2850     EL_EM_GATE_4_GRAY,
2851     EL_SWITCHGATE_OPEN,
2852     EL_SWITCHGATE_OPENING,
2853     EL_SWITCHGATE_CLOSED,
2854     EL_SWITCHGATE_CLOSING,
2855     EL_TIMEGATE_OPEN,
2856     EL_TIMEGATE_OPENING,
2857     EL_TIMEGATE_CLOSED,
2858     EL_TIMEGATE_CLOSING,
2859     EL_TUBE_ANY,
2860     EL_TUBE_VERTICAL,
2861     EL_TUBE_HORIZONTAL,
2862     EL_TUBE_VERTICAL_LEFT,
2863     EL_TUBE_VERTICAL_RIGHT,
2864     EL_TUBE_HORIZONTAL_UP,
2865     EL_TUBE_HORIZONTAL_DOWN,
2866     EL_TUBE_LEFT_UP,
2867     EL_TUBE_LEFT_DOWN,
2868     EL_TUBE_RIGHT_UP,
2869     EL_TUBE_RIGHT_DOWN,
2870     -1
2871   };
2872
2873   static int ep_classic_enemy[] =
2874   {
2875     EL_BUG,
2876     EL_SPACESHIP,
2877     EL_BD_BUTTERFLY,
2878     EL_BD_FIREFLY,
2879
2880     EL_YAMYAM,
2881     EL_DARK_YAMYAM,
2882     EL_ROBOT,
2883     EL_PACMAN,
2884     EL_SP_SNIKSNAK,
2885     EL_SP_ELECTRON,
2886     -1
2887   };
2888
2889   static int ep_belt[] =
2890   {
2891     EL_CONVEYOR_BELT_1_LEFT,
2892     EL_CONVEYOR_BELT_1_MIDDLE,
2893     EL_CONVEYOR_BELT_1_RIGHT,
2894     EL_CONVEYOR_BELT_2_LEFT,
2895     EL_CONVEYOR_BELT_2_MIDDLE,
2896     EL_CONVEYOR_BELT_2_RIGHT,
2897     EL_CONVEYOR_BELT_3_LEFT,
2898     EL_CONVEYOR_BELT_3_MIDDLE,
2899     EL_CONVEYOR_BELT_3_RIGHT,
2900     EL_CONVEYOR_BELT_4_LEFT,
2901     EL_CONVEYOR_BELT_4_MIDDLE,
2902     EL_CONVEYOR_BELT_4_RIGHT,
2903     -1
2904   };
2905
2906   static int ep_belt_active[] =
2907   {
2908     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2909     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2910     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2911     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2912     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2913     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2914     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2915     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2916     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2917     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2918     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2919     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2920     -1
2921   };
2922
2923   static int ep_belt_switch[] =
2924   {
2925     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2926     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2927     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2928     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2929     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2930     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2931     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2932     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2933     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2934     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2935     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2936     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2937     -1
2938   };
2939
2940   static int ep_tube[] =
2941   {
2942     EL_TUBE_LEFT_UP,
2943     EL_TUBE_LEFT_DOWN,
2944     EL_TUBE_RIGHT_UP,
2945     EL_TUBE_RIGHT_DOWN,
2946     EL_TUBE_HORIZONTAL,
2947     EL_TUBE_HORIZONTAL_UP,
2948     EL_TUBE_HORIZONTAL_DOWN,
2949     EL_TUBE_VERTICAL,
2950     EL_TUBE_VERTICAL_LEFT,
2951     EL_TUBE_VERTICAL_RIGHT,
2952     EL_TUBE_ANY,
2953     -1
2954   };
2955
2956   static int ep_keygate[] =
2957   {
2958     EL_GATE_1,
2959     EL_GATE_2,
2960     EL_GATE_3,
2961     EL_GATE_4,
2962     EL_GATE_1_GRAY,
2963     EL_GATE_2_GRAY,
2964     EL_GATE_3_GRAY,
2965     EL_GATE_4_GRAY,
2966     EL_EM_GATE_1,
2967     EL_EM_GATE_2,
2968     EL_EM_GATE_3,
2969     EL_EM_GATE_4,
2970     EL_EM_GATE_1_GRAY,
2971     EL_EM_GATE_2_GRAY,
2972     EL_EM_GATE_3_GRAY,
2973     EL_EM_GATE_4_GRAY,
2974     -1
2975   };
2976
2977   static int ep_amoeboid[] =
2978   {
2979     EL_AMOEBA_DEAD,
2980     EL_AMOEBA_WET,
2981     EL_AMOEBA_DRY,
2982     EL_AMOEBA_FULL,
2983     EL_BD_AMOEBA,
2984     -1
2985   };
2986
2987   static int ep_amoebalive[] =
2988   {
2989     EL_AMOEBA_WET,
2990     EL_AMOEBA_DRY,
2991     EL_AMOEBA_FULL,
2992     EL_BD_AMOEBA,
2993     -1
2994   };
2995
2996   static int ep_has_content[] =
2997   {
2998     EL_YAMYAM,
2999     EL_AMOEBA_WET,
3000     EL_AMOEBA_DRY,
3001     EL_AMOEBA_FULL,
3002     EL_BD_AMOEBA,
3003     -1
3004   };
3005
3006   static int ep_can_turn_each_move[] =
3007   {
3008     /* !!! do something with this one !!! */
3009     -1
3010   };
3011
3012   static int ep_can_grow[] =
3013   {
3014     EL_BD_AMOEBA,
3015     EL_AMOEBA_DROP,
3016     EL_AMOEBA_WET,
3017     EL_AMOEBA_DRY,
3018     EL_AMOEBA_FULL,
3019     EL_GAME_OF_LIFE,
3020     EL_BIOMAZE,
3021     -1
3022   };
3023
3024   static int ep_active_bomb[] =
3025   {
3026     EL_DYNAMITE_ACTIVE,
3027     EL_DYNABOMB_PLAYER_1_ACTIVE,
3028     EL_DYNABOMB_PLAYER_2_ACTIVE,
3029     EL_DYNABOMB_PLAYER_3_ACTIVE,
3030     EL_DYNABOMB_PLAYER_4_ACTIVE,
3031     EL_SP_DISK_RED_ACTIVE,
3032     -1
3033   };
3034
3035   static int ep_inactive[] =
3036   {
3037     EL_EMPTY,
3038     EL_SAND,
3039     EL_WALL,
3040     EL_BD_WALL,
3041     EL_WALL_SLIPPERY,
3042     EL_STEELWALL,
3043     EL_AMOEBA_DEAD,
3044     EL_QUICKSAND_EMPTY,
3045     EL_STONEBLOCK,
3046     EL_ROBOT_WHEEL,
3047     EL_KEY_1,
3048     EL_KEY_2,
3049     EL_KEY_3,
3050     EL_KEY_4,
3051     EL_EM_KEY_1,
3052     EL_EM_KEY_2,
3053     EL_EM_KEY_3,
3054     EL_EM_KEY_4,
3055     EL_GATE_1,
3056     EL_GATE_2,
3057     EL_GATE_3,
3058     EL_GATE_4,
3059     EL_GATE_1_GRAY,
3060     EL_GATE_2_GRAY,
3061     EL_GATE_3_GRAY,
3062     EL_GATE_4_GRAY,
3063     EL_EM_GATE_1,
3064     EL_EM_GATE_2,
3065     EL_EM_GATE_3,
3066     EL_EM_GATE_4,
3067     EL_EM_GATE_1_GRAY,
3068     EL_EM_GATE_2_GRAY,
3069     EL_EM_GATE_3_GRAY,
3070     EL_EM_GATE_4_GRAY,
3071     EL_DYNAMITE,
3072     EL_INVISIBLE_STEELWALL,
3073     EL_INVISIBLE_WALL,
3074     EL_INVISIBLE_SAND,
3075     EL_LAMP,
3076     EL_LAMP_ACTIVE,
3077     EL_WALL_EMERALD,
3078     EL_WALL_DIAMOND,
3079     EL_WALL_BD_DIAMOND,
3080     EL_WALL_EMERALD_YELLOW,
3081     EL_DYNABOMB_INCREASE_NUMBER,
3082     EL_DYNABOMB_INCREASE_SIZE,
3083     EL_DYNABOMB_INCREASE_POWER,
3084 #if 0
3085     EL_SOKOBAN_OBJECT,
3086 #endif
3087     EL_SOKOBAN_FIELD_EMPTY,
3088     EL_SOKOBAN_FIELD_FULL,
3089     EL_WALL_EMERALD_RED,
3090     EL_WALL_EMERALD_PURPLE,
3091     EL_ACID_POOL_TOPLEFT,
3092     EL_ACID_POOL_TOPRIGHT,
3093     EL_ACID_POOL_BOTTOMLEFT,
3094     EL_ACID_POOL_BOTTOM,
3095     EL_ACID_POOL_BOTTOMRIGHT,
3096     EL_MAGIC_WALL,
3097     EL_MAGIC_WALL_DEAD,
3098     EL_BD_MAGIC_WALL,
3099     EL_BD_MAGIC_WALL_DEAD,
3100     EL_AMOEBA_TO_DIAMOND,
3101     EL_BLOCKED,
3102     EL_SP_EMPTY,
3103     EL_SP_BASE,
3104     EL_SP_PORT_RIGHT,
3105     EL_SP_PORT_DOWN,
3106     EL_SP_PORT_LEFT,
3107     EL_SP_PORT_UP,
3108     EL_SP_GRAVITY_PORT_RIGHT,
3109     EL_SP_GRAVITY_PORT_DOWN,
3110     EL_SP_GRAVITY_PORT_LEFT,
3111     EL_SP_GRAVITY_PORT_UP,
3112     EL_SP_PORT_HORIZONTAL,
3113     EL_SP_PORT_VERTICAL,
3114     EL_SP_PORT_ANY,
3115     EL_SP_DISK_RED,
3116 #if 0
3117     EL_SP_DISK_YELLOW,
3118 #endif
3119     EL_SP_CHIP_SINGLE,
3120     EL_SP_CHIP_LEFT,
3121     EL_SP_CHIP_RIGHT,
3122     EL_SP_CHIP_TOP,
3123     EL_SP_CHIP_BOTTOM,
3124     EL_SP_HARDWARE_GRAY,
3125     EL_SP_HARDWARE_GREEN,
3126     EL_SP_HARDWARE_BLUE,
3127     EL_SP_HARDWARE_RED,
3128     EL_SP_HARDWARE_YELLOW,
3129     EL_SP_HARDWARE_BASE_1,
3130     EL_SP_HARDWARE_BASE_2,
3131     EL_SP_HARDWARE_BASE_3,
3132     EL_SP_HARDWARE_BASE_4,
3133     EL_SP_HARDWARE_BASE_5,
3134     EL_SP_HARDWARE_BASE_6,
3135     EL_SP_GRAVITY_ON_PORT_LEFT,
3136     EL_SP_GRAVITY_ON_PORT_RIGHT,
3137     EL_SP_GRAVITY_ON_PORT_UP,
3138     EL_SP_GRAVITY_ON_PORT_DOWN,
3139     EL_SP_GRAVITY_OFF_PORT_LEFT,
3140     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3141     EL_SP_GRAVITY_OFF_PORT_UP,
3142     EL_SP_GRAVITY_OFF_PORT_DOWN,
3143     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3144     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3145     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3146     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3147     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3148     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3149     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3150     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3151     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3152     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3153     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3154     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3155     EL_SIGN_EXCLAMATION,
3156     EL_SIGN_RADIOACTIVITY,
3157     EL_SIGN_STOP,
3158     EL_SIGN_WHEELCHAIR,
3159     EL_SIGN_PARKING,
3160     EL_SIGN_ONEWAY,
3161     EL_SIGN_HEART,
3162     EL_SIGN_TRIANGLE,
3163     EL_SIGN_ROUND,
3164     EL_SIGN_EXIT,
3165     EL_SIGN_YINYANG,
3166     EL_SIGN_OTHER,
3167     EL_STEELWALL_SLIPPERY,
3168     EL_EMC_STEELWALL_1,
3169     EL_EMC_STEELWALL_2,
3170     EL_EMC_STEELWALL_3,
3171     EL_EMC_STEELWALL_4,
3172     EL_EMC_WALL_1,
3173     EL_EMC_WALL_2,
3174     EL_EMC_WALL_3,
3175     EL_EMC_WALL_4,
3176     EL_EMC_WALL_5,
3177     EL_EMC_WALL_6,
3178     EL_EMC_WALL_7,
3179     EL_EMC_WALL_8,
3180     -1
3181   };
3182
3183   static int ep_em_slippery_wall[] =
3184   {
3185     -1
3186   };
3187
3188   static int ep_gfx_crumbled[] =
3189   {
3190     EL_SAND,
3191     EL_LANDMINE,
3192     EL_TRAP,
3193     EL_TRAP_ACTIVE,
3194     -1
3195   };
3196
3197   static struct
3198   {
3199     int *elements;
3200     int property;
3201   } element_properties[] =
3202   {
3203     { ep_diggable,              EP_DIGGABLE             },
3204     { ep_collectible_only,      EP_COLLECTIBLE_ONLY     },
3205     { ep_dont_run_into,         EP_DONT_RUN_INTO        },
3206     { ep_dont_collide_with,     EP_DONT_COLLIDE_WITH    },
3207     { ep_dont_touch,            EP_DONT_TOUCH           },
3208     { ep_indestructible,        EP_INDESTRUCTIBLE       },
3209     { ep_slippery,              EP_SLIPPERY             },
3210     { ep_can_change,            EP_CAN_CHANGE           },
3211     { ep_can_move,              EP_CAN_MOVE             },
3212     { ep_can_fall,              EP_CAN_FALL             },
3213     { ep_can_smash_player,      EP_CAN_SMASH_PLAYER     },
3214     { ep_can_smash_enemies,     EP_CAN_SMASH_ENEMIES    },
3215     { ep_can_smash_everything,  EP_CAN_SMASH_EVERYTHING },
3216     { ep_explodes_by_fire,      EP_EXPLODES_BY_FIRE     },
3217     { ep_explodes_smashed,      EP_EXPLODES_SMASHED     },
3218     { ep_explodes_impact,       EP_EXPLODES_IMPACT      },
3219     { ep_walkable_over,         EP_WALKABLE_OVER        },
3220     { ep_walkable_inside,       EP_WALKABLE_INSIDE      },
3221     { ep_walkable_under,        EP_WALKABLE_UNDER       },
3222     { ep_passable_over,         EP_PASSABLE_OVER        },
3223     { ep_passable_inside,       EP_PASSABLE_INSIDE      },
3224     { ep_passable_under,        EP_PASSABLE_UNDER       },
3225     { ep_droppable,             EP_DROPPABLE            },
3226     { ep_explodes_1x1_old,      EP_EXPLODES_1X1_OLD     },
3227     { ep_pushable,              EP_PUSHABLE             },
3228     { ep_explodes_cross_old,    EP_EXPLODES_CROSS_OLD   },
3229     { ep_protected,             EP_PROTECTED            },
3230     { ep_throwable,             EP_THROWABLE            },
3231     { ep_can_explode,           EP_CAN_EXPLODE          },
3232     { ep_gravity_reachable,     EP_GRAVITY_REACHABLE    },
3233
3234     { ep_player,                EP_PLAYER               },
3235     { ep_can_pass_magic_wall,   EP_CAN_PASS_MAGIC_WALL  },
3236     { ep_switchable,            EP_SWITCHABLE           },
3237     { ep_bd_element,            EP_BD_ELEMENT           },
3238     { ep_sp_element,            EP_SP_ELEMENT           },
3239     { ep_sb_element,            EP_SB_ELEMENT           },
3240     { ep_gem,                   EP_GEM                  },
3241     { ep_food_dark_yamyam,      EP_FOOD_DARK_YAMYAM     },
3242     { ep_food_penguin,          EP_FOOD_PENGUIN         },
3243     { ep_food_pig,              EP_FOOD_PIG             },
3244     { ep_historic_wall,         EP_HISTORIC_WALL        },
3245     { ep_historic_solid,        EP_HISTORIC_SOLID       },
3246     { ep_classic_enemy,         EP_CLASSIC_ENEMY        },
3247     { ep_belt,                  EP_BELT                 },
3248     { ep_belt_active,           EP_BELT_ACTIVE          },
3249     { ep_belt_switch,           EP_BELT_SWITCH          },
3250     { ep_tube,                  EP_TUBE                 },
3251     { ep_keygate,               EP_KEYGATE              },
3252     { ep_amoeboid,              EP_AMOEBOID             },
3253     { ep_amoebalive,            EP_AMOEBALIVE           },
3254     { ep_has_content,           EP_HAS_CONTENT          },
3255     { ep_can_turn_each_move,    EP_CAN_TURN_EACH_MOVE   },
3256     { ep_can_grow,              EP_CAN_GROW             },
3257     { ep_active_bomb,           EP_ACTIVE_BOMB          },
3258     { ep_inactive,              EP_INACTIVE             },
3259
3260     { ep_em_slippery_wall,      EP_EM_SLIPPERY_WALL     },
3261
3262     { ep_gfx_crumbled,          EP_GFX_CRUMBLED         },
3263
3264     { NULL,                     -1                      }
3265   };
3266
3267   static int copy_properties[][5] =
3268   {
3269     {
3270       EL_BUG,
3271       EL_BUG_LEFT,              EL_BUG_RIGHT,
3272       EL_BUG_UP,                EL_BUG_DOWN
3273     },
3274     {
3275       EL_SPACESHIP,
3276       EL_SPACESHIP_LEFT,        EL_SPACESHIP_RIGHT,
3277       EL_SPACESHIP_UP,          EL_SPACESHIP_DOWN
3278     },
3279     {
3280       EL_BD_BUTTERFLY,
3281       EL_BD_BUTTERFLY_LEFT,     EL_BD_BUTTERFLY_RIGHT,
3282       EL_BD_BUTTERFLY_UP,       EL_BD_BUTTERFLY_DOWN
3283     },
3284     {
3285       EL_BD_FIREFLY,
3286       EL_BD_FIREFLY_LEFT,       EL_BD_FIREFLY_RIGHT,
3287       EL_BD_FIREFLY_UP,         EL_BD_FIREFLY_DOWN
3288     },
3289     {
3290       EL_PACMAN,
3291       EL_PACMAN_LEFT,           EL_PACMAN_RIGHT,
3292       EL_PACMAN_UP,             EL_PACMAN_DOWN
3293     },
3294     {
3295       EL_MOLE,
3296       EL_MOLE_LEFT,             EL_MOLE_RIGHT,
3297       EL_MOLE_UP,               EL_MOLE_DOWN
3298     },
3299     {
3300       -1,
3301       -1, -1, -1, -1
3302     }
3303   };
3304
3305   int i, j, k;
3306
3307   /* always start with reliable default values (element has no properties) */
3308   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3309     for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3310       SET_PROPERTY(i, j, FALSE);
3311
3312   /* set all base element properties from above array definitions */
3313   for (i = 0; element_properties[i].elements != NULL; i++)
3314     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3315       SET_PROPERTY((element_properties[i].elements)[j],
3316                    element_properties[i].property, TRUE);
3317
3318   /* copy properties to some elements that are only stored in level file */
3319   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3320     for (j = 0; copy_properties[j][0] != -1; j++)
3321       if (HAS_PROPERTY(copy_properties[j][0], i))
3322         for (k = 1; k <= 4; k++)
3323           SET_PROPERTY(copy_properties[j][k], i, TRUE);
3324 }
3325
3326 void InitElementPropertiesEngine(int engine_version)
3327 {
3328 #if 0
3329   static int active_properties[] =
3330   {
3331     EP_AMOEBALIVE,
3332     EP_AMOEBOID,
3333     EP_PFORTE,
3334     EP_DONT_COLLIDE_WITH,
3335     EP_MAUER,
3336     EP_CAN_FALL,
3337     EP_CAN_SMASH,
3338     EP_CAN_PASS_MAGIC_WALL,
3339     EP_CAN_MOVE,
3340     EP_DONT_TOUCH,
3341     EP_DONT_RUN_INTO,
3342     EP_GEM,
3343     EP_EXPLODES_BY_FIRE,
3344     EP_PUSHABLE,
3345     EP_PLAYER,
3346     EP_HAS_CONTENT,
3347     EP_DIGGABLE,
3348     EP_PASSABLE_INSIDE,
3349     EP_OVER_PLAYER,
3350     EP_ACTIVE_BOMB,
3351
3352     EP_BELT,
3353     EP_BELT_ACTIVE,
3354     EP_BELT_SWITCH,
3355     EP_WALKABLE_UNDER,
3356     EP_EM_SLIPPERY_WALL,
3357   };
3358 #endif
3359
3360   static int no_wall_properties[] =
3361   {
3362     EP_DIGGABLE,
3363     EP_COLLECTIBLE_ONLY,
3364     EP_DONT_RUN_INTO,
3365     EP_DONT_COLLIDE_WITH,
3366     EP_CAN_MOVE,
3367     EP_CAN_FALL,
3368     EP_CAN_SMASH_PLAYER,
3369     EP_CAN_SMASH_ENEMIES,
3370     EP_CAN_SMASH_EVERYTHING,
3371     EP_PUSHABLE,
3372
3373     EP_PLAYER,
3374     EP_GEM,
3375     EP_FOOD_DARK_YAMYAM,
3376     EP_FOOD_PENGUIN,
3377     EP_BELT,
3378     EP_BELT_ACTIVE,
3379     EP_TUBE,
3380     EP_AMOEBOID,
3381     EP_AMOEBALIVE,
3382     EP_ACTIVE_BOMB,
3383
3384     EP_ACCESSIBLE,
3385
3386     -1
3387   };
3388
3389   int i, j;
3390
3391 #if 0
3392   InitElementPropertiesStatic();
3393 #endif
3394
3395   /* important: after initialization in InitElementPropertiesStatic(), the
3396      elements are not again initialized to a default value; therefore all
3397      changes have to make sure that they leave the element with a defined
3398      property (which means that conditional property changes must be set to
3399      a reliable default value before) */
3400
3401   /* set all special, combined or engine dependent element properties */
3402   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3403   {
3404 #if 0
3405     for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3406       SET_PROPERTY(i, j, FALSE);
3407 #endif
3408
3409     /* ---------- INACTIVE ------------------------------------------------- */
3410     SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3411
3412     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3413     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3414                                   IS_WALKABLE_INSIDE(i) ||
3415                                   IS_WALKABLE_UNDER(i)));
3416
3417     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3418                                   IS_PASSABLE_INSIDE(i) ||
3419                                   IS_PASSABLE_UNDER(i)));
3420
3421     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3422                                          IS_PASSABLE_OVER(i)));
3423
3424     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3425                                            IS_PASSABLE_INSIDE(i)));
3426
3427     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3428                                           IS_PASSABLE_UNDER(i)));
3429
3430     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3431                                     IS_PASSABLE(i)));
3432
3433     /* ---------- COLLECTIBLE ---------------------------------------------- */
3434     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3435                                      IS_DROPPABLE(i) ||
3436                                      IS_THROWABLE(i)));
3437
3438     /* ---------- SNAPPABLE ------------------------------------------------ */
3439     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3440                                    IS_COLLECTIBLE(i) ||
3441                                    IS_SWITCHABLE(i) ||
3442                                    i == EL_BD_ROCK));
3443
3444     /* ---------- WALL ----------------------------------------------------- */
3445     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
3446
3447     for (j = 0; no_wall_properties[j] != -1; j++)
3448       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3449           i >= EL_FIRST_RUNTIME_UNREAL)
3450         SET_PROPERTY(i, EP_WALL, FALSE);
3451
3452     if (IS_HISTORIC_WALL(i))
3453       SET_PROPERTY(i, EP_WALL, TRUE);
3454
3455     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3456     if (engine_version < VERSION_IDENT(2,2,0,0))
3457       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3458     else
3459       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3460                                              !IS_DIGGABLE(i) &&
3461                                              !IS_COLLECTIBLE(i)));
3462
3463 #if 0
3464     /* ---------- PROTECTED ------------------------------------------------ */
3465     if (IS_ACCESSIBLE_INSIDE(i))
3466       SET_PROPERTY(i, EP_PROTECTED, TRUE);
3467 #endif
3468
3469     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3470
3471     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3472       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3473     else
3474       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3475                                             IS_INDESTRUCTIBLE(i)));
3476
3477     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3478     if (i == EL_FLAMES)
3479       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3480     else if (engine_version < VERSION_IDENT(2,2,0,0))
3481       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3482     else
3483 #if 1
3484       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3485                                            (!IS_WALKABLE(i) ||
3486                                             IS_PROTECTED(i))));
3487 #else
3488 #if 1
3489       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3490                                            !IS_WALKABLE_OVER(i) &&
3491                                            !IS_WALKABLE_UNDER(i)));
3492 #else
3493       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3494                                            IS_PROTECTED(i)));
3495 #endif
3496 #endif
3497
3498     if (IS_CUSTOM_ELEMENT(i))
3499     {
3500       /* these are additional properties which are initially false when set */
3501
3502       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3503       if (DONT_TOUCH(i))
3504         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3505       if (DONT_COLLIDE_WITH(i))
3506         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3507
3508       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3509       if (CAN_SMASH_EVERYTHING(i))
3510         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3511       if (CAN_SMASH_ENEMIES(i))
3512         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3513     }
3514
3515     /* ---------- CAN_SMASH ------------------------------------------------ */
3516     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3517                                    CAN_SMASH_ENEMIES(i) ||
3518                                    CAN_SMASH_EVERYTHING(i)));
3519
3520 #if 0
3521     /* ---------- CAN_EXPLODE ---------------------------------------------- */
3522     SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3523                                      CAN_EXPLODE_SMASHED(i) ||
3524                                      CAN_EXPLODE_IMPACT(i)));
3525 #endif
3526
3527 #if 0
3528     /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3529 #if 0
3530     SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3531                                          !CAN_EXPLODE_CROSS(i)));
3532 #else
3533     SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3534                                          !CAN_EXPLODE_1X1(i) &&
3535                                          !CAN_EXPLODE_CROSS(i)));
3536 #endif
3537 #endif
3538
3539     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3540     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3541                                              EXPLODES_BY_FIRE(i)));
3542
3543     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3544     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3545                                              EXPLODES_SMASHED(i)));
3546
3547     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3548     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3549                                             EXPLODES_IMPACT(i)));
3550
3551     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3552     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3553
3554     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3555     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3556                                                   i == EL_BLACK_ORB));
3557
3558     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3559     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3560                                               CAN_MOVE(i) ||
3561                                               IS_CUSTOM_ELEMENT(i)));
3562
3563     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3564     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3565                                                  i == EL_SP_ELECTRON));
3566
3567     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3568     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3569       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3570                    getMoveIntoAcidProperty(&level, i));
3571
3572     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3573     if (MAYBE_DONT_COLLIDE_WITH(i))
3574       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3575                    getDontCollideWithProperty(&level, i));
3576
3577     /* ---------- SP_PORT -------------------------------------------------- */
3578     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3579                                  IS_PASSABLE_INSIDE(i)));
3580
3581     /* ---------- CAN_CHANGE ----------------------------------------------- */
3582     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
3583     for (j = 0; j < element_info[i].num_change_pages; j++)
3584       if (element_info[i].change_page[j].can_change)
3585         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3586
3587     /* ---------- GFX_CRUMBLED --------------------------------------------- */
3588     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3589                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3590   }
3591
3592 #if 0
3593   /* determine inactive elements (used for engine main loop optimization) */
3594   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3595   {
3596     boolean active = FALSE;
3597
3598     for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3599     {
3600       if (HAS_PROPERTY(i, j))
3601         active = TRUE;
3602     }
3603
3604 #if 0
3605     if (!active)
3606       SET_PROPERTY(i, EP_INACTIVE, TRUE);
3607 #endif
3608   }
3609 #endif
3610
3611   /* dynamically adjust element properties according to game engine version */
3612   {
3613     static int ep_em_slippery_wall[] =
3614     {
3615       EL_STEELWALL,
3616       EL_WALL,
3617       EL_EXPANDABLE_WALL,
3618       EL_EXPANDABLE_WALL_HORIZONTAL,
3619       EL_EXPANDABLE_WALL_VERTICAL,
3620       EL_EXPANDABLE_WALL_ANY,
3621       -1
3622     };
3623
3624     /* special EM style gems behaviour */
3625     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3626       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3627                    level.em_slippery_gems);
3628
3629     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3630     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3631                  (level.em_slippery_gems &&
3632                   engine_version > VERSION_IDENT(2,0,1,0)));
3633   }
3634
3635 #if 1
3636   /* set default push delay values (corrected since version 3.0.7-1) */
3637   if (engine_version < VERSION_IDENT(3,0,7,1))
3638   {
3639     game.default_push_delay_fixed = 2;
3640     game.default_push_delay_random = 8;
3641   }
3642   else
3643   {
3644     game.default_push_delay_fixed = 8;
3645     game.default_push_delay_random = 8;
3646   }
3647
3648   /* set uninitialized push delay values of custom elements in older levels */
3649   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3650   {
3651     int element = EL_CUSTOM_START + i;
3652
3653     if (element_info[element].push_delay_fixed == -1)
3654       element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3655     if (element_info[element].push_delay_random == -1)
3656       element_info[element].push_delay_random = game.default_push_delay_random;
3657   }
3658
3659   /* set some other uninitialized values of custom elements in older levels */
3660   if (engine_version < VERSION_IDENT(3,1,0,0))
3661   {
3662     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3663     {
3664       int element = EL_CUSTOM_START + i;
3665
3666       element_info[element].access_direction = MV_ALL_DIRECTIONS;
3667
3668       element_info[element].explosion_delay = 17;
3669       element_info[element].ignition_delay = 8;
3670     }
3671   }
3672
3673 #if 0
3674   /* set element properties that were handled incorrectly in older levels */
3675   if (engine_version < VERSION_IDENT(3,1,0,0))
3676   {
3677     SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3678     SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3679   }
3680 #endif
3681
3682 #endif
3683
3684   /* this is needed because some graphics depend on element properties */
3685   if (game_status == GAME_MODE_PLAYING)
3686     InitElementGraphicInfo();
3687 }
3688
3689 static void InitGlobal()
3690 {
3691   int i;
3692
3693   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3694   {
3695     element_info[i].token_name = element_name_info[i].token_name;
3696     element_info[i].class_name = element_name_info[i].class_name;
3697     element_info[i].editor_description=element_name_info[i].editor_description;
3698   }
3699
3700   global.autoplay_leveldir = NULL;
3701   global.convert_leveldir = NULL;
3702
3703   global.frames_per_second = 0;
3704   global.fps_slowdown = FALSE;
3705   global.fps_slowdown_factor = 1;
3706 }
3707
3708 void Execute_Command(char *command)
3709 {
3710   int i;
3711
3712   if (strcmp(command, "print graphicsinfo.conf") == 0)
3713   {
3714     printf("# You can configure additional/alternative image files here.\n");
3715     printf("# (The entries below are default and therefore commented out.)\n");
3716     printf("\n");
3717     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3718     printf("\n");
3719     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3720     printf("\n");
3721
3722     for (i = 0; image_config[i].token != NULL; i++)
3723       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3724                                               image_config[i].value));
3725
3726     exit(0);
3727   }
3728   else if (strcmp(command, "print soundsinfo.conf") == 0)
3729   {
3730     printf("# You can configure additional/alternative sound files here.\n");
3731     printf("# (The entries below are default and therefore commented out.)\n");
3732     printf("\n");
3733     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3734     printf("\n");
3735     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3736     printf("\n");
3737
3738     for (i = 0; sound_config[i].token != NULL; i++)
3739       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3740                                               sound_config[i].value));
3741
3742     exit(0);
3743   }
3744   else if (strcmp(command, "print musicinfo.conf") == 0)
3745   {
3746     printf("# You can configure additional/alternative music files here.\n");
3747     printf("# (The entries below are default and therefore commented out.)\n");
3748     printf("\n");
3749     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3750     printf("\n");
3751     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3752     printf("\n");
3753
3754     for (i = 0; music_config[i].token != NULL; i++)
3755       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3756                                               music_config[i].value));
3757
3758     exit(0);
3759   }
3760   else if (strcmp(command, "print editorsetup.conf") == 0)
3761   {
3762     printf("# You can configure your personal editor element list here.\n");
3763     printf("# (The entries below are default and therefore commented out.)\n");
3764     printf("\n");
3765
3766     PrintEditorElementList();
3767
3768     exit(0);
3769   }
3770   else if (strcmp(command, "print helpanim.conf") == 0)
3771   {
3772     printf("# You can configure different element help animations here.\n");
3773     printf("# (The entries below are default and therefore commented out.)\n");
3774     printf("\n");
3775
3776     for (i = 0; helpanim_config[i].token != NULL; i++)
3777     {
3778       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3779                                               helpanim_config[i].value));
3780
3781       if (strcmp(helpanim_config[i].token, "end") == 0)
3782         printf("#\n");
3783     }
3784
3785     exit(0);
3786   }
3787   else if (strcmp(command, "print helptext.conf") == 0)
3788   {
3789     printf("# You can configure different element help text here.\n");
3790     printf("# (The entries below are default and therefore commented out.)\n");
3791     printf("\n");
3792
3793     for (i = 0; helptext_config[i].token != NULL; i++)
3794       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3795                                               helptext_config[i].value));
3796
3797     exit(0);
3798   }
3799   else if (strncmp(command, "dump level ", 11) == 0)
3800   {
3801     char *filename = &command[11];
3802
3803     if (access(filename, F_OK) != 0)
3804       Error(ERR_EXIT, "cannot open file '%s'", filename);
3805
3806     LoadLevelFromFilename(&level, filename);
3807     DumpLevel(&level);
3808
3809     exit(0);
3810   }
3811   else if (strncmp(command, "dump tape ", 10) == 0)
3812   {
3813     char *filename = &command[10];
3814
3815     if (access(filename, F_OK) != 0)
3816       Error(ERR_EXIT, "cannot open file '%s'", filename);
3817
3818     LoadTapeFromFilename(filename);
3819     DumpTape(&tape);
3820
3821     exit(0);
3822   }
3823   else if (strncmp(command, "autoplay ", 9) == 0)
3824   {
3825     char *str_copy = getStringCopy(&command[9]);
3826     char *str_ptr = strchr(str_copy, ' ');
3827
3828     global.autoplay_leveldir = str_copy;
3829     global.autoplay_level_nr = -1;
3830
3831     if (str_ptr != NULL)
3832     {
3833       *str_ptr++ = '\0';                        /* terminate leveldir string */
3834       global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
3835     }
3836   }
3837   else if (strncmp(command, "convert ", 8) == 0)
3838   {
3839     char *str_copy = getStringCopy(&command[8]);
3840     char *str_ptr = strchr(str_copy, ' ');
3841
3842     global.convert_leveldir = str_copy;
3843     global.convert_level_nr = -1;
3844
3845     if (str_ptr != NULL)
3846     {
3847       *str_ptr++ = '\0';                        /* terminate leveldir string */
3848       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
3849     }
3850   }
3851   else
3852   {
3853     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3854   }
3855 }
3856
3857 static void InitSetup()
3858 {
3859   LoadSetup();                                  /* global setup info */
3860
3861   /* set some options from setup file */
3862
3863   if (setup.options.verbose)
3864     options.verbose = TRUE;
3865 }
3866
3867 static void InitPlayerInfo()
3868 {
3869   int i;
3870
3871   /* choose default local player */
3872   local_player = &stored_player[0];
3873
3874   for (i = 0; i < MAX_PLAYERS; i++)
3875     stored_player[i].connected = FALSE;
3876
3877   local_player->connected = TRUE;
3878 }
3879
3880 static void InitArtworkInfo()
3881 {
3882   LoadArtworkInfo();
3883 }
3884
3885 static char *get_string_in_brackets(char *string)
3886 {
3887   char *string_in_brackets = checked_malloc(strlen(string) + 3);
3888
3889   sprintf(string_in_brackets, "[%s]", string);
3890
3891   return string_in_brackets;
3892 }
3893
3894 static char *get_level_id_suffix(int id_nr)
3895 {
3896   char *id_suffix = checked_malloc(1 + 3 + 1);
3897
3898   if (id_nr < 0 || id_nr > 999)
3899     id_nr = 0;
3900
3901   sprintf(id_suffix, ".%03d", id_nr);
3902
3903   return id_suffix;
3904 }
3905
3906 #if 0
3907 static char *get_element_class_token(int element)
3908 {
3909   char *element_class_name = element_info[element].class_name;
3910   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3911
3912   sprintf(element_class_token, "[%s]", element_class_name);
3913
3914   return element_class_token;
3915 }
3916
3917 static char *get_action_class_token(int action)
3918 {
3919   char *action_class_name = &element_action_info[action].suffix[1];
3920   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3921
3922   sprintf(action_class_token, "[%s]", action_class_name);
3923
3924   return action_class_token;
3925 }
3926 #endif
3927
3928 static void InitArtworkConfig()
3929 {
3930   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3931   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3932   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3933   static char *action_id_suffix[NUM_ACTIONS + 1];
3934   static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3935   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3936   static char *level_id_suffix[MAX_LEVELS + 1];
3937   static char *dummy[1] = { NULL };
3938   static char *ignore_generic_tokens[] =
3939   {
3940     "name",
3941     "sort_priority",
3942     NULL
3943   };
3944   static char **ignore_image_tokens;
3945   static char **ignore_sound_tokens;
3946   static char **ignore_music_tokens;
3947   int num_ignore_generic_tokens;
3948   int num_ignore_image_tokens;
3949   int num_ignore_sound_tokens;
3950   int num_ignore_music_tokens;
3951   int i;
3952
3953   /* dynamically determine list of generic tokens to be ignored */
3954   num_ignore_generic_tokens = 0;
3955   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3956     num_ignore_generic_tokens++;
3957
3958   /* dynamically determine list of image tokens to be ignored */
3959   num_ignore_image_tokens = num_ignore_generic_tokens;
3960   for (i = 0; image_config_vars[i].token != NULL; i++)
3961     num_ignore_image_tokens++;
3962   ignore_image_tokens =
3963     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
3964   for (i = 0; i < num_ignore_generic_tokens; i++)
3965     ignore_image_tokens[i] = ignore_generic_tokens[i];
3966   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
3967     ignore_image_tokens[num_ignore_generic_tokens + i] =
3968       image_config_vars[i].token;
3969   ignore_image_tokens[num_ignore_image_tokens] = NULL;
3970
3971   /* dynamically determine list of sound tokens to be ignored */
3972   num_ignore_sound_tokens = num_ignore_generic_tokens;
3973   ignore_sound_tokens =
3974     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
3975   for (i = 0; i < num_ignore_generic_tokens; i++)
3976     ignore_sound_tokens[i] = ignore_generic_tokens[i];
3977   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
3978
3979   /* dynamically determine list of music tokens to be ignored */
3980   num_ignore_music_tokens = num_ignore_generic_tokens;
3981   ignore_music_tokens =
3982     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
3983   for (i = 0; i < num_ignore_generic_tokens; i++)
3984     ignore_music_tokens[i] = ignore_generic_tokens[i];
3985   ignore_music_tokens[num_ignore_music_tokens] = NULL;
3986
3987   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3988     image_id_prefix[i] = element_info[i].token_name;
3989   for (i = 0; i < NUM_FONTS; i++)
3990     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
3991   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
3992
3993   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3994     sound_id_prefix[i] = element_info[i].token_name;
3995   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3996     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
3997       get_string_in_brackets(element_info[i].class_name);
3998   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
3999
4000   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4001     music_id_prefix[i] = music_prefix_info[i].prefix;
4002   music_id_prefix[MAX_LEVELS] = NULL;
4003
4004   for (i = 0; i < NUM_ACTIONS; i++)
4005     action_id_suffix[i] = element_action_info[i].suffix;
4006   action_id_suffix[NUM_ACTIONS] = NULL;
4007
4008   for (i = 0; i < NUM_DIRECTIONS; i++)
4009     direction_id_suffix[i] = element_direction_info[i].suffix;
4010   direction_id_suffix[NUM_DIRECTIONS] = NULL;
4011
4012   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4013     special_id_suffix[i] = special_suffix_info[i].suffix;
4014   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4015
4016   for (i = 0; i < MAX_LEVELS; i++)
4017     level_id_suffix[i] = get_level_id_suffix(i);
4018   level_id_suffix[MAX_LEVELS] = NULL;
4019
4020   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4021                 image_id_prefix, action_id_suffix, direction_id_suffix,
4022                 special_id_suffix, ignore_image_tokens);
4023   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4024                 sound_id_prefix, action_id_suffix, dummy,
4025                 special_id_suffix, ignore_sound_tokens);
4026   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4027                 music_id_prefix, special_id_suffix, level_id_suffix,
4028                 dummy, ignore_music_tokens);
4029 }
4030
4031 static void InitMixer()
4032 {
4033   OpenAudio();
4034   StartMixer();
4035 }
4036
4037 void InitGfx()
4038 {
4039   char *filename_font_initial = NULL;
4040   Bitmap *bitmap_font_initial = NULL;
4041   int i, j;
4042
4043   /* determine settings for initial font (for displaying startup messages) */
4044   for (i = 0; image_config[i].token != NULL; i++)
4045   {
4046     for (j = 0; j < NUM_INITIAL_FONTS; j++)
4047     {
4048       char font_token[128];
4049       int len_font_token;
4050
4051       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4052       len_font_token = strlen(font_token);
4053
4054       if (strcmp(image_config[i].token, font_token) == 0)
4055         filename_font_initial = image_config[i].value;
4056       else if (strlen(image_config[i].token) > len_font_token &&
4057                strncmp(image_config[i].token, font_token, len_font_token) == 0)
4058       {
4059         if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4060           font_initial[j].src_x = atoi(image_config[i].value);
4061         else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4062           font_initial[j].src_y = atoi(image_config[i].value);
4063         else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4064           font_initial[j].width = atoi(image_config[i].value);
4065         else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4066           font_initial[j].height = atoi(image_config[i].value);
4067       }
4068     }
4069   }
4070
4071   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4072   {
4073     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4074     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4075   }
4076
4077   if (filename_font_initial == NULL)    /* should not happen */
4078     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4079
4080   /* create additional image buffers for double-buffering */
4081   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4082   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4083
4084   /* initialize screen properties */
4085   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4086                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4087                    bitmap_db_field);
4088   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4089   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4090   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4091
4092   bitmap_font_initial = LoadCustomImage(filename_font_initial);
4093
4094   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4095     font_initial[j].bitmap = bitmap_font_initial;
4096
4097   InitFontGraphicInfo();
4098
4099   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4100   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4101
4102   DrawInitText("Loading graphics:", 120, FC_GREEN);
4103
4104   InitTileClipmasks();
4105 }
4106
4107 void InitGfxBackground()
4108 {
4109   int x, y;
4110
4111   drawto = backbuffer;
4112   fieldbuffer = bitmap_db_field;
4113   SetDrawtoField(DRAW_BACKBUFFER);
4114
4115   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4116              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4117   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4118   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4119
4120   for (x = 0; x < MAX_BUF_XSIZE; x++)
4121     for (y = 0; y < MAX_BUF_YSIZE; y++)
4122       redraw[x][y] = 0;
4123   redraw_tiles = 0;
4124   redraw_mask = REDRAW_ALL;
4125 }
4126
4127 static void InitLevelInfo()
4128 {
4129   LoadLevelInfo();                              /* global level info */
4130   LoadLevelSetup_LastSeries();                  /* last played series info */
4131   LoadLevelSetup_SeriesInfo();                  /* last played level info */
4132 }
4133
4134 void InitLevelArtworkInfo()
4135 {
4136   LoadLevelArtworkInfo();
4137 }
4138
4139 static void InitImages()
4140 {
4141 #if 1
4142   setLevelArtworkDir(artwork.gfx_first);
4143 #endif
4144
4145 #if 0
4146   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4147          leveldir_current->identifier,
4148          artwork.gfx_current_identifier,
4149          artwork.gfx_current->identifier,
4150          leveldir_current->graphics_set,
4151          leveldir_current->graphics_path);
4152 #endif
4153
4154   ReloadCustomImages();
4155
4156   LoadCustomElementDescriptions();
4157   LoadSpecialMenuDesignSettings();
4158
4159   ReinitializeGraphics();
4160 }
4161
4162 static void InitSound(char *identifier)
4163 {
4164   if (identifier == NULL)
4165     identifier = artwork.snd_current->identifier;
4166
4167 #if 1
4168   /* set artwork path to send it to the sound server process */
4169   setLevelArtworkDir(artwork.snd_first);
4170 #endif
4171
4172   InitReloadCustomSounds(identifier);
4173   ReinitializeSounds();
4174 }
4175
4176 static void InitMusic(char *identifier)
4177 {
4178   if (identifier == NULL)
4179     identifier = artwork.mus_current->identifier;
4180
4181 #if 1
4182   /* set artwork path to send it to the sound server process */
4183   setLevelArtworkDir(artwork.mus_first);
4184 #endif
4185
4186   InitReloadCustomMusic(identifier);
4187   ReinitializeMusic();
4188 }
4189
4190 void InitNetworkServer()
4191 {
4192 #if defined(NETWORK_AVALIABLE)
4193   int nr_wanted;
4194 #endif
4195
4196   if (!options.network)
4197     return;
4198
4199 #if defined(NETWORK_AVALIABLE)
4200   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4201
4202   if (!ConnectToServer(options.server_host, options.server_port))
4203     Error(ERR_EXIT, "cannot connect to network game server");
4204
4205   SendToServer_PlayerName(setup.player_name);
4206   SendToServer_ProtocolVersion();
4207
4208   if (nr_wanted)
4209     SendToServer_NrWanted(nr_wanted);
4210 #endif
4211 }
4212
4213 static char *getNewArtworkIdentifier(int type)
4214 {
4215   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4216   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4217   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4218   static boolean initialized[3] = { FALSE, FALSE, FALSE };
4219   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4220   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4221   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4222   char *leveldir_identifier = leveldir_current->identifier;
4223 #if 1
4224   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4225   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4226 #else
4227   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4228 #endif
4229   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4230   char *artwork_current_identifier;
4231   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
4232
4233   /* leveldir_current may be invalid (level group, parent link) */
4234   if (!validLevelSeries(leveldir_current))
4235     return NULL;
4236
4237   /* 1st step: determine artwork set to be activated in descending order:
4238      --------------------------------------------------------------------
4239      1. setup artwork (when configured to override everything else)
4240      2. artwork set configured in "levelinfo.conf" of current level set
4241         (artwork in level directory will have priority when loading later)
4242      3. artwork in level directory (stored in artwork sub-directory)
4243      4. setup artwork (currently configured in setup menu) */
4244
4245   if (setup_override_artwork)
4246     artwork_current_identifier = setup_artwork_set;
4247   else if (leveldir_artwork_set != NULL)
4248     artwork_current_identifier = leveldir_artwork_set;
4249   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4250     artwork_current_identifier = leveldir_identifier;
4251   else
4252     artwork_current_identifier = setup_artwork_set;
4253
4254
4255   /* 2nd step: check if it is really needed to reload artwork set
4256      ------------------------------------------------------------ */
4257
4258 #if 0
4259   if (type == ARTWORK_TYPE_GRAPHICS)
4260     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4261            artwork_new_identifier,
4262            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4263            artwork_current_identifier,
4264            leveldir_current->graphics_set,
4265            leveldir_current->identifier);
4266 #endif
4267
4268   /* ---------- reload if level set and also artwork set has changed ------- */
4269   if (leveldir_current_identifier[type] != leveldir_identifier &&
4270       (last_has_level_artwork_set[type] || has_level_artwork_set))
4271     artwork_new_identifier = artwork_current_identifier;
4272
4273   leveldir_current_identifier[type] = leveldir_identifier;
4274   last_has_level_artwork_set[type] = has_level_artwork_set;
4275
4276 #if 0
4277   if (type == ARTWORK_TYPE_GRAPHICS)
4278     printf("::: 1: '%s'\n", artwork_new_identifier);
4279 #endif
4280
4281   /* ---------- reload if "override artwork" setting has changed ----------- */
4282   if (last_override_level_artwork[type] != setup_override_artwork)
4283     artwork_new_identifier = artwork_current_identifier;
4284
4285   last_override_level_artwork[type] = setup_override_artwork;
4286
4287 #if 0
4288   if (type == ARTWORK_TYPE_GRAPHICS)
4289     printf("::: 2: '%s'\n", artwork_new_identifier);
4290 #endif
4291
4292   /* ---------- reload if current artwork identifier has changed ----------- */
4293   if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4294              artwork_current_identifier) != 0)
4295     artwork_new_identifier = artwork_current_identifier;
4296
4297   *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4298
4299 #if 0
4300   if (type == ARTWORK_TYPE_GRAPHICS)
4301     printf("::: 3: '%s'\n", artwork_new_identifier);
4302 #endif
4303
4304   /* ---------- do not reload directly after starting ---------------------- */
4305   if (!initialized[type])
4306     artwork_new_identifier = NULL;
4307
4308   initialized[type] = TRUE;
4309
4310 #if 0
4311   if (type == ARTWORK_TYPE_GRAPHICS)
4312     printf("::: 4: '%s'\n", artwork_new_identifier);
4313 #endif
4314
4315 #if 0
4316   if (type == ARTWORK_TYPE_GRAPHICS)
4317     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4318            artwork.gfx_current_identifier, artwork_current_identifier,
4319            artwork.gfx_current->identifier, leveldir_current->graphics_set,
4320            artwork_new_identifier);
4321 #endif
4322
4323   return artwork_new_identifier;
4324 }
4325
4326 void ReloadCustomArtwork(int force_reload)
4327 {
4328   char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4329   char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4330   char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4331   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4332   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4333   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4334   boolean redraw_screen = FALSE;
4335
4336   if (gfx_new_identifier != NULL || force_reload_gfx)
4337   {
4338 #if 0
4339     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4340            artwork.gfx_current_identifier,
4341            gfx_new_identifier,
4342            artwork.gfx_current->identifier,
4343            leveldir_current->graphics_set);
4344 #endif
4345
4346     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4347
4348     InitImages();
4349
4350 #if 0
4351     printf("... '%s'\n",
4352            leveldir_current->graphics_set);
4353 #endif
4354
4355     FreeTileClipmasks();
4356     InitTileClipmasks();
4357
4358     redraw_screen = TRUE;
4359   }
4360
4361   if (snd_new_identifier != NULL || force_reload_snd)
4362   {
4363     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4364
4365     InitSound(snd_new_identifier);
4366
4367     redraw_screen = TRUE;
4368   }
4369
4370   if (mus_new_identifier != NULL || force_reload_mus)
4371   {
4372     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4373
4374     InitMusic(mus_new_identifier);
4375
4376     redraw_screen = TRUE;
4377   }
4378
4379   if (redraw_screen)
4380   {
4381     InitGfxBackground();
4382
4383     /* force redraw of (open or closed) door graphics */
4384     SetDoorState(DOOR_OPEN_ALL);
4385     CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4386   }
4387 }
4388
4389 void KeyboardAutoRepeatOffUnlessAutoplay()
4390 {
4391   if (global.autoplay_leveldir == NULL)
4392     KeyboardAutoRepeatOff();
4393 }
4394
4395
4396 /* ========================================================================= */
4397 /* OpenAll()                                                                 */
4398 /* ========================================================================= */
4399
4400 void OpenAll()
4401 {
4402   InitGlobal();         /* initialize some global variables */
4403
4404   if (options.execute_command)
4405     Execute_Command(options.execute_command);
4406
4407   if (options.serveronly)
4408   {
4409 #if defined(PLATFORM_UNIX)
4410     NetworkServer(options.server_port, options.serveronly);
4411 #else
4412     Error(ERR_WARN, "networking only supported in Unix version");
4413 #endif
4414     exit(0);    /* never reached */
4415   }
4416
4417   InitSetup();
4418
4419   InitPlayerInfo();
4420   InitArtworkInfo();            /* needed before loading gfx, sound & music */
4421   InitArtworkConfig();          /* needed before forking sound child process */
4422   InitMixer();
4423
4424   InitCounter();
4425
4426   InitRND(NEW_RANDOMIZE);
4427   InitSimpleRND(NEW_RANDOMIZE);
4428
4429   InitJoysticks();
4430
4431   InitVideoDisplay();
4432   InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4433                   setup.fullscreen);
4434
4435   InitEventFilter(FilterMouseMotionEvents);
4436
4437   InitElementPropertiesStatic();
4438   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4439
4440   InitGfx();
4441
4442   InitLevelInfo();
4443   InitLevelArtworkInfo();
4444
4445   InitImages();                 /* needs to know current level directory */
4446   InitSound(NULL);              /* needs to know current level directory */
4447   InitMusic(NULL);              /* needs to know current level directory */
4448
4449   InitGfxBackground();
4450
4451   if (global.autoplay_leveldir)
4452   {
4453     AutoPlayTape();
4454     return;
4455   }
4456   else if (global.convert_leveldir)
4457   {
4458     ConvertLevels();
4459     return;
4460   }
4461
4462   game_status = GAME_MODE_MAIN;
4463
4464 #if 1
4465   em_open_all();
4466 #endif
4467
4468   DrawMainMenu();
4469
4470   InitNetworkServer();
4471 }
4472
4473 void CloseAllAndExit(int exit_value)
4474 {
4475   StopSounds();
4476   FreeAllSounds();
4477   FreeAllMusic();
4478   CloseAudio();         /* called after freeing sounds (needed for SDL) */
4479
4480 #if 1
4481   em_close_all();
4482 #endif
4483
4484   FreeAllImages();
4485   FreeTileClipmasks();
4486
4487 #if defined(TARGET_SDL)
4488   if (network_server)   /* terminate network server */
4489     SDL_KillThread(server_thread);
4490 #endif
4491
4492   CloseVideoDisplay();
4493   ClosePlatformDependentStuff();
4494
4495   exit(exit_value);
4496 }