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