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