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