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