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