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