dbecf851dd941b4d69dc4ed6b69375b5c9f944a9
[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     -1
2533   };
2534
2535   static int ep_walkable_inside[] =
2536   {
2537     EL_TUBE_ANY,
2538     EL_TUBE_VERTICAL,
2539     EL_TUBE_HORIZONTAL,
2540     EL_TUBE_VERTICAL_LEFT,
2541     EL_TUBE_VERTICAL_RIGHT,
2542     EL_TUBE_HORIZONTAL_UP,
2543     EL_TUBE_HORIZONTAL_DOWN,
2544     EL_TUBE_LEFT_UP,
2545     EL_TUBE_LEFT_DOWN,
2546     EL_TUBE_RIGHT_UP,
2547     EL_TUBE_RIGHT_DOWN,
2548     -1
2549   };
2550
2551   static int ep_walkable_under[] =
2552   {
2553     -1
2554   };
2555
2556   static int ep_passable_over[] =
2557   {
2558     EL_EM_GATE_1,
2559     EL_EM_GATE_2,
2560     EL_EM_GATE_3,
2561     EL_EM_GATE_4,
2562     EL_EM_GATE_1_GRAY,
2563     EL_EM_GATE_2_GRAY,
2564     EL_EM_GATE_3_GRAY,
2565     EL_EM_GATE_4_GRAY,
2566     EL_EMC_GATE_5,
2567     EL_EMC_GATE_6,
2568     EL_EMC_GATE_7,
2569     EL_EMC_GATE_8,
2570     EL_EMC_GATE_5_GRAY,
2571     EL_EMC_GATE_6_GRAY,
2572     EL_EMC_GATE_7_GRAY,
2573     EL_EMC_GATE_8_GRAY,
2574     EL_SWITCHGATE_OPEN,
2575     EL_TIMEGATE_OPEN,
2576     -1
2577   };
2578
2579   static int ep_passable_inside[] =
2580   {
2581     EL_SP_PORT_LEFT,
2582     EL_SP_PORT_RIGHT,
2583     EL_SP_PORT_UP,
2584     EL_SP_PORT_DOWN,
2585     EL_SP_PORT_HORIZONTAL,
2586     EL_SP_PORT_VERTICAL,
2587     EL_SP_PORT_ANY,
2588     EL_SP_GRAVITY_PORT_LEFT,
2589     EL_SP_GRAVITY_PORT_RIGHT,
2590     EL_SP_GRAVITY_PORT_UP,
2591     EL_SP_GRAVITY_PORT_DOWN,
2592     EL_SP_GRAVITY_ON_PORT_LEFT,
2593     EL_SP_GRAVITY_ON_PORT_RIGHT,
2594     EL_SP_GRAVITY_ON_PORT_UP,
2595     EL_SP_GRAVITY_ON_PORT_DOWN,
2596     EL_SP_GRAVITY_OFF_PORT_LEFT,
2597     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2598     EL_SP_GRAVITY_OFF_PORT_UP,
2599     EL_SP_GRAVITY_OFF_PORT_DOWN,
2600     -1
2601   };
2602
2603   static int ep_passable_under[] =
2604   {
2605     -1
2606   };
2607
2608   static int ep_droppable[] =
2609   {
2610     -1
2611   };
2612
2613   static int ep_explodes_1x1_old[] =
2614   {
2615     -1
2616   };
2617
2618   static int ep_pushable[] =
2619   {
2620     EL_ROCK,
2621     EL_BOMB,
2622     EL_DX_SUPABOMB,
2623     EL_NUT,
2624     EL_TIME_ORB_EMPTY,
2625     EL_SP_ZONK,
2626     EL_SP_DISK_ORANGE,
2627     EL_SPRING,
2628     EL_BD_ROCK,
2629     EL_SOKOBAN_OBJECT,
2630     EL_SOKOBAN_FIELD_FULL,
2631     EL_SATELLITE,
2632     EL_SP_DISK_YELLOW,
2633     EL_BALLOON,
2634     EL_EMC_ANDROID,
2635     -1
2636   };
2637
2638   static int ep_explodes_cross_old[] =
2639   {
2640     -1
2641   };
2642
2643   static int ep_protected[] =
2644   {
2645     /* same elements as in 'ep_walkable_inside' */
2646     EL_TUBE_ANY,
2647     EL_TUBE_VERTICAL,
2648     EL_TUBE_HORIZONTAL,
2649     EL_TUBE_VERTICAL_LEFT,
2650     EL_TUBE_VERTICAL_RIGHT,
2651     EL_TUBE_HORIZONTAL_UP,
2652     EL_TUBE_HORIZONTAL_DOWN,
2653     EL_TUBE_LEFT_UP,
2654     EL_TUBE_LEFT_DOWN,
2655     EL_TUBE_RIGHT_UP,
2656     EL_TUBE_RIGHT_DOWN,
2657
2658     /* same elements as in 'ep_passable_over' */
2659     EL_EM_GATE_1,
2660     EL_EM_GATE_2,
2661     EL_EM_GATE_3,
2662     EL_EM_GATE_4,
2663     EL_EM_GATE_1_GRAY,
2664     EL_EM_GATE_2_GRAY,
2665     EL_EM_GATE_3_GRAY,
2666     EL_EM_GATE_4_GRAY,
2667     EL_EMC_GATE_5,
2668     EL_EMC_GATE_6,
2669     EL_EMC_GATE_7,
2670     EL_EMC_GATE_8,
2671     EL_EMC_GATE_5_GRAY,
2672     EL_EMC_GATE_6_GRAY,
2673     EL_EMC_GATE_7_GRAY,
2674     EL_EMC_GATE_8_GRAY,
2675     EL_SWITCHGATE_OPEN,
2676     EL_TIMEGATE_OPEN,
2677
2678     /* same elements as in 'ep_passable_inside' */
2679     EL_SP_PORT_LEFT,
2680     EL_SP_PORT_RIGHT,
2681     EL_SP_PORT_UP,
2682     EL_SP_PORT_DOWN,
2683     EL_SP_PORT_HORIZONTAL,
2684     EL_SP_PORT_VERTICAL,
2685     EL_SP_PORT_ANY,
2686     EL_SP_GRAVITY_PORT_LEFT,
2687     EL_SP_GRAVITY_PORT_RIGHT,
2688     EL_SP_GRAVITY_PORT_UP,
2689     EL_SP_GRAVITY_PORT_DOWN,
2690     EL_SP_GRAVITY_ON_PORT_LEFT,
2691     EL_SP_GRAVITY_ON_PORT_RIGHT,
2692     EL_SP_GRAVITY_ON_PORT_UP,
2693     EL_SP_GRAVITY_ON_PORT_DOWN,
2694     EL_SP_GRAVITY_OFF_PORT_LEFT,
2695     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2696     EL_SP_GRAVITY_OFF_PORT_UP,
2697     EL_SP_GRAVITY_OFF_PORT_DOWN,
2698     -1
2699   };
2700
2701   static int ep_throwable[] =
2702   {
2703     -1
2704   };
2705
2706   static int ep_can_explode[] =
2707   {
2708     /* same elements as in 'ep_explodes_impact' */
2709     EL_BOMB,
2710     EL_SP_DISK_ORANGE,
2711     EL_DX_SUPABOMB,
2712
2713     /* same elements as in 'ep_explodes_smashed' */
2714     EL_SATELLITE,
2715     EL_PIG,
2716     EL_DRAGON,
2717     EL_MOLE,
2718
2719     /* elements that can explode by explosion or by dragonfire */
2720     EL_DYNAMITE_ACTIVE,
2721     EL_DYNAMITE,
2722     EL_DYNABOMB_PLAYER_1_ACTIVE,
2723     EL_DYNABOMB_PLAYER_2_ACTIVE,
2724     EL_DYNABOMB_PLAYER_3_ACTIVE,
2725     EL_DYNABOMB_PLAYER_4_ACTIVE,
2726     EL_DYNABOMB_INCREASE_NUMBER,
2727     EL_DYNABOMB_INCREASE_SIZE,
2728     EL_DYNABOMB_INCREASE_POWER,
2729     EL_SP_DISK_RED_ACTIVE,
2730     EL_BUG,
2731     EL_PENGUIN,
2732     EL_SP_DISK_RED,
2733     EL_SP_DISK_YELLOW,
2734     EL_SP_SNIKSNAK,
2735     EL_SP_ELECTRON,
2736
2737     /* elements that can explode only by explosion */
2738     EL_BLACK_ORB,
2739     -1
2740   };
2741
2742   static int ep_gravity_reachable[] =
2743   {
2744     EL_SAND,
2745     EL_SP_BASE,
2746     EL_TRAP,
2747     EL_INVISIBLE_SAND,
2748     EL_INVISIBLE_SAND_ACTIVE,
2749     EL_SP_PORT_LEFT,
2750     EL_SP_PORT_RIGHT,
2751     EL_SP_PORT_UP,
2752     EL_SP_PORT_DOWN,
2753     EL_SP_PORT_HORIZONTAL,
2754     EL_SP_PORT_VERTICAL,
2755     EL_SP_PORT_ANY,
2756     EL_SP_GRAVITY_PORT_LEFT,
2757     EL_SP_GRAVITY_PORT_RIGHT,
2758     EL_SP_GRAVITY_PORT_UP,
2759     EL_SP_GRAVITY_PORT_DOWN,
2760     EL_SP_GRAVITY_ON_PORT_LEFT,
2761     EL_SP_GRAVITY_ON_PORT_RIGHT,
2762     EL_SP_GRAVITY_ON_PORT_UP,
2763     EL_SP_GRAVITY_ON_PORT_DOWN,
2764     EL_SP_GRAVITY_OFF_PORT_LEFT,
2765     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2766     EL_SP_GRAVITY_OFF_PORT_UP,
2767     EL_SP_GRAVITY_OFF_PORT_DOWN,
2768     EL_EMC_GRASS,
2769     -1
2770   };
2771
2772   static int ep_player[] =
2773   {
2774     EL_PLAYER_1,
2775     EL_PLAYER_2,
2776     EL_PLAYER_3,
2777     EL_PLAYER_4,
2778     EL_SP_MURPHY,
2779     EL_SOKOBAN_FIELD_PLAYER,
2780     EL_TRIGGER_PLAYER,
2781     -1
2782   };
2783
2784   static int ep_can_pass_magic_wall[] =
2785   {
2786     EL_ROCK,
2787     EL_BD_ROCK,
2788     EL_EMERALD,
2789     EL_BD_DIAMOND,
2790     EL_EMERALD_YELLOW,
2791     EL_EMERALD_RED,
2792     EL_EMERALD_PURPLE,
2793     EL_DIAMOND,
2794     -1
2795   };
2796
2797   static int ep_switchable[] =
2798   {
2799     EL_ROBOT_WHEEL,
2800     EL_SP_TERMINAL,
2801     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2802     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2803     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2804     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2805     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2806     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2807     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2808     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2809     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2810     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2811     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2812     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2813     EL_SWITCHGATE_SWITCH_UP,
2814     EL_SWITCHGATE_SWITCH_DOWN,
2815     EL_LIGHT_SWITCH,
2816     EL_LIGHT_SWITCH_ACTIVE,
2817     EL_TIMEGATE_SWITCH,
2818     EL_BALLOON_SWITCH_LEFT,
2819     EL_BALLOON_SWITCH_RIGHT,
2820     EL_BALLOON_SWITCH_UP,
2821     EL_BALLOON_SWITCH_DOWN,
2822     EL_BALLOON_SWITCH_ANY,
2823     EL_LAMP,
2824     EL_TIME_ORB_FULL,
2825     EL_EMC_MAGIC_BALL_SWITCH,
2826     -1
2827   };
2828
2829   static int ep_bd_element[] =
2830   {
2831     EL_EMPTY,
2832     EL_SAND,
2833     EL_WALL_SLIPPERY,
2834     EL_BD_WALL,
2835     EL_ROCK,
2836     EL_BD_ROCK,
2837     EL_BD_DIAMOND,
2838     EL_BD_MAGIC_WALL,
2839     EL_EXIT_CLOSED,
2840     EL_EXIT_OPEN,
2841     EL_STEELWALL,
2842     EL_PLAYER_1,
2843     EL_PLAYER_2,
2844     EL_PLAYER_3,
2845     EL_PLAYER_4,
2846     EL_BD_FIREFLY,
2847     EL_BD_FIREFLY_1,
2848     EL_BD_FIREFLY_2,
2849     EL_BD_FIREFLY_3,
2850     EL_BD_FIREFLY_4,
2851     EL_BD_BUTTERFLY,
2852     EL_BD_BUTTERFLY_1,
2853     EL_BD_BUTTERFLY_2,
2854     EL_BD_BUTTERFLY_3,
2855     EL_BD_BUTTERFLY_4,
2856     EL_BD_AMOEBA,
2857     EL_CHAR_QUESTION,
2858     EL_UNKNOWN,
2859     -1
2860   };
2861
2862   static int ep_sp_element[] =
2863   {
2864     /* should always be valid */
2865     EL_EMPTY,
2866
2867     /* standard classic Supaplex elements */
2868     EL_SP_EMPTY,
2869     EL_SP_ZONK,
2870     EL_SP_BASE,
2871     EL_SP_MURPHY,
2872     EL_SP_INFOTRON,
2873     EL_SP_CHIP_SINGLE,
2874     EL_SP_HARDWARE_GRAY,
2875     EL_SP_EXIT_CLOSED,
2876     EL_SP_EXIT_OPEN,
2877     EL_SP_DISK_ORANGE,
2878     EL_SP_PORT_RIGHT,
2879     EL_SP_PORT_DOWN,
2880     EL_SP_PORT_LEFT,
2881     EL_SP_PORT_UP,
2882     EL_SP_GRAVITY_PORT_RIGHT,
2883     EL_SP_GRAVITY_PORT_DOWN,
2884     EL_SP_GRAVITY_PORT_LEFT,
2885     EL_SP_GRAVITY_PORT_UP,
2886     EL_SP_SNIKSNAK,
2887     EL_SP_DISK_YELLOW,
2888     EL_SP_TERMINAL,
2889     EL_SP_DISK_RED,
2890     EL_SP_PORT_VERTICAL,
2891     EL_SP_PORT_HORIZONTAL,
2892     EL_SP_PORT_ANY,
2893     EL_SP_ELECTRON,
2894     EL_SP_BUGGY_BASE,
2895     EL_SP_CHIP_LEFT,
2896     EL_SP_CHIP_RIGHT,
2897     EL_SP_HARDWARE_BASE_1,
2898     EL_SP_HARDWARE_GREEN,
2899     EL_SP_HARDWARE_BLUE,
2900     EL_SP_HARDWARE_RED,
2901     EL_SP_HARDWARE_YELLOW,
2902     EL_SP_HARDWARE_BASE_2,
2903     EL_SP_HARDWARE_BASE_3,
2904     EL_SP_HARDWARE_BASE_4,
2905     EL_SP_HARDWARE_BASE_5,
2906     EL_SP_HARDWARE_BASE_6,
2907     EL_SP_CHIP_TOP,
2908     EL_SP_CHIP_BOTTOM,
2909
2910     /* additional elements that appeared in newer Supaplex levels */
2911     EL_INVISIBLE_WALL,
2912
2913     /* additional gravity port elements (not switching, but setting gravity) */
2914     EL_SP_GRAVITY_ON_PORT_LEFT,
2915     EL_SP_GRAVITY_ON_PORT_RIGHT,
2916     EL_SP_GRAVITY_ON_PORT_UP,
2917     EL_SP_GRAVITY_ON_PORT_DOWN,
2918     EL_SP_GRAVITY_OFF_PORT_LEFT,
2919     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2920     EL_SP_GRAVITY_OFF_PORT_UP,
2921     EL_SP_GRAVITY_OFF_PORT_DOWN,
2922
2923     /* more than one Murphy in a level results in an inactive clone */
2924     EL_SP_MURPHY_CLONE,
2925
2926     /* runtime Supaplex elements */
2927     EL_SP_DISK_RED_ACTIVE,
2928     EL_SP_TERMINAL_ACTIVE,
2929     EL_SP_BUGGY_BASE_ACTIVATING,
2930     EL_SP_BUGGY_BASE_ACTIVE,
2931     EL_SP_EXIT_OPENING,
2932     EL_SP_EXIT_CLOSING,
2933     -1
2934   };
2935
2936   static int ep_sb_element[] =
2937   {
2938     EL_EMPTY,
2939     EL_STEELWALL,
2940     EL_SOKOBAN_OBJECT,
2941     EL_SOKOBAN_FIELD_EMPTY,
2942     EL_SOKOBAN_FIELD_FULL,
2943     EL_SOKOBAN_FIELD_PLAYER,
2944     EL_PLAYER_1,
2945     EL_PLAYER_2,
2946     EL_PLAYER_3,
2947     EL_PLAYER_4,
2948     EL_INVISIBLE_STEELWALL,
2949     -1
2950   };
2951
2952   static int ep_gem[] =
2953   {
2954     EL_BD_DIAMOND,
2955     EL_EMERALD,
2956     EL_EMERALD_YELLOW,
2957     EL_EMERALD_RED,
2958     EL_EMERALD_PURPLE,
2959     EL_DIAMOND,
2960     -1
2961   };
2962
2963   static int ep_food_dark_yamyam[] =
2964   {
2965     EL_SAND,
2966     EL_BUG,
2967     EL_SPACESHIP,
2968     EL_BD_BUTTERFLY,
2969     EL_BD_FIREFLY,
2970     EL_YAMYAM,
2971     EL_ROBOT,
2972     EL_PACMAN,
2973     EL_AMOEBA_DROP,
2974     EL_AMOEBA_DEAD,
2975     EL_AMOEBA_WET,
2976     EL_AMOEBA_DRY,
2977     EL_AMOEBA_FULL,
2978     EL_BD_AMOEBA,
2979     EL_EMERALD,
2980     EL_BD_DIAMOND,
2981     EL_EMERALD_YELLOW,
2982     EL_EMERALD_RED,
2983     EL_EMERALD_PURPLE,
2984     EL_DIAMOND,
2985     EL_PEARL,
2986     EL_CRYSTAL,
2987     -1
2988   };
2989
2990   static int ep_food_penguin[] =
2991   {
2992     EL_EMERALD,
2993     EL_BD_DIAMOND,
2994     EL_EMERALD_YELLOW,
2995     EL_EMERALD_RED,
2996     EL_EMERALD_PURPLE,
2997     EL_DIAMOND,
2998     EL_PEARL,
2999     EL_CRYSTAL,
3000     -1
3001   };
3002
3003   static int ep_food_pig[] =
3004   {
3005     EL_EMERALD,
3006     EL_BD_DIAMOND,
3007     EL_EMERALD_YELLOW,
3008     EL_EMERALD_RED,
3009     EL_EMERALD_PURPLE,
3010     EL_DIAMOND,
3011     -1
3012   };
3013
3014   static int ep_historic_wall[] =
3015   {
3016     EL_STEELWALL,
3017     EL_GATE_1,
3018     EL_GATE_2,
3019     EL_GATE_3,
3020     EL_GATE_4,
3021     EL_GATE_1_GRAY,
3022     EL_GATE_2_GRAY,
3023     EL_GATE_3_GRAY,
3024     EL_GATE_4_GRAY,
3025     EL_EM_GATE_1,
3026     EL_EM_GATE_2,
3027     EL_EM_GATE_3,
3028     EL_EM_GATE_4,
3029     EL_EM_GATE_1_GRAY,
3030     EL_EM_GATE_2_GRAY,
3031     EL_EM_GATE_3_GRAY,
3032     EL_EM_GATE_4_GRAY,
3033     EL_EXIT_CLOSED,
3034     EL_EXIT_OPENING,
3035     EL_EXIT_OPEN,
3036     EL_WALL,
3037     EL_WALL_SLIPPERY,
3038     EL_EXPANDABLE_WALL,
3039     EL_EXPANDABLE_WALL_HORIZONTAL,
3040     EL_EXPANDABLE_WALL_VERTICAL,
3041     EL_EXPANDABLE_WALL_ANY,
3042     EL_EXPANDABLE_WALL_GROWING,
3043     EL_BD_WALL,
3044     EL_SP_CHIP_SINGLE,
3045     EL_SP_CHIP_LEFT,
3046     EL_SP_CHIP_RIGHT,
3047     EL_SP_CHIP_TOP,
3048     EL_SP_CHIP_BOTTOM,
3049     EL_SP_HARDWARE_GRAY,
3050     EL_SP_HARDWARE_GREEN,
3051     EL_SP_HARDWARE_BLUE,
3052     EL_SP_HARDWARE_RED,
3053     EL_SP_HARDWARE_YELLOW,
3054     EL_SP_HARDWARE_BASE_1,
3055     EL_SP_HARDWARE_BASE_2,
3056     EL_SP_HARDWARE_BASE_3,
3057     EL_SP_HARDWARE_BASE_4,
3058     EL_SP_HARDWARE_BASE_5,
3059     EL_SP_HARDWARE_BASE_6,
3060     EL_SP_TERMINAL,
3061     EL_SP_TERMINAL_ACTIVE,
3062     EL_SP_EXIT_CLOSED,
3063     EL_SP_EXIT_OPEN,
3064     EL_INVISIBLE_STEELWALL,
3065     EL_INVISIBLE_STEELWALL_ACTIVE,
3066     EL_INVISIBLE_WALL,
3067     EL_INVISIBLE_WALL_ACTIVE,
3068     EL_STEELWALL_SLIPPERY,
3069     EL_EMC_STEELWALL_1,
3070     EL_EMC_STEELWALL_2,
3071     EL_EMC_STEELWALL_3,
3072     EL_EMC_STEELWALL_4,
3073     EL_EMC_WALL_1,
3074     EL_EMC_WALL_2,
3075     EL_EMC_WALL_3,
3076     EL_EMC_WALL_4,
3077     EL_EMC_WALL_5,
3078     EL_EMC_WALL_6,
3079     EL_EMC_WALL_7,
3080     EL_EMC_WALL_8,
3081     -1
3082   };
3083
3084   static int ep_historic_solid[] =
3085   {
3086     EL_WALL,
3087     EL_EXPANDABLE_WALL,
3088     EL_EXPANDABLE_WALL_HORIZONTAL,
3089     EL_EXPANDABLE_WALL_VERTICAL,
3090     EL_EXPANDABLE_WALL_ANY,
3091     EL_BD_WALL,
3092     EL_WALL_SLIPPERY,
3093     EL_EXIT_CLOSED,
3094     EL_EXIT_OPENING,
3095     EL_EXIT_OPEN,
3096     EL_AMOEBA_DEAD,
3097     EL_AMOEBA_WET,
3098     EL_AMOEBA_DRY,
3099     EL_AMOEBA_FULL,
3100     EL_BD_AMOEBA,
3101     EL_QUICKSAND_EMPTY,
3102     EL_QUICKSAND_FULL,
3103     EL_QUICKSAND_FILLING,
3104     EL_QUICKSAND_EMPTYING,
3105     EL_MAGIC_WALL,
3106     EL_MAGIC_WALL_ACTIVE,
3107     EL_MAGIC_WALL_EMPTYING,
3108     EL_MAGIC_WALL_FILLING,
3109     EL_MAGIC_WALL_FULL,
3110     EL_MAGIC_WALL_DEAD,
3111     EL_BD_MAGIC_WALL,
3112     EL_BD_MAGIC_WALL_ACTIVE,
3113     EL_BD_MAGIC_WALL_EMPTYING,
3114     EL_BD_MAGIC_WALL_FULL,
3115     EL_BD_MAGIC_WALL_FILLING,
3116     EL_BD_MAGIC_WALL_DEAD,
3117     EL_GAME_OF_LIFE,
3118     EL_BIOMAZE,
3119     EL_SP_CHIP_SINGLE,
3120     EL_SP_CHIP_LEFT,
3121     EL_SP_CHIP_RIGHT,
3122     EL_SP_CHIP_TOP,
3123     EL_SP_CHIP_BOTTOM,
3124     EL_SP_TERMINAL,
3125     EL_SP_TERMINAL_ACTIVE,
3126     EL_SP_EXIT_CLOSED,
3127     EL_SP_EXIT_OPEN,
3128     EL_INVISIBLE_WALL,
3129     EL_INVISIBLE_WALL_ACTIVE,
3130     EL_SWITCHGATE_SWITCH_UP,
3131     EL_SWITCHGATE_SWITCH_DOWN,
3132     EL_TIMEGATE_SWITCH,
3133     EL_TIMEGATE_SWITCH_ACTIVE,
3134     EL_EMC_WALL_1,
3135     EL_EMC_WALL_2,
3136     EL_EMC_WALL_3,
3137     EL_EMC_WALL_4,
3138     EL_EMC_WALL_5,
3139     EL_EMC_WALL_6,
3140     EL_EMC_WALL_7,
3141     EL_EMC_WALL_8,
3142     EL_WALL_PEARL,
3143     EL_WALL_CRYSTAL,
3144
3145     /* the following elements are a direct copy of "indestructible" elements,
3146        except "EL_ACID", which is "indestructible", but not "solid"! */
3147 #if 0
3148     EL_ACID,
3149 #endif
3150     EL_STEELWALL,
3151     EL_ACID_POOL_TOPLEFT,
3152     EL_ACID_POOL_TOPRIGHT,
3153     EL_ACID_POOL_BOTTOMLEFT,
3154     EL_ACID_POOL_BOTTOM,
3155     EL_ACID_POOL_BOTTOMRIGHT,
3156     EL_SP_HARDWARE_GRAY,
3157     EL_SP_HARDWARE_GREEN,
3158     EL_SP_HARDWARE_BLUE,
3159     EL_SP_HARDWARE_RED,
3160     EL_SP_HARDWARE_YELLOW,
3161     EL_SP_HARDWARE_BASE_1,
3162     EL_SP_HARDWARE_BASE_2,
3163     EL_SP_HARDWARE_BASE_3,
3164     EL_SP_HARDWARE_BASE_4,
3165     EL_SP_HARDWARE_BASE_5,
3166     EL_SP_HARDWARE_BASE_6,
3167     EL_INVISIBLE_STEELWALL,
3168     EL_INVISIBLE_STEELWALL_ACTIVE,
3169     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3170     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3171     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3172     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3173     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3174     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3175     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3176     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3177     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3178     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3179     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3180     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3181     EL_LIGHT_SWITCH,
3182     EL_LIGHT_SWITCH_ACTIVE,
3183     EL_SIGN_EXCLAMATION,
3184     EL_SIGN_RADIOACTIVITY,
3185     EL_SIGN_STOP,
3186     EL_SIGN_WHEELCHAIR,
3187     EL_SIGN_PARKING,
3188     EL_SIGN_ONEWAY,
3189     EL_SIGN_HEART,
3190     EL_SIGN_TRIANGLE,
3191     EL_SIGN_ROUND,
3192     EL_SIGN_EXIT,
3193     EL_SIGN_YINYANG,
3194     EL_SIGN_OTHER,
3195     EL_STEELWALL_SLIPPERY,
3196     EL_EMC_STEELWALL_1,
3197     EL_EMC_STEELWALL_2,
3198     EL_EMC_STEELWALL_3,
3199     EL_EMC_STEELWALL_4,
3200     EL_CRYSTAL,
3201     EL_GATE_1,
3202     EL_GATE_2,
3203     EL_GATE_3,
3204     EL_GATE_4,
3205     EL_GATE_1_GRAY,
3206     EL_GATE_2_GRAY,
3207     EL_GATE_3_GRAY,
3208     EL_GATE_4_GRAY,
3209     EL_EM_GATE_1,
3210     EL_EM_GATE_2,
3211     EL_EM_GATE_3,
3212     EL_EM_GATE_4,
3213     EL_EM_GATE_1_GRAY,
3214     EL_EM_GATE_2_GRAY,
3215     EL_EM_GATE_3_GRAY,
3216     EL_EM_GATE_4_GRAY,
3217     EL_SWITCHGATE_OPEN,
3218     EL_SWITCHGATE_OPENING,
3219     EL_SWITCHGATE_CLOSED,
3220     EL_SWITCHGATE_CLOSING,
3221     EL_TIMEGATE_OPEN,
3222     EL_TIMEGATE_OPENING,
3223     EL_TIMEGATE_CLOSED,
3224     EL_TIMEGATE_CLOSING,
3225     EL_TUBE_ANY,
3226     EL_TUBE_VERTICAL,
3227     EL_TUBE_HORIZONTAL,
3228     EL_TUBE_VERTICAL_LEFT,
3229     EL_TUBE_VERTICAL_RIGHT,
3230     EL_TUBE_HORIZONTAL_UP,
3231     EL_TUBE_HORIZONTAL_DOWN,
3232     EL_TUBE_LEFT_UP,
3233     EL_TUBE_LEFT_DOWN,
3234     EL_TUBE_RIGHT_UP,
3235     EL_TUBE_RIGHT_DOWN,
3236     -1
3237   };
3238
3239   static int ep_classic_enemy[] =
3240   {
3241     EL_BUG,
3242     EL_SPACESHIP,
3243     EL_BD_BUTTERFLY,
3244     EL_BD_FIREFLY,
3245
3246     EL_YAMYAM,
3247     EL_DARK_YAMYAM,
3248     EL_ROBOT,
3249     EL_PACMAN,
3250     EL_SP_SNIKSNAK,
3251     EL_SP_ELECTRON,
3252     -1
3253   };
3254
3255   static int ep_belt[] =
3256   {
3257     EL_CONVEYOR_BELT_1_LEFT,
3258     EL_CONVEYOR_BELT_1_MIDDLE,
3259     EL_CONVEYOR_BELT_1_RIGHT,
3260     EL_CONVEYOR_BELT_2_LEFT,
3261     EL_CONVEYOR_BELT_2_MIDDLE,
3262     EL_CONVEYOR_BELT_2_RIGHT,
3263     EL_CONVEYOR_BELT_3_LEFT,
3264     EL_CONVEYOR_BELT_3_MIDDLE,
3265     EL_CONVEYOR_BELT_3_RIGHT,
3266     EL_CONVEYOR_BELT_4_LEFT,
3267     EL_CONVEYOR_BELT_4_MIDDLE,
3268     EL_CONVEYOR_BELT_4_RIGHT,
3269     -1
3270   };
3271
3272   static int ep_belt_active[] =
3273   {
3274     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3275     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3276     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3277     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3278     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3279     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3280     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3281     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3282     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3283     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3284     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3285     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3286     -1
3287   };
3288
3289   static int ep_belt_switch[] =
3290   {
3291     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3292     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3293     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3294     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3295     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3296     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3297     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3298     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3299     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3300     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3301     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3302     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3303     -1
3304   };
3305
3306   static int ep_tube[] =
3307   {
3308     EL_TUBE_LEFT_UP,
3309     EL_TUBE_LEFT_DOWN,
3310     EL_TUBE_RIGHT_UP,
3311     EL_TUBE_RIGHT_DOWN,
3312     EL_TUBE_HORIZONTAL,
3313     EL_TUBE_HORIZONTAL_UP,
3314     EL_TUBE_HORIZONTAL_DOWN,
3315     EL_TUBE_VERTICAL,
3316     EL_TUBE_VERTICAL_LEFT,
3317     EL_TUBE_VERTICAL_RIGHT,
3318     EL_TUBE_ANY,
3319     -1
3320   };
3321
3322   static int ep_keygate[] =
3323   {
3324     EL_GATE_1,
3325     EL_GATE_2,
3326     EL_GATE_3,
3327     EL_GATE_4,
3328     EL_GATE_1_GRAY,
3329     EL_GATE_2_GRAY,
3330     EL_GATE_3_GRAY,
3331     EL_GATE_4_GRAY,
3332     EL_EM_GATE_1,
3333     EL_EM_GATE_2,
3334     EL_EM_GATE_3,
3335     EL_EM_GATE_4,
3336     EL_EM_GATE_1_GRAY,
3337     EL_EM_GATE_2_GRAY,
3338     EL_EM_GATE_3_GRAY,
3339     EL_EM_GATE_4_GRAY,
3340     EL_EMC_GATE_5,
3341     EL_EMC_GATE_6,
3342     EL_EMC_GATE_7,
3343     EL_EMC_GATE_8,
3344     EL_EMC_GATE_5_GRAY,
3345     EL_EMC_GATE_6_GRAY,
3346     EL_EMC_GATE_7_GRAY,
3347     EL_EMC_GATE_8_GRAY,
3348     -1
3349   };
3350
3351   static int ep_amoeboid[] =
3352   {
3353     EL_AMOEBA_DEAD,
3354     EL_AMOEBA_WET,
3355     EL_AMOEBA_DRY,
3356     EL_AMOEBA_FULL,
3357     EL_BD_AMOEBA,
3358     -1
3359   };
3360
3361   static int ep_amoebalive[] =
3362   {
3363     EL_AMOEBA_WET,
3364     EL_AMOEBA_DRY,
3365     EL_AMOEBA_FULL,
3366     EL_BD_AMOEBA,
3367     -1
3368   };
3369
3370   static int ep_has_content[] =
3371   {
3372     EL_YAMYAM,
3373     EL_AMOEBA_WET,
3374     EL_AMOEBA_DRY,
3375     EL_AMOEBA_FULL,
3376     EL_BD_AMOEBA,
3377     -1
3378   };
3379
3380   static int ep_can_turn_each_move[] =
3381   {
3382     /* !!! do something with this one !!! */
3383     -1
3384   };
3385
3386   static int ep_can_grow[] =
3387   {
3388     EL_BD_AMOEBA,
3389     EL_AMOEBA_DROP,
3390     EL_AMOEBA_WET,
3391     EL_AMOEBA_DRY,
3392     EL_AMOEBA_FULL,
3393     EL_GAME_OF_LIFE,
3394     EL_BIOMAZE,
3395     -1
3396   };
3397
3398   static int ep_active_bomb[] =
3399   {
3400     EL_DYNAMITE_ACTIVE,
3401     EL_DYNABOMB_PLAYER_1_ACTIVE,
3402     EL_DYNABOMB_PLAYER_2_ACTIVE,
3403     EL_DYNABOMB_PLAYER_3_ACTIVE,
3404     EL_DYNABOMB_PLAYER_4_ACTIVE,
3405     EL_SP_DISK_RED_ACTIVE,
3406     -1
3407   };
3408
3409   static int ep_inactive[] =
3410   {
3411     EL_EMPTY,
3412     EL_SAND,
3413     EL_WALL,
3414     EL_BD_WALL,
3415     EL_WALL_SLIPPERY,
3416     EL_STEELWALL,
3417     EL_AMOEBA_DEAD,
3418     EL_QUICKSAND_EMPTY,
3419     EL_STONEBLOCK,
3420     EL_ROBOT_WHEEL,
3421     EL_KEY_1,
3422     EL_KEY_2,
3423     EL_KEY_3,
3424     EL_KEY_4,
3425     EL_EM_KEY_1,
3426     EL_EM_KEY_2,
3427     EL_EM_KEY_3,
3428     EL_EM_KEY_4,
3429     EL_EMC_KEY_5,
3430     EL_EMC_KEY_6,
3431     EL_EMC_KEY_7,
3432     EL_EMC_KEY_8,
3433     EL_GATE_1,
3434     EL_GATE_2,
3435     EL_GATE_3,
3436     EL_GATE_4,
3437     EL_GATE_1_GRAY,
3438     EL_GATE_2_GRAY,
3439     EL_GATE_3_GRAY,
3440     EL_GATE_4_GRAY,
3441     EL_EM_GATE_1,
3442     EL_EM_GATE_2,
3443     EL_EM_GATE_3,
3444     EL_EM_GATE_4,
3445     EL_EM_GATE_1_GRAY,
3446     EL_EM_GATE_2_GRAY,
3447     EL_EM_GATE_3_GRAY,
3448     EL_EM_GATE_4_GRAY,
3449     EL_EMC_GATE_5,
3450     EL_EMC_GATE_6,
3451     EL_EMC_GATE_7,
3452     EL_EMC_GATE_8,
3453     EL_EMC_GATE_5_GRAY,
3454     EL_EMC_GATE_6_GRAY,
3455     EL_EMC_GATE_7_GRAY,
3456     EL_EMC_GATE_8_GRAY,
3457     EL_DYNAMITE,
3458     EL_INVISIBLE_STEELWALL,
3459     EL_INVISIBLE_WALL,
3460     EL_INVISIBLE_SAND,
3461     EL_LAMP,
3462     EL_LAMP_ACTIVE,
3463     EL_WALL_EMERALD,
3464     EL_WALL_DIAMOND,
3465     EL_WALL_BD_DIAMOND,
3466     EL_WALL_EMERALD_YELLOW,
3467     EL_DYNABOMB_INCREASE_NUMBER,
3468     EL_DYNABOMB_INCREASE_SIZE,
3469     EL_DYNABOMB_INCREASE_POWER,
3470 #if 0
3471     EL_SOKOBAN_OBJECT,
3472 #endif
3473     EL_SOKOBAN_FIELD_EMPTY,
3474     EL_SOKOBAN_FIELD_FULL,
3475     EL_WALL_EMERALD_RED,
3476     EL_WALL_EMERALD_PURPLE,
3477     EL_ACID_POOL_TOPLEFT,
3478     EL_ACID_POOL_TOPRIGHT,
3479     EL_ACID_POOL_BOTTOMLEFT,
3480     EL_ACID_POOL_BOTTOM,
3481     EL_ACID_POOL_BOTTOMRIGHT,
3482     EL_MAGIC_WALL,
3483     EL_MAGIC_WALL_DEAD,
3484     EL_BD_MAGIC_WALL,
3485     EL_BD_MAGIC_WALL_DEAD,
3486     EL_AMOEBA_TO_DIAMOND,
3487     EL_BLOCKED,
3488     EL_SP_EMPTY,
3489     EL_SP_BASE,
3490     EL_SP_PORT_RIGHT,
3491     EL_SP_PORT_DOWN,
3492     EL_SP_PORT_LEFT,
3493     EL_SP_PORT_UP,
3494     EL_SP_GRAVITY_PORT_RIGHT,
3495     EL_SP_GRAVITY_PORT_DOWN,
3496     EL_SP_GRAVITY_PORT_LEFT,
3497     EL_SP_GRAVITY_PORT_UP,
3498     EL_SP_PORT_HORIZONTAL,
3499     EL_SP_PORT_VERTICAL,
3500     EL_SP_PORT_ANY,
3501     EL_SP_DISK_RED,
3502 #if 0
3503     EL_SP_DISK_YELLOW,
3504 #endif
3505     EL_SP_CHIP_SINGLE,
3506     EL_SP_CHIP_LEFT,
3507     EL_SP_CHIP_RIGHT,
3508     EL_SP_CHIP_TOP,
3509     EL_SP_CHIP_BOTTOM,
3510     EL_SP_HARDWARE_GRAY,
3511     EL_SP_HARDWARE_GREEN,
3512     EL_SP_HARDWARE_BLUE,
3513     EL_SP_HARDWARE_RED,
3514     EL_SP_HARDWARE_YELLOW,
3515     EL_SP_HARDWARE_BASE_1,
3516     EL_SP_HARDWARE_BASE_2,
3517     EL_SP_HARDWARE_BASE_3,
3518     EL_SP_HARDWARE_BASE_4,
3519     EL_SP_HARDWARE_BASE_5,
3520     EL_SP_HARDWARE_BASE_6,
3521     EL_SP_GRAVITY_ON_PORT_LEFT,
3522     EL_SP_GRAVITY_ON_PORT_RIGHT,
3523     EL_SP_GRAVITY_ON_PORT_UP,
3524     EL_SP_GRAVITY_ON_PORT_DOWN,
3525     EL_SP_GRAVITY_OFF_PORT_LEFT,
3526     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3527     EL_SP_GRAVITY_OFF_PORT_UP,
3528     EL_SP_GRAVITY_OFF_PORT_DOWN,
3529     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3530     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3531     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3532     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3533     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3534     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3535     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3536     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3537     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3538     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3539     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3540     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3541     EL_SIGN_EXCLAMATION,
3542     EL_SIGN_RADIOACTIVITY,
3543     EL_SIGN_STOP,
3544     EL_SIGN_WHEELCHAIR,
3545     EL_SIGN_PARKING,
3546     EL_SIGN_ONEWAY,
3547     EL_SIGN_HEART,
3548     EL_SIGN_TRIANGLE,
3549     EL_SIGN_ROUND,
3550     EL_SIGN_EXIT,
3551     EL_SIGN_YINYANG,
3552     EL_SIGN_OTHER,
3553     EL_STEELWALL_SLIPPERY,
3554     EL_EMC_STEELWALL_1,
3555     EL_EMC_STEELWALL_2,
3556     EL_EMC_STEELWALL_3,
3557     EL_EMC_STEELWALL_4,
3558     EL_EMC_WALL_SLIPPERY_1,
3559     EL_EMC_WALL_SLIPPERY_2,
3560     EL_EMC_WALL_SLIPPERY_3,
3561     EL_EMC_WALL_SLIPPERY_4,
3562     EL_EMC_WALL_1,
3563     EL_EMC_WALL_2,
3564     EL_EMC_WALL_3,
3565     EL_EMC_WALL_4,
3566     EL_EMC_WALL_5,
3567     EL_EMC_WALL_6,
3568     EL_EMC_WALL_7,
3569     EL_EMC_WALL_8,
3570     EL_EMC_WALL_9,
3571     EL_EMC_WALL_10,
3572     EL_EMC_WALL_11,
3573     EL_EMC_WALL_12,
3574     EL_EMC_WALL_13,
3575     EL_EMC_WALL_14,
3576     EL_EMC_WALL_15,
3577     EL_EMC_WALL_16,
3578     -1
3579   };
3580
3581   static int ep_em_slippery_wall[] =
3582   {
3583     -1
3584   };
3585
3586   static int ep_gfx_crumbled[] =
3587   {
3588     EL_SAND,
3589     EL_LANDMINE,
3590     EL_TRAP,
3591     EL_TRAP_ACTIVE,
3592     -1
3593   };
3594
3595   static struct
3596   {
3597     int *elements;
3598     int property;
3599   } element_properties[] =
3600   {
3601     { ep_diggable,              EP_DIGGABLE             },
3602     { ep_collectible_only,      EP_COLLECTIBLE_ONLY     },
3603     { ep_dont_run_into,         EP_DONT_RUN_INTO        },
3604     { ep_dont_collide_with,     EP_DONT_COLLIDE_WITH    },
3605     { ep_dont_touch,            EP_DONT_TOUCH           },
3606     { ep_indestructible,        EP_INDESTRUCTIBLE       },
3607     { ep_slippery,              EP_SLIPPERY             },
3608     { ep_can_change,            EP_CAN_CHANGE           },
3609     { ep_can_move,              EP_CAN_MOVE             },
3610     { ep_can_fall,              EP_CAN_FALL             },
3611     { ep_can_smash_player,      EP_CAN_SMASH_PLAYER     },
3612     { ep_can_smash_enemies,     EP_CAN_SMASH_ENEMIES    },
3613     { ep_can_smash_everything,  EP_CAN_SMASH_EVERYTHING },
3614     { ep_explodes_by_fire,      EP_EXPLODES_BY_FIRE     },
3615     { ep_explodes_smashed,      EP_EXPLODES_SMASHED     },
3616     { ep_explodes_impact,       EP_EXPLODES_IMPACT      },
3617     { ep_walkable_over,         EP_WALKABLE_OVER        },
3618     { ep_walkable_inside,       EP_WALKABLE_INSIDE      },
3619     { ep_walkable_under,        EP_WALKABLE_UNDER       },
3620     { ep_passable_over,         EP_PASSABLE_OVER        },
3621     { ep_passable_inside,       EP_PASSABLE_INSIDE      },
3622     { ep_passable_under,        EP_PASSABLE_UNDER       },
3623     { ep_droppable,             EP_DROPPABLE            },
3624     { ep_explodes_1x1_old,      EP_EXPLODES_1X1_OLD     },
3625     { ep_pushable,              EP_PUSHABLE             },
3626     { ep_explodes_cross_old,    EP_EXPLODES_CROSS_OLD   },
3627     { ep_protected,             EP_PROTECTED            },
3628     { ep_throwable,             EP_THROWABLE            },
3629     { ep_can_explode,           EP_CAN_EXPLODE          },
3630     { ep_gravity_reachable,     EP_GRAVITY_REACHABLE    },
3631
3632     { ep_player,                EP_PLAYER               },
3633     { ep_can_pass_magic_wall,   EP_CAN_PASS_MAGIC_WALL  },
3634     { ep_switchable,            EP_SWITCHABLE           },
3635     { ep_bd_element,            EP_BD_ELEMENT           },
3636     { ep_sp_element,            EP_SP_ELEMENT           },
3637     { ep_sb_element,            EP_SB_ELEMENT           },
3638     { ep_gem,                   EP_GEM                  },
3639     { ep_food_dark_yamyam,      EP_FOOD_DARK_YAMYAM     },
3640     { ep_food_penguin,          EP_FOOD_PENGUIN         },
3641     { ep_food_pig,              EP_FOOD_PIG             },
3642     { ep_historic_wall,         EP_HISTORIC_WALL        },
3643     { ep_historic_solid,        EP_HISTORIC_SOLID       },
3644     { ep_classic_enemy,         EP_CLASSIC_ENEMY        },
3645     { ep_belt,                  EP_BELT                 },
3646     { ep_belt_active,           EP_BELT_ACTIVE          },
3647     { ep_belt_switch,           EP_BELT_SWITCH          },
3648     { ep_tube,                  EP_TUBE                 },
3649     { ep_keygate,               EP_KEYGATE              },
3650     { ep_amoeboid,              EP_AMOEBOID             },
3651     { ep_amoebalive,            EP_AMOEBALIVE           },
3652     { ep_has_content,           EP_HAS_CONTENT          },
3653     { ep_can_turn_each_move,    EP_CAN_TURN_EACH_MOVE   },
3654     { ep_can_grow,              EP_CAN_GROW             },
3655     { ep_active_bomb,           EP_ACTIVE_BOMB          },
3656     { ep_inactive,              EP_INACTIVE             },
3657
3658     { ep_em_slippery_wall,      EP_EM_SLIPPERY_WALL     },
3659
3660     { ep_gfx_crumbled,          EP_GFX_CRUMBLED         },
3661
3662     { NULL,                     -1                      }
3663   };
3664
3665   int i, j, k;
3666
3667   /* always start with reliable default values (element has no properties) */
3668   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3669     for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3670       SET_PROPERTY(i, j, FALSE);
3671
3672   /* set all base element properties from above array definitions */
3673   for (i = 0; element_properties[i].elements != NULL; i++)
3674     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3675       SET_PROPERTY((element_properties[i].elements)[j],
3676                    element_properties[i].property, TRUE);
3677
3678   /* copy properties to some elements that are only stored in level file */
3679   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3680     for (j = 0; copy_properties[j][0] != -1; j++)
3681       if (HAS_PROPERTY(copy_properties[j][0], i))
3682         for (k = 1; k <= 4; k++)
3683           SET_PROPERTY(copy_properties[j][k], i, TRUE);
3684 }
3685
3686 void InitElementPropertiesEngine(int engine_version)
3687 {
3688 #if 0
3689   static int active_properties[] =
3690   {
3691     EP_AMOEBALIVE,
3692     EP_AMOEBOID,
3693     EP_PFORTE,
3694     EP_DONT_COLLIDE_WITH,
3695     EP_MAUER,
3696     EP_CAN_FALL,
3697     EP_CAN_SMASH,
3698     EP_CAN_PASS_MAGIC_WALL,
3699     EP_CAN_MOVE,
3700     EP_DONT_TOUCH,
3701     EP_DONT_RUN_INTO,
3702     EP_GEM,
3703     EP_EXPLODES_BY_FIRE,
3704     EP_PUSHABLE,
3705     EP_PLAYER,
3706     EP_HAS_CONTENT,
3707     EP_DIGGABLE,
3708     EP_PASSABLE_INSIDE,
3709     EP_OVER_PLAYER,
3710     EP_ACTIVE_BOMB,
3711
3712     EP_BELT,
3713     EP_BELT_ACTIVE,
3714     EP_BELT_SWITCH,
3715     EP_WALKABLE_UNDER,
3716     EP_EM_SLIPPERY_WALL,
3717   };
3718 #endif
3719
3720   static int no_wall_properties[] =
3721   {
3722     EP_DIGGABLE,
3723     EP_COLLECTIBLE_ONLY,
3724     EP_DONT_RUN_INTO,
3725     EP_DONT_COLLIDE_WITH,
3726     EP_CAN_MOVE,
3727     EP_CAN_FALL,
3728     EP_CAN_SMASH_PLAYER,
3729     EP_CAN_SMASH_ENEMIES,
3730     EP_CAN_SMASH_EVERYTHING,
3731     EP_PUSHABLE,
3732
3733     EP_PLAYER,
3734     EP_GEM,
3735     EP_FOOD_DARK_YAMYAM,
3736     EP_FOOD_PENGUIN,
3737     EP_BELT,
3738     EP_BELT_ACTIVE,
3739     EP_TUBE,
3740     EP_AMOEBOID,
3741     EP_AMOEBALIVE,
3742     EP_ACTIVE_BOMB,
3743
3744     EP_ACCESSIBLE,
3745
3746     -1
3747   };
3748
3749   int i, j;
3750
3751 #if 0
3752   InitElementPropertiesStatic();
3753 #endif
3754
3755   /* important: after initialization in InitElementPropertiesStatic(), the
3756      elements are not again initialized to a default value; therefore all
3757      changes have to make sure that they leave the element with a defined
3758      property (which means that conditional property changes must be set to
3759      a reliable default value before) */
3760
3761   /* set all special, combined or engine dependent element properties */
3762   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3763   {
3764 #if 0
3765     for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
3766       SET_PROPERTY(i, j, FALSE);
3767 #endif
3768
3769     /* ---------- INACTIVE ------------------------------------------------- */
3770     SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3771
3772     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3773     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3774                                   IS_WALKABLE_INSIDE(i) ||
3775                                   IS_WALKABLE_UNDER(i)));
3776
3777     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3778                                   IS_PASSABLE_INSIDE(i) ||
3779                                   IS_PASSABLE_UNDER(i)));
3780
3781     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3782                                          IS_PASSABLE_OVER(i)));
3783
3784     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3785                                            IS_PASSABLE_INSIDE(i)));
3786
3787     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3788                                           IS_PASSABLE_UNDER(i)));
3789
3790     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3791                                     IS_PASSABLE(i)));
3792
3793     /* ---------- COLLECTIBLE ---------------------------------------------- */
3794     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3795                                      IS_DROPPABLE(i) ||
3796                                      IS_THROWABLE(i)));
3797
3798     /* ---------- SNAPPABLE ------------------------------------------------ */
3799     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3800                                    IS_COLLECTIBLE(i) ||
3801                                    IS_SWITCHABLE(i) ||
3802                                    i == EL_BD_ROCK));
3803
3804     /* ---------- WALL ----------------------------------------------------- */
3805     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
3806
3807     for (j = 0; no_wall_properties[j] != -1; j++)
3808       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3809           i >= EL_FIRST_RUNTIME_UNREAL)
3810         SET_PROPERTY(i, EP_WALL, FALSE);
3811
3812     if (IS_HISTORIC_WALL(i))
3813       SET_PROPERTY(i, EP_WALL, TRUE);
3814
3815     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3816     if (engine_version < VERSION_IDENT(2,2,0,0))
3817       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3818     else
3819       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3820                                              !IS_DIGGABLE(i) &&
3821                                              !IS_COLLECTIBLE(i)));
3822
3823 #if 0
3824     /* ---------- PROTECTED ------------------------------------------------ */
3825     if (IS_ACCESSIBLE_INSIDE(i))
3826       SET_PROPERTY(i, EP_PROTECTED, TRUE);
3827 #endif
3828
3829     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3830
3831     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3832       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3833     else
3834       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3835                                             IS_INDESTRUCTIBLE(i)));
3836
3837     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3838     if (i == EL_FLAMES)
3839       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3840     else if (engine_version < VERSION_IDENT(2,2,0,0))
3841       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3842     else
3843 #if 1
3844       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3845                                            (!IS_WALKABLE(i) ||
3846                                             IS_PROTECTED(i))));
3847 #else
3848 #if 1
3849       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3850                                            !IS_WALKABLE_OVER(i) &&
3851                                            !IS_WALKABLE_UNDER(i)));
3852 #else
3853       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3854                                            IS_PROTECTED(i)));
3855 #endif
3856 #endif
3857
3858     if (IS_CUSTOM_ELEMENT(i))
3859     {
3860       /* these are additional properties which are initially false when set */
3861
3862       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3863       if (DONT_TOUCH(i))
3864         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3865       if (DONT_COLLIDE_WITH(i))
3866         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3867
3868       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3869       if (CAN_SMASH_EVERYTHING(i))
3870         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3871       if (CAN_SMASH_ENEMIES(i))
3872         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3873     }
3874
3875     /* ---------- CAN_SMASH ------------------------------------------------ */
3876     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3877                                    CAN_SMASH_ENEMIES(i) ||
3878                                    CAN_SMASH_EVERYTHING(i)));
3879
3880 #if 0
3881     /* ---------- CAN_EXPLODE ---------------------------------------------- */
3882     SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
3883                                      CAN_EXPLODE_SMASHED(i) ||
3884                                      CAN_EXPLODE_IMPACT(i)));
3885 #endif
3886
3887 #if 0
3888     /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
3889 #if 0
3890     SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
3891                                          !CAN_EXPLODE_CROSS(i)));
3892 #else
3893     SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
3894                                          !CAN_EXPLODE_1X1(i) &&
3895                                          !CAN_EXPLODE_CROSS(i)));
3896 #endif
3897 #endif
3898
3899     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3900     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3901                                              EXPLODES_BY_FIRE(i)));
3902
3903     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3904     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3905                                              EXPLODES_SMASHED(i)));
3906
3907     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3908     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3909                                             EXPLODES_IMPACT(i)));
3910
3911     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3912     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3913
3914     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3915     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3916                                                   i == EL_BLACK_ORB));
3917
3918     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3919     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3920                                               CAN_MOVE(i) ||
3921                                               IS_CUSTOM_ELEMENT(i)));
3922
3923     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3924     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3925                                                  i == EL_SP_ELECTRON));
3926
3927     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3928     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3929       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3930                    getMoveIntoAcidProperty(&level, i));
3931
3932     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3933     if (MAYBE_DONT_COLLIDE_WITH(i))
3934       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3935                    getDontCollideWithProperty(&level, i));
3936
3937     /* ---------- SP_PORT -------------------------------------------------- */
3938     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3939                                  IS_PASSABLE_INSIDE(i)));
3940
3941     /* ---------- CAN_CHANGE ----------------------------------------------- */
3942     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
3943     for (j = 0; j < element_info[i].num_change_pages; j++)
3944       if (element_info[i].change_page[j].can_change)
3945         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3946
3947     /* ---------- GFX_CRUMBLED --------------------------------------------- */
3948 #if 1
3949     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3950                  element_info[i].crumbled[ACTION_DEFAULT] !=
3951                  element_info[i].graphic[ACTION_DEFAULT]);
3952 #else
3953     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3954     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3955                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3956 #endif
3957   }
3958
3959 #if 0
3960   /* determine inactive elements (used for engine main loop optimization) */
3961   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3962   {
3963     boolean active = FALSE;
3964
3965     for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++)
3966     {
3967       if (HAS_PROPERTY(i, j))
3968         active = TRUE;
3969     }
3970
3971 #if 0
3972     if (!active)
3973       SET_PROPERTY(i, EP_INACTIVE, TRUE);
3974 #endif
3975   }
3976 #endif
3977
3978   /* dynamically adjust element properties according to game engine version */
3979   {
3980     static int ep_em_slippery_wall[] =
3981     {
3982       EL_STEELWALL,
3983       EL_WALL,
3984       EL_EXPANDABLE_WALL,
3985       EL_EXPANDABLE_WALL_HORIZONTAL,
3986       EL_EXPANDABLE_WALL_VERTICAL,
3987       EL_EXPANDABLE_WALL_ANY,
3988       -1
3989     };
3990
3991     /* special EM style gems behaviour */
3992     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3993       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3994                    level.em_slippery_gems);
3995
3996     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3997     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3998                  (level.em_slippery_gems &&
3999                   engine_version > VERSION_IDENT(2,0,1,0)));
4000   }
4001
4002 #if 1
4003   /* set default push delay values (corrected since version 3.0.7-1) */
4004   if (engine_version < VERSION_IDENT(3,0,7,1))
4005   {
4006     game.default_push_delay_fixed = 2;
4007     game.default_push_delay_random = 8;
4008   }
4009   else
4010   {
4011     game.default_push_delay_fixed = 8;
4012     game.default_push_delay_random = 8;
4013   }
4014
4015   /* set uninitialized push delay values of custom elements in older levels */
4016   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4017   {
4018     int element = EL_CUSTOM_START + i;
4019
4020     if (element_info[element].push_delay_fixed == -1)
4021       element_info[element].push_delay_fixed = game.default_push_delay_fixed;
4022     if (element_info[element].push_delay_random == -1)
4023       element_info[element].push_delay_random = game.default_push_delay_random;
4024   }
4025
4026   /* set some other uninitialized values of custom elements in older levels */
4027   if (engine_version < VERSION_IDENT(3,1,0,0))
4028   {
4029     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4030     {
4031       int element = EL_CUSTOM_START + i;
4032
4033       element_info[element].access_direction = MV_ALL_DIRECTIONS;
4034
4035       element_info[element].explosion_delay = 17;
4036       element_info[element].ignition_delay = 8;
4037     }
4038   }
4039
4040 #if 0
4041   /* set element properties that were handled incorrectly in older levels */
4042   if (engine_version < VERSION_IDENT(3,1,0,0))
4043   {
4044     SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
4045     SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
4046   }
4047 #endif
4048
4049 #endif
4050
4051   /* this is needed because some graphics depend on element properties */
4052   if (game_status == GAME_MODE_PLAYING)
4053     InitElementGraphicInfo();
4054 }
4055
4056 static void InitGlobal()
4057 {
4058   int i;
4059
4060   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4061   {
4062     /* check if element_name_info entry defined for each element in "main.h" */
4063     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4064       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4065
4066     element_info[i].token_name = element_name_info[i].token_name;
4067     element_info[i].class_name = element_name_info[i].class_name;
4068     element_info[i].editor_description=element_name_info[i].editor_description;
4069   }
4070
4071   global.autoplay_leveldir = NULL;
4072   global.convert_leveldir = NULL;
4073
4074   global.frames_per_second = 0;
4075   global.fps_slowdown = FALSE;
4076   global.fps_slowdown_factor = 1;
4077 }
4078
4079 void Execute_Command(char *command)
4080 {
4081   int i;
4082
4083   if (strcmp(command, "print graphicsinfo.conf") == 0)
4084   {
4085     printf("# You can configure additional/alternative image files here.\n");
4086     printf("# (The entries below are default and therefore commented out.)\n");
4087     printf("\n");
4088     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4089     printf("\n");
4090     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4091     printf("\n");
4092
4093     for (i = 0; image_config[i].token != NULL; i++)
4094       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4095                                               image_config[i].value));
4096
4097     exit(0);
4098   }
4099   else if (strcmp(command, "print soundsinfo.conf") == 0)
4100   {
4101     printf("# You can configure additional/alternative sound files here.\n");
4102     printf("# (The entries below are default and therefore commented out.)\n");
4103     printf("\n");
4104     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4105     printf("\n");
4106     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4107     printf("\n");
4108
4109     for (i = 0; sound_config[i].token != NULL; i++)
4110       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4111                                               sound_config[i].value));
4112
4113     exit(0);
4114   }
4115   else if (strcmp(command, "print musicinfo.conf") == 0)
4116   {
4117     printf("# You can configure additional/alternative music files here.\n");
4118     printf("# (The entries below are default and therefore commented out.)\n");
4119     printf("\n");
4120     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4121     printf("\n");
4122     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4123     printf("\n");
4124
4125     for (i = 0; music_config[i].token != NULL; i++)
4126       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4127                                               music_config[i].value));
4128
4129     exit(0);
4130   }
4131   else if (strcmp(command, "print editorsetup.conf") == 0)
4132   {
4133     printf("# You can configure your personal editor element list here.\n");
4134     printf("# (The entries below are default and therefore commented out.)\n");
4135     printf("\n");
4136
4137     PrintEditorElementList();
4138
4139     exit(0);
4140   }
4141   else if (strcmp(command, "print helpanim.conf") == 0)
4142   {
4143     printf("# You can configure different element help animations here.\n");
4144     printf("# (The entries below are default and therefore commented out.)\n");
4145     printf("\n");
4146
4147     for (i = 0; helpanim_config[i].token != NULL; i++)
4148     {
4149       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4150                                               helpanim_config[i].value));
4151
4152       if (strcmp(helpanim_config[i].token, "end") == 0)
4153         printf("#\n");
4154     }
4155
4156     exit(0);
4157   }
4158   else if (strcmp(command, "print helptext.conf") == 0)
4159   {
4160     printf("# You can configure different element help text here.\n");
4161     printf("# (The entries below are default and therefore commented out.)\n");
4162     printf("\n");
4163
4164     for (i = 0; helptext_config[i].token != NULL; i++)
4165       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4166                                               helptext_config[i].value));
4167
4168     exit(0);
4169   }
4170   else if (strncmp(command, "dump level ", 11) == 0)
4171   {
4172     char *filename = &command[11];
4173
4174     if (access(filename, F_OK) != 0)
4175       Error(ERR_EXIT, "cannot open file '%s'", filename);
4176
4177     LoadLevelFromFilename(&level, filename);
4178     DumpLevel(&level);
4179
4180     exit(0);
4181   }
4182   else if (strncmp(command, "dump tape ", 10) == 0)
4183   {
4184     char *filename = &command[10];
4185
4186     if (access(filename, F_OK) != 0)
4187       Error(ERR_EXIT, "cannot open file '%s'", filename);
4188
4189     LoadTapeFromFilename(filename);
4190     DumpTape(&tape);
4191
4192     exit(0);
4193   }
4194   else if (strncmp(command, "autoplay ", 9) == 0)
4195   {
4196     char *str_copy = getStringCopy(&command[9]);
4197     char *str_ptr = strchr(str_copy, ' ');
4198
4199     global.autoplay_leveldir = str_copy;
4200     global.autoplay_level_nr = -1;
4201
4202     if (str_ptr != NULL)
4203     {
4204       *str_ptr++ = '\0';                        /* terminate leveldir string */
4205       global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
4206     }
4207   }
4208   else if (strncmp(command, "convert ", 8) == 0)
4209   {
4210     char *str_copy = getStringCopy(&command[8]);
4211     char *str_ptr = strchr(str_copy, ' ');
4212
4213     global.convert_leveldir = str_copy;
4214     global.convert_level_nr = -1;
4215
4216     if (str_ptr != NULL)
4217     {
4218       *str_ptr++ = '\0';                        /* terminate leveldir string */
4219       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
4220     }
4221   }
4222   else
4223   {
4224     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4225   }
4226 }
4227
4228 static void InitSetup()
4229 {
4230   LoadSetup();                                  /* global setup info */
4231
4232   /* set some options from setup file */
4233
4234   if (setup.options.verbose)
4235     options.verbose = TRUE;
4236 }
4237
4238 static void InitPlayerInfo()
4239 {
4240   int i;
4241
4242   /* choose default local player */
4243   local_player = &stored_player[0];
4244
4245   for (i = 0; i < MAX_PLAYERS; i++)
4246     stored_player[i].connected = FALSE;
4247
4248   local_player->connected = TRUE;
4249 }
4250
4251 static void InitArtworkInfo()
4252 {
4253   LoadArtworkInfo();
4254 }
4255
4256 static char *get_string_in_brackets(char *string)
4257 {
4258   char *string_in_brackets = checked_malloc(strlen(string) + 3);
4259
4260   sprintf(string_in_brackets, "[%s]", string);
4261
4262   return string_in_brackets;
4263 }
4264
4265 static char *get_level_id_suffix(int id_nr)
4266 {
4267   char *id_suffix = checked_malloc(1 + 3 + 1);
4268
4269   if (id_nr < 0 || id_nr > 999)
4270     id_nr = 0;
4271
4272   sprintf(id_suffix, ".%03d", id_nr);
4273
4274   return id_suffix;
4275 }
4276
4277 #if 0
4278 static char *get_element_class_token(int element)
4279 {
4280   char *element_class_name = element_info[element].class_name;
4281   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4282
4283   sprintf(element_class_token, "[%s]", element_class_name);
4284
4285   return element_class_token;
4286 }
4287
4288 static char *get_action_class_token(int action)
4289 {
4290   char *action_class_name = &element_action_info[action].suffix[1];
4291   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4292
4293   sprintf(action_class_token, "[%s]", action_class_name);
4294
4295   return action_class_token;
4296 }
4297 #endif
4298
4299 static void InitArtworkConfig()
4300 {
4301   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4302   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4303   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4304   static char *action_id_suffix[NUM_ACTIONS + 1];
4305   static char *direction_id_suffix[NUM_DIRECTIONS + 1];
4306   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4307   static char *level_id_suffix[MAX_LEVELS + 1];
4308   static char *dummy[1] = { NULL };
4309   static char *ignore_generic_tokens[] =
4310   {
4311     "name",
4312     "sort_priority",
4313     NULL
4314   };
4315   static char **ignore_image_tokens;
4316   static char **ignore_sound_tokens;
4317   static char **ignore_music_tokens;
4318   int num_ignore_generic_tokens;
4319   int num_ignore_image_tokens;
4320   int num_ignore_sound_tokens;
4321   int num_ignore_music_tokens;
4322   int i;
4323
4324   /* dynamically determine list of generic tokens to be ignored */
4325   num_ignore_generic_tokens = 0;
4326   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4327     num_ignore_generic_tokens++;
4328
4329   /* dynamically determine list of image tokens to be ignored */
4330   num_ignore_image_tokens = num_ignore_generic_tokens;
4331   for (i = 0; image_config_vars[i].token != NULL; i++)
4332     num_ignore_image_tokens++;
4333   ignore_image_tokens =
4334     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4335   for (i = 0; i < num_ignore_generic_tokens; i++)
4336     ignore_image_tokens[i] = ignore_generic_tokens[i];
4337   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4338     ignore_image_tokens[num_ignore_generic_tokens + i] =
4339       image_config_vars[i].token;
4340   ignore_image_tokens[num_ignore_image_tokens] = NULL;
4341
4342   /* dynamically determine list of sound tokens to be ignored */
4343   num_ignore_sound_tokens = num_ignore_generic_tokens;
4344   ignore_sound_tokens =
4345     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4346   for (i = 0; i < num_ignore_generic_tokens; i++)
4347     ignore_sound_tokens[i] = ignore_generic_tokens[i];
4348   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4349
4350   /* dynamically determine list of music tokens to be ignored */
4351   num_ignore_music_tokens = num_ignore_generic_tokens;
4352   ignore_music_tokens =
4353     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4354   for (i = 0; i < num_ignore_generic_tokens; i++)
4355     ignore_music_tokens[i] = ignore_generic_tokens[i];
4356   ignore_music_tokens[num_ignore_music_tokens] = NULL;
4357
4358   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4359     image_id_prefix[i] = element_info[i].token_name;
4360   for (i = 0; i < NUM_FONTS; i++)
4361     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4362   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4363
4364   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4365     sound_id_prefix[i] = element_info[i].token_name;
4366   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4367     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4368       get_string_in_brackets(element_info[i].class_name);
4369   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4370
4371   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4372     music_id_prefix[i] = music_prefix_info[i].prefix;
4373   music_id_prefix[MAX_LEVELS] = NULL;
4374
4375   for (i = 0; i < NUM_ACTIONS; i++)
4376     action_id_suffix[i] = element_action_info[i].suffix;
4377   action_id_suffix[NUM_ACTIONS] = NULL;
4378
4379   for (i = 0; i < NUM_DIRECTIONS; i++)
4380     direction_id_suffix[i] = element_direction_info[i].suffix;
4381   direction_id_suffix[NUM_DIRECTIONS] = NULL;
4382
4383   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4384     special_id_suffix[i] = special_suffix_info[i].suffix;
4385   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4386
4387   for (i = 0; i < MAX_LEVELS; i++)
4388     level_id_suffix[i] = get_level_id_suffix(i);
4389   level_id_suffix[MAX_LEVELS] = NULL;
4390
4391   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4392                 image_id_prefix, action_id_suffix, direction_id_suffix,
4393                 special_id_suffix, ignore_image_tokens);
4394   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4395                 sound_id_prefix, action_id_suffix, dummy,
4396                 special_id_suffix, ignore_sound_tokens);
4397   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4398                 music_id_prefix, special_id_suffix, level_id_suffix,
4399                 dummy, ignore_music_tokens);
4400 }
4401
4402 static void InitMixer()
4403 {
4404   OpenAudio();
4405   StartMixer();
4406 }
4407
4408 void InitGfx()
4409 {
4410   char *filename_font_initial = NULL;
4411   Bitmap *bitmap_font_initial = NULL;
4412   int i, j;
4413
4414   /* determine settings for initial font (for displaying startup messages) */
4415   for (i = 0; image_config[i].token != NULL; i++)
4416   {
4417     for (j = 0; j < NUM_INITIAL_FONTS; j++)
4418     {
4419       char font_token[128];
4420       int len_font_token;
4421
4422       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4423       len_font_token = strlen(font_token);
4424
4425       if (strcmp(image_config[i].token, font_token) == 0)
4426         filename_font_initial = image_config[i].value;
4427       else if (strlen(image_config[i].token) > len_font_token &&
4428                strncmp(image_config[i].token, font_token, len_font_token) == 0)
4429       {
4430         if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4431           font_initial[j].src_x = atoi(image_config[i].value);
4432         else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4433           font_initial[j].src_y = atoi(image_config[i].value);
4434         else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4435           font_initial[j].width = atoi(image_config[i].value);
4436         else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4437           font_initial[j].height = atoi(image_config[i].value);
4438       }
4439     }
4440   }
4441
4442   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4443   {
4444     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4445     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4446   }
4447
4448   if (filename_font_initial == NULL)    /* should not happen */
4449     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4450
4451   /* create additional image buffers for double-buffering */
4452   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4453   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4454
4455   /* initialize screen properties */
4456   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4457                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4458                    bitmap_db_field);
4459   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4460   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4461   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4462
4463   bitmap_font_initial = LoadCustomImage(filename_font_initial);
4464
4465   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4466     font_initial[j].bitmap = bitmap_font_initial;
4467
4468   InitFontGraphicInfo();
4469
4470   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4471   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4472
4473   DrawInitText("Loading graphics:", 120, FC_GREEN);
4474
4475   InitTileClipmasks();
4476 }
4477
4478 void InitGfxBackground()
4479 {
4480   int x, y;
4481
4482   drawto = backbuffer;
4483   fieldbuffer = bitmap_db_field;
4484   SetDrawtoField(DRAW_BACKBUFFER);
4485
4486   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4487              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4488   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4489   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4490
4491   for (x = 0; x < MAX_BUF_XSIZE; x++)
4492     for (y = 0; y < MAX_BUF_YSIZE; y++)
4493       redraw[x][y] = 0;
4494   redraw_tiles = 0;
4495   redraw_mask = REDRAW_ALL;
4496 }
4497
4498 static void InitLevelInfo()
4499 {
4500   LoadLevelInfo();                              /* global level info */
4501   LoadLevelSetup_LastSeries();                  /* last played series info */
4502   LoadLevelSetup_SeriesInfo();                  /* last played level info */
4503 }
4504
4505 void InitLevelArtworkInfo()
4506 {
4507   LoadLevelArtworkInfo();
4508 }
4509
4510 static void InitImages()
4511 {
4512 #if 1
4513   setLevelArtworkDir(artwork.gfx_first);
4514 #endif
4515
4516 #if 0
4517   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4518          leveldir_current->identifier,
4519          artwork.gfx_current_identifier,
4520          artwork.gfx_current->identifier,
4521          leveldir_current->graphics_set,
4522          leveldir_current->graphics_path);
4523 #endif
4524
4525   ReloadCustomImages();
4526
4527   LoadCustomElementDescriptions();
4528   LoadSpecialMenuDesignSettings();
4529
4530   ReinitializeGraphics();
4531 }
4532
4533 static void InitSound(char *identifier)
4534 {
4535   if (identifier == NULL)
4536     identifier = artwork.snd_current->identifier;
4537
4538 #if 1
4539   /* set artwork path to send it to the sound server process */
4540   setLevelArtworkDir(artwork.snd_first);
4541 #endif
4542
4543   InitReloadCustomSounds(identifier);
4544   ReinitializeSounds();
4545 }
4546
4547 static void InitMusic(char *identifier)
4548 {
4549   if (identifier == NULL)
4550     identifier = artwork.mus_current->identifier;
4551
4552 #if 1
4553   /* set artwork path to send it to the sound server process */
4554   setLevelArtworkDir(artwork.mus_first);
4555 #endif
4556
4557   InitReloadCustomMusic(identifier);
4558   ReinitializeMusic();
4559 }
4560
4561 void InitNetworkServer()
4562 {
4563 #if defined(NETWORK_AVALIABLE)
4564   int nr_wanted;
4565 #endif
4566
4567   if (!options.network)
4568     return;
4569
4570 #if defined(NETWORK_AVALIABLE)
4571   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4572
4573   if (!ConnectToServer(options.server_host, options.server_port))
4574     Error(ERR_EXIT, "cannot connect to network game server");
4575
4576   SendToServer_PlayerName(setup.player_name);
4577   SendToServer_ProtocolVersion();
4578
4579   if (nr_wanted)
4580     SendToServer_NrWanted(nr_wanted);
4581 #endif
4582 }
4583
4584 static char *getNewArtworkIdentifier(int type)
4585 {
4586   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4587   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4588   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4589   static boolean initialized[3] = { FALSE, FALSE, FALSE };
4590   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4591   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4592   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4593   char *leveldir_identifier = leveldir_current->identifier;
4594 #if 1
4595   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4596   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4597 #else
4598   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4599 #endif
4600   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4601   char *artwork_current_identifier;
4602   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
4603
4604   /* leveldir_current may be invalid (level group, parent link) */
4605   if (!validLevelSeries(leveldir_current))
4606     return NULL;
4607
4608   /* 1st step: determine artwork set to be activated in descending order:
4609      --------------------------------------------------------------------
4610      1. setup artwork (when configured to override everything else)
4611      2. artwork set configured in "levelinfo.conf" of current level set
4612         (artwork in level directory will have priority when loading later)
4613      3. artwork in level directory (stored in artwork sub-directory)
4614      4. setup artwork (currently configured in setup menu) */
4615
4616   if (setup_override_artwork)
4617     artwork_current_identifier = setup_artwork_set;
4618   else if (leveldir_artwork_set != NULL)
4619     artwork_current_identifier = leveldir_artwork_set;
4620   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4621     artwork_current_identifier = leveldir_identifier;
4622   else
4623     artwork_current_identifier = setup_artwork_set;
4624
4625
4626   /* 2nd step: check if it is really needed to reload artwork set
4627      ------------------------------------------------------------ */
4628
4629 #if 0
4630   if (type == ARTWORK_TYPE_GRAPHICS)
4631     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4632            artwork_new_identifier,
4633            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4634            artwork_current_identifier,
4635            leveldir_current->graphics_set,
4636            leveldir_current->identifier);
4637 #endif
4638
4639   /* ---------- reload if level set and also artwork set has changed ------- */
4640   if (leveldir_current_identifier[type] != leveldir_identifier &&
4641       (last_has_level_artwork_set[type] || has_level_artwork_set))
4642     artwork_new_identifier = artwork_current_identifier;
4643
4644   leveldir_current_identifier[type] = leveldir_identifier;
4645   last_has_level_artwork_set[type] = has_level_artwork_set;
4646
4647 #if 0
4648   if (type == ARTWORK_TYPE_GRAPHICS)
4649     printf("::: 1: '%s'\n", artwork_new_identifier);
4650 #endif
4651
4652   /* ---------- reload if "override artwork" setting has changed ----------- */
4653   if (last_override_level_artwork[type] != setup_override_artwork)
4654     artwork_new_identifier = artwork_current_identifier;
4655
4656   last_override_level_artwork[type] = setup_override_artwork;
4657
4658 #if 0
4659   if (type == ARTWORK_TYPE_GRAPHICS)
4660     printf("::: 2: '%s'\n", artwork_new_identifier);
4661 #endif
4662
4663   /* ---------- reload if current artwork identifier has changed ----------- */
4664   if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4665              artwork_current_identifier) != 0)
4666     artwork_new_identifier = artwork_current_identifier;
4667
4668   *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
4669
4670 #if 0
4671   if (type == ARTWORK_TYPE_GRAPHICS)
4672     printf("::: 3: '%s'\n", artwork_new_identifier);
4673 #endif
4674
4675   /* ---------- do not reload directly after starting ---------------------- */
4676   if (!initialized[type])
4677     artwork_new_identifier = NULL;
4678
4679   initialized[type] = TRUE;
4680
4681 #if 0
4682   if (type == ARTWORK_TYPE_GRAPHICS)
4683     printf("::: 4: '%s'\n", artwork_new_identifier);
4684 #endif
4685
4686 #if 0
4687   if (type == ARTWORK_TYPE_GRAPHICS)
4688     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4689            artwork.gfx_current_identifier, artwork_current_identifier,
4690            artwork.gfx_current->identifier, leveldir_current->graphics_set,
4691            artwork_new_identifier);
4692 #endif
4693
4694   return artwork_new_identifier;
4695 }
4696
4697 void ReloadCustomArtwork(int force_reload)
4698 {
4699   char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4700   char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4701   char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4702   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4703   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4704   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4705   boolean redraw_screen = FALSE;
4706
4707   if (gfx_new_identifier != NULL || force_reload_gfx)
4708   {
4709 #if 0
4710     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4711            artwork.gfx_current_identifier,
4712            gfx_new_identifier,
4713            artwork.gfx_current->identifier,
4714            leveldir_current->graphics_set);
4715 #endif
4716
4717     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4718
4719     InitImages();
4720
4721 #if 0
4722     printf("... '%s'\n",
4723            leveldir_current->graphics_set);
4724 #endif
4725
4726     FreeTileClipmasks();
4727     InitTileClipmasks();
4728
4729     redraw_screen = TRUE;
4730   }
4731
4732   if (snd_new_identifier != NULL || force_reload_snd)
4733   {
4734     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4735
4736     InitSound(snd_new_identifier);
4737
4738     redraw_screen = TRUE;
4739   }
4740
4741   if (mus_new_identifier != NULL || force_reload_mus)
4742   {
4743     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4744
4745     InitMusic(mus_new_identifier);
4746
4747     redraw_screen = TRUE;
4748   }
4749
4750   if (redraw_screen)
4751   {
4752     InitGfxBackground();
4753
4754     /* force redraw of (open or closed) door graphics */
4755     SetDoorState(DOOR_OPEN_ALL);
4756     CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4757   }
4758 }
4759
4760 void KeyboardAutoRepeatOffUnlessAutoplay()
4761 {
4762   if (global.autoplay_leveldir == NULL)
4763     KeyboardAutoRepeatOff();
4764 }
4765
4766
4767 /* ========================================================================= */
4768 /* OpenAll()                                                                 */
4769 /* ========================================================================= */
4770
4771 void OpenAll()
4772 {
4773   InitGlobal();                 /* initialize some global variables */
4774
4775   if (options.execute_command)
4776     Execute_Command(options.execute_command);
4777
4778   if (options.serveronly)
4779   {
4780 #if defined(PLATFORM_UNIX)
4781     NetworkServer(options.server_port, options.serveronly);
4782 #else
4783     Error(ERR_WARN, "networking only supported in Unix version");
4784 #endif
4785
4786     exit(0);                    /* never reached, server loops forever */
4787   }
4788
4789   InitSetup();
4790
4791   InitPlayerInfo();
4792   InitArtworkInfo();            /* needed before loading gfx, sound & music */
4793   InitArtworkConfig();          /* needed before forking sound child process */
4794   InitMixer();
4795
4796   InitCounter();
4797
4798   InitRND(NEW_RANDOMIZE);
4799   InitSimpleRND(NEW_RANDOMIZE);
4800
4801   InitJoysticks();
4802
4803   InitVideoDisplay();
4804   InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4805                   setup.fullscreen);
4806
4807   InitEventFilter(FilterMouseMotionEvents);
4808
4809   InitElementPropertiesStatic();
4810   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4811
4812   InitGfx();
4813
4814   InitLevelInfo();
4815   InitLevelArtworkInfo();
4816
4817   InitImages();                 /* needs to know current level directory */
4818   InitSound(NULL);              /* needs to know current level directory */
4819   InitMusic(NULL);              /* needs to know current level directory */
4820
4821   InitGfxBackground();
4822
4823   if (global.autoplay_leveldir)
4824   {
4825     AutoPlayTape();
4826     return;
4827   }
4828   else if (global.convert_leveldir)
4829   {
4830     ConvertLevels();
4831     return;
4832   }
4833
4834   game_status = GAME_MODE_MAIN;
4835
4836 #if 1
4837   em_open_all();
4838 #endif
4839
4840   DrawMainMenu();
4841
4842   InitNetworkServer();
4843 }
4844
4845 void CloseAllAndExit(int exit_value)
4846 {
4847   StopSounds();
4848   FreeAllSounds();
4849   FreeAllMusic();
4850   CloseAudio();         /* called after freeing sounds (needed for SDL) */
4851
4852 #if 1
4853   em_close_all();
4854 #endif
4855
4856   FreeAllImages();
4857   FreeTileClipmasks();
4858
4859 #if defined(TARGET_SDL)
4860   if (network_server)   /* terminate network server */
4861     SDL_KillThread(server_thread);
4862 #endif
4863
4864   CloseVideoDisplay();
4865   ClosePlatformDependentStuff();
4866
4867   exit(exit_value);
4868 }