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