rnd-20070428-2-src
[rocksndiamonds.git] / src / init.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 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 #include "conf_act.c"   /* include auto-generated data structure definitions */
36
37
38 #define CONFIG_TOKEN_FONT_INITIAL               "font.initial"
39 #define CONFIG_TOKEN_GLOBAL_BUSY                "global.busy"
40
41 #define DEBUG_PRINT_INIT_TIMESTAMPS             TRUE
42 #define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH       1
43
44
45 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
46 static struct GraphicInfo    anim_initial;
47
48 static int copy_properties[][5] =
49 {
50   {
51     EL_BUG,
52     EL_BUG_LEFT,                EL_BUG_RIGHT,
53     EL_BUG_UP,                  EL_BUG_DOWN
54   },
55   {
56     EL_SPACESHIP,
57     EL_SPACESHIP_LEFT,          EL_SPACESHIP_RIGHT,
58     EL_SPACESHIP_UP,            EL_SPACESHIP_DOWN
59   },
60   {
61     EL_BD_BUTTERFLY,
62     EL_BD_BUTTERFLY_LEFT,       EL_BD_BUTTERFLY_RIGHT,
63     EL_BD_BUTTERFLY_UP,         EL_BD_BUTTERFLY_DOWN
64   },
65   {
66     EL_BD_FIREFLY,
67     EL_BD_FIREFLY_LEFT,         EL_BD_FIREFLY_RIGHT,
68     EL_BD_FIREFLY_UP,           EL_BD_FIREFLY_DOWN
69   },
70   {
71     EL_PACMAN,
72     EL_PACMAN_LEFT,             EL_PACMAN_RIGHT,
73     EL_PACMAN_UP,               EL_PACMAN_DOWN
74   },
75   {
76     EL_YAMYAM,
77     EL_YAMYAM_LEFT,             EL_YAMYAM_RIGHT,
78     EL_YAMYAM_UP,               EL_YAMYAM_DOWN
79   },
80   {
81     EL_MOLE,
82     EL_MOLE_LEFT,               EL_MOLE_RIGHT,
83     EL_MOLE_UP,                 EL_MOLE_DOWN
84   },
85   {
86     -1,
87     -1, -1, -1, -1
88   }
89 };
90
91
92 static void print_timestamp_ext(char *message, char *mode)
93 {
94 #if DEBUG
95 #if DEBUG_PRINT_INIT_TIMESTAMPS
96   static char *debug_message = NULL;
97   static char *last_message = NULL;
98   static int counter_nr = 0;
99   int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH;
100
101   checked_free(debug_message);
102   debug_message = getStringCat3(mode, " ", message);
103
104   if (strEqual(mode, "INIT"))
105   {
106     debug_print_timestamp(counter_nr, NULL);
107
108     if (counter_nr + 1 < max_depth)
109       debug_print_timestamp(counter_nr, debug_message);
110
111     counter_nr++;
112
113     debug_print_timestamp(counter_nr, NULL);
114   }
115   else if (strEqual(mode, "DONE"))
116   {
117     counter_nr--;
118
119     if (counter_nr + 1 < max_depth ||
120         (counter_nr == 0 && max_depth == 1))
121     {
122       last_message = message;
123
124       if (counter_nr == 0 && max_depth == 1)
125       {
126         checked_free(debug_message);
127         debug_message = getStringCat3("TIME", " ", message);
128       }
129
130       debug_print_timestamp(counter_nr, debug_message);
131     }
132   }
133   else if (!strEqual(mode, "TIME") ||
134            !strEqual(message, last_message))
135   {
136     if (counter_nr < max_depth)
137       debug_print_timestamp(counter_nr, debug_message);
138   }
139 #endif
140 #endif
141 }
142
143 static void print_timestamp_init(char *message)
144 {
145   print_timestamp_ext(message, "INIT");
146 }
147
148 static void print_timestamp_time(char *message)
149 {
150   print_timestamp_ext(message, "TIME");
151 }
152
153 static void print_timestamp_done(char *message)
154 {
155   print_timestamp_ext(message, "DONE");
156 }
157
158 void DrawInitAnim()
159 {
160   struct GraphicInfo *graphic_info_last = graphic_info;
161   int graphic = 0;
162   static unsigned long action_delay = 0;
163   unsigned long action_delay_value = GameFrameDelay;
164   int sync_frame = FrameCounter;
165   int x, y;
166
167   if (game_status != GAME_MODE_LOADING)
168     return;
169
170   if (anim_initial.bitmap == NULL || window == NULL)
171     return;
172
173   if (!DelayReached(&action_delay, action_delay_value))
174     return;
175
176 #if 0
177   {
178     static unsigned long last_counter = -1;
179     unsigned long current_counter = Counter();
180     unsigned long delay = current_counter - last_counter;
181
182     if (last_counter != -1 && delay > action_delay_value + 5)
183       printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
184
185     last_counter = current_counter;
186   }
187 #endif
188
189 #if 0
190   anim_initial.anim_mode = ANIM_LOOP;
191   anim_initial.anim_start_frame = 0;
192   anim_initial.offset_x = anim_initial.width;
193   anim_initial.offset_y = 0;
194 #endif
195
196 #if 1
197   x = ALIGNED_TEXT_XPOS(&init.busy);
198   y = ALIGNED_TEXT_YPOS(&init.busy);
199 #else
200   x = WIN_XSIZE / 2 - TILESIZE / 2;
201   y = WIN_YSIZE / 2 - TILESIZE / 2;
202 #endif
203
204 #if 0
205   {
206     static boolean done = FALSE;
207
208     if (!done)
209       printf("::: %d, %d, %d, %d => %d, %d\n",
210              init.busy.x, init.busy.y,
211              init.busy.align, init.busy.valign,
212              x, y);
213
214     done = TRUE;
215   }
216 #endif
217
218   graphic_info = &anim_initial;         /* graphic == 0 => anim_initial */
219
220   if (sync_frame % anim_initial.anim_delay == 0)
221     DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
222
223   graphic_info = graphic_info_last;
224
225   FrameCounter++;
226 }
227
228 void FreeGadgets()
229 {
230   FreeLevelEditorGadgets();
231   FreeGameButtons();
232   FreeTapeButtons();
233   FreeToolButtons();
234   FreeScreenGadgets();
235 }
236
237 void InitGadgets()
238 {
239   static boolean gadgets_initialized = FALSE;
240
241   if (gadgets_initialized)
242     FreeGadgets();
243
244   CreateLevelEditorGadgets();
245   CreateGameButtons();
246   CreateTapeButtons();
247   CreateToolButtons();
248   CreateScreenGadgets();
249
250   InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
251
252   gadgets_initialized = TRUE;
253 }
254
255 inline void InitElementSmallImagesScaledUp(int graphic)
256 {
257 #if 0
258   struct FileInfo *fi = getImageListEntryFromImageID(graphic);
259
260   printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
261 #endif
262
263   CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
264 }
265
266 void InitElementSmallImages()
267 {
268   static int special_graphics[] =
269   {
270     IMG_EDITOR_ELEMENT_BORDER,
271     IMG_EDITOR_ELEMENT_BORDER_INPUT,
272     IMG_EDITOR_CASCADE_LIST,
273     IMG_EDITOR_CASCADE_LIST_ACTIVE,
274     -1
275   };
276   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
277   int num_property_mappings = getImageListPropertyMappingSize();
278   int i;
279
280   /* initialize normal images from static configuration */
281   for (i = 0; element_to_graphic[i].element > -1; i++)
282     InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
283
284   /* initialize special images from static configuration */
285   for (i = 0; element_to_special_graphic[i].element > -1; i++)
286     InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
287
288   /* initialize images from dynamic configuration (may be elements or other) */
289   for (i = 0; i < num_property_mappings; i++)
290     InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
291
292   /* initialize special images from above list (non-element images) */
293   for (i = 0; special_graphics[i] > -1; i++)
294     InitElementSmallImagesScaledUp(special_graphics[i]);
295 }
296
297 void InitScaledImages()
298 {
299   int i;
300
301   /* scale normal images from static configuration, if not already scaled */
302   for (i = 0; i < NUM_IMAGE_FILES; i++)
303     ScaleImage(i, graphic_info[i].scale_up_factor);
304 }
305
306 #if 1
307 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
308 void SetBitmaps_EM(Bitmap **em_bitmap)
309 {
310   em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
311   em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
312 }
313 #endif
314
315 static int getFontBitmapID(int font_nr)
316 {
317   int special = -1;
318
319   /* (special case: do not use special font for GAME_MODE_LOADING) */
320   if (game_status >= GAME_MODE_TITLE_INITIAL &&
321       game_status <= GAME_MODE_PSEUDO_PREVIEW)
322     special = game_status;
323   else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
324     special = GFX_SPECIAL_ARG_MAIN;
325 #if 0
326   else if (game_status == GAME_MODE_PLAYING)
327     special = GFX_SPECIAL_ARG_DOOR;
328 #endif
329
330   if (special != -1)
331     return font_info[font_nr].special_bitmap_id[special];
332   else
333     return font_nr;
334 }
335
336 static int getFontFromToken(char *token)
337 {
338 #if 1
339   char *value = getHashEntry(font_token_hash, token);
340
341   if (value != NULL)
342     return atoi(value);
343 #else
344   int i;
345
346   /* !!! OPTIMIZE THIS BY USING HASH !!! */
347   for (i = 0; i < NUM_FONTS; i++)
348     if (strEqual(token, font_info[i].token_name))
349       return i;
350 #endif
351
352   /* if font not found, use reliable default value */
353   return FONT_INITIAL_1;
354 }
355
356 void InitFontGraphicInfo()
357 {
358   static struct FontBitmapInfo *font_bitmap_info = NULL;
359   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
360   int num_property_mappings = getImageListPropertyMappingSize();
361   int num_font_bitmaps = NUM_FONTS;
362   int i, j;
363
364   if (graphic_info == NULL)             /* still at startup phase */
365   {
366     InitFontInfo(font_initial, NUM_INITIAL_FONTS,
367                  getFontBitmapID, getFontFromToken);
368
369     return;
370   }
371
372   /* ---------- initialize font graphic definitions ---------- */
373
374   /* always start with reliable default values (normal font graphics) */
375   for (i = 0; i < NUM_FONTS; i++)
376     font_info[i].graphic = IMG_FONT_INITIAL_1;
377
378   /* initialize normal font/graphic mapping from static configuration */
379   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
380   {
381     int font_nr = font_to_graphic[i].font_nr;
382     int special = font_to_graphic[i].special;
383     int graphic = font_to_graphic[i].graphic;
384
385     if (special != -1)
386       continue;
387
388     font_info[font_nr].graphic = graphic;
389   }
390
391   /* always start with reliable default values (special font graphics) */
392   for (i = 0; i < NUM_FONTS; i++)
393   {
394     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
395     {
396       font_info[i].special_graphic[j] = font_info[i].graphic;
397       font_info[i].special_bitmap_id[j] = i;
398     }
399   }
400
401   /* initialize special font/graphic mapping from static configuration */
402   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
403   {
404     int font_nr      = font_to_graphic[i].font_nr;
405     int special      = font_to_graphic[i].special;
406     int graphic      = font_to_graphic[i].graphic;
407     int base_graphic = font2baseimg(font_nr);
408
409     if (IS_SPECIAL_GFX_ARG(special))
410     {
411       boolean base_redefined =
412         getImageListEntryFromImageID(base_graphic)->redefined;
413       boolean special_redefined =
414         getImageListEntryFromImageID(graphic)->redefined;
415       boolean special_cloned = (graphic_info[graphic].clone_from != -1);
416
417       /* if the base font ("font.title_1", for example) has been redefined,
418          but not the special font ("font.title_1.LEVELS", for example), do not
419          use an existing (in this case considered obsolete) special font
420          anymore, but use the automatically determined default font */
421       /* special case: cloned special fonts must be explicitly redefined,
422          but are not automatically redefined by redefining base font */
423       if (base_redefined && !special_redefined && !special_cloned)
424         continue;
425
426       font_info[font_nr].special_graphic[special] = graphic;
427       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
428       num_font_bitmaps++;
429     }
430   }
431
432   /* initialize special font/graphic mapping from dynamic configuration */
433   for (i = 0; i < num_property_mappings; i++)
434   {
435     int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
436     int special = property_mapping[i].ext3_index;
437     int graphic = property_mapping[i].artwork_index;
438
439     if (font_nr < 0)
440       continue;
441
442     if (IS_SPECIAL_GFX_ARG(special))
443     {
444       font_info[font_nr].special_graphic[special] = graphic;
445       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
446       num_font_bitmaps++;
447     }
448   }
449
450   /* correct special font/graphic mapping for cloned fonts for downwards
451      compatibility of PREVIEW fonts -- this is only needed for implicit
452      redefinition of special font by redefined base font, and only if other
453      fonts are cloned from this special font (like in the "Zelda" level set) */
454   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
455   {
456     int font_nr = font_to_graphic[i].font_nr;
457     int special = font_to_graphic[i].special;
458     int graphic = font_to_graphic[i].graphic;
459
460     if (IS_SPECIAL_GFX_ARG(special))
461     {
462       boolean special_redefined =
463         getImageListEntryFromImageID(graphic)->redefined;
464       boolean special_cloned = (graphic_info[graphic].clone_from != -1);
465
466       if (special_cloned && !special_redefined)
467       {
468         int j;
469
470         for (j = 0; font_to_graphic[j].font_nr > -1; j++)
471         {
472           int font_nr2 = font_to_graphic[j].font_nr;
473           int special2 = font_to_graphic[j].special;
474           int graphic2 = font_to_graphic[j].graphic;
475
476           if (IS_SPECIAL_GFX_ARG(special2) &&
477               graphic2 == graphic_info[graphic].clone_from)
478           {
479             font_info[font_nr].special_graphic[special] =
480               font_info[font_nr2].special_graphic[special2];
481             font_info[font_nr].special_bitmap_id[special] =
482               font_info[font_nr2].special_bitmap_id[special2];
483           }
484         }
485       }
486     }
487   }
488
489   /* reset non-redefined ".active" font graphics if normal font is redefined */
490   /* (this different treatment is needed because normal and active fonts are
491      independently defined ("active" is not a property of font definitions!) */
492   for (i = 0; i < NUM_FONTS; i++)
493   {
494     int font_nr_base = i;
495     int font_nr_active = FONT_ACTIVE(font_nr_base);
496
497     /* check only those fonts with exist as normal and ".active" variant */
498     if (font_nr_base != font_nr_active)
499     {
500       int base_graphic = font_info[font_nr_base].graphic;
501       int active_graphic = font_info[font_nr_active].graphic;
502       boolean base_redefined =
503         getImageListEntryFromImageID(base_graphic)->redefined;
504       boolean active_redefined =
505         getImageListEntryFromImageID(active_graphic)->redefined;
506
507       /* if the base font ("font.menu_1", for example) has been redefined,
508          but not the active font ("font.menu_1.active", for example), do not
509          use an existing (in this case considered obsolete) active font
510          anymore, but use the automatically determined default font */
511       if (base_redefined && !active_redefined)
512         font_info[font_nr_active].graphic = base_graphic;
513
514       /* now also check each "special" font (which may be the same as above) */
515       for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
516       {
517         int base_graphic = font_info[font_nr_base].special_graphic[j];
518         int active_graphic = font_info[font_nr_active].special_graphic[j];
519         boolean base_redefined =
520           getImageListEntryFromImageID(base_graphic)->redefined;
521         boolean active_redefined =
522           getImageListEntryFromImageID(active_graphic)->redefined;
523
524         /* same as above, but check special graphic definitions, for example:
525            redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
526         if (base_redefined && !active_redefined)
527         {
528           font_info[font_nr_active].special_graphic[j] =
529             font_info[font_nr_base].special_graphic[j];
530           font_info[font_nr_active].special_bitmap_id[j] =
531             font_info[font_nr_base].special_bitmap_id[j];
532         }
533       }
534     }
535   }
536
537   /* ---------- initialize font bitmap array ---------- */
538
539   if (font_bitmap_info != NULL)
540     FreeFontInfo(font_bitmap_info);
541
542   font_bitmap_info =
543     checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
544
545   /* ---------- initialize font bitmap definitions ---------- */
546
547   for (i = 0; i < NUM_FONTS; i++)
548   {
549     if (i < NUM_INITIAL_FONTS)
550     {
551       font_bitmap_info[i] = font_initial[i];
552       continue;
553     }
554
555     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
556     {
557       int font_bitmap_id = font_info[i].special_bitmap_id[j];
558       int graphic = font_info[i].special_graphic[j];
559
560       /* set 'graphic_info' for font entries, if uninitialized (guessed) */
561       if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
562       {
563         graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
564         graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
565       }
566
567       /* copy font relevant information from graphics information */
568       font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
569       font_bitmap_info[font_bitmap_id].src_x  = graphic_info[graphic].src_x;
570       font_bitmap_info[font_bitmap_id].src_y  = graphic_info[graphic].src_y;
571       font_bitmap_info[font_bitmap_id].width  = graphic_info[graphic].width;
572       font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
573
574       font_bitmap_info[font_bitmap_id].draw_xoffset =
575         graphic_info[graphic].draw_xoffset;
576       font_bitmap_info[font_bitmap_id].draw_yoffset =
577         graphic_info[graphic].draw_yoffset;
578
579       font_bitmap_info[font_bitmap_id].num_chars =
580         graphic_info[graphic].anim_frames;
581       font_bitmap_info[font_bitmap_id].num_chars_per_line =
582         graphic_info[graphic].anim_frames_per_line;
583     }
584   }
585
586   InitFontInfo(font_bitmap_info, num_font_bitmaps,
587                getFontBitmapID, getFontFromToken);
588 }
589
590 void InitElementGraphicInfo()
591 {
592   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
593   int num_property_mappings = getImageListPropertyMappingSize();
594   int i, act, dir;
595
596   if (graphic_info == NULL)             /* still at startup phase */
597     return;
598
599   /* set values to -1 to identify later as "uninitialized" values */
600   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
601   {
602     for (act = 0; act < NUM_ACTIONS; act++)
603     {
604       element_info[i].graphic[act] = -1;
605       element_info[i].crumbled[act] = -1;
606
607       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
608       {
609         element_info[i].direction_graphic[act][dir] = -1;
610         element_info[i].direction_crumbled[act][dir] = -1;
611       }
612     }
613   }
614
615   UPDATE_BUSY_STATE();
616
617   /* initialize normal element/graphic mapping from static configuration */
618   for (i = 0; element_to_graphic[i].element > -1; i++)
619   {
620     int element      = element_to_graphic[i].element;
621     int action       = element_to_graphic[i].action;
622     int direction    = element_to_graphic[i].direction;
623     boolean crumbled = element_to_graphic[i].crumbled;
624     int graphic      = element_to_graphic[i].graphic;
625     int base_graphic = el2baseimg(element);
626
627     if (graphic_info[graphic].bitmap == NULL)
628       continue;
629
630     if ((action > -1 || direction > -1 || crumbled == TRUE) &&
631         base_graphic != -1)
632     {
633       boolean base_redefined =
634         getImageListEntryFromImageID(base_graphic)->redefined;
635       boolean act_dir_redefined =
636         getImageListEntryFromImageID(graphic)->redefined;
637
638       /* if the base graphic ("emerald", for example) has been redefined,
639          but not the action graphic ("emerald.falling", for example), do not
640          use an existing (in this case considered obsolete) action graphic
641          anymore, but use the automatically determined default graphic */
642       if (base_redefined && !act_dir_redefined)
643         continue;
644     }
645
646     if (action < 0)
647       action = ACTION_DEFAULT;
648
649     if (crumbled)
650     {
651       if (direction > -1)
652         element_info[element].direction_crumbled[action][direction] = graphic;
653       else
654         element_info[element].crumbled[action] = graphic;
655     }
656     else
657     {
658       if (direction > -1)
659         element_info[element].direction_graphic[action][direction] = graphic;
660       else
661         element_info[element].graphic[action] = graphic;
662     }
663   }
664
665   /* initialize normal element/graphic mapping from dynamic configuration */
666   for (i = 0; i < num_property_mappings; i++)
667   {
668     int element   = property_mapping[i].base_index;
669     int action    = property_mapping[i].ext1_index;
670     int direction = property_mapping[i].ext2_index;
671     int special   = property_mapping[i].ext3_index;
672     int graphic   = property_mapping[i].artwork_index;
673     boolean crumbled = FALSE;
674
675 #if 0
676     if ((element == EL_EM_DYNAMITE ||
677          element == EL_EM_DYNAMITE_ACTIVE) &&
678         action == ACTION_ACTIVE &&
679         (special == GFX_SPECIAL_ARG_EDITOR ||
680          special == GFX_SPECIAL_ARG_PANEL))
681       printf("::: DYNAMIC: %d, %d, %d -> %d\n",
682              element, action, special, graphic);
683 #endif
684
685     if (special == GFX_SPECIAL_ARG_CRUMBLED)
686     {
687       special = -1;
688       crumbled = TRUE;
689     }
690
691     if (graphic_info[graphic].bitmap == NULL)
692       continue;
693
694     if (element >= MAX_NUM_ELEMENTS || special != -1)
695       continue;
696
697     if (action < 0)
698       action = ACTION_DEFAULT;
699
700     if (crumbled)
701     {
702       if (direction < 0)
703         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
704           element_info[element].direction_crumbled[action][dir] = -1;
705
706       if (direction > -1)
707         element_info[element].direction_crumbled[action][direction] = graphic;
708       else
709         element_info[element].crumbled[action] = graphic;
710     }
711     else
712     {
713       if (direction < 0)
714         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
715           element_info[element].direction_graphic[action][dir] = -1;
716
717       if (direction > -1)
718         element_info[element].direction_graphic[action][direction] = graphic;
719       else
720         element_info[element].graphic[action] = graphic;
721     }
722   }
723
724   /* now copy all graphics that are defined to be cloned from other graphics */
725   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
726   {
727     int graphic = element_info[i].graphic[ACTION_DEFAULT];
728     int crumbled_like, diggable_like;
729
730     if (graphic == -1)
731       continue;
732
733     crumbled_like = graphic_info[graphic].crumbled_like;
734     diggable_like = graphic_info[graphic].diggable_like;
735
736     if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
737     {
738       for (act = 0; act < NUM_ACTIONS; act++)
739         element_info[i].crumbled[act] =
740           element_info[crumbled_like].crumbled[act];
741       for (act = 0; act < NUM_ACTIONS; act++)
742         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
743           element_info[i].direction_crumbled[act][dir] =
744             element_info[crumbled_like].direction_crumbled[act][dir];
745     }
746
747     if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
748     {
749       element_info[i].graphic[ACTION_DIGGING] =
750         element_info[diggable_like].graphic[ACTION_DIGGING];
751       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
752         element_info[i].direction_graphic[ACTION_DIGGING][dir] =
753           element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
754     }
755   }
756
757 #if 1
758   /* set hardcoded definitions for some runtime elements without graphic */
759   element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
760 #endif
761
762 #if 1
763   /* set hardcoded definitions for some internal elements without graphic */
764   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
765   {
766     if (IS_EDITOR_CASCADE_INACTIVE(i))
767       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
768     else if (IS_EDITOR_CASCADE_ACTIVE(i))
769       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
770   }
771 #endif
772
773   /* now set all undefined/invalid graphics to -1 to set to default after it */
774   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
775   {
776     for (act = 0; act < NUM_ACTIONS; act++)
777     {
778       int graphic;
779
780       graphic = element_info[i].graphic[act];
781       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
782         element_info[i].graphic[act] = -1;
783
784       graphic = element_info[i].crumbled[act];
785       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
786         element_info[i].crumbled[act] = -1;
787
788       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
789       {
790         graphic = element_info[i].direction_graphic[act][dir];
791         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
792           element_info[i].direction_graphic[act][dir] = -1;
793
794         graphic = element_info[i].direction_crumbled[act][dir];
795         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
796           element_info[i].direction_crumbled[act][dir] = -1;
797       }
798     }
799   }
800
801   UPDATE_BUSY_STATE();
802
803   /* adjust graphics with 2nd tile for movement according to direction
804      (do this before correcting '-1' values to minimize calculations) */
805   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
806   {
807     for (act = 0; act < NUM_ACTIONS; act++)
808     {
809       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
810       {
811         int graphic = element_info[i].direction_graphic[act][dir];
812         int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
813
814         if (act == ACTION_FALLING)      /* special case */
815           graphic = element_info[i].graphic[act];
816
817         if (graphic != -1 &&
818             graphic_info[graphic].double_movement &&
819             graphic_info[graphic].swap_double_tiles != 0)
820         {
821           struct GraphicInfo *g = &graphic_info[graphic];
822           int src_x_front = g->src_x;
823           int src_y_front = g->src_y;
824           int src_x_back = g->src_x + g->offset2_x;
825           int src_y_back = g->src_y + g->offset2_y;
826           boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
827                                                    g->offset_y != 0);
828           boolean front_is_left_or_upper = (src_x_front < src_x_back ||
829                                             src_y_front < src_y_back);
830           boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
831           boolean swap_movement_tiles_autodetected =
832             (!frames_are_ordered_diagonally &&
833              ((move_dir == MV_BIT_LEFT  && !front_is_left_or_upper) ||
834               (move_dir == MV_BIT_UP    && !front_is_left_or_upper) ||
835               (move_dir == MV_BIT_RIGHT &&  front_is_left_or_upper) ||
836               (move_dir == MV_BIT_DOWN  &&  front_is_left_or_upper)));
837           Bitmap *dummy;
838
839           /* swap frontside and backside graphic tile coordinates, if needed */
840           if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
841           {
842             /* get current (wrong) backside tile coordinates */
843             getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
844                                 TRUE);
845
846             /* set frontside tile coordinates to backside tile coordinates */
847             g->src_x = src_x_back;
848             g->src_y = src_y_back;
849
850             /* invert tile offset to point to new backside tile coordinates */
851             g->offset2_x *= -1;
852             g->offset2_y *= -1;
853
854             /* do not swap front and backside tiles again after correction */
855             g->swap_double_tiles = 0;
856           }
857         }
858       }
859     }
860   }
861
862   UPDATE_BUSY_STATE();
863
864   /* now set all '-1' values to element specific default values */
865   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
866   {
867     int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
868     int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
869     int default_direction_graphic[NUM_DIRECTIONS_FULL];
870     int default_direction_crumbled[NUM_DIRECTIONS_FULL];
871
872     if (default_graphic == -1)
873       default_graphic = IMG_UNKNOWN;
874 #if 1
875     if (default_crumbled == -1)
876       default_crumbled = default_graphic;
877 #else
878     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
879     if (default_crumbled == -1)
880       default_crumbled = IMG_EMPTY;
881 #endif
882
883     for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
884     {
885       default_direction_graphic[dir] =
886         element_info[i].direction_graphic[ACTION_DEFAULT][dir];
887       default_direction_crumbled[dir] =
888         element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
889
890       if (default_direction_graphic[dir] == -1)
891         default_direction_graphic[dir] = default_graphic;
892 #if 1
893       if (default_direction_crumbled[dir] == -1)
894         default_direction_crumbled[dir] = default_direction_graphic[dir];
895 #else
896       /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
897       if (default_direction_crumbled[dir] == -1)
898         default_direction_crumbled[dir] = default_crumbled;
899 #endif
900     }
901
902     for (act = 0; act < NUM_ACTIONS; act++)
903     {
904       boolean act_remove = ((IS_DIGGABLE(i)    && act == ACTION_DIGGING)  ||
905                             (IS_SNAPPABLE(i)   && act == ACTION_SNAPPING) ||
906                             (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
907       boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
908                              act == ACTION_TURNING_FROM_RIGHT ||
909                              act == ACTION_TURNING_FROM_UP ||
910                              act == ACTION_TURNING_FROM_DOWN);
911
912       /* generic default action graphic (defined by "[default]" directive) */
913       int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
914       int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
915       int default_remove_graphic = IMG_EMPTY;
916
917       if (act_remove && default_action_graphic != -1)
918         default_remove_graphic = default_action_graphic;
919
920       /* look for special default action graphic (classic game specific) */
921       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
922         default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
923       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
924         default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
925       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
926         default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
927
928       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
929         default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
930       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
931         default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
932       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
933         default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
934
935 #if 1
936       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
937       /* !!! make this better !!! */
938       if (i == EL_EMPTY_SPACE)
939       {
940         default_action_graphic = element_info[EL_DEFAULT].graphic[act];
941         default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
942       }
943 #endif
944
945       if (default_action_graphic == -1)
946         default_action_graphic = default_graphic;
947 #if 1
948       if (default_action_crumbled == -1)
949         default_action_crumbled = default_action_graphic;
950 #else
951       /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
952       if (default_action_crumbled == -1)
953         default_action_crumbled = default_crumbled;
954 #endif
955
956       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
957       {
958         /* use action graphic as the default direction graphic, if undefined */
959         int default_action_direction_graphic = element_info[i].graphic[act];
960         int default_action_direction_crumbled = element_info[i].crumbled[act];
961
962         /* no graphic for current action -- use default direction graphic */
963         if (default_action_direction_graphic == -1)
964           default_action_direction_graphic =
965             (act_remove ? default_remove_graphic :
966              act_turning ?
967              element_info[i].direction_graphic[ACTION_TURNING][dir] :
968              default_action_graphic != default_graphic ?
969              default_action_graphic :
970              default_direction_graphic[dir]);
971
972         if (element_info[i].direction_graphic[act][dir] == -1)
973           element_info[i].direction_graphic[act][dir] =
974             default_action_direction_graphic;
975
976 #if 1
977         if (default_action_direction_crumbled == -1)
978           default_action_direction_crumbled =
979             element_info[i].direction_graphic[act][dir];
980 #else
981         if (default_action_direction_crumbled == -1)
982           default_action_direction_crumbled =
983             (act_remove ? default_remove_graphic :
984              act_turning ?
985              element_info[i].direction_crumbled[ACTION_TURNING][dir] :
986              default_action_crumbled != default_crumbled ?
987              default_action_crumbled :
988              default_direction_crumbled[dir]);
989 #endif
990
991         if (element_info[i].direction_crumbled[act][dir] == -1)
992           element_info[i].direction_crumbled[act][dir] =
993             default_action_direction_crumbled;
994       }
995
996       /* no graphic for this specific action -- use default action graphic */
997       if (element_info[i].graphic[act] == -1)
998         element_info[i].graphic[act] =
999           (act_remove ? default_remove_graphic :
1000            act_turning ? element_info[i].graphic[ACTION_TURNING] :
1001            default_action_graphic);
1002 #if 1
1003       if (element_info[i].crumbled[act] == -1)
1004         element_info[i].crumbled[act] = element_info[i].graphic[act];
1005 #else
1006       if (element_info[i].crumbled[act] == -1)
1007         element_info[i].crumbled[act] =
1008           (act_remove ? default_remove_graphic :
1009            act_turning ? element_info[i].crumbled[ACTION_TURNING] :
1010            default_action_crumbled);
1011 #endif
1012     }
1013   }
1014
1015   UPDATE_BUSY_STATE();
1016
1017 #if 0
1018   /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
1019   /* set animation mode to "none" for each graphic with only 1 frame */
1020   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1021   {
1022     for (act = 0; act < NUM_ACTIONS; act++)
1023     {
1024       int graphic = element_info[i].graphic[act];
1025       int crumbled = element_info[i].crumbled[act];
1026
1027       if (graphic_info[graphic].anim_frames == 1)
1028         graphic_info[graphic].anim_mode = ANIM_NONE;
1029       if (graphic_info[crumbled].anim_frames == 1)
1030         graphic_info[crumbled].anim_mode = ANIM_NONE;
1031
1032       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1033       {
1034         graphic = element_info[i].direction_graphic[act][dir];
1035         crumbled = element_info[i].direction_crumbled[act][dir];
1036
1037         if (graphic_info[graphic].anim_frames == 1)
1038           graphic_info[graphic].anim_mode = ANIM_NONE;
1039         if (graphic_info[crumbled].anim_frames == 1)
1040           graphic_info[crumbled].anim_mode = ANIM_NONE;
1041       }
1042     }
1043   }
1044 #endif
1045
1046 #if 0
1047 #if DEBUG
1048   if (options.verbose)
1049   {
1050     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1051       if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1052           i != EL_UNKNOWN)
1053         Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1054               element_info[i].token_name, i);
1055   }
1056 #endif
1057 #endif
1058 }
1059
1060 void InitElementSpecialGraphicInfo()
1061 {
1062   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1063   int num_property_mappings = getImageListPropertyMappingSize();
1064   int i, j;
1065
1066   /* always start with reliable default values */
1067   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1068     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1069       element_info[i].special_graphic[j] =
1070         element_info[i].graphic[ACTION_DEFAULT];
1071
1072   /* initialize special element/graphic mapping from static configuration */
1073   for (i = 0; element_to_special_graphic[i].element > -1; i++)
1074   {
1075     int element = element_to_special_graphic[i].element;
1076     int special = element_to_special_graphic[i].special;
1077     int graphic = element_to_special_graphic[i].graphic;
1078     int base_graphic = el2baseimg(element);
1079     boolean base_redefined =
1080       getImageListEntryFromImageID(base_graphic)->redefined;
1081     boolean special_redefined =
1082       getImageListEntryFromImageID(graphic)->redefined;
1083
1084 #if 0
1085     if ((element == EL_EM_DYNAMITE ||
1086          element == EL_EM_DYNAMITE_ACTIVE) &&
1087         (special == GFX_SPECIAL_ARG_EDITOR ||
1088          special == GFX_SPECIAL_ARG_PANEL))
1089       printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1090              element, special, graphic);
1091 #endif
1092
1093     /* if the base graphic ("emerald", for example) has been redefined,
1094        but not the special graphic ("emerald.EDITOR", for example), do not
1095        use an existing (in this case considered obsolete) special graphic
1096        anymore, but use the automatically created (down-scaled) graphic */
1097     if (base_redefined && !special_redefined)
1098       continue;
1099
1100     element_info[element].special_graphic[special] = graphic;
1101   }
1102
1103   /* initialize special element/graphic mapping from dynamic configuration */
1104   for (i = 0; i < num_property_mappings; i++)
1105   {
1106     int element   = property_mapping[i].base_index;
1107     int action    = property_mapping[i].ext1_index;
1108     int direction = property_mapping[i].ext2_index;
1109     int special   = property_mapping[i].ext3_index;
1110     int graphic   = property_mapping[i].artwork_index;
1111
1112 #if 0
1113     if ((element == EL_EM_DYNAMITE ||
1114          element == EL_EM_DYNAMITE_ACTIVE ||
1115          element == EL_CONVEYOR_BELT_1_MIDDLE ||
1116          element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1117         (special == GFX_SPECIAL_ARG_EDITOR ||
1118          special == GFX_SPECIAL_ARG_PANEL))
1119       printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1120              element, special, graphic, property_mapping[i].ext1_index);
1121 #endif
1122
1123 #if 0
1124     if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1125         action == ACTION_ACTIVE)
1126     {
1127       element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1128       action = -1;
1129     }
1130 #endif
1131
1132 #if 0
1133     if (element == EL_MAGIC_WALL &&
1134         action == ACTION_ACTIVE)
1135     {
1136       element = EL_MAGIC_WALL_ACTIVE;
1137       action = -1;
1138     }
1139 #endif
1140
1141 #if 1
1142     /* for action ".active", replace element with active element, if exists */
1143     if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1144     {
1145       element = ELEMENT_ACTIVE(element);
1146       action = -1;
1147     }
1148 #endif
1149
1150     if (element >= MAX_NUM_ELEMENTS)
1151       continue;
1152
1153     /* do not change special graphic if action or direction was specified */
1154     if (action != -1 || direction != -1)
1155       continue;
1156
1157     if (IS_SPECIAL_GFX_ARG(special))
1158       element_info[element].special_graphic[special] = graphic;
1159   }
1160
1161   /* now set all undefined/invalid graphics to default */
1162   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1163     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1164       if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1165         element_info[i].special_graphic[j] =
1166           element_info[i].graphic[ACTION_DEFAULT];
1167 }
1168
1169 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1170 {
1171   if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1172     return get_parameter_value(value_raw, suffix, type);
1173
1174   if (strEqual(value_raw, ARG_UNDEFINED))
1175     return ARG_UNDEFINED_VALUE;
1176
1177 #if 1
1178   if (type == TYPE_ELEMENT)
1179   {
1180     char *value = getHashEntry(element_token_hash, value_raw);
1181
1182     return (value != NULL ? atoi(value) : EL_UNDEFINED);
1183   }
1184   else if (type == TYPE_GRAPHIC)
1185   {
1186     char *value = getHashEntry(graphic_token_hash, value_raw);
1187
1188     return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1189   }
1190
1191 #else
1192
1193   int i;
1194   int x = 0;
1195
1196   /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1197   /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1198
1199   /* !!! OPTIMIZE THIS BY USING HASH !!! */
1200   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1201     if (strEqual(element_info[i].token_name, value_raw))
1202       return i;
1203
1204   /* !!! OPTIMIZE THIS BY USING HASH !!! */
1205   for (i = 0; image_config[i].token != NULL; i++)
1206   {
1207     int len_config_value = strlen(image_config[i].value);
1208
1209     if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1210         !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1211         !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1212       continue;
1213
1214     if (strEqual(image_config[i].token, value_raw))
1215       return x;
1216
1217     x++;
1218   }
1219 #endif
1220
1221   return -1;
1222 }
1223
1224 static int get_scaled_graphic_width(int graphic)
1225 {
1226   int original_width = getOriginalImageWidthFromImageID(graphic);
1227   int scale_up_factor = graphic_info[graphic].scale_up_factor;
1228
1229   return original_width * scale_up_factor;
1230 }
1231
1232 static int get_scaled_graphic_height(int graphic)
1233 {
1234   int original_height = getOriginalImageHeightFromImageID(graphic);
1235   int scale_up_factor = graphic_info[graphic].scale_up_factor;
1236
1237   return original_height * scale_up_factor;
1238 }
1239
1240 static void set_graphic_parameters_ext(int graphic, struct GraphicInfo *g,
1241                                        int *parameter, Bitmap *src_bitmap)
1242 {
1243   int anim_frames_per_row = 1, anim_frames_per_col = 1;
1244   int anim_frames_per_line = 1;
1245
1246   /* always start with reliable default values */
1247   g->src_image_width = 0;
1248   g->src_image_height = 0;
1249   g->src_x = 0;
1250   g->src_y = 0;
1251   g->width  = TILEX;                    /* default for element graphics */
1252   g->height = TILEY;                    /* default for element graphics */
1253   g->offset_x = 0;                      /* one or both of these values ... */
1254   g->offset_y = 0;                      /* ... will be corrected later */
1255   g->offset2_x = 0;                     /* one or both of these values ... */
1256   g->offset2_y = 0;                     /* ... will be corrected later */
1257   g->swap_double_tiles = -1;            /* auto-detect tile swapping */
1258   g->crumbled_like = -1;                /* do not use clone element */
1259   g->diggable_like = -1;                /* do not use clone element */
1260   g->border_size = TILEX / 8;           /* "CRUMBLED" border size */
1261   g->scale_up_factor = 1;               /* default: no scaling up */
1262   g->clone_from = -1;                   /* do not use clone graphic */
1263   g->anim_delay_fixed = 0;
1264   g->anim_delay_random = 0;
1265   g->post_delay_fixed = 0;
1266   g->post_delay_random = 0;
1267   g->fade_mode = FADE_MODE_DEFAULT;
1268   g->fade_delay = -1;
1269   g->post_delay = -1;
1270   g->auto_delay = -1;
1271   g->align = ALIGN_CENTER;              /* default for title screens */
1272   g->valign = VALIGN_MIDDLE;            /* default for title screens */
1273   g->sort_priority = 0;                 /* default for title screens */
1274
1275   g->bitmap = src_bitmap;
1276
1277 #if 1
1278   /* optional zoom factor for scaling up the image to a larger size */
1279   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1280     g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1281   if (g->scale_up_factor < 1)
1282     g->scale_up_factor = 1;             /* no scaling */
1283 #endif
1284
1285 #if 1
1286   if (g->use_image_size)
1287   {
1288     /* set new default bitmap size (with scaling, but without small images) */
1289     g->width  = get_scaled_graphic_width(graphic);
1290     g->height = get_scaled_graphic_height(graphic);
1291   }
1292 #endif
1293
1294   /* optional x and y tile position of animation frame sequence */
1295   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1296     g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1297   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1298     g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1299
1300   /* optional x and y pixel position of animation frame sequence */
1301   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1302     g->src_x = parameter[GFX_ARG_X];
1303   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1304     g->src_y = parameter[GFX_ARG_Y];
1305
1306   /* optional width and height of each animation frame */
1307   if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1308     g->width = parameter[GFX_ARG_WIDTH];
1309   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1310     g->height = parameter[GFX_ARG_HEIGHT];
1311
1312 #if 0
1313   /* optional zoom factor for scaling up the image to a larger size */
1314   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1315     g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1316   if (g->scale_up_factor < 1)
1317     g->scale_up_factor = 1;             /* no scaling */
1318 #endif
1319
1320   if (src_bitmap)
1321   {
1322     /* get final bitmap size (with scaling, but without small images) */
1323     int src_image_width  = get_scaled_graphic_width(graphic);
1324     int src_image_height = get_scaled_graphic_height(graphic);
1325
1326     anim_frames_per_row = src_image_width  / g->width;
1327     anim_frames_per_col = src_image_height / g->height;
1328
1329     g->src_image_width  = src_image_width;
1330     g->src_image_height = src_image_height;
1331   }
1332
1333   /* correct x or y offset dependent of vertical or horizontal frame order */
1334   if (parameter[GFX_ARG_VERTICAL])      /* frames are ordered vertically */
1335   {
1336     g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1337                    parameter[GFX_ARG_OFFSET] : g->height);
1338     anim_frames_per_line = anim_frames_per_col;
1339   }
1340   else                                  /* frames are ordered horizontally */
1341   {
1342     g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1343                    parameter[GFX_ARG_OFFSET] : g->width);
1344     anim_frames_per_line = anim_frames_per_row;
1345   }
1346
1347   /* optionally, the x and y offset of frames can be specified directly */
1348   if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1349     g->offset_x = parameter[GFX_ARG_XOFFSET];
1350   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1351     g->offset_y = parameter[GFX_ARG_YOFFSET];
1352
1353   /* optionally, moving animations may have separate start and end graphics */
1354   g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1355
1356   if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1357     parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1358
1359   /* correct x or y offset2 dependent of vertical or horizontal frame order */
1360   if (parameter[GFX_ARG_2ND_VERTICAL])  /* frames are ordered vertically */
1361     g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1362                     parameter[GFX_ARG_2ND_OFFSET] : g->height);
1363   else                                  /* frames are ordered horizontally */
1364     g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1365                     parameter[GFX_ARG_2ND_OFFSET] : g->width);
1366
1367   /* optionally, the x and y offset of 2nd graphic can be specified directly */
1368   if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1369     g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1370   if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1371     g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1372
1373   /* optionally, the second movement tile can be specified as start tile */
1374   if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1375     g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1376
1377   /* automatically determine correct number of frames, if not defined */
1378   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1379     g->anim_frames = parameter[GFX_ARG_FRAMES];
1380   else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1381     g->anim_frames = anim_frames_per_row;
1382   else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1383     g->anim_frames = anim_frames_per_col;
1384   else
1385     g->anim_frames = 1;
1386
1387   if (g->anim_frames == 0)              /* frames must be at least 1 */
1388     g->anim_frames = 1;
1389
1390   g->anim_frames_per_line =
1391     (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1392      parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1393
1394   g->anim_delay = parameter[GFX_ARG_DELAY];
1395   if (g->anim_delay == 0)               /* delay must be at least 1 */
1396     g->anim_delay = 1;
1397
1398   g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1399 #if 0
1400   if (g->anim_frames == 1)
1401     g->anim_mode = ANIM_NONE;
1402 #endif
1403
1404   /* automatically determine correct start frame, if not defined */
1405   if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1406     g->anim_start_frame = 0;
1407   else if (g->anim_mode & ANIM_REVERSE)
1408     g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1409   else
1410     g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1411
1412   /* animation synchronized with global frame counter, not move position */
1413   g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1414
1415   /* optional element for cloning crumble graphics */
1416   if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1417     g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1418
1419   /* optional element for cloning digging graphics */
1420   if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1421     g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1422
1423   /* optional border size for "crumbling" diggable graphics */
1424   if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1425     g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1426
1427   /* this is only used for player "boring" and "sleeping" actions */
1428   if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1429     g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1430   if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1431     g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1432   if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1433     g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1434   if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1435     g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1436
1437   /* this is only used for toon animations */
1438   g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1439   g->step_delay  = parameter[GFX_ARG_STEP_DELAY];
1440
1441   /* this is only used for drawing font characters */
1442   g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1443   g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1444
1445   /* this is only used for drawing envelope graphics */
1446   g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1447
1448   /* optional graphic for cloning all graphics settings */
1449   if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1450     g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1451
1452   /* optional settings for drawing title screens and title messages */
1453   if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1454     g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1455   if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1456     g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1457   if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1458     g->post_delay = parameter[GFX_ARG_POST_DELAY];
1459   if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1460     g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1461   if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1462     g->align = parameter[GFX_ARG_ALIGN];
1463   if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1464     g->valign = parameter[GFX_ARG_VALIGN];
1465   if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1466     g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1467 }
1468
1469 static void set_graphic_parameters(int graphic)
1470 {
1471 #if 1
1472   struct FileInfo *image = getImageListEntryFromImageID(graphic);
1473   char **parameter_raw = image->parameter;
1474   Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1475   int parameter[NUM_GFX_ARGS];
1476   int i;
1477
1478   /* if fallback to default artwork is done, also use the default parameters */
1479   if (image->fallback_to_default)
1480     parameter_raw = image->default_parameter;
1481
1482   /* get integer values from string parameters */
1483   for (i = 0; i < NUM_GFX_ARGS; i++)
1484     parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1485                                                image_config_suffix[i].token,
1486                                                image_config_suffix[i].type);
1487
1488   set_graphic_parameters_ext(graphic, &graphic_info[graphic],
1489                              parameter, src_bitmap);
1490
1491 #else
1492
1493   struct FileInfo *image = getImageListEntryFromImageID(graphic);
1494   char **parameter_raw = image->parameter;
1495   Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1496   int parameter[NUM_GFX_ARGS];
1497   int anim_frames_per_row = 1, anim_frames_per_col = 1;
1498   int anim_frames_per_line = 1;
1499   int i;
1500
1501   /* if fallback to default artwork is done, also use the default parameters */
1502   if (image->fallback_to_default)
1503     parameter_raw = image->default_parameter;
1504
1505   /* get integer values from string parameters */
1506   for (i = 0; i < NUM_GFX_ARGS; i++)
1507     parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1508                                                image_config_suffix[i].token,
1509                                                image_config_suffix[i].type);
1510
1511   graphic_info[graphic].bitmap = src_bitmap;
1512
1513   /* always start with reliable default values */
1514   graphic_info[graphic].src_image_width = 0;
1515   graphic_info[graphic].src_image_height = 0;
1516   graphic_info[graphic].src_x = 0;
1517   graphic_info[graphic].src_y = 0;
1518   graphic_info[graphic].width  = TILEX; /* default for element graphics */
1519   graphic_info[graphic].height = TILEY; /* default for element graphics */
1520   graphic_info[graphic].offset_x = 0;   /* one or both of these values ... */
1521   graphic_info[graphic].offset_y = 0;   /* ... will be corrected later */
1522   graphic_info[graphic].offset2_x = 0;  /* one or both of these values ... */
1523   graphic_info[graphic].offset2_y = 0;  /* ... will be corrected later */
1524   graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1525   graphic_info[graphic].crumbled_like = -1;     /* do not use clone element */
1526   graphic_info[graphic].diggable_like = -1;     /* do not use clone element */
1527   graphic_info[graphic].border_size = TILEX / 8;  /* "CRUMBLED" border size */
1528   graphic_info[graphic].scale_up_factor = 1;    /* default: no scaling up */
1529   graphic_info[graphic].clone_from = -1;        /* do not use clone graphic */
1530   graphic_info[graphic].anim_delay_fixed = 0;
1531   graphic_info[graphic].anim_delay_random = 0;
1532   graphic_info[graphic].post_delay_fixed = 0;
1533   graphic_info[graphic].post_delay_random = 0;
1534   graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1535   graphic_info[graphic].fade_delay = -1;
1536   graphic_info[graphic].post_delay = -1;
1537   graphic_info[graphic].auto_delay = -1;
1538   graphic_info[graphic].align = ALIGN_CENTER;   /* default for title screens */
1539   graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1540   graphic_info[graphic].sort_priority = 0;      /* default for title screens */
1541
1542 #if 1
1543   /* optional zoom factor for scaling up the image to a larger size */
1544   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1545     graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1546   if (graphic_info[graphic].scale_up_factor < 1)
1547     graphic_info[graphic].scale_up_factor = 1;          /* no scaling */
1548 #endif
1549
1550 #if 1
1551   if (graphic_info[graphic].use_image_size)
1552   {
1553     /* set new default bitmap size (with scaling, but without small images) */
1554     graphic_info[graphic].width  = get_scaled_graphic_width(graphic);
1555     graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1556   }
1557 #endif
1558
1559   /* optional x and y tile position of animation frame sequence */
1560   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1561     graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1562   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1563     graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1564
1565   /* optional x and y pixel position of animation frame sequence */
1566   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1567     graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1568   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1569     graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1570
1571   /* optional width and height of each animation frame */
1572   if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1573     graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1574   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1575     graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1576
1577 #if 0
1578   /* optional zoom factor for scaling up the image to a larger size */
1579   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1580     graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1581   if (graphic_info[graphic].scale_up_factor < 1)
1582     graphic_info[graphic].scale_up_factor = 1;          /* no scaling */
1583 #endif
1584
1585   if (src_bitmap)
1586   {
1587     /* get final bitmap size (with scaling, but without small images) */
1588     int src_image_width  = get_scaled_graphic_width(graphic);
1589     int src_image_height = get_scaled_graphic_height(graphic);
1590
1591     anim_frames_per_row = src_image_width  / graphic_info[graphic].width;
1592     anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1593
1594     graphic_info[graphic].src_image_width  = src_image_width;
1595     graphic_info[graphic].src_image_height = src_image_height;
1596   }
1597
1598   /* correct x or y offset dependent of vertical or horizontal frame order */
1599   if (parameter[GFX_ARG_VERTICAL])      /* frames are ordered vertically */
1600   {
1601     graphic_info[graphic].offset_y =
1602       (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1603        parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1604     anim_frames_per_line = anim_frames_per_col;
1605   }
1606   else                                  /* frames are ordered horizontally */
1607   {
1608     graphic_info[graphic].offset_x =
1609       (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1610        parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1611     anim_frames_per_line = anim_frames_per_row;
1612   }
1613
1614   /* optionally, the x and y offset of frames can be specified directly */
1615   if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1616     graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1617   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1618     graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1619
1620   /* optionally, moving animations may have separate start and end graphics */
1621   graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1622
1623   if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1624     parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1625
1626   /* correct x or y offset2 dependent of vertical or horizontal frame order */
1627   if (parameter[GFX_ARG_2ND_VERTICAL])  /* frames are ordered vertically */
1628     graphic_info[graphic].offset2_y =
1629       (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1630        parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1631   else                                  /* frames are ordered horizontally */
1632     graphic_info[graphic].offset2_x =
1633       (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1634        parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1635
1636   /* optionally, the x and y offset of 2nd graphic can be specified directly */
1637   if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1638     graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1639   if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1640     graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1641
1642   /* optionally, the second movement tile can be specified as start tile */
1643   if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1644     graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1645
1646   /* automatically determine correct number of frames, if not defined */
1647   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1648     graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1649   else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1650     graphic_info[graphic].anim_frames = anim_frames_per_row;
1651   else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1652     graphic_info[graphic].anim_frames = anim_frames_per_col;
1653   else
1654     graphic_info[graphic].anim_frames = 1;
1655
1656   if (graphic_info[graphic].anim_frames == 0)   /* frames must be at least 1 */
1657     graphic_info[graphic].anim_frames = 1;
1658
1659   graphic_info[graphic].anim_frames_per_line =
1660     (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1661      parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1662
1663   graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1664   if (graphic_info[graphic].anim_delay == 0)    /* delay must be at least 1 */
1665     graphic_info[graphic].anim_delay = 1;
1666
1667   graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1668 #if 0
1669   if (graphic_info[graphic].anim_frames == 1)
1670     graphic_info[graphic].anim_mode = ANIM_NONE;
1671 #endif
1672
1673   /* automatically determine correct start frame, if not defined */
1674   if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1675     graphic_info[graphic].anim_start_frame = 0;
1676   else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1677     graphic_info[graphic].anim_start_frame =
1678       graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1679   else
1680     graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1681
1682   /* animation synchronized with global frame counter, not move position */
1683   graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1684
1685   /* optional element for cloning crumble graphics */
1686   if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1687     graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1688
1689   /* optional element for cloning digging graphics */
1690   if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1691     graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1692
1693   /* optional border size for "crumbling" diggable graphics */
1694   if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1695     graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1696
1697   /* this is only used for player "boring" and "sleeping" actions */
1698   if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1699     graphic_info[graphic].anim_delay_fixed =
1700       parameter[GFX_ARG_ANIM_DELAY_FIXED];
1701   if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1702     graphic_info[graphic].anim_delay_random =
1703       parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1704   if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1705     graphic_info[graphic].post_delay_fixed =
1706       parameter[GFX_ARG_POST_DELAY_FIXED];
1707   if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1708     graphic_info[graphic].post_delay_random =
1709       parameter[GFX_ARG_POST_DELAY_RANDOM];
1710
1711   /* this is only used for toon animations */
1712   graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1713   graphic_info[graphic].step_delay  = parameter[GFX_ARG_STEP_DELAY];
1714
1715   /* this is only used for drawing font characters */
1716   graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1717   graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1718
1719   /* this is only used for drawing envelope graphics */
1720   graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1721
1722   /* optional graphic for cloning all graphics settings */
1723   if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1724     graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1725
1726   /* optional settings for drawing title screens and title messages */
1727   if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1728     graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1729   if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1730     graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1731   if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1732     graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1733   if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1734     graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1735   if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1736     graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1737   if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1738     graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1739   if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1740     graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1741 #endif
1742
1743   UPDATE_BUSY_STATE();
1744 }
1745
1746 static void set_cloned_graphic_parameters(int graphic)
1747 {
1748   int fallback_graphic = IMG_CHAR_EXCLAM;
1749   int max_num_images = getImageListSize();
1750   int clone_graphic = graphic_info[graphic].clone_from;
1751   int num_references_followed = 1;
1752
1753   while (graphic_info[clone_graphic].clone_from != -1 &&
1754          num_references_followed < max_num_images)
1755   {
1756     clone_graphic = graphic_info[clone_graphic].clone_from;
1757
1758     num_references_followed++;
1759   }
1760
1761   if (num_references_followed >= max_num_images)
1762   {
1763     Error(ERR_INFO_LINE, "-");
1764     Error(ERR_INFO, "warning: error found in config file:");
1765     Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1766     Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1767     Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1768     Error(ERR_INFO, "custom graphic rejected for this element/action");
1769
1770     if (graphic == fallback_graphic)
1771       Error(ERR_EXIT, "fatal error: no fallback graphic available");
1772
1773     Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1774     Error(ERR_INFO_LINE, "-");
1775
1776     graphic_info[graphic] = graphic_info[fallback_graphic];
1777   }
1778   else
1779   {
1780     graphic_info[graphic] = graphic_info[clone_graphic];
1781     graphic_info[graphic].clone_from = clone_graphic;
1782   }
1783 }
1784
1785 static void InitGraphicInfo()
1786 {
1787   int fallback_graphic = IMG_CHAR_EXCLAM;
1788   int num_images = getImageListSize();
1789   int i;
1790
1791 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1792   static boolean clipmasks_initialized = FALSE;
1793   Pixmap src_pixmap;
1794   XGCValues clip_gc_values;
1795   unsigned long clip_gc_valuemask;
1796   GC copy_clipmask_gc = None;
1797 #endif
1798
1799   /* use image size as default values for width and height for these images */
1800   static int full_size_graphics[] =
1801   {
1802     IMG_GLOBAL_BORDER,
1803     IMG_GLOBAL_DOOR,
1804
1805     IMG_BACKGROUND_ENVELOPE_1,
1806     IMG_BACKGROUND_ENVELOPE_2,
1807     IMG_BACKGROUND_ENVELOPE_3,
1808     IMG_BACKGROUND_ENVELOPE_4,
1809
1810     IMG_BACKGROUND,
1811     IMG_BACKGROUND_TITLE_INITIAL,
1812     IMG_BACKGROUND_TITLE,
1813     IMG_BACKGROUND_MAIN,
1814     IMG_BACKGROUND_LEVELS,
1815     IMG_BACKGROUND_SCORES,
1816     IMG_BACKGROUND_EDITOR,
1817     IMG_BACKGROUND_INFO,
1818     IMG_BACKGROUND_INFO_ELEMENTS,
1819     IMG_BACKGROUND_INFO_MUSIC,
1820     IMG_BACKGROUND_INFO_CREDITS,
1821     IMG_BACKGROUND_INFO_PROGRAM,
1822     IMG_BACKGROUND_INFO_LEVELSET,
1823     IMG_BACKGROUND_SETUP,
1824     IMG_BACKGROUND_DOOR,
1825
1826     IMG_TITLESCREEN_INITIAL_1,
1827     IMG_TITLESCREEN_INITIAL_2,
1828     IMG_TITLESCREEN_INITIAL_3,
1829     IMG_TITLESCREEN_INITIAL_4,
1830     IMG_TITLESCREEN_INITIAL_5,
1831     IMG_TITLESCREEN_1,
1832     IMG_TITLESCREEN_2,
1833     IMG_TITLESCREEN_3,
1834     IMG_TITLESCREEN_4,
1835     IMG_TITLESCREEN_5,
1836
1837     -1
1838   };
1839
1840   checked_free(graphic_info);
1841
1842   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1843
1844 #if 1
1845   /* initialize "use_image_size" flag with default value */
1846   for (i = 0; i < num_images; i++)
1847     graphic_info[i].use_image_size = FALSE;
1848
1849   /* initialize "use_image_size" flag from static configuration above */
1850   for (i = 0; full_size_graphics[i] != -1; i++)
1851     graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1852 #endif
1853
1854 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1855   if (clipmasks_initialized)
1856   {
1857     for (i = 0; i < num_images; i++)
1858     {
1859       if (graphic_info[i].clip_mask)
1860         XFreePixmap(display, graphic_info[i].clip_mask);
1861       if (graphic_info[i].clip_gc)
1862         XFreeGC(display, graphic_info[i].clip_gc);
1863
1864       graphic_info[i].clip_mask = None;
1865       graphic_info[i].clip_gc = None;
1866     }
1867   }
1868 #endif
1869
1870   /* first set all graphic paramaters ... */
1871   for (i = 0; i < num_images; i++)
1872     set_graphic_parameters(i);
1873
1874   /* ... then copy these parameters for cloned graphics */
1875   for (i = 0; i < num_images; i++)
1876     if (graphic_info[i].clone_from != -1)
1877       set_cloned_graphic_parameters(i);
1878
1879   for (i = 0; i < num_images; i++)
1880   {
1881     Bitmap *src_bitmap;
1882     int src_x, src_y;
1883     int width, height;
1884     int first_frame, last_frame;
1885     int src_bitmap_width, src_bitmap_height;
1886
1887     /* now check if no animation frames are outside of the loaded image */
1888
1889     if (graphic_info[i].bitmap == NULL)
1890       continue;         /* skip check for optional images that are undefined */
1891
1892     /* get image size (this can differ from the standard element tile size!) */
1893     width  = graphic_info[i].width;
1894     height = graphic_info[i].height;
1895
1896     /* get final bitmap size (with scaling, but without small images) */
1897     src_bitmap_width  = graphic_info[i].src_image_width;
1898     src_bitmap_height = graphic_info[i].src_image_height;
1899
1900     /* check if first animation frame is inside specified bitmap */
1901
1902     first_frame = 0;
1903     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1904
1905 #if 1
1906     /* this avoids calculating wrong start position for out-of-bounds frame */
1907     src_x = graphic_info[i].src_x;
1908     src_y = graphic_info[i].src_y;
1909 #endif
1910
1911     if (src_x < 0 || src_y < 0 ||
1912         src_x + width  > src_bitmap_width ||
1913         src_y + height > src_bitmap_height)
1914     {
1915       Error(ERR_INFO_LINE, "-");
1916       Error(ERR_INFO, "warning: error found in config file:");
1917       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1918       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1919       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1920       Error(ERR_INFO,
1921             "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1922             src_x, src_y, src_bitmap_width, src_bitmap_height);
1923       Error(ERR_INFO, "custom graphic rejected for this element/action");
1924
1925       if (i == fallback_graphic)
1926         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1927
1928       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1929       Error(ERR_INFO_LINE, "-");
1930
1931       graphic_info[i] = graphic_info[fallback_graphic];
1932     }
1933
1934     /* check if last animation frame is inside specified bitmap */
1935
1936     last_frame = graphic_info[i].anim_frames - 1;
1937     getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1938
1939     if (src_x < 0 || src_y < 0 ||
1940         src_x + width  > src_bitmap_width ||
1941         src_y + height > src_bitmap_height)
1942     {
1943       Error(ERR_INFO_LINE, "-");
1944       Error(ERR_INFO, "warning: error found in config file:");
1945       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1946       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1947       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1948       Error(ERR_INFO,
1949             "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1950             last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1951       Error(ERR_INFO, "custom graphic rejected for this element/action");
1952
1953       if (i == fallback_graphic)
1954         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1955
1956       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1957       Error(ERR_INFO_LINE, "-");
1958
1959       graphic_info[i] = graphic_info[fallback_graphic];
1960     }
1961
1962 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1963     /* currently we only need a tile clip mask from the first frame */
1964     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1965
1966     if (copy_clipmask_gc == None)
1967     {
1968       clip_gc_values.graphics_exposures = False;
1969       clip_gc_valuemask = GCGraphicsExposures;
1970       copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1971                                    clip_gc_valuemask, &clip_gc_values);
1972     }
1973
1974     graphic_info[i].clip_mask =
1975       XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1976
1977     src_pixmap = src_bitmap->clip_mask;
1978     XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1979               copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1980
1981     clip_gc_values.graphics_exposures = False;
1982     clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1983     clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1984
1985     graphic_info[i].clip_gc =
1986       XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1987 #endif
1988   }
1989
1990 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1991   if (copy_clipmask_gc)
1992     XFreeGC(display, copy_clipmask_gc);
1993
1994   clipmasks_initialized = TRUE;
1995 #endif
1996 }
1997
1998 static void InitElementSoundInfo()
1999 {
2000   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2001   int num_property_mappings = getSoundListPropertyMappingSize();
2002   int i, j, act;
2003
2004   /* set values to -1 to identify later as "uninitialized" values */
2005   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2006     for (act = 0; act < NUM_ACTIONS; act++)
2007       element_info[i].sound[act] = -1;
2008
2009   /* initialize element/sound mapping from static configuration */
2010   for (i = 0; element_to_sound[i].element > -1; i++)
2011   {
2012     int element      = element_to_sound[i].element;
2013     int action       = element_to_sound[i].action;
2014     int sound        = element_to_sound[i].sound;
2015     boolean is_class = element_to_sound[i].is_class;
2016
2017     if (action < 0)
2018       action = ACTION_DEFAULT;
2019
2020     if (!is_class)
2021       element_info[element].sound[action] = sound;
2022     else
2023       for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2024         if (strEqual(element_info[j].class_name,
2025                      element_info[element].class_name))
2026           element_info[j].sound[action] = sound;
2027   }
2028
2029   /* initialize element class/sound mapping from dynamic configuration */
2030   for (i = 0; i < num_property_mappings; i++)
2031   {
2032     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2033     int action        = property_mapping[i].ext1_index;
2034     int sound         = property_mapping[i].artwork_index;
2035
2036     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2037       continue;
2038
2039     if (action < 0)
2040       action = ACTION_DEFAULT;
2041
2042     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2043       if (strEqual(element_info[j].class_name,
2044                    element_info[element_class].class_name))
2045         element_info[j].sound[action] = sound;
2046   }
2047
2048   /* initialize element/sound mapping from dynamic configuration */
2049   for (i = 0; i < num_property_mappings; i++)
2050   {
2051     int element = property_mapping[i].base_index;
2052     int action  = property_mapping[i].ext1_index;
2053     int sound   = property_mapping[i].artwork_index;
2054
2055     if (element >= MAX_NUM_ELEMENTS)
2056       continue;
2057
2058     if (action < 0)
2059       action = ACTION_DEFAULT;
2060
2061     element_info[element].sound[action] = sound;
2062   }
2063
2064   /* now set all '-1' values to element specific default values */
2065   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2066   {
2067     for (act = 0; act < NUM_ACTIONS; act++)
2068     {
2069       /* generic default action sound (defined by "[default]" directive) */
2070       int default_action_sound = element_info[EL_DEFAULT].sound[act];
2071
2072       /* look for special default action sound (classic game specific) */
2073       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2074         default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2075       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2076         default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2077       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2078         default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2079
2080       /* !!! there's no such thing as a "default action sound" !!! */
2081 #if 0
2082       /* look for element specific default sound (independent from action) */
2083       if (element_info[i].sound[ACTION_DEFAULT] != -1)
2084         default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2085 #endif
2086
2087 #if 1
2088       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2089       /* !!! make this better !!! */
2090       if (i == EL_EMPTY_SPACE)
2091         default_action_sound = element_info[EL_DEFAULT].sound[act];
2092 #endif
2093
2094       /* no sound for this specific action -- use default action sound */
2095       if (element_info[i].sound[act] == -1)
2096         element_info[i].sound[act] = default_action_sound;
2097     }
2098   }
2099
2100   /* copy sound settings to some elements that are only stored in level file
2101      in native R'n'D levels, but are used by game engine in native EM levels */
2102   for (i = 0; copy_properties[i][0] != -1; i++)
2103     for (j = 1; j <= 4; j++)
2104       for (act = 0; act < NUM_ACTIONS; act++)
2105         element_info[copy_properties[i][j]].sound[act] =
2106           element_info[copy_properties[i][0]].sound[act];
2107 }
2108
2109 static void InitGameModeSoundInfo()
2110 {
2111   int i;
2112
2113   /* set values to -1 to identify later as "uninitialized" values */
2114   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2115     menu.sound[i] = -1;
2116
2117   /* initialize gamemode/sound mapping from static configuration */
2118   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2119   {
2120     int gamemode = gamemode_to_sound[i].gamemode;
2121     int sound    = gamemode_to_sound[i].sound;
2122
2123     if (gamemode < 0)
2124       gamemode = GAME_MODE_DEFAULT;
2125
2126     menu.sound[gamemode] = sound;
2127   }
2128
2129   /* now set all '-1' values to levelset specific default values */
2130   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2131     if (menu.sound[i] == -1)
2132       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2133
2134 #if 0
2135   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2136     if (menu.sound[i] != -1)
2137       printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2138 #endif
2139 }
2140
2141 static void set_sound_parameters(int sound, char **parameter_raw)
2142 {
2143   int parameter[NUM_SND_ARGS];
2144   int i;
2145
2146   /* get integer values from string parameters */
2147   for (i = 0; i < NUM_SND_ARGS; i++)
2148     parameter[i] =
2149       get_parameter_value(parameter_raw[i],
2150                           sound_config_suffix[i].token,
2151                           sound_config_suffix[i].type);
2152
2153   /* explicit loop mode setting in configuration overrides default value */
2154   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2155     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2156
2157   /* sound volume to change the original volume when loading the sound file */
2158   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2159
2160   /* sound priority to give certain sounds a higher or lower priority */
2161   sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2162 }
2163
2164 static void InitSoundInfo()
2165 {
2166   int *sound_effect_properties;
2167   int num_sounds = getSoundListSize();
2168   int i, j;
2169
2170   checked_free(sound_info);
2171
2172   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2173   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2174
2175   /* initialize sound effect for all elements to "no sound" */
2176   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2177     for (j = 0; j < NUM_ACTIONS; j++)
2178       element_info[i].sound[j] = SND_UNDEFINED;
2179
2180   for (i = 0; i < num_sounds; i++)
2181   {
2182     struct FileInfo *sound = getSoundListEntry(i);
2183     int len_effect_text = strlen(sound->token);
2184
2185     sound_effect_properties[i] = ACTION_OTHER;
2186     sound_info[i].loop = FALSE;         /* default: play sound only once */
2187
2188 #if 0
2189     printf("::: sound %d: '%s'\n", i, sound->token);
2190 #endif
2191
2192     /* determine all loop sounds and identify certain sound classes */
2193
2194     for (j = 0; element_action_info[j].suffix; j++)
2195     {
2196       int len_action_text = strlen(element_action_info[j].suffix);
2197
2198       if (len_action_text < len_effect_text &&
2199           strEqual(&sound->token[len_effect_text - len_action_text],
2200                    element_action_info[j].suffix))
2201       {
2202         sound_effect_properties[i] = element_action_info[j].value;
2203         sound_info[i].loop = element_action_info[j].is_loop_sound;
2204
2205         break;
2206       }
2207     }
2208
2209     /* associate elements and some selected sound actions */
2210
2211     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2212     {
2213       if (element_info[j].class_name)
2214       {
2215         int len_class_text = strlen(element_info[j].class_name);
2216
2217         if (len_class_text + 1 < len_effect_text &&
2218             strncmp(sound->token,
2219                     element_info[j].class_name, len_class_text) == 0 &&
2220             sound->token[len_class_text] == '.')
2221         {
2222           int sound_action_value = sound_effect_properties[i];
2223
2224           element_info[j].sound[sound_action_value] = i;
2225         }
2226       }
2227     }
2228
2229     set_sound_parameters(i, sound->parameter);
2230   }
2231
2232   free(sound_effect_properties);
2233 }
2234
2235 static void InitGameModeMusicInfo()
2236 {
2237   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2238   int num_property_mappings = getMusicListPropertyMappingSize();
2239   int default_levelset_music = -1;
2240   int i;
2241
2242   /* set values to -1 to identify later as "uninitialized" values */
2243   for (i = 0; i < MAX_LEVELS; i++)
2244     levelset.music[i] = -1;
2245   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2246     menu.music[i] = -1;
2247
2248   /* initialize gamemode/music mapping from static configuration */
2249   for (i = 0; gamemode_to_music[i].music > -1; i++)
2250   {
2251     int gamemode = gamemode_to_music[i].gamemode;
2252     int music    = gamemode_to_music[i].music;
2253
2254 #if 0
2255     printf("::: gamemode == %d, music == %d\n", gamemode, music);
2256 #endif
2257
2258     if (gamemode < 0)
2259       gamemode = GAME_MODE_DEFAULT;
2260
2261     menu.music[gamemode] = music;
2262   }
2263
2264   /* initialize gamemode/music mapping from dynamic configuration */
2265   for (i = 0; i < num_property_mappings; i++)
2266   {
2267     int prefix   = property_mapping[i].base_index;
2268     int gamemode = property_mapping[i].ext1_index;
2269     int level    = property_mapping[i].ext2_index;
2270     int music    = property_mapping[i].artwork_index;
2271
2272 #if 0
2273     printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2274            prefix, gamemode, level, music);
2275 #endif
2276
2277     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2278       continue;
2279
2280     if (gamemode < 0)
2281       gamemode = GAME_MODE_DEFAULT;
2282
2283     /* level specific music only allowed for in-game music */
2284     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2285       gamemode = GAME_MODE_PLAYING;
2286
2287     if (level == -1)
2288     {
2289       level = 0;
2290       default_levelset_music = music;
2291     }
2292
2293     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2294       levelset.music[level] = music;
2295     if (gamemode != GAME_MODE_PLAYING)
2296       menu.music[gamemode] = music;
2297   }
2298
2299   /* now set all '-1' values to menu specific default values */
2300   /* (undefined values of "levelset.music[]" might stay at "-1" to
2301      allow dynamic selection of music files from music directory!) */
2302   for (i = 0; i < MAX_LEVELS; i++)
2303     if (levelset.music[i] == -1)
2304       levelset.music[i] = default_levelset_music;
2305   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2306     if (menu.music[i] == -1)
2307       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2308
2309 #if 0
2310   for (i = 0; i < MAX_LEVELS; i++)
2311     if (levelset.music[i] != -1)
2312       printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2313   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2314     if (menu.music[i] != -1)
2315       printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2316 #endif
2317 }
2318
2319 static void set_music_parameters(int music, char **parameter_raw)
2320 {
2321   int parameter[NUM_MUS_ARGS];
2322   int i;
2323
2324   /* get integer values from string parameters */
2325   for (i = 0; i < NUM_MUS_ARGS; i++)
2326     parameter[i] =
2327       get_parameter_value(parameter_raw[i],
2328                           music_config_suffix[i].token,
2329                           music_config_suffix[i].type);
2330
2331   /* explicit loop mode setting in configuration overrides default value */
2332   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2333     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2334 }
2335
2336 static void InitMusicInfo()
2337 {
2338   int num_music = getMusicListSize();
2339   int i, j;
2340
2341   checked_free(music_info);
2342
2343   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2344
2345   for (i = 0; i < num_music; i++)
2346   {
2347     struct FileInfo *music = getMusicListEntry(i);
2348     int len_music_text = strlen(music->token);
2349
2350     music_info[i].loop = TRUE;          /* default: play music in loop mode */
2351
2352     /* determine all loop music */
2353
2354     for (j = 0; music_prefix_info[j].prefix; j++)
2355     {
2356       int len_prefix_text = strlen(music_prefix_info[j].prefix);
2357
2358       if (len_prefix_text < len_music_text &&
2359           strncmp(music->token,
2360                   music_prefix_info[j].prefix, len_prefix_text) == 0)
2361       {
2362         music_info[i].loop = music_prefix_info[j].is_loop_music;
2363
2364         break;
2365       }
2366     }
2367
2368     set_music_parameters(i, music->parameter);
2369   }
2370 }
2371
2372 static void ReinitializeGraphics()
2373 {
2374   print_timestamp_init("ReinitializeGraphics");
2375
2376   InitGraphicInfo();                    /* graphic properties mapping */
2377   print_timestamp_time("InitGraphicInfo");
2378   InitElementGraphicInfo();             /* element game graphic mapping */
2379   print_timestamp_time("InitElementGraphicInfo");
2380   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
2381   print_timestamp_time("InitElementSpecialGraphicInfo");
2382
2383   InitElementSmallImages();             /* scale elements to all needed sizes */
2384   print_timestamp_time("InitElementSmallImages");
2385   InitScaledImages();                   /* scale all other images, if needed */
2386   print_timestamp_time("InitScaledImages");
2387   InitFontGraphicInfo();                /* initialize text drawing functions */
2388   print_timestamp_time("InitFontGraphicInfo");
2389
2390   InitGraphicInfo_EM();                 /* graphic mapping for EM engine */
2391   print_timestamp_time("InitGraphicInfo_EM");
2392
2393   SetMainBackgroundImage(IMG_BACKGROUND);
2394   print_timestamp_time("SetMainBackgroundImage");
2395   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2396   print_timestamp_time("SetDoorBackgroundImage");
2397
2398   InitGadgets();
2399   print_timestamp_time("InitGadgets");
2400   InitToons();
2401   print_timestamp_time("InitToons");
2402
2403   print_timestamp_done("ReinitializeGraphics");
2404 }
2405
2406 static void ReinitializeSounds()
2407 {
2408   InitSoundInfo();              /* sound properties mapping */
2409   InitElementSoundInfo();       /* element game sound mapping */
2410   InitGameModeSoundInfo();      /* game mode sound mapping */
2411
2412   InitPlayLevelSound();         /* internal game sound settings */
2413 }
2414
2415 static void ReinitializeMusic()
2416 {
2417   InitMusicInfo();              /* music properties mapping */
2418   InitGameModeMusicInfo();      /* game mode music mapping */
2419 }
2420
2421 static int get_special_property_bit(int element, int property_bit_nr)
2422 {
2423   struct PropertyBitInfo
2424   {
2425     int element;
2426     int bit_nr;
2427   };
2428
2429   static struct PropertyBitInfo pb_can_move_into_acid[] =
2430   {
2431     /* the player may be able fall into acid when gravity is activated */
2432     { EL_PLAYER_1,              0       },
2433     { EL_PLAYER_2,              0       },
2434     { EL_PLAYER_3,              0       },
2435     { EL_PLAYER_4,              0       },
2436     { EL_SP_MURPHY,             0       },
2437     { EL_SOKOBAN_FIELD_PLAYER,  0       },
2438
2439     /* all elements that can move may be able to also move into acid */
2440     { EL_BUG,                   1       },
2441     { EL_BUG_LEFT,              1       },
2442     { EL_BUG_RIGHT,             1       },
2443     { EL_BUG_UP,                1       },
2444     { EL_BUG_DOWN,              1       },
2445     { EL_SPACESHIP,             2       },
2446     { EL_SPACESHIP_LEFT,        2       },
2447     { EL_SPACESHIP_RIGHT,       2       },
2448     { EL_SPACESHIP_UP,          2       },
2449     { EL_SPACESHIP_DOWN,        2       },
2450     { EL_BD_BUTTERFLY,          3       },
2451     { EL_BD_BUTTERFLY_LEFT,     3       },
2452     { EL_BD_BUTTERFLY_RIGHT,    3       },
2453     { EL_BD_BUTTERFLY_UP,       3       },
2454     { EL_BD_BUTTERFLY_DOWN,     3       },
2455     { EL_BD_FIREFLY,            4       },
2456     { EL_BD_FIREFLY_LEFT,       4       },
2457     { EL_BD_FIREFLY_RIGHT,      4       },
2458     { EL_BD_FIREFLY_UP,         4       },
2459     { EL_BD_FIREFLY_DOWN,       4       },
2460     { EL_YAMYAM,                5       },
2461     { EL_YAMYAM_LEFT,           5       },
2462     { EL_YAMYAM_RIGHT,          5       },
2463     { EL_YAMYAM_UP,             5       },
2464     { EL_YAMYAM_DOWN,           5       },
2465     { EL_DARK_YAMYAM,           6       },
2466     { EL_ROBOT,                 7       },
2467     { EL_PACMAN,                8       },
2468     { EL_PACMAN_LEFT,           8       },
2469     { EL_PACMAN_RIGHT,          8       },
2470     { EL_PACMAN_UP,             8       },
2471     { EL_PACMAN_DOWN,           8       },
2472     { EL_MOLE,                  9       },
2473     { EL_MOLE_LEFT,             9       },
2474     { EL_MOLE_RIGHT,            9       },
2475     { EL_MOLE_UP,               9       },
2476     { EL_MOLE_DOWN,             9       },
2477     { EL_PENGUIN,               10      },
2478     { EL_PIG,                   11      },
2479     { EL_DRAGON,                12      },
2480     { EL_SATELLITE,             13      },
2481     { EL_SP_SNIKSNAK,           14      },
2482     { EL_SP_ELECTRON,           15      },
2483     { EL_BALLOON,               16      },
2484     { EL_SPRING,                17      },
2485     { EL_EMC_ANDROID,           18      },
2486
2487     { -1,                       -1      },
2488   };
2489
2490   static struct PropertyBitInfo pb_dont_collide_with[] =
2491   {
2492     { EL_SP_SNIKSNAK,           0       },
2493     { EL_SP_ELECTRON,           1       },
2494
2495     { -1,                       -1      },
2496   };
2497
2498   static struct
2499   {
2500     int bit_nr;
2501     struct PropertyBitInfo *pb_info;
2502   } pb_definition[] =
2503   {
2504     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
2505     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
2506
2507     { -1,                       NULL                    },
2508   };
2509
2510   struct PropertyBitInfo *pb_info = NULL;
2511   int i;
2512
2513   for (i = 0; pb_definition[i].bit_nr != -1; i++)
2514     if (pb_definition[i].bit_nr == property_bit_nr)
2515       pb_info = pb_definition[i].pb_info;
2516
2517   if (pb_info == NULL)
2518     return -1;
2519
2520   for (i = 0; pb_info[i].element != -1; i++)
2521     if (pb_info[i].element == element)
2522       return pb_info[i].bit_nr;
2523
2524   return -1;
2525 }
2526
2527 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2528                          boolean property_value)
2529 {
2530   int bit_nr = get_special_property_bit(element, property_bit_nr);
2531
2532   if (bit_nr > -1)
2533   {
2534     if (property_value)
2535       *bitfield |=  (1 << bit_nr);
2536     else
2537       *bitfield &= ~(1 << bit_nr);
2538   }
2539 }
2540
2541 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2542 {
2543   int bit_nr = get_special_property_bit(element, property_bit_nr);
2544
2545   if (bit_nr > -1)
2546     return ((*bitfield & (1 << bit_nr)) != 0);
2547
2548   return FALSE;
2549 }
2550
2551 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2552 {
2553   static int group_nr;
2554   static struct ElementGroupInfo *group;
2555   struct ElementGroupInfo *actual_group = element_info[group_element].group;
2556   int i;
2557
2558   if (actual_group == NULL)                     /* not yet initialized */
2559     return;
2560
2561   if (recursion_depth > NUM_GROUP_ELEMENTS)     /* recursion too deep */
2562   {
2563     Error(ERR_WARN, "recursion too deep when resolving group element %d",
2564           group_element - EL_GROUP_START + 1);
2565
2566     /* replace element which caused too deep recursion by question mark */
2567     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2568
2569     return;
2570   }
2571
2572   if (recursion_depth == 0)                     /* initialization */
2573   {
2574     group = actual_group;
2575     group_nr = GROUP_NR(group_element);
2576
2577     group->num_elements_resolved = 0;
2578     group->choice_pos = 0;
2579
2580     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2581       element_info[i].in_group[group_nr] = FALSE;
2582   }
2583
2584   for (i = 0; i < actual_group->num_elements; i++)
2585   {
2586     int element = actual_group->element[i];
2587
2588     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2589       break;
2590
2591     if (IS_GROUP_ELEMENT(element))
2592       ResolveGroupElementExt(element, recursion_depth + 1);
2593     else
2594     {
2595       group->element_resolved[group->num_elements_resolved++] = element;
2596       element_info[element].in_group[group_nr] = TRUE;
2597     }
2598   }
2599 }
2600
2601 void ResolveGroupElement(int group_element)
2602 {
2603   ResolveGroupElementExt(group_element, 0);
2604 }
2605
2606 void InitElementPropertiesStatic()
2607 {
2608   static int ep_diggable[] =
2609   {
2610     EL_SAND,
2611     EL_SP_BASE,
2612     EL_SP_BUGGY_BASE,
2613     EL_SP_BUGGY_BASE_ACTIVATING,
2614     EL_TRAP,
2615     EL_INVISIBLE_SAND,
2616     EL_INVISIBLE_SAND_ACTIVE,
2617     EL_EMC_GRASS,
2618
2619     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2620     /* (if amoeba can grow into anything diggable, maybe keep these out) */
2621 #if 0
2622     EL_LANDMINE,
2623     EL_DC_LANDMINE,
2624     EL_TRAP_ACTIVE,
2625     EL_SP_BUGGY_BASE_ACTIVE,
2626     EL_EMC_PLANT,
2627 #endif
2628
2629     -1
2630   };
2631
2632   static int ep_collectible_only[] =
2633   {
2634     EL_BD_DIAMOND,
2635     EL_EMERALD,
2636     EL_DIAMOND,
2637     EL_EMERALD_YELLOW,
2638     EL_EMERALD_RED,
2639     EL_EMERALD_PURPLE,
2640     EL_KEY_1,
2641     EL_KEY_2,
2642     EL_KEY_3,
2643     EL_KEY_4,
2644     EL_EM_KEY_1,
2645     EL_EM_KEY_2,
2646     EL_EM_KEY_3,
2647     EL_EM_KEY_4,
2648     EL_EMC_KEY_5,
2649     EL_EMC_KEY_6,
2650     EL_EMC_KEY_7,
2651     EL_EMC_KEY_8,
2652     EL_DYNAMITE,
2653     EL_EM_DYNAMITE,
2654     EL_DYNABOMB_INCREASE_NUMBER,
2655     EL_DYNABOMB_INCREASE_SIZE,
2656     EL_DYNABOMB_INCREASE_POWER,
2657     EL_SP_INFOTRON,
2658     EL_SP_DISK_RED,
2659     EL_PEARL,
2660     EL_CRYSTAL,
2661     EL_DC_KEY_WHITE,
2662     EL_SHIELD_NORMAL,
2663     EL_SHIELD_DEADLY,
2664     EL_EXTRA_TIME,
2665     EL_ENVELOPE_1,
2666     EL_ENVELOPE_2,
2667     EL_ENVELOPE_3,
2668     EL_ENVELOPE_4,
2669     EL_SPEED_PILL,
2670     EL_EMC_LENSES,
2671     EL_EMC_MAGNIFIER,
2672
2673 #if 0
2674     /* !!! handle separately !!! */
2675     EL_DC_LANDMINE,     /* deadly when running into, but can be snapped */
2676 #endif
2677
2678     -1
2679   };
2680
2681   static int ep_dont_run_into[] =
2682   {
2683     /* same elements as in 'ep_dont_touch' */
2684     EL_BUG,
2685     EL_SPACESHIP,
2686     EL_BD_BUTTERFLY,
2687     EL_BD_FIREFLY,
2688
2689     /* same elements as in 'ep_dont_collide_with' */
2690     EL_YAMYAM,
2691     EL_DARK_YAMYAM,
2692     EL_ROBOT,
2693     EL_PACMAN,
2694     EL_SP_SNIKSNAK,
2695     EL_SP_ELECTRON,
2696
2697     /* new elements */
2698     EL_AMOEBA_DROP,
2699     EL_ACID,
2700
2701     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2702 #if 1
2703     EL_LANDMINE,
2704     EL_DC_LANDMINE,
2705     EL_TRAP_ACTIVE,
2706     EL_SP_BUGGY_BASE_ACTIVE,
2707     EL_EMC_PLANT,
2708 #endif
2709
2710     -1
2711   };
2712
2713   static int ep_dont_collide_with[] =
2714   {
2715     /* same elements as in 'ep_dont_touch' */
2716     EL_BUG,
2717     EL_SPACESHIP,
2718     EL_BD_BUTTERFLY,
2719     EL_BD_FIREFLY,
2720
2721     /* new elements */
2722     EL_YAMYAM,
2723     EL_DARK_YAMYAM,
2724     EL_ROBOT,
2725     EL_PACMAN,
2726     EL_SP_SNIKSNAK,
2727     EL_SP_ELECTRON,
2728
2729     -1
2730   };
2731
2732   static int ep_dont_touch[] =
2733   {
2734     EL_BUG,
2735     EL_SPACESHIP,
2736     EL_BD_BUTTERFLY,
2737     EL_BD_FIREFLY,
2738
2739     -1
2740   };
2741
2742   static int ep_indestructible[] =
2743   {
2744     EL_STEELWALL,
2745     EL_ACID,
2746     EL_ACID_POOL_TOPLEFT,
2747     EL_ACID_POOL_TOPRIGHT,
2748     EL_ACID_POOL_BOTTOMLEFT,
2749     EL_ACID_POOL_BOTTOM,
2750     EL_ACID_POOL_BOTTOMRIGHT,
2751     EL_SP_HARDWARE_GRAY,
2752     EL_SP_HARDWARE_GREEN,
2753     EL_SP_HARDWARE_BLUE,
2754     EL_SP_HARDWARE_RED,
2755     EL_SP_HARDWARE_YELLOW,
2756     EL_SP_HARDWARE_BASE_1,
2757     EL_SP_HARDWARE_BASE_2,
2758     EL_SP_HARDWARE_BASE_3,
2759     EL_SP_HARDWARE_BASE_4,
2760     EL_SP_HARDWARE_BASE_5,
2761     EL_SP_HARDWARE_BASE_6,
2762     EL_INVISIBLE_STEELWALL,
2763     EL_INVISIBLE_STEELWALL_ACTIVE,
2764     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2765     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2766     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2767     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2768     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2769     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2770     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2771     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2772     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2773     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2774     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2775     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2776     EL_LIGHT_SWITCH,
2777     EL_LIGHT_SWITCH_ACTIVE,
2778     EL_SIGN_EXCLAMATION,
2779     EL_SIGN_RADIOACTIVITY,
2780     EL_SIGN_STOP,
2781     EL_SIGN_WHEELCHAIR,
2782     EL_SIGN_PARKING,
2783     EL_SIGN_NO_ENTRY,
2784     EL_SIGN_UNUSED_1,
2785     EL_SIGN_GIVE_WAY,
2786     EL_SIGN_ENTRY_FORBIDDEN,
2787     EL_SIGN_EMERGENCY_EXIT,
2788     EL_SIGN_YIN_YANG,
2789     EL_SIGN_UNUSED_2,
2790     EL_SIGN_SPERMS,
2791     EL_SIGN_BULLET,
2792     EL_SIGN_HEART,
2793     EL_SIGN_CROSS,
2794     EL_SIGN_FRANKIE,
2795     EL_STEEL_EXIT_CLOSED,
2796     EL_STEEL_EXIT_OPEN,
2797     EL_EM_STEEL_EXIT_CLOSED,
2798     EL_EM_STEEL_EXIT_OPEN,
2799     EL_DC_STEELWALL_1_LEFT,
2800     EL_DC_STEELWALL_1_RIGHT,
2801     EL_DC_STEELWALL_1_TOP,
2802     EL_DC_STEELWALL_1_BOTTOM,
2803     EL_DC_STEELWALL_1_HORIZONTAL,
2804     EL_DC_STEELWALL_1_VERTICAL,
2805     EL_DC_STEELWALL_1_TOPLEFT,
2806     EL_DC_STEELWALL_1_TOPRIGHT,
2807     EL_DC_STEELWALL_1_BOTTOMLEFT,
2808     EL_DC_STEELWALL_1_BOTTOMRIGHT,
2809     EL_DC_STEELWALL_1_TOPLEFT_2,
2810     EL_DC_STEELWALL_1_TOPRIGHT_2,
2811     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2812     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2813     EL_DC_STEELWALL_2_LEFT,
2814     EL_DC_STEELWALL_2_RIGHT,
2815     EL_DC_STEELWALL_2_TOP,
2816     EL_DC_STEELWALL_2_BOTTOM,
2817     EL_DC_STEELWALL_2_HORIZONTAL,
2818     EL_DC_STEELWALL_2_VERTICAL,
2819     EL_DC_STEELWALL_2_MIDDLE,
2820     EL_DC_STEELWALL_2_SINGLE,
2821     EL_STEELWALL_SLIPPERY,
2822     EL_EMC_STEELWALL_1,
2823     EL_EMC_STEELWALL_2,
2824     EL_EMC_STEELWALL_3,
2825     EL_EMC_STEELWALL_4,
2826     EL_CRYSTAL,
2827     EL_GATE_1,
2828     EL_GATE_2,
2829     EL_GATE_3,
2830     EL_GATE_4,
2831     EL_GATE_1_GRAY,
2832     EL_GATE_2_GRAY,
2833     EL_GATE_3_GRAY,
2834     EL_GATE_4_GRAY,
2835     EL_GATE_1_GRAY_ACTIVE,
2836     EL_GATE_2_GRAY_ACTIVE,
2837     EL_GATE_3_GRAY_ACTIVE,
2838     EL_GATE_4_GRAY_ACTIVE,
2839     EL_EM_GATE_1,
2840     EL_EM_GATE_2,
2841     EL_EM_GATE_3,
2842     EL_EM_GATE_4,
2843     EL_EM_GATE_1_GRAY,
2844     EL_EM_GATE_2_GRAY,
2845     EL_EM_GATE_3_GRAY,
2846     EL_EM_GATE_4_GRAY,
2847     EL_EM_GATE_1_GRAY_ACTIVE,
2848     EL_EM_GATE_2_GRAY_ACTIVE,
2849     EL_EM_GATE_3_GRAY_ACTIVE,
2850     EL_EM_GATE_4_GRAY_ACTIVE,
2851     EL_EMC_GATE_5,
2852     EL_EMC_GATE_6,
2853     EL_EMC_GATE_7,
2854     EL_EMC_GATE_8,
2855     EL_EMC_GATE_5_GRAY,
2856     EL_EMC_GATE_6_GRAY,
2857     EL_EMC_GATE_7_GRAY,
2858     EL_EMC_GATE_8_GRAY,
2859     EL_EMC_GATE_5_GRAY_ACTIVE,
2860     EL_EMC_GATE_6_GRAY_ACTIVE,
2861     EL_EMC_GATE_7_GRAY_ACTIVE,
2862     EL_EMC_GATE_8_GRAY_ACTIVE,
2863     EL_DC_GATE_WHITE,
2864     EL_DC_GATE_WHITE_GRAY,
2865     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2866     EL_DC_GATE_FAKE_GRAY,
2867     EL_SWITCHGATE_OPEN,
2868     EL_SWITCHGATE_OPENING,
2869     EL_SWITCHGATE_CLOSED,
2870     EL_SWITCHGATE_CLOSING,
2871 #if 1
2872     EL_DC_SWITCHGATE_SWITCH_UP,
2873     EL_DC_SWITCHGATE_SWITCH_DOWN,
2874 #endif
2875     EL_TIMEGATE_OPEN,
2876     EL_TIMEGATE_OPENING,
2877     EL_TIMEGATE_CLOSED,
2878     EL_TIMEGATE_CLOSING,
2879 #if 1
2880     EL_DC_TIMEGATE_SWITCH,
2881     EL_DC_TIMEGATE_SWITCH_ACTIVE,
2882 #endif
2883     EL_TUBE_ANY,
2884     EL_TUBE_VERTICAL,
2885     EL_TUBE_HORIZONTAL,
2886     EL_TUBE_VERTICAL_LEFT,
2887     EL_TUBE_VERTICAL_RIGHT,
2888     EL_TUBE_HORIZONTAL_UP,
2889     EL_TUBE_HORIZONTAL_DOWN,
2890     EL_TUBE_LEFT_UP,
2891     EL_TUBE_LEFT_DOWN,
2892     EL_TUBE_RIGHT_UP,
2893     EL_TUBE_RIGHT_DOWN,
2894     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2895     EL_EXPANDABLE_STEELWALL_VERTICAL,
2896     EL_EXPANDABLE_STEELWALL_ANY,
2897
2898     -1
2899   };
2900
2901   static int ep_slippery[] =
2902   {
2903     EL_WALL_SLIPPERY,
2904     EL_BD_WALL,
2905     EL_ROCK,
2906     EL_BD_ROCK,
2907     EL_EMERALD,
2908     EL_BD_DIAMOND,
2909     EL_EMERALD_YELLOW,
2910     EL_EMERALD_RED,
2911     EL_EMERALD_PURPLE,
2912     EL_DIAMOND,
2913     EL_BOMB,
2914     EL_NUT,
2915     EL_ROBOT_WHEEL_ACTIVE,
2916     EL_ROBOT_WHEEL,
2917     EL_TIME_ORB_FULL,
2918     EL_TIME_ORB_EMPTY,
2919     EL_LAMP_ACTIVE,
2920     EL_LAMP,
2921     EL_ACID_POOL_TOPLEFT,
2922     EL_ACID_POOL_TOPRIGHT,
2923     EL_SATELLITE,
2924     EL_SP_ZONK,
2925     EL_SP_INFOTRON,
2926     EL_SP_CHIP_SINGLE,
2927     EL_SP_CHIP_LEFT,
2928     EL_SP_CHIP_RIGHT,
2929     EL_SP_CHIP_TOP,
2930     EL_SP_CHIP_BOTTOM,
2931     EL_SPEED_PILL,
2932     EL_STEELWALL_SLIPPERY,
2933     EL_PEARL,
2934     EL_CRYSTAL,
2935     EL_EMC_WALL_SLIPPERY_1,
2936     EL_EMC_WALL_SLIPPERY_2,
2937     EL_EMC_WALL_SLIPPERY_3,
2938     EL_EMC_WALL_SLIPPERY_4,
2939     EL_EMC_MAGIC_BALL,
2940     EL_EMC_MAGIC_BALL_ACTIVE,
2941
2942     -1
2943   };
2944
2945   static int ep_can_change[] =
2946   {
2947     -1
2948   };
2949
2950   static int ep_can_move[] =
2951   {
2952     /* same elements as in 'pb_can_move_into_acid' */
2953     EL_BUG,
2954     EL_SPACESHIP,
2955     EL_BD_BUTTERFLY,
2956     EL_BD_FIREFLY,
2957     EL_YAMYAM,
2958     EL_DARK_YAMYAM,
2959     EL_ROBOT,
2960     EL_PACMAN,
2961     EL_MOLE,
2962     EL_PENGUIN,
2963     EL_PIG,
2964     EL_DRAGON,
2965     EL_SATELLITE,
2966     EL_SP_SNIKSNAK,
2967     EL_SP_ELECTRON,
2968     EL_BALLOON,
2969     EL_SPRING,
2970     EL_EMC_ANDROID,
2971
2972     -1
2973   };
2974
2975   static int ep_can_fall[] =
2976   {
2977     EL_ROCK,
2978     EL_BD_ROCK,
2979     EL_EMERALD,
2980     EL_BD_DIAMOND,
2981     EL_EMERALD_YELLOW,
2982     EL_EMERALD_RED,
2983     EL_EMERALD_PURPLE,
2984     EL_DIAMOND,
2985     EL_BOMB,
2986     EL_NUT,
2987     EL_AMOEBA_DROP,
2988     EL_QUICKSAND_FULL,
2989     EL_QUICKSAND_FAST_FULL,
2990     EL_MAGIC_WALL_FULL,
2991     EL_BD_MAGIC_WALL_FULL,
2992     EL_DC_MAGIC_WALL_FULL,
2993     EL_TIME_ORB_FULL,
2994     EL_TIME_ORB_EMPTY,
2995     EL_SP_ZONK,
2996     EL_SP_INFOTRON,
2997     EL_SP_DISK_ORANGE,
2998     EL_PEARL,
2999     EL_CRYSTAL,
3000     EL_SPRING,
3001     EL_DX_SUPABOMB,
3002
3003     -1
3004   };
3005
3006   static int ep_can_smash_player[] =
3007   {
3008     EL_ROCK,
3009     EL_BD_ROCK,
3010     EL_EMERALD,
3011     EL_BD_DIAMOND,
3012     EL_EMERALD_YELLOW,
3013     EL_EMERALD_RED,
3014     EL_EMERALD_PURPLE,
3015     EL_DIAMOND,
3016     EL_BOMB,
3017     EL_NUT,
3018     EL_AMOEBA_DROP,
3019     EL_TIME_ORB_FULL,
3020     EL_TIME_ORB_EMPTY,
3021     EL_SP_ZONK,
3022     EL_SP_INFOTRON,
3023     EL_SP_DISK_ORANGE,
3024     EL_PEARL,
3025     EL_CRYSTAL,
3026     EL_SPRING,
3027     EL_DX_SUPABOMB,
3028
3029     -1
3030   };
3031
3032   static int ep_can_smash_enemies[] =
3033   {
3034     EL_ROCK,
3035     EL_BD_ROCK,
3036     EL_SP_ZONK,
3037
3038     -1
3039   };
3040
3041   static int ep_can_smash_everything[] =
3042   {
3043     EL_ROCK,
3044     EL_BD_ROCK,
3045     EL_SP_ZONK,
3046
3047     -1
3048   };
3049
3050   static int ep_explodes_by_fire[] =
3051   {
3052     /* same elements as in 'ep_explodes_impact' */
3053     EL_BOMB,
3054     EL_SP_DISK_ORANGE,
3055     EL_DX_SUPABOMB,
3056
3057     /* same elements as in 'ep_explodes_smashed' */
3058     EL_SATELLITE,
3059     EL_PIG,
3060     EL_DRAGON,
3061     EL_MOLE,
3062
3063     /* new elements */
3064     EL_DYNAMITE,
3065     EL_DYNAMITE_ACTIVE,
3066     EL_EM_DYNAMITE,
3067     EL_EM_DYNAMITE_ACTIVE,
3068     EL_DYNABOMB_PLAYER_1_ACTIVE,
3069     EL_DYNABOMB_PLAYER_2_ACTIVE,
3070     EL_DYNABOMB_PLAYER_3_ACTIVE,
3071     EL_DYNABOMB_PLAYER_4_ACTIVE,
3072     EL_DYNABOMB_INCREASE_NUMBER,
3073     EL_DYNABOMB_INCREASE_SIZE,
3074     EL_DYNABOMB_INCREASE_POWER,
3075     EL_SP_DISK_RED_ACTIVE,
3076     EL_BUG,
3077     EL_PENGUIN,
3078     EL_SP_DISK_RED,
3079     EL_SP_DISK_YELLOW,
3080     EL_SP_SNIKSNAK,
3081     EL_SP_ELECTRON,
3082 #if 0
3083     EL_BLACK_ORB,
3084 #endif
3085
3086     -1
3087   };
3088
3089   static int ep_explodes_smashed[] =
3090   {
3091     /* same elements as in 'ep_explodes_impact' */
3092     EL_BOMB,
3093     EL_SP_DISK_ORANGE,
3094     EL_DX_SUPABOMB,
3095
3096     /* new elements */
3097     EL_SATELLITE,
3098     EL_PIG,
3099     EL_DRAGON,
3100     EL_MOLE,
3101
3102     -1
3103   };
3104
3105   static int ep_explodes_impact[] =
3106   {
3107     EL_BOMB,
3108     EL_SP_DISK_ORANGE,
3109     EL_DX_SUPABOMB,
3110
3111     -1
3112   };
3113
3114   static int ep_walkable_over[] =
3115   {
3116     EL_EMPTY_SPACE,
3117     EL_SP_EMPTY_SPACE,
3118     EL_SOKOBAN_FIELD_EMPTY,
3119     EL_EXIT_OPEN,
3120     EL_EM_EXIT_OPEN,
3121     EL_SP_EXIT_OPEN,
3122     EL_SP_EXIT_OPENING,
3123     EL_STEEL_EXIT_OPEN,
3124     EL_EM_STEEL_EXIT_OPEN,
3125     EL_GATE_1,
3126     EL_GATE_2,
3127     EL_GATE_3,
3128     EL_GATE_4,
3129     EL_GATE_1_GRAY,
3130     EL_GATE_2_GRAY,
3131     EL_GATE_3_GRAY,
3132     EL_GATE_4_GRAY,
3133     EL_GATE_1_GRAY_ACTIVE,
3134     EL_GATE_2_GRAY_ACTIVE,
3135     EL_GATE_3_GRAY_ACTIVE,
3136     EL_GATE_4_GRAY_ACTIVE,
3137     EL_PENGUIN,
3138     EL_PIG,
3139     EL_DRAGON,
3140
3141     -1
3142   };
3143
3144   static int ep_walkable_inside[] =
3145   {
3146     EL_TUBE_ANY,
3147     EL_TUBE_VERTICAL,
3148     EL_TUBE_HORIZONTAL,
3149     EL_TUBE_VERTICAL_LEFT,
3150     EL_TUBE_VERTICAL_RIGHT,
3151     EL_TUBE_HORIZONTAL_UP,
3152     EL_TUBE_HORIZONTAL_DOWN,
3153     EL_TUBE_LEFT_UP,
3154     EL_TUBE_LEFT_DOWN,
3155     EL_TUBE_RIGHT_UP,
3156     EL_TUBE_RIGHT_DOWN,
3157
3158     -1
3159   };
3160
3161   static int ep_walkable_under[] =
3162   {
3163     -1
3164   };
3165
3166   static int ep_passable_over[] =
3167   {
3168     EL_EM_GATE_1,
3169     EL_EM_GATE_2,
3170     EL_EM_GATE_3,
3171     EL_EM_GATE_4,
3172     EL_EM_GATE_1_GRAY,
3173     EL_EM_GATE_2_GRAY,
3174     EL_EM_GATE_3_GRAY,
3175     EL_EM_GATE_4_GRAY,
3176     EL_EM_GATE_1_GRAY_ACTIVE,
3177     EL_EM_GATE_2_GRAY_ACTIVE,
3178     EL_EM_GATE_3_GRAY_ACTIVE,
3179     EL_EM_GATE_4_GRAY_ACTIVE,
3180     EL_EMC_GATE_5,
3181     EL_EMC_GATE_6,
3182     EL_EMC_GATE_7,
3183     EL_EMC_GATE_8,
3184     EL_EMC_GATE_5_GRAY,
3185     EL_EMC_GATE_6_GRAY,
3186     EL_EMC_GATE_7_GRAY,
3187     EL_EMC_GATE_8_GRAY,
3188     EL_EMC_GATE_5_GRAY_ACTIVE,
3189     EL_EMC_GATE_6_GRAY_ACTIVE,
3190     EL_EMC_GATE_7_GRAY_ACTIVE,
3191     EL_EMC_GATE_8_GRAY_ACTIVE,
3192     EL_DC_GATE_WHITE,
3193     EL_DC_GATE_WHITE_GRAY,
3194     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3195     EL_SWITCHGATE_OPEN,
3196     EL_TIMEGATE_OPEN,
3197
3198     -1
3199   };
3200
3201   static int ep_passable_inside[] =
3202   {
3203     EL_SP_PORT_LEFT,
3204     EL_SP_PORT_RIGHT,
3205     EL_SP_PORT_UP,
3206     EL_SP_PORT_DOWN,
3207     EL_SP_PORT_HORIZONTAL,
3208     EL_SP_PORT_VERTICAL,
3209     EL_SP_PORT_ANY,
3210     EL_SP_GRAVITY_PORT_LEFT,
3211     EL_SP_GRAVITY_PORT_RIGHT,
3212     EL_SP_GRAVITY_PORT_UP,
3213     EL_SP_GRAVITY_PORT_DOWN,
3214     EL_SP_GRAVITY_ON_PORT_LEFT,
3215     EL_SP_GRAVITY_ON_PORT_RIGHT,
3216     EL_SP_GRAVITY_ON_PORT_UP,
3217     EL_SP_GRAVITY_ON_PORT_DOWN,
3218     EL_SP_GRAVITY_OFF_PORT_LEFT,
3219     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3220     EL_SP_GRAVITY_OFF_PORT_UP,
3221     EL_SP_GRAVITY_OFF_PORT_DOWN,
3222
3223     -1
3224   };
3225
3226   static int ep_passable_under[] =
3227   {
3228     -1
3229   };
3230
3231   static int ep_droppable[] =
3232   {
3233     -1
3234   };
3235
3236   static int ep_explodes_1x1_old[] =
3237   {
3238     -1
3239   };
3240
3241   static int ep_pushable[] =
3242   {
3243     EL_ROCK,
3244     EL_BOMB,
3245     EL_DX_SUPABOMB,
3246     EL_NUT,
3247     EL_TIME_ORB_EMPTY,
3248     EL_SP_ZONK,
3249     EL_SP_DISK_ORANGE,
3250     EL_SPRING,
3251     EL_BD_ROCK,
3252     EL_SOKOBAN_OBJECT,
3253     EL_SOKOBAN_FIELD_FULL,
3254     EL_SATELLITE,
3255     EL_SP_DISK_YELLOW,
3256     EL_BALLOON,
3257     EL_EMC_ANDROID,
3258
3259     -1
3260   };
3261
3262   static int ep_explodes_cross_old[] =
3263   {
3264     -1
3265   };
3266
3267   static int ep_protected[] =
3268   {
3269     /* same elements as in 'ep_walkable_inside' */
3270     EL_TUBE_ANY,
3271     EL_TUBE_VERTICAL,
3272     EL_TUBE_HORIZONTAL,
3273     EL_TUBE_VERTICAL_LEFT,
3274     EL_TUBE_VERTICAL_RIGHT,
3275     EL_TUBE_HORIZONTAL_UP,
3276     EL_TUBE_HORIZONTAL_DOWN,
3277     EL_TUBE_LEFT_UP,
3278     EL_TUBE_LEFT_DOWN,
3279     EL_TUBE_RIGHT_UP,
3280     EL_TUBE_RIGHT_DOWN,
3281
3282     /* same elements as in 'ep_passable_over' */
3283     EL_EM_GATE_1,
3284     EL_EM_GATE_2,
3285     EL_EM_GATE_3,
3286     EL_EM_GATE_4,
3287     EL_EM_GATE_1_GRAY,
3288     EL_EM_GATE_2_GRAY,
3289     EL_EM_GATE_3_GRAY,
3290     EL_EM_GATE_4_GRAY,
3291     EL_EM_GATE_1_GRAY_ACTIVE,
3292     EL_EM_GATE_2_GRAY_ACTIVE,
3293     EL_EM_GATE_3_GRAY_ACTIVE,
3294     EL_EM_GATE_4_GRAY_ACTIVE,
3295     EL_EMC_GATE_5,
3296     EL_EMC_GATE_6,
3297     EL_EMC_GATE_7,
3298     EL_EMC_GATE_8,
3299     EL_EMC_GATE_5_GRAY,
3300     EL_EMC_GATE_6_GRAY,
3301     EL_EMC_GATE_7_GRAY,
3302     EL_EMC_GATE_8_GRAY,
3303     EL_EMC_GATE_5_GRAY_ACTIVE,
3304     EL_EMC_GATE_6_GRAY_ACTIVE,
3305     EL_EMC_GATE_7_GRAY_ACTIVE,
3306     EL_EMC_GATE_8_GRAY_ACTIVE,
3307     EL_DC_GATE_WHITE,
3308     EL_DC_GATE_WHITE_GRAY,
3309     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3310     EL_SWITCHGATE_OPEN,
3311     EL_TIMEGATE_OPEN,
3312
3313     /* same elements as in 'ep_passable_inside' */
3314     EL_SP_PORT_LEFT,
3315     EL_SP_PORT_RIGHT,
3316     EL_SP_PORT_UP,
3317     EL_SP_PORT_DOWN,
3318     EL_SP_PORT_HORIZONTAL,
3319     EL_SP_PORT_VERTICAL,
3320     EL_SP_PORT_ANY,
3321     EL_SP_GRAVITY_PORT_LEFT,
3322     EL_SP_GRAVITY_PORT_RIGHT,
3323     EL_SP_GRAVITY_PORT_UP,
3324     EL_SP_GRAVITY_PORT_DOWN,
3325     EL_SP_GRAVITY_ON_PORT_LEFT,
3326     EL_SP_GRAVITY_ON_PORT_RIGHT,
3327     EL_SP_GRAVITY_ON_PORT_UP,
3328     EL_SP_GRAVITY_ON_PORT_DOWN,
3329     EL_SP_GRAVITY_OFF_PORT_LEFT,
3330     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3331     EL_SP_GRAVITY_OFF_PORT_UP,
3332     EL_SP_GRAVITY_OFF_PORT_DOWN,
3333
3334     -1
3335   };
3336
3337   static int ep_throwable[] =
3338   {
3339     -1
3340   };
3341
3342   static int ep_can_explode[] =
3343   {
3344     /* same elements as in 'ep_explodes_impact' */
3345     EL_BOMB,
3346     EL_SP_DISK_ORANGE,
3347     EL_DX_SUPABOMB,
3348
3349     /* same elements as in 'ep_explodes_smashed' */
3350     EL_SATELLITE,
3351     EL_PIG,
3352     EL_DRAGON,
3353     EL_MOLE,
3354
3355     /* elements that can explode by explosion or by dragonfire */
3356     EL_DYNAMITE,
3357     EL_DYNAMITE_ACTIVE,
3358     EL_EM_DYNAMITE,
3359     EL_EM_DYNAMITE_ACTIVE,
3360     EL_DYNABOMB_PLAYER_1_ACTIVE,
3361     EL_DYNABOMB_PLAYER_2_ACTIVE,
3362     EL_DYNABOMB_PLAYER_3_ACTIVE,
3363     EL_DYNABOMB_PLAYER_4_ACTIVE,
3364     EL_DYNABOMB_INCREASE_NUMBER,
3365     EL_DYNABOMB_INCREASE_SIZE,
3366     EL_DYNABOMB_INCREASE_POWER,
3367     EL_SP_DISK_RED_ACTIVE,
3368     EL_BUG,
3369     EL_PENGUIN,
3370     EL_SP_DISK_RED,
3371     EL_SP_DISK_YELLOW,
3372     EL_SP_SNIKSNAK,
3373     EL_SP_ELECTRON,
3374
3375     /* elements that can explode only by explosion */
3376     EL_BLACK_ORB,
3377
3378     -1
3379   };
3380
3381   static int ep_gravity_reachable[] =
3382   {
3383     EL_SAND,
3384     EL_SP_BASE,
3385     EL_TRAP,
3386     EL_INVISIBLE_SAND,
3387     EL_INVISIBLE_SAND_ACTIVE,
3388     EL_SP_PORT_LEFT,
3389     EL_SP_PORT_RIGHT,
3390     EL_SP_PORT_UP,
3391     EL_SP_PORT_DOWN,
3392     EL_SP_PORT_HORIZONTAL,
3393     EL_SP_PORT_VERTICAL,
3394     EL_SP_PORT_ANY,
3395     EL_SP_GRAVITY_PORT_LEFT,
3396     EL_SP_GRAVITY_PORT_RIGHT,
3397     EL_SP_GRAVITY_PORT_UP,
3398     EL_SP_GRAVITY_PORT_DOWN,
3399     EL_SP_GRAVITY_ON_PORT_LEFT,
3400     EL_SP_GRAVITY_ON_PORT_RIGHT,
3401     EL_SP_GRAVITY_ON_PORT_UP,
3402     EL_SP_GRAVITY_ON_PORT_DOWN,
3403     EL_SP_GRAVITY_OFF_PORT_LEFT,
3404     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3405     EL_SP_GRAVITY_OFF_PORT_UP,
3406     EL_SP_GRAVITY_OFF_PORT_DOWN,
3407     EL_EMC_GRASS,
3408
3409     -1
3410   };
3411
3412   static int ep_player[] =
3413   {
3414     EL_PLAYER_1,
3415     EL_PLAYER_2,
3416     EL_PLAYER_3,
3417     EL_PLAYER_4,
3418     EL_SP_MURPHY,
3419     EL_SOKOBAN_FIELD_PLAYER,
3420     EL_TRIGGER_PLAYER,
3421
3422     -1
3423   };
3424
3425   static int ep_can_pass_magic_wall[] =
3426   {
3427     EL_ROCK,
3428     EL_BD_ROCK,
3429     EL_EMERALD,
3430     EL_BD_DIAMOND,
3431     EL_EMERALD_YELLOW,
3432     EL_EMERALD_RED,
3433     EL_EMERALD_PURPLE,
3434     EL_DIAMOND,
3435
3436     -1
3437   };
3438
3439   static int ep_can_pass_dc_magic_wall[] =
3440   {
3441     EL_ROCK,
3442     EL_BD_ROCK,
3443     EL_EMERALD,
3444     EL_BD_DIAMOND,
3445     EL_EMERALD_YELLOW,
3446     EL_EMERALD_RED,
3447     EL_EMERALD_PURPLE,
3448     EL_DIAMOND,
3449     EL_PEARL,
3450     EL_CRYSTAL,
3451
3452     -1
3453   };
3454
3455   static int ep_switchable[] =
3456   {
3457     EL_ROBOT_WHEEL,
3458     EL_SP_TERMINAL,
3459     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3460     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3461     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3462     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3463     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3464     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3465     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3466     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3467     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3468     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3469     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3470     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3471     EL_SWITCHGATE_SWITCH_UP,
3472     EL_SWITCHGATE_SWITCH_DOWN,
3473     EL_DC_SWITCHGATE_SWITCH_UP,
3474     EL_DC_SWITCHGATE_SWITCH_DOWN,
3475     EL_LIGHT_SWITCH,
3476     EL_LIGHT_SWITCH_ACTIVE,
3477     EL_TIMEGATE_SWITCH,
3478     EL_DC_TIMEGATE_SWITCH,
3479     EL_BALLOON_SWITCH_LEFT,
3480     EL_BALLOON_SWITCH_RIGHT,
3481     EL_BALLOON_SWITCH_UP,
3482     EL_BALLOON_SWITCH_DOWN,
3483     EL_BALLOON_SWITCH_ANY,
3484     EL_BALLOON_SWITCH_NONE,
3485     EL_LAMP,
3486     EL_TIME_ORB_FULL,
3487     EL_EMC_MAGIC_BALL_SWITCH,
3488     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3489
3490     -1
3491   };
3492
3493   static int ep_bd_element[] =
3494   {
3495     EL_EMPTY,
3496     EL_SAND,
3497     EL_WALL_SLIPPERY,
3498     EL_BD_WALL,
3499     EL_ROCK,
3500     EL_BD_ROCK,
3501     EL_BD_DIAMOND,
3502     EL_BD_MAGIC_WALL,
3503     EL_EXIT_CLOSED,
3504     EL_EXIT_OPEN,
3505     EL_STEELWALL,
3506     EL_PLAYER_1,
3507     EL_PLAYER_2,
3508     EL_PLAYER_3,
3509     EL_PLAYER_4,
3510     EL_BD_FIREFLY,
3511     EL_BD_FIREFLY_1,
3512     EL_BD_FIREFLY_2,
3513     EL_BD_FIREFLY_3,
3514     EL_BD_FIREFLY_4,
3515     EL_BD_BUTTERFLY,
3516     EL_BD_BUTTERFLY_1,
3517     EL_BD_BUTTERFLY_2,
3518     EL_BD_BUTTERFLY_3,
3519     EL_BD_BUTTERFLY_4,
3520     EL_BD_AMOEBA,
3521     EL_CHAR_QUESTION,
3522     EL_UNKNOWN,
3523
3524     -1
3525   };
3526
3527   static int ep_sp_element[] =
3528   {
3529     /* should always be valid */
3530     EL_EMPTY,
3531
3532     /* standard classic Supaplex elements */
3533     EL_SP_EMPTY,
3534     EL_SP_ZONK,
3535     EL_SP_BASE,
3536     EL_SP_MURPHY,
3537     EL_SP_INFOTRON,
3538     EL_SP_CHIP_SINGLE,
3539     EL_SP_HARDWARE_GRAY,
3540     EL_SP_EXIT_CLOSED,
3541     EL_SP_EXIT_OPEN,
3542     EL_SP_DISK_ORANGE,
3543     EL_SP_PORT_RIGHT,
3544     EL_SP_PORT_DOWN,
3545     EL_SP_PORT_LEFT,
3546     EL_SP_PORT_UP,
3547     EL_SP_GRAVITY_PORT_RIGHT,
3548     EL_SP_GRAVITY_PORT_DOWN,
3549     EL_SP_GRAVITY_PORT_LEFT,
3550     EL_SP_GRAVITY_PORT_UP,
3551     EL_SP_SNIKSNAK,
3552     EL_SP_DISK_YELLOW,
3553     EL_SP_TERMINAL,
3554     EL_SP_DISK_RED,
3555     EL_SP_PORT_VERTICAL,
3556     EL_SP_PORT_HORIZONTAL,
3557     EL_SP_PORT_ANY,
3558     EL_SP_ELECTRON,
3559     EL_SP_BUGGY_BASE,
3560     EL_SP_CHIP_LEFT,
3561     EL_SP_CHIP_RIGHT,
3562     EL_SP_HARDWARE_BASE_1,
3563     EL_SP_HARDWARE_GREEN,
3564     EL_SP_HARDWARE_BLUE,
3565     EL_SP_HARDWARE_RED,
3566     EL_SP_HARDWARE_YELLOW,
3567     EL_SP_HARDWARE_BASE_2,
3568     EL_SP_HARDWARE_BASE_3,
3569     EL_SP_HARDWARE_BASE_4,
3570     EL_SP_HARDWARE_BASE_5,
3571     EL_SP_HARDWARE_BASE_6,
3572     EL_SP_CHIP_TOP,
3573     EL_SP_CHIP_BOTTOM,
3574
3575     /* additional elements that appeared in newer Supaplex levels */
3576     EL_INVISIBLE_WALL,
3577
3578     /* additional gravity port elements (not switching, but setting gravity) */
3579     EL_SP_GRAVITY_ON_PORT_LEFT,
3580     EL_SP_GRAVITY_ON_PORT_RIGHT,
3581     EL_SP_GRAVITY_ON_PORT_UP,
3582     EL_SP_GRAVITY_ON_PORT_DOWN,
3583     EL_SP_GRAVITY_OFF_PORT_LEFT,
3584     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3585     EL_SP_GRAVITY_OFF_PORT_UP,
3586     EL_SP_GRAVITY_OFF_PORT_DOWN,
3587
3588     /* more than one Murphy in a level results in an inactive clone */
3589     EL_SP_MURPHY_CLONE,
3590
3591     /* runtime Supaplex elements */
3592     EL_SP_DISK_RED_ACTIVE,
3593     EL_SP_TERMINAL_ACTIVE,
3594     EL_SP_BUGGY_BASE_ACTIVATING,
3595     EL_SP_BUGGY_BASE_ACTIVE,
3596     EL_SP_EXIT_OPENING,
3597     EL_SP_EXIT_CLOSING,
3598
3599     -1
3600   };
3601
3602   static int ep_sb_element[] =
3603   {
3604     EL_EMPTY,
3605     EL_STEELWALL,
3606     EL_SOKOBAN_OBJECT,
3607     EL_SOKOBAN_FIELD_EMPTY,
3608     EL_SOKOBAN_FIELD_FULL,
3609     EL_SOKOBAN_FIELD_PLAYER,
3610     EL_PLAYER_1,
3611     EL_PLAYER_2,
3612     EL_PLAYER_3,
3613     EL_PLAYER_4,
3614     EL_INVISIBLE_STEELWALL,
3615
3616     -1
3617   };
3618
3619   static int ep_gem[] =
3620   {
3621     EL_BD_DIAMOND,
3622     EL_EMERALD,
3623     EL_EMERALD_YELLOW,
3624     EL_EMERALD_RED,
3625     EL_EMERALD_PURPLE,
3626     EL_DIAMOND,
3627
3628     -1
3629   };
3630
3631   static int ep_food_dark_yamyam[] =
3632   {
3633     EL_SAND,
3634     EL_BUG,
3635     EL_SPACESHIP,
3636     EL_BD_BUTTERFLY,
3637     EL_BD_FIREFLY,
3638     EL_YAMYAM,
3639     EL_ROBOT,
3640     EL_PACMAN,
3641     EL_AMOEBA_DROP,
3642     EL_AMOEBA_DEAD,
3643     EL_AMOEBA_WET,
3644     EL_AMOEBA_DRY,
3645     EL_AMOEBA_FULL,
3646     EL_BD_AMOEBA,
3647     EL_EMERALD,
3648     EL_BD_DIAMOND,
3649     EL_EMERALD_YELLOW,
3650     EL_EMERALD_RED,
3651     EL_EMERALD_PURPLE,
3652     EL_DIAMOND,
3653     EL_PEARL,
3654     EL_CRYSTAL,
3655
3656     -1
3657   };
3658
3659   static int ep_food_penguin[] =
3660   {
3661     EL_EMERALD,
3662     EL_BD_DIAMOND,
3663     EL_EMERALD_YELLOW,
3664     EL_EMERALD_RED,
3665     EL_EMERALD_PURPLE,
3666     EL_DIAMOND,
3667     EL_PEARL,
3668     EL_CRYSTAL,
3669
3670     -1
3671   };
3672
3673   static int ep_food_pig[] =
3674   {
3675     EL_EMERALD,
3676     EL_BD_DIAMOND,
3677     EL_EMERALD_YELLOW,
3678     EL_EMERALD_RED,
3679     EL_EMERALD_PURPLE,
3680     EL_DIAMOND,
3681
3682     -1
3683   };
3684
3685   static int ep_historic_wall[] =
3686   {
3687     EL_STEELWALL,
3688     EL_GATE_1,
3689     EL_GATE_2,
3690     EL_GATE_3,
3691     EL_GATE_4,
3692     EL_GATE_1_GRAY,
3693     EL_GATE_2_GRAY,
3694     EL_GATE_3_GRAY,
3695     EL_GATE_4_GRAY,
3696     EL_GATE_1_GRAY_ACTIVE,
3697     EL_GATE_2_GRAY_ACTIVE,
3698     EL_GATE_3_GRAY_ACTIVE,
3699     EL_GATE_4_GRAY_ACTIVE,
3700     EL_EM_GATE_1,
3701     EL_EM_GATE_2,
3702     EL_EM_GATE_3,
3703     EL_EM_GATE_4,
3704     EL_EM_GATE_1_GRAY,
3705     EL_EM_GATE_2_GRAY,
3706     EL_EM_GATE_3_GRAY,
3707     EL_EM_GATE_4_GRAY,
3708     EL_EM_GATE_1_GRAY_ACTIVE,
3709     EL_EM_GATE_2_GRAY_ACTIVE,
3710     EL_EM_GATE_3_GRAY_ACTIVE,
3711     EL_EM_GATE_4_GRAY_ACTIVE,
3712     EL_EXIT_CLOSED,
3713     EL_EXIT_OPENING,
3714     EL_EXIT_OPEN,
3715     EL_WALL,
3716     EL_WALL_SLIPPERY,
3717     EL_EXPANDABLE_WALL,
3718     EL_EXPANDABLE_WALL_HORIZONTAL,
3719     EL_EXPANDABLE_WALL_VERTICAL,
3720     EL_EXPANDABLE_WALL_ANY,
3721     EL_EXPANDABLE_WALL_GROWING,
3722     EL_BD_EXPANDABLE_WALL,
3723     EL_BD_WALL,
3724     EL_SP_CHIP_SINGLE,
3725     EL_SP_CHIP_LEFT,
3726     EL_SP_CHIP_RIGHT,
3727     EL_SP_CHIP_TOP,
3728     EL_SP_CHIP_BOTTOM,
3729     EL_SP_HARDWARE_GRAY,
3730     EL_SP_HARDWARE_GREEN,
3731     EL_SP_HARDWARE_BLUE,
3732     EL_SP_HARDWARE_RED,
3733     EL_SP_HARDWARE_YELLOW,
3734     EL_SP_HARDWARE_BASE_1,
3735     EL_SP_HARDWARE_BASE_2,
3736     EL_SP_HARDWARE_BASE_3,
3737     EL_SP_HARDWARE_BASE_4,
3738     EL_SP_HARDWARE_BASE_5,
3739     EL_SP_HARDWARE_BASE_6,
3740     EL_SP_TERMINAL,
3741     EL_SP_TERMINAL_ACTIVE,
3742     EL_SP_EXIT_CLOSED,
3743     EL_SP_EXIT_OPEN,
3744     EL_INVISIBLE_STEELWALL,
3745     EL_INVISIBLE_STEELWALL_ACTIVE,
3746     EL_INVISIBLE_WALL,
3747     EL_INVISIBLE_WALL_ACTIVE,
3748     EL_STEELWALL_SLIPPERY,
3749     EL_EMC_STEELWALL_1,
3750     EL_EMC_STEELWALL_2,
3751     EL_EMC_STEELWALL_3,
3752     EL_EMC_STEELWALL_4,
3753     EL_EMC_WALL_1,
3754     EL_EMC_WALL_2,
3755     EL_EMC_WALL_3,
3756     EL_EMC_WALL_4,
3757     EL_EMC_WALL_5,
3758     EL_EMC_WALL_6,
3759     EL_EMC_WALL_7,
3760     EL_EMC_WALL_8,
3761
3762     -1
3763   };
3764
3765   static int ep_historic_solid[] =
3766   {
3767     EL_WALL,
3768     EL_EXPANDABLE_WALL,
3769     EL_EXPANDABLE_WALL_HORIZONTAL,
3770     EL_EXPANDABLE_WALL_VERTICAL,
3771     EL_EXPANDABLE_WALL_ANY,
3772     EL_BD_EXPANDABLE_WALL,
3773     EL_BD_WALL,
3774     EL_WALL_SLIPPERY,
3775     EL_EXIT_CLOSED,
3776     EL_EXIT_OPENING,
3777     EL_EXIT_OPEN,
3778     EL_AMOEBA_DEAD,
3779     EL_AMOEBA_WET,
3780     EL_AMOEBA_DRY,
3781     EL_AMOEBA_FULL,
3782     EL_BD_AMOEBA,
3783     EL_QUICKSAND_EMPTY,
3784     EL_QUICKSAND_FULL,
3785     EL_QUICKSAND_FILLING,
3786     EL_QUICKSAND_EMPTYING,
3787     EL_MAGIC_WALL,
3788     EL_MAGIC_WALL_ACTIVE,
3789     EL_MAGIC_WALL_EMPTYING,
3790     EL_MAGIC_WALL_FILLING,
3791     EL_MAGIC_WALL_FULL,
3792     EL_MAGIC_WALL_DEAD,
3793     EL_BD_MAGIC_WALL,
3794     EL_BD_MAGIC_WALL_ACTIVE,
3795     EL_BD_MAGIC_WALL_EMPTYING,
3796     EL_BD_MAGIC_WALL_FULL,
3797     EL_BD_MAGIC_WALL_FILLING,
3798     EL_BD_MAGIC_WALL_DEAD,
3799     EL_GAME_OF_LIFE,
3800     EL_BIOMAZE,
3801     EL_SP_CHIP_SINGLE,
3802     EL_SP_CHIP_LEFT,
3803     EL_SP_CHIP_RIGHT,
3804     EL_SP_CHIP_TOP,
3805     EL_SP_CHIP_BOTTOM,
3806     EL_SP_TERMINAL,
3807     EL_SP_TERMINAL_ACTIVE,
3808     EL_SP_EXIT_CLOSED,
3809     EL_SP_EXIT_OPEN,
3810     EL_INVISIBLE_WALL,
3811     EL_INVISIBLE_WALL_ACTIVE,
3812     EL_SWITCHGATE_SWITCH_UP,
3813     EL_SWITCHGATE_SWITCH_DOWN,
3814     EL_DC_SWITCHGATE_SWITCH_UP,
3815     EL_DC_SWITCHGATE_SWITCH_DOWN,
3816     EL_TIMEGATE_SWITCH,
3817     EL_TIMEGATE_SWITCH_ACTIVE,
3818     EL_DC_TIMEGATE_SWITCH,
3819     EL_DC_TIMEGATE_SWITCH_ACTIVE,
3820     EL_EMC_WALL_1,
3821     EL_EMC_WALL_2,
3822     EL_EMC_WALL_3,
3823     EL_EMC_WALL_4,
3824     EL_EMC_WALL_5,
3825     EL_EMC_WALL_6,
3826     EL_EMC_WALL_7,
3827     EL_EMC_WALL_8,
3828     EL_WALL_PEARL,
3829     EL_WALL_CRYSTAL,
3830
3831     /* the following elements are a direct copy of "indestructible" elements,
3832        except "EL_ACID", which is "indestructible", but not "solid"! */
3833 #if 0
3834     EL_ACID,
3835 #endif
3836     EL_STEELWALL,
3837     EL_ACID_POOL_TOPLEFT,
3838     EL_ACID_POOL_TOPRIGHT,
3839     EL_ACID_POOL_BOTTOMLEFT,
3840     EL_ACID_POOL_BOTTOM,
3841     EL_ACID_POOL_BOTTOMRIGHT,
3842     EL_SP_HARDWARE_GRAY,
3843     EL_SP_HARDWARE_GREEN,
3844     EL_SP_HARDWARE_BLUE,
3845     EL_SP_HARDWARE_RED,
3846     EL_SP_HARDWARE_YELLOW,
3847     EL_SP_HARDWARE_BASE_1,
3848     EL_SP_HARDWARE_BASE_2,
3849     EL_SP_HARDWARE_BASE_3,
3850     EL_SP_HARDWARE_BASE_4,
3851     EL_SP_HARDWARE_BASE_5,
3852     EL_SP_HARDWARE_BASE_6,
3853     EL_INVISIBLE_STEELWALL,
3854     EL_INVISIBLE_STEELWALL_ACTIVE,
3855     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3856     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3857     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3858     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3859     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3860     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3861     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3862     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3863     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3864     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3865     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3866     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3867     EL_LIGHT_SWITCH,
3868     EL_LIGHT_SWITCH_ACTIVE,
3869     EL_SIGN_EXCLAMATION,
3870     EL_SIGN_RADIOACTIVITY,
3871     EL_SIGN_STOP,
3872     EL_SIGN_WHEELCHAIR,
3873     EL_SIGN_PARKING,
3874     EL_SIGN_NO_ENTRY,
3875     EL_SIGN_UNUSED_1,
3876     EL_SIGN_GIVE_WAY,
3877     EL_SIGN_ENTRY_FORBIDDEN,
3878     EL_SIGN_EMERGENCY_EXIT,
3879     EL_SIGN_YIN_YANG,
3880     EL_SIGN_UNUSED_2,
3881     EL_SIGN_SPERMS,
3882     EL_SIGN_BULLET,
3883     EL_SIGN_HEART,
3884     EL_SIGN_CROSS,
3885     EL_SIGN_FRANKIE,
3886     EL_STEEL_EXIT_CLOSED,
3887     EL_STEEL_EXIT_OPEN,
3888     EL_DC_STEELWALL_1_LEFT,
3889     EL_DC_STEELWALL_1_RIGHT,
3890     EL_DC_STEELWALL_1_TOP,
3891     EL_DC_STEELWALL_1_BOTTOM,
3892     EL_DC_STEELWALL_1_HORIZONTAL,
3893     EL_DC_STEELWALL_1_VERTICAL,
3894     EL_DC_STEELWALL_1_TOPLEFT,
3895     EL_DC_STEELWALL_1_TOPRIGHT,
3896     EL_DC_STEELWALL_1_BOTTOMLEFT,
3897     EL_DC_STEELWALL_1_BOTTOMRIGHT,
3898     EL_DC_STEELWALL_1_TOPLEFT_2,
3899     EL_DC_STEELWALL_1_TOPRIGHT_2,
3900     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3901     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3902     EL_DC_STEELWALL_2_LEFT,
3903     EL_DC_STEELWALL_2_RIGHT,
3904     EL_DC_STEELWALL_2_TOP,
3905     EL_DC_STEELWALL_2_BOTTOM,
3906     EL_DC_STEELWALL_2_HORIZONTAL,
3907     EL_DC_STEELWALL_2_VERTICAL,
3908     EL_DC_STEELWALL_2_MIDDLE,
3909     EL_DC_STEELWALL_2_SINGLE,
3910     EL_STEELWALL_SLIPPERY,
3911     EL_EMC_STEELWALL_1,
3912     EL_EMC_STEELWALL_2,
3913     EL_EMC_STEELWALL_3,
3914     EL_EMC_STEELWALL_4,
3915     EL_CRYSTAL,
3916     EL_GATE_1,
3917     EL_GATE_2,
3918     EL_GATE_3,
3919     EL_GATE_4,
3920     EL_GATE_1_GRAY,
3921     EL_GATE_2_GRAY,
3922     EL_GATE_3_GRAY,
3923     EL_GATE_4_GRAY,
3924     EL_GATE_1_GRAY_ACTIVE,
3925     EL_GATE_2_GRAY_ACTIVE,
3926     EL_GATE_3_GRAY_ACTIVE,
3927     EL_GATE_4_GRAY_ACTIVE,
3928     EL_EM_GATE_1,
3929     EL_EM_GATE_2,
3930     EL_EM_GATE_3,
3931     EL_EM_GATE_4,
3932     EL_EM_GATE_1_GRAY,
3933     EL_EM_GATE_2_GRAY,
3934     EL_EM_GATE_3_GRAY,
3935     EL_EM_GATE_4_GRAY,
3936     EL_EM_GATE_1_GRAY_ACTIVE,
3937     EL_EM_GATE_2_GRAY_ACTIVE,
3938     EL_EM_GATE_3_GRAY_ACTIVE,
3939     EL_EM_GATE_4_GRAY_ACTIVE,
3940     EL_SWITCHGATE_OPEN,
3941     EL_SWITCHGATE_OPENING,
3942     EL_SWITCHGATE_CLOSED,
3943     EL_SWITCHGATE_CLOSING,
3944     EL_TIMEGATE_OPEN,
3945     EL_TIMEGATE_OPENING,
3946     EL_TIMEGATE_CLOSED,
3947     EL_TIMEGATE_CLOSING,
3948     EL_TUBE_ANY,
3949     EL_TUBE_VERTICAL,
3950     EL_TUBE_HORIZONTAL,
3951     EL_TUBE_VERTICAL_LEFT,
3952     EL_TUBE_VERTICAL_RIGHT,
3953     EL_TUBE_HORIZONTAL_UP,
3954     EL_TUBE_HORIZONTAL_DOWN,
3955     EL_TUBE_LEFT_UP,
3956     EL_TUBE_LEFT_DOWN,
3957     EL_TUBE_RIGHT_UP,
3958     EL_TUBE_RIGHT_DOWN,
3959
3960     -1
3961   };
3962
3963   static int ep_classic_enemy[] =
3964   {
3965     EL_BUG,
3966     EL_SPACESHIP,
3967     EL_BD_BUTTERFLY,
3968     EL_BD_FIREFLY,
3969
3970     EL_YAMYAM,
3971     EL_DARK_YAMYAM,
3972     EL_ROBOT,
3973     EL_PACMAN,
3974     EL_SP_SNIKSNAK,
3975     EL_SP_ELECTRON,
3976
3977     -1
3978   };
3979
3980   static int ep_belt[] =
3981   {
3982     EL_CONVEYOR_BELT_1_LEFT,
3983     EL_CONVEYOR_BELT_1_MIDDLE,
3984     EL_CONVEYOR_BELT_1_RIGHT,
3985     EL_CONVEYOR_BELT_2_LEFT,
3986     EL_CONVEYOR_BELT_2_MIDDLE,
3987     EL_CONVEYOR_BELT_2_RIGHT,
3988     EL_CONVEYOR_BELT_3_LEFT,
3989     EL_CONVEYOR_BELT_3_MIDDLE,
3990     EL_CONVEYOR_BELT_3_RIGHT,
3991     EL_CONVEYOR_BELT_4_LEFT,
3992     EL_CONVEYOR_BELT_4_MIDDLE,
3993     EL_CONVEYOR_BELT_4_RIGHT,
3994
3995     -1
3996   };
3997
3998   static int ep_belt_active[] =
3999   {
4000     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4001     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4002     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4003     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4004     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4005     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4006     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4007     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4008     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4009     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4010     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4011     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4012
4013     -1
4014   };
4015
4016   static int ep_belt_switch[] =
4017   {
4018     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4019     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4020     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4021     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4022     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4023     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4024     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4025     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4026     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4027     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4028     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4029     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4030
4031     -1
4032   };
4033
4034   static int ep_tube[] =
4035   {
4036     EL_TUBE_LEFT_UP,
4037     EL_TUBE_LEFT_DOWN,
4038     EL_TUBE_RIGHT_UP,
4039     EL_TUBE_RIGHT_DOWN,
4040     EL_TUBE_HORIZONTAL,
4041     EL_TUBE_HORIZONTAL_UP,
4042     EL_TUBE_HORIZONTAL_DOWN,
4043     EL_TUBE_VERTICAL,
4044     EL_TUBE_VERTICAL_LEFT,
4045     EL_TUBE_VERTICAL_RIGHT,
4046     EL_TUBE_ANY,
4047
4048     -1
4049   };
4050
4051   static int ep_acid_pool[] =
4052   {
4053     EL_ACID_POOL_TOPLEFT,
4054     EL_ACID_POOL_TOPRIGHT,
4055     EL_ACID_POOL_BOTTOMLEFT,
4056     EL_ACID_POOL_BOTTOM,
4057     EL_ACID_POOL_BOTTOMRIGHT,
4058
4059     -1
4060   };
4061
4062   static int ep_keygate[] =
4063   {
4064     EL_GATE_1,
4065     EL_GATE_2,
4066     EL_GATE_3,
4067     EL_GATE_4,
4068     EL_GATE_1_GRAY,
4069     EL_GATE_2_GRAY,
4070     EL_GATE_3_GRAY,
4071     EL_GATE_4_GRAY,
4072     EL_GATE_1_GRAY_ACTIVE,
4073     EL_GATE_2_GRAY_ACTIVE,
4074     EL_GATE_3_GRAY_ACTIVE,
4075     EL_GATE_4_GRAY_ACTIVE,
4076     EL_EM_GATE_1,
4077     EL_EM_GATE_2,
4078     EL_EM_GATE_3,
4079     EL_EM_GATE_4,
4080     EL_EM_GATE_1_GRAY,
4081     EL_EM_GATE_2_GRAY,
4082     EL_EM_GATE_3_GRAY,
4083     EL_EM_GATE_4_GRAY,
4084     EL_EM_GATE_1_GRAY_ACTIVE,
4085     EL_EM_GATE_2_GRAY_ACTIVE,
4086     EL_EM_GATE_3_GRAY_ACTIVE,
4087     EL_EM_GATE_4_GRAY_ACTIVE,
4088     EL_EMC_GATE_5,
4089     EL_EMC_GATE_6,
4090     EL_EMC_GATE_7,
4091     EL_EMC_GATE_8,
4092     EL_EMC_GATE_5_GRAY,
4093     EL_EMC_GATE_6_GRAY,
4094     EL_EMC_GATE_7_GRAY,
4095     EL_EMC_GATE_8_GRAY,
4096     EL_EMC_GATE_5_GRAY_ACTIVE,
4097     EL_EMC_GATE_6_GRAY_ACTIVE,
4098     EL_EMC_GATE_7_GRAY_ACTIVE,
4099     EL_EMC_GATE_8_GRAY_ACTIVE,
4100     EL_DC_GATE_WHITE,
4101     EL_DC_GATE_WHITE_GRAY,
4102     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4103
4104     -1
4105   };
4106
4107   static int ep_amoeboid[] =
4108   {
4109     EL_AMOEBA_DEAD,
4110     EL_AMOEBA_WET,
4111     EL_AMOEBA_DRY,
4112     EL_AMOEBA_FULL,
4113     EL_BD_AMOEBA,
4114     EL_EMC_DRIPPER,
4115
4116     -1
4117   };
4118
4119   static int ep_amoebalive[] =
4120   {
4121     EL_AMOEBA_WET,
4122     EL_AMOEBA_DRY,
4123     EL_AMOEBA_FULL,
4124     EL_BD_AMOEBA,
4125     EL_EMC_DRIPPER,
4126
4127     -1
4128   };
4129
4130   static int ep_has_editor_content[] =
4131   {
4132     EL_PLAYER_1,
4133     EL_PLAYER_2,
4134     EL_PLAYER_3,
4135     EL_PLAYER_4,
4136     EL_SP_MURPHY,
4137     EL_YAMYAM,
4138     EL_YAMYAM_LEFT,
4139     EL_YAMYAM_RIGHT,
4140     EL_YAMYAM_UP,
4141     EL_YAMYAM_DOWN,
4142     EL_AMOEBA_WET,
4143     EL_AMOEBA_DRY,
4144     EL_AMOEBA_FULL,
4145     EL_BD_AMOEBA,
4146     EL_EMC_MAGIC_BALL,
4147     EL_EMC_ANDROID,
4148
4149     -1
4150   };
4151
4152   static int ep_can_turn_each_move[] =
4153   {
4154     /* !!! do something with this one !!! */
4155     -1
4156   };
4157
4158   static int ep_can_grow[] =
4159   {
4160     EL_BD_AMOEBA,
4161     EL_AMOEBA_DROP,
4162     EL_AMOEBA_WET,
4163     EL_AMOEBA_DRY,
4164     EL_AMOEBA_FULL,
4165     EL_GAME_OF_LIFE,
4166     EL_BIOMAZE,
4167     EL_EMC_DRIPPER,
4168
4169     -1
4170   };
4171
4172   static int ep_active_bomb[] =
4173   {
4174     EL_DYNAMITE_ACTIVE,
4175     EL_EM_DYNAMITE_ACTIVE,
4176     EL_DYNABOMB_PLAYER_1_ACTIVE,
4177     EL_DYNABOMB_PLAYER_2_ACTIVE,
4178     EL_DYNABOMB_PLAYER_3_ACTIVE,
4179     EL_DYNABOMB_PLAYER_4_ACTIVE,
4180     EL_SP_DISK_RED_ACTIVE,
4181
4182     -1
4183   };
4184
4185   static int ep_inactive[] =
4186   {
4187     EL_EMPTY,
4188     EL_SAND,
4189     EL_WALL,
4190     EL_BD_WALL,
4191     EL_WALL_SLIPPERY,
4192     EL_STEELWALL,
4193     EL_AMOEBA_DEAD,
4194     EL_QUICKSAND_EMPTY,
4195     EL_QUICKSAND_FAST_EMPTY,
4196     EL_STONEBLOCK,
4197     EL_ROBOT_WHEEL,
4198     EL_KEY_1,
4199     EL_KEY_2,
4200     EL_KEY_3,
4201     EL_KEY_4,
4202     EL_EM_KEY_1,
4203     EL_EM_KEY_2,
4204     EL_EM_KEY_3,
4205     EL_EM_KEY_4,
4206     EL_EMC_KEY_5,
4207     EL_EMC_KEY_6,
4208     EL_EMC_KEY_7,
4209     EL_EMC_KEY_8,
4210     EL_GATE_1,
4211     EL_GATE_2,
4212     EL_GATE_3,
4213     EL_GATE_4,
4214     EL_GATE_1_GRAY,
4215     EL_GATE_2_GRAY,
4216     EL_GATE_3_GRAY,
4217     EL_GATE_4_GRAY,
4218     EL_GATE_1_GRAY_ACTIVE,
4219     EL_GATE_2_GRAY_ACTIVE,
4220     EL_GATE_3_GRAY_ACTIVE,
4221     EL_GATE_4_GRAY_ACTIVE,
4222     EL_EM_GATE_1,
4223     EL_EM_GATE_2,
4224     EL_EM_GATE_3,
4225     EL_EM_GATE_4,
4226     EL_EM_GATE_1_GRAY,
4227     EL_EM_GATE_2_GRAY,
4228     EL_EM_GATE_3_GRAY,
4229     EL_EM_GATE_4_GRAY,
4230     EL_EM_GATE_1_GRAY_ACTIVE,
4231     EL_EM_GATE_2_GRAY_ACTIVE,
4232     EL_EM_GATE_3_GRAY_ACTIVE,
4233     EL_EM_GATE_4_GRAY_ACTIVE,
4234     EL_EMC_GATE_5,
4235     EL_EMC_GATE_6,
4236     EL_EMC_GATE_7,
4237     EL_EMC_GATE_8,
4238     EL_EMC_GATE_5_GRAY,
4239     EL_EMC_GATE_6_GRAY,
4240     EL_EMC_GATE_7_GRAY,
4241     EL_EMC_GATE_8_GRAY,
4242     EL_EMC_GATE_5_GRAY_ACTIVE,
4243     EL_EMC_GATE_6_GRAY_ACTIVE,
4244     EL_EMC_GATE_7_GRAY_ACTIVE,
4245     EL_EMC_GATE_8_GRAY_ACTIVE,
4246     EL_DC_GATE_WHITE,
4247     EL_DC_GATE_WHITE_GRAY,
4248     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4249     EL_DC_GATE_FAKE_GRAY,
4250     EL_DYNAMITE,
4251     EL_EM_DYNAMITE,
4252     EL_INVISIBLE_STEELWALL,
4253     EL_INVISIBLE_WALL,
4254     EL_INVISIBLE_SAND,
4255     EL_LAMP,
4256     EL_LAMP_ACTIVE,
4257     EL_WALL_EMERALD,
4258     EL_WALL_DIAMOND,
4259     EL_WALL_BD_DIAMOND,
4260     EL_WALL_EMERALD_YELLOW,
4261     EL_DYNABOMB_INCREASE_NUMBER,
4262     EL_DYNABOMB_INCREASE_SIZE,
4263     EL_DYNABOMB_INCREASE_POWER,
4264 #if 0
4265     EL_SOKOBAN_OBJECT,
4266 #endif
4267     EL_SOKOBAN_FIELD_EMPTY,
4268     EL_SOKOBAN_FIELD_FULL,
4269     EL_WALL_EMERALD_RED,
4270     EL_WALL_EMERALD_PURPLE,
4271     EL_ACID_POOL_TOPLEFT,
4272     EL_ACID_POOL_TOPRIGHT,
4273     EL_ACID_POOL_BOTTOMLEFT,
4274     EL_ACID_POOL_BOTTOM,
4275     EL_ACID_POOL_BOTTOMRIGHT,
4276     EL_MAGIC_WALL,
4277     EL_MAGIC_WALL_DEAD,
4278     EL_BD_MAGIC_WALL,
4279     EL_BD_MAGIC_WALL_DEAD,
4280     EL_DC_MAGIC_WALL,
4281     EL_DC_MAGIC_WALL_DEAD,
4282     EL_AMOEBA_TO_DIAMOND,
4283     EL_BLOCKED,
4284     EL_SP_EMPTY,
4285     EL_SP_BASE,
4286     EL_SP_PORT_RIGHT,
4287     EL_SP_PORT_DOWN,
4288     EL_SP_PORT_LEFT,
4289     EL_SP_PORT_UP,
4290     EL_SP_GRAVITY_PORT_RIGHT,
4291     EL_SP_GRAVITY_PORT_DOWN,
4292     EL_SP_GRAVITY_PORT_LEFT,
4293     EL_SP_GRAVITY_PORT_UP,
4294     EL_SP_PORT_HORIZONTAL,
4295     EL_SP_PORT_VERTICAL,
4296     EL_SP_PORT_ANY,
4297     EL_SP_DISK_RED,
4298 #if 0
4299     EL_SP_DISK_YELLOW,
4300 #endif
4301     EL_SP_CHIP_SINGLE,
4302     EL_SP_CHIP_LEFT,
4303     EL_SP_CHIP_RIGHT,
4304     EL_SP_CHIP_TOP,
4305     EL_SP_CHIP_BOTTOM,
4306     EL_SP_HARDWARE_GRAY,
4307     EL_SP_HARDWARE_GREEN,
4308     EL_SP_HARDWARE_BLUE,
4309     EL_SP_HARDWARE_RED,
4310     EL_SP_HARDWARE_YELLOW,
4311     EL_SP_HARDWARE_BASE_1,
4312     EL_SP_HARDWARE_BASE_2,
4313     EL_SP_HARDWARE_BASE_3,
4314     EL_SP_HARDWARE_BASE_4,
4315     EL_SP_HARDWARE_BASE_5,
4316     EL_SP_HARDWARE_BASE_6,
4317     EL_SP_GRAVITY_ON_PORT_LEFT,
4318     EL_SP_GRAVITY_ON_PORT_RIGHT,
4319     EL_SP_GRAVITY_ON_PORT_UP,
4320     EL_SP_GRAVITY_ON_PORT_DOWN,
4321     EL_SP_GRAVITY_OFF_PORT_LEFT,
4322     EL_SP_GRAVITY_OFF_PORT_RIGHT,
4323     EL_SP_GRAVITY_OFF_PORT_UP,
4324     EL_SP_GRAVITY_OFF_PORT_DOWN,
4325     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4326     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4327     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4328     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4329     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4330     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4331     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4332     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4333     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4334     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4335     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4336     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4337     EL_SIGN_EXCLAMATION,
4338     EL_SIGN_RADIOACTIVITY,
4339     EL_SIGN_STOP,
4340     EL_SIGN_WHEELCHAIR,
4341     EL_SIGN_PARKING,
4342     EL_SIGN_NO_ENTRY,
4343     EL_SIGN_UNUSED_1,
4344     EL_SIGN_GIVE_WAY,
4345     EL_SIGN_ENTRY_FORBIDDEN,
4346     EL_SIGN_EMERGENCY_EXIT,
4347     EL_SIGN_YIN_YANG,
4348     EL_SIGN_UNUSED_2,
4349     EL_SIGN_SPERMS,
4350     EL_SIGN_BULLET,
4351     EL_SIGN_HEART,
4352     EL_SIGN_CROSS,
4353     EL_SIGN_FRANKIE,
4354     EL_DC_STEELWALL_1_LEFT,
4355     EL_DC_STEELWALL_1_RIGHT,
4356     EL_DC_STEELWALL_1_TOP,
4357     EL_DC_STEELWALL_1_BOTTOM,
4358     EL_DC_STEELWALL_1_HORIZONTAL,
4359     EL_DC_STEELWALL_1_VERTICAL,
4360     EL_DC_STEELWALL_1_TOPLEFT,
4361     EL_DC_STEELWALL_1_TOPRIGHT,
4362     EL_DC_STEELWALL_1_BOTTOMLEFT,
4363     EL_DC_STEELWALL_1_BOTTOMRIGHT,
4364     EL_DC_STEELWALL_1_TOPLEFT_2,
4365     EL_DC_STEELWALL_1_TOPRIGHT_2,
4366     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4367     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4368     EL_DC_STEELWALL_2_LEFT,
4369     EL_DC_STEELWALL_2_RIGHT,
4370     EL_DC_STEELWALL_2_TOP,
4371     EL_DC_STEELWALL_2_BOTTOM,
4372     EL_DC_STEELWALL_2_HORIZONTAL,
4373     EL_DC_STEELWALL_2_VERTICAL,
4374     EL_DC_STEELWALL_2_MIDDLE,
4375     EL_DC_STEELWALL_2_SINGLE,
4376     EL_STEELWALL_SLIPPERY,
4377     EL_EMC_STEELWALL_1,
4378     EL_EMC_STEELWALL_2,
4379     EL_EMC_STEELWALL_3,
4380     EL_EMC_STEELWALL_4,
4381     EL_EMC_WALL_SLIPPERY_1,
4382     EL_EMC_WALL_SLIPPERY_2,
4383     EL_EMC_WALL_SLIPPERY_3,
4384     EL_EMC_WALL_SLIPPERY_4,
4385     EL_EMC_WALL_1,
4386     EL_EMC_WALL_2,
4387     EL_EMC_WALL_3,
4388     EL_EMC_WALL_4,
4389     EL_EMC_WALL_5,
4390     EL_EMC_WALL_6,
4391     EL_EMC_WALL_7,
4392     EL_EMC_WALL_8,
4393     EL_EMC_WALL_9,
4394     EL_EMC_WALL_10,
4395     EL_EMC_WALL_11,
4396     EL_EMC_WALL_12,
4397     EL_EMC_WALL_13,
4398     EL_EMC_WALL_14,
4399     EL_EMC_WALL_15,
4400     EL_EMC_WALL_16,
4401
4402     -1
4403   };
4404
4405   static int ep_em_slippery_wall[] =
4406   {
4407     -1
4408   };
4409
4410   static int ep_gfx_crumbled[] =
4411   {
4412     EL_SAND,
4413     EL_LANDMINE,
4414     EL_DC_LANDMINE,
4415     EL_TRAP,
4416     EL_TRAP_ACTIVE,
4417
4418     -1
4419   };
4420
4421   static int ep_editor_cascade_active[] =
4422   {
4423     EL_INTERNAL_CASCADE_BD_ACTIVE,
4424     EL_INTERNAL_CASCADE_EM_ACTIVE,
4425     EL_INTERNAL_CASCADE_EMC_ACTIVE,
4426     EL_INTERNAL_CASCADE_RND_ACTIVE,
4427     EL_INTERNAL_CASCADE_SB_ACTIVE,
4428     EL_INTERNAL_CASCADE_SP_ACTIVE,
4429     EL_INTERNAL_CASCADE_DC_ACTIVE,
4430     EL_INTERNAL_CASCADE_DX_ACTIVE,
4431     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4432     EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4433     EL_INTERNAL_CASCADE_CE_ACTIVE,
4434     EL_INTERNAL_CASCADE_GE_ACTIVE,
4435     EL_INTERNAL_CASCADE_REF_ACTIVE,
4436     EL_INTERNAL_CASCADE_USER_ACTIVE,
4437     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4438
4439     -1
4440   };
4441
4442   static int ep_editor_cascade_inactive[] =
4443   {
4444     EL_INTERNAL_CASCADE_BD,
4445     EL_INTERNAL_CASCADE_EM,
4446     EL_INTERNAL_CASCADE_EMC,
4447     EL_INTERNAL_CASCADE_RND,
4448     EL_INTERNAL_CASCADE_SB,
4449     EL_INTERNAL_CASCADE_SP,
4450     EL_INTERNAL_CASCADE_DC,
4451     EL_INTERNAL_CASCADE_DX,
4452     EL_INTERNAL_CASCADE_CHARS,
4453     EL_INTERNAL_CASCADE_STEEL_CHARS,
4454     EL_INTERNAL_CASCADE_CE,
4455     EL_INTERNAL_CASCADE_GE,
4456     EL_INTERNAL_CASCADE_REF,
4457     EL_INTERNAL_CASCADE_USER,
4458     EL_INTERNAL_CASCADE_DYNAMIC,
4459
4460     -1
4461   };
4462
4463   static int ep_obsolete[] =
4464   {
4465     EL_PLAYER_OBSOLETE,
4466     EL_KEY_OBSOLETE,
4467     EL_EM_KEY_1_FILE_OBSOLETE,
4468     EL_EM_KEY_2_FILE_OBSOLETE,
4469     EL_EM_KEY_3_FILE_OBSOLETE,
4470     EL_EM_KEY_4_FILE_OBSOLETE,
4471     EL_ENVELOPE_OBSOLETE,
4472
4473     -1
4474   };
4475
4476   static struct
4477   {
4478     int *elements;
4479     int property;
4480   } element_properties[] =
4481   {
4482     { ep_diggable,                      EP_DIGGABLE                     },
4483     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
4484     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
4485     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
4486     { ep_dont_touch,                    EP_DONT_TOUCH                   },
4487     { ep_indestructible,                EP_INDESTRUCTIBLE               },
4488     { ep_slippery,                      EP_SLIPPERY                     },
4489     { ep_can_change,                    EP_CAN_CHANGE                   },
4490     { ep_can_move,                      EP_CAN_MOVE                     },
4491     { ep_can_fall,                      EP_CAN_FALL                     },
4492     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
4493     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
4494     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
4495     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
4496     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
4497     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
4498     { ep_walkable_over,                 EP_WALKABLE_OVER                },
4499     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
4500     { ep_walkable_under,                EP_WALKABLE_UNDER               },
4501     { ep_passable_over,                 EP_PASSABLE_OVER                },
4502     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
4503     { ep_passable_under,                EP_PASSABLE_UNDER               },
4504     { ep_droppable,                     EP_DROPPABLE                    },
4505     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
4506     { ep_pushable,                      EP_PUSHABLE                     },
4507     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
4508     { ep_protected,                     EP_PROTECTED                    },
4509     { ep_throwable,                     EP_THROWABLE                    },
4510     { ep_can_explode,                   EP_CAN_EXPLODE                  },
4511     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
4512
4513     { ep_player,                        EP_PLAYER                       },
4514     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
4515     { ep_can_pass_dc_magic_wall,        EP_CAN_PASS_DC_MAGIC_WALL       },
4516     { ep_switchable,                    EP_SWITCHABLE                   },
4517     { ep_bd_element,                    EP_BD_ELEMENT                   },
4518     { ep_sp_element,                    EP_SP_ELEMENT                   },
4519     { ep_sb_element,                    EP_SB_ELEMENT                   },
4520     { ep_gem,                           EP_GEM                          },
4521     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
4522     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
4523     { ep_food_pig,                      EP_FOOD_PIG                     },
4524     { ep_historic_wall,                 EP_HISTORIC_WALL                },
4525     { ep_historic_solid,                EP_HISTORIC_SOLID               },
4526     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
4527     { ep_belt,                          EP_BELT                         },
4528     { ep_belt_active,                   EP_BELT_ACTIVE                  },
4529     { ep_belt_switch,                   EP_BELT_SWITCH                  },
4530     { ep_tube,                          EP_TUBE                         },
4531     { ep_acid_pool,                     EP_ACID_POOL                    },
4532     { ep_keygate,                       EP_KEYGATE                      },
4533     { ep_amoeboid,                      EP_AMOEBOID                     },
4534     { ep_amoebalive,                    EP_AMOEBALIVE                   },
4535     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
4536     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
4537     { ep_can_grow,                      EP_CAN_GROW                     },
4538     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
4539     { ep_inactive,                      EP_INACTIVE                     },
4540
4541     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
4542
4543     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
4544
4545     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
4546     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
4547
4548     { ep_obsolete,                      EP_OBSOLETE                     },
4549
4550     { NULL,                             -1                              }
4551   };
4552
4553   int i, j, k;
4554
4555   /* always start with reliable default values (element has no properties) */
4556   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4557     for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4558       SET_PROPERTY(i, j, FALSE);
4559
4560   /* set all base element properties from above array definitions */
4561   for (i = 0; element_properties[i].elements != NULL; i++)
4562     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4563       SET_PROPERTY((element_properties[i].elements)[j],
4564                    element_properties[i].property, TRUE);
4565
4566   /* copy properties to some elements that are only stored in level file */
4567   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4568     for (j = 0; copy_properties[j][0] != -1; j++)
4569       if (HAS_PROPERTY(copy_properties[j][0], i))
4570         for (k = 1; k <= 4; k++)
4571           SET_PROPERTY(copy_properties[j][k], i, TRUE);
4572
4573   /* set static element properties that are not listed in array definitions */
4574   for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4575     SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4576 }
4577
4578 void InitElementPropertiesEngine(int engine_version)
4579 {
4580   static int no_wall_properties[] =
4581   {
4582     EP_DIGGABLE,
4583     EP_COLLECTIBLE_ONLY,
4584     EP_DONT_RUN_INTO,
4585     EP_DONT_COLLIDE_WITH,
4586     EP_CAN_MOVE,
4587     EP_CAN_FALL,
4588     EP_CAN_SMASH_PLAYER,
4589     EP_CAN_SMASH_ENEMIES,
4590     EP_CAN_SMASH_EVERYTHING,
4591     EP_PUSHABLE,
4592
4593     EP_PLAYER,
4594     EP_GEM,
4595     EP_FOOD_DARK_YAMYAM,
4596     EP_FOOD_PENGUIN,
4597     EP_BELT,
4598     EP_BELT_ACTIVE,
4599     EP_TUBE,
4600     EP_AMOEBOID,
4601     EP_AMOEBALIVE,
4602     EP_ACTIVE_BOMB,
4603
4604     EP_ACCESSIBLE,
4605
4606     -1
4607   };
4608
4609   int i, j;
4610
4611   /* important: after initialization in InitElementPropertiesStatic(), the
4612      elements are not again initialized to a default value; therefore all
4613      changes have to make sure that they leave the element with a defined
4614      property (which means that conditional property changes must be set to
4615      a reliable default value before) */
4616
4617   /* resolve group elements */
4618   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4619     ResolveGroupElement(EL_GROUP_START + i);
4620
4621   /* set all special, combined or engine dependent element properties */
4622   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4623   {
4624     /* ---------- INACTIVE ------------------------------------------------- */
4625     SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4626                                    i <= EL_CHAR_END) ||
4627                                   (i >= EL_STEEL_CHAR_START &&
4628                                    i <= EL_STEEL_CHAR_END)));
4629
4630     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4631     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4632                                   IS_WALKABLE_INSIDE(i) ||
4633                                   IS_WALKABLE_UNDER(i)));
4634
4635     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4636                                   IS_PASSABLE_INSIDE(i) ||
4637                                   IS_PASSABLE_UNDER(i)));
4638
4639     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4640                                          IS_PASSABLE_OVER(i)));
4641
4642     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4643                                            IS_PASSABLE_INSIDE(i)));
4644
4645     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4646                                           IS_PASSABLE_UNDER(i)));
4647
4648     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4649                                     IS_PASSABLE(i)));
4650
4651     /* ---------- COLLECTIBLE ---------------------------------------------- */
4652     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4653                                      IS_DROPPABLE(i) ||
4654                                      IS_THROWABLE(i)));
4655
4656     /* ---------- SNAPPABLE ------------------------------------------------ */
4657     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4658                                    IS_COLLECTIBLE(i) ||
4659                                    IS_SWITCHABLE(i) ||
4660                                    i == EL_BD_ROCK));
4661
4662     /* ---------- WALL ----------------------------------------------------- */
4663     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
4664
4665     for (j = 0; no_wall_properties[j] != -1; j++)
4666       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4667           i >= EL_FIRST_RUNTIME_UNREAL)
4668         SET_PROPERTY(i, EP_WALL, FALSE);
4669
4670     if (IS_HISTORIC_WALL(i))
4671       SET_PROPERTY(i, EP_WALL, TRUE);
4672
4673     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4674     if (engine_version < VERSION_IDENT(2,2,0,0))
4675       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4676     else
4677       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4678                                              !IS_DIGGABLE(i) &&
4679                                              !IS_COLLECTIBLE(i)));
4680
4681     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4682     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4683       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4684     else
4685       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4686                                             IS_INDESTRUCTIBLE(i)));
4687
4688     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4689     if (i == EL_FLAMES)
4690       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4691     else if (engine_version < VERSION_IDENT(2,2,0,0))
4692       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4693     else
4694       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4695                                            (!IS_WALKABLE(i) ||
4696                                             IS_PROTECTED(i))));
4697
4698     if (IS_CUSTOM_ELEMENT(i))
4699     {
4700       /* these are additional properties which are initially false when set */
4701
4702       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4703       if (DONT_TOUCH(i))
4704         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4705       if (DONT_COLLIDE_WITH(i))
4706         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4707
4708       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4709       if (CAN_SMASH_EVERYTHING(i))
4710         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4711       if (CAN_SMASH_ENEMIES(i))
4712         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4713     }
4714
4715     /* ---------- CAN_SMASH ------------------------------------------------ */
4716     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4717                                    CAN_SMASH_ENEMIES(i) ||
4718                                    CAN_SMASH_EVERYTHING(i)));
4719
4720     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4721     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4722                                              EXPLODES_BY_FIRE(i)));
4723
4724     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4725     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4726                                              EXPLODES_SMASHED(i)));
4727
4728     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4729     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4730                                             EXPLODES_IMPACT(i)));
4731
4732     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4733     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4734
4735     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4736     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4737                                                   i == EL_BLACK_ORB));
4738
4739     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4740     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4741                                               CAN_MOVE(i) ||
4742                                               IS_CUSTOM_ELEMENT(i)));
4743
4744     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4745     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4746                                                  i == EL_SP_ELECTRON));
4747
4748     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4749     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4750       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4751                    getMoveIntoAcidProperty(&level, i));
4752
4753     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4754     if (MAYBE_DONT_COLLIDE_WITH(i))
4755       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4756                    getDontCollideWithProperty(&level, i));
4757
4758     /* ---------- SP_PORT -------------------------------------------------- */
4759     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4760                                  IS_PASSABLE_INSIDE(i)));
4761
4762     /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4763     for (j = 0; j < level.num_android_clone_elements; j++)
4764       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4765                    (i != EL_EMPTY &&
4766                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4767
4768     /* ---------- CAN_CHANGE ----------------------------------------------- */
4769     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
4770     for (j = 0; j < element_info[i].num_change_pages; j++)
4771       if (element_info[i].change_page[j].can_change)
4772         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4773
4774     /* ---------- HAS_ACTION ----------------------------------------------- */
4775     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      /* default: has no action */
4776     for (j = 0; j < element_info[i].num_change_pages; j++)
4777       if (element_info[i].change_page[j].has_action)
4778         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4779
4780     /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4781     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4782                                                   HAS_ACTION(i)));
4783
4784     /* ---------- GFX_CRUMBLED --------------------------------------------- */
4785 #if 1
4786     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4787                  element_info[i].crumbled[ACTION_DEFAULT] !=
4788                  element_info[i].graphic[ACTION_DEFAULT]);
4789 #else
4790     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4791     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4792                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4793 #endif
4794
4795     /* ---------- EDITOR_CASCADE ------------------------------------------- */
4796     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4797                                         IS_EDITOR_CASCADE_INACTIVE(i)));
4798   }
4799
4800   /* dynamically adjust element properties according to game engine version */
4801   {
4802     static int ep_em_slippery_wall[] =
4803     {
4804       EL_WALL,
4805       EL_STEELWALL,
4806       EL_EXPANDABLE_WALL,
4807       EL_EXPANDABLE_WALL_HORIZONTAL,
4808       EL_EXPANDABLE_WALL_VERTICAL,
4809       EL_EXPANDABLE_WALL_ANY,
4810       EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4811       EL_EXPANDABLE_STEELWALL_VERTICAL,
4812       EL_EXPANDABLE_STEELWALL_ANY,
4813       EL_EXPANDABLE_STEELWALL_GROWING,
4814       -1
4815     };
4816
4817     /* special EM style gems behaviour */
4818     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4819       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4820                    level.em_slippery_gems);
4821
4822     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4823     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4824                  (level.em_slippery_gems &&
4825                   engine_version > VERSION_IDENT(2,0,1,0)));
4826   }
4827
4828   /* this is needed because some graphics depend on element properties */
4829   if (game_status == GAME_MODE_PLAYING)
4830     InitElementGraphicInfo();
4831 }
4832
4833 void InitElementPropertiesAfterLoading(int engine_version)
4834 {
4835   int i;
4836
4837   /* set some other uninitialized values of custom elements in older levels */
4838   if (engine_version < VERSION_IDENT(3,1,0,0))
4839   {
4840     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4841     {
4842       int element = EL_CUSTOM_START + i;
4843
4844       element_info[element].access_direction = MV_ALL_DIRECTIONS;
4845
4846       element_info[element].explosion_delay = 17;
4847       element_info[element].ignition_delay = 8;
4848     }
4849   }
4850 }
4851
4852 static void InitGlobal()
4853 {
4854   int graphic;
4855   int i;
4856
4857   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4858   {
4859     /* check if element_name_info entry defined for each element in "main.h" */
4860     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4861       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4862
4863     element_info[i].token_name = element_name_info[i].token_name;
4864     element_info[i].class_name = element_name_info[i].class_name;
4865     element_info[i].editor_description= element_name_info[i].editor_description;
4866
4867 #if 0
4868     printf("%04d: %s\n", i, element_name_info[i].token_name);
4869 #endif
4870   }
4871
4872   /* create hash from image config list */
4873   image_config_hash = newSetupFileHash();
4874   for (i = 0; image_config[i].token != NULL; i++)
4875     setHashEntry(image_config_hash,
4876                  image_config[i].token,
4877                  image_config[i].value);
4878
4879   /* create hash from element token list */
4880   element_token_hash = newSetupFileHash();
4881   for (i = 0; element_name_info[i].token_name != NULL; i++)
4882     setHashEntry(element_token_hash,
4883                  element_name_info[i].token_name,
4884                  int2str(i, 0));
4885
4886   /* create hash from graphic token list */
4887   graphic_token_hash = newSetupFileHash();
4888   for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4889     if (strSuffix(image_config[i].value, ".pcx") ||
4890         strSuffix(image_config[i].value, ".wav") ||
4891         strEqual(image_config[i].value, UNDEFINED_FILENAME))
4892       setHashEntry(graphic_token_hash,
4893                    image_config[i].token,
4894                    int2str(graphic++, 0));
4895
4896   /* create hash from font token list */
4897   font_token_hash = newSetupFileHash();
4898   for (i = 0; font_info[i].token_name != NULL; i++)
4899     setHashEntry(font_token_hash,
4900                  font_info[i].token_name,
4901                  int2str(i, 0));
4902
4903   /* always start with reliable default values (all elements) */
4904   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4905     ActiveElement[i] = i;
4906
4907   /* now add all entries that have an active state (active elements) */
4908   for (i = 0; element_with_active_state[i].element != -1; i++)
4909   {
4910     int element = element_with_active_state[i].element;
4911     int element_active = element_with_active_state[i].element_active;
4912
4913     ActiveElement[element] = element_active;
4914   }
4915
4916   /* always start with reliable default values (all buttons) */
4917   for (i = 0; i < NUM_IMAGE_FILES; i++)
4918     ActiveButton[i] = i;
4919
4920   /* now add all entries that have an active state (active buttons) */
4921   for (i = 0; button_with_active_state[i].button != -1; i++)
4922   {
4923     int button = button_with_active_state[i].button;
4924     int button_active = button_with_active_state[i].button_active;
4925
4926     ActiveButton[button] = button_active;
4927   }
4928
4929   /* always start with reliable default values (all fonts) */
4930   for (i = 0; i < NUM_FONTS; i++)
4931     ActiveFont[i] = i;
4932
4933   /* now add all entries that have an active state (active fonts) */
4934   for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4935   {
4936     int font = font_with_active_state[i].font_nr;
4937     int font_active = font_with_active_state[i].font_nr_active;
4938
4939     ActiveFont[font] = font_active;
4940   }
4941
4942   global.autoplay_leveldir = NULL;
4943   global.convert_leveldir = NULL;
4944
4945   global.frames_per_second = 0;
4946   global.fps_slowdown = FALSE;
4947   global.fps_slowdown_factor = 1;
4948
4949   global.border_status = GAME_MODE_MAIN;
4950 #if 0
4951   global.fading_status = GAME_MODE_MAIN;
4952   global.fading_type = TYPE_ENTER_MENU;
4953 #endif
4954 }
4955
4956 void Execute_Command(char *command)
4957 {
4958   int i;
4959
4960   if (strEqual(command, "print graphicsinfo.conf"))
4961   {
4962     printf("# You can configure additional/alternative image files here.\n");
4963     printf("# (The entries below are default and therefore commented out.)\n");
4964     printf("\n");
4965     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4966     printf("\n");
4967     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4968     printf("\n");
4969
4970     for (i = 0; image_config[i].token != NULL; i++)
4971       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4972                                               image_config[i].value));
4973
4974     exit(0);
4975   }
4976   else if (strEqual(command, "print soundsinfo.conf"))
4977   {
4978     printf("# You can configure additional/alternative sound files here.\n");
4979     printf("# (The entries below are default and therefore commented out.)\n");
4980     printf("\n");
4981     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4982     printf("\n");
4983     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4984     printf("\n");
4985
4986     for (i = 0; sound_config[i].token != NULL; i++)
4987       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4988                                               sound_config[i].value));
4989
4990     exit(0);
4991   }
4992   else if (strEqual(command, "print musicinfo.conf"))
4993   {
4994     printf("# You can configure additional/alternative music files here.\n");
4995     printf("# (The entries below are default and therefore commented out.)\n");
4996     printf("\n");
4997     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4998     printf("\n");
4999     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5000     printf("\n");
5001
5002     for (i = 0; music_config[i].token != NULL; i++)
5003       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5004                                               music_config[i].value));
5005
5006     exit(0);
5007   }
5008   else if (strEqual(command, "print editorsetup.conf"))
5009   {
5010     printf("# You can configure your personal editor element list here.\n");
5011     printf("# (The entries below are default and therefore commented out.)\n");
5012     printf("\n");
5013
5014     /* this is needed to be able to check element list for cascade elements */
5015     InitElementPropertiesStatic();
5016     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5017
5018     PrintEditorElementList();
5019
5020     exit(0);
5021   }
5022   else if (strEqual(command, "print helpanim.conf"))
5023   {
5024     printf("# You can configure different element help animations here.\n");
5025     printf("# (The entries below are default and therefore commented out.)\n");
5026     printf("\n");
5027
5028     for (i = 0; helpanim_config[i].token != NULL; i++)
5029     {
5030       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5031                                               helpanim_config[i].value));
5032
5033       if (strEqual(helpanim_config[i].token, "end"))
5034         printf("#\n");
5035     }
5036
5037     exit(0);
5038   }
5039   else if (strEqual(command, "print helptext.conf"))
5040   {
5041     printf("# You can configure different element help text here.\n");
5042     printf("# (The entries below are default and therefore commented out.)\n");
5043     printf("\n");
5044
5045     for (i = 0; helptext_config[i].token != NULL; i++)
5046       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5047                                               helptext_config[i].value));
5048
5049     exit(0);
5050   }
5051   else if (strncmp(command, "dump level ", 11) == 0)
5052   {
5053     char *filename = &command[11];
5054
5055     if (!fileExists(filename))
5056       Error(ERR_EXIT, "cannot open file '%s'", filename);
5057
5058     LoadLevelFromFilename(&level, filename);
5059     DumpLevel(&level);
5060
5061     exit(0);
5062   }
5063   else if (strncmp(command, "dump tape ", 10) == 0)
5064   {
5065     char *filename = &command[10];
5066
5067     if (!fileExists(filename))
5068       Error(ERR_EXIT, "cannot open file '%s'", filename);
5069
5070     LoadTapeFromFilename(filename);
5071     DumpTape(&tape);
5072
5073     exit(0);
5074   }
5075   else if (strncmp(command, "autoplay ", 9) == 0)
5076   {
5077     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5078
5079     while (*str_ptr != '\0')                    /* continue parsing string */
5080     {
5081       /* cut leading whitespace from string, replace it by string terminator */
5082       while (*str_ptr == ' ' || *str_ptr == '\t')
5083         *str_ptr++ = '\0';
5084
5085       if (*str_ptr == '\0')                     /* end of string reached */
5086         break;
5087
5088       if (global.autoplay_leveldir == NULL)     /* read level set string */
5089       {
5090         global.autoplay_leveldir = str_ptr;
5091         global.autoplay_all = TRUE;             /* default: play all tapes */
5092
5093         for (i = 0; i < MAX_TAPES_PER_SET; i++)
5094           global.autoplay_level[i] = FALSE;
5095       }
5096       else                                      /* read level number string */
5097       {
5098         int level_nr = atoi(str_ptr);           /* get level_nr value */
5099
5100         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5101           global.autoplay_level[level_nr] = TRUE;
5102
5103         global.autoplay_all = FALSE;
5104       }
5105
5106       /* advance string pointer to the next whitespace (or end of string) */
5107       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5108         str_ptr++;
5109     }
5110   }
5111   else if (strncmp(command, "convert ", 8) == 0)
5112   {
5113     char *str_copy = getStringCopy(&command[8]);
5114     char *str_ptr = strchr(str_copy, ' ');
5115
5116     global.convert_leveldir = str_copy;
5117     global.convert_level_nr = -1;
5118
5119     if (str_ptr != NULL)                        /* level number follows */
5120     {
5121       *str_ptr++ = '\0';                        /* terminate leveldir string */
5122       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
5123     }
5124   }
5125
5126 #if DEBUG
5127 #if defined(TARGET_SDL)
5128   else if (strEqual(command, "SDL_ListModes"))
5129   {
5130     SDL_Rect **modes;
5131     int i;
5132
5133     SDL_Init(SDL_INIT_VIDEO);
5134
5135     /* get available fullscreen/hardware modes */
5136     modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5137
5138     /* check if there are any modes available */
5139     if (modes == NULL)
5140     {
5141       printf("No modes available!\n");
5142
5143       exit(-1);
5144     }
5145
5146     /* check if our resolution is restricted */
5147     if (modes == (SDL_Rect **)-1)
5148     {
5149       printf("All resolutions available.\n");
5150     }
5151     else
5152     {
5153       printf("Available Modes:\n");
5154
5155       for(i = 0; modes[i]; i++)
5156         printf("  %d x %d\n", modes[i]->w, modes[i]->h);
5157     }
5158
5159     exit(0);
5160   }
5161 #endif
5162 #endif
5163
5164   else
5165   {
5166     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5167   }
5168 }
5169
5170 static void InitSetup()
5171 {
5172   LoadSetup();                                  /* global setup info */
5173
5174   /* set some options from setup file */
5175
5176   if (setup.options.verbose)
5177     options.verbose = TRUE;
5178 }
5179
5180 static void InitGameInfo()
5181 {
5182   game.restart_level = FALSE;
5183 }
5184
5185 static void InitPlayerInfo()
5186 {
5187   int i;
5188
5189   /* choose default local player */
5190   local_player = &stored_player[0];
5191
5192   for (i = 0; i < MAX_PLAYERS; i++)
5193     stored_player[i].connected = FALSE;
5194
5195   local_player->connected = TRUE;
5196 }
5197
5198 static void InitArtworkInfo()
5199 {
5200   LoadArtworkInfo();
5201 }
5202
5203 static char *get_string_in_brackets(char *string)
5204 {
5205   char *string_in_brackets = checked_malloc(strlen(string) + 3);
5206
5207   sprintf(string_in_brackets, "[%s]", string);
5208
5209   return string_in_brackets;
5210 }
5211
5212 static char *get_level_id_suffix(int id_nr)
5213 {
5214   char *id_suffix = checked_malloc(1 + 3 + 1);
5215
5216   if (id_nr < 0 || id_nr > 999)
5217     id_nr = 0;
5218
5219   sprintf(id_suffix, ".%03d", id_nr);
5220
5221   return id_suffix;
5222 }
5223
5224 #if 0
5225 static char *get_element_class_token(int element)
5226 {
5227   char *element_class_name = element_info[element].class_name;
5228   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5229
5230   sprintf(element_class_token, "[%s]", element_class_name);
5231
5232   return element_class_token;
5233 }
5234
5235 static char *get_action_class_token(int action)
5236 {
5237   char *action_class_name = &element_action_info[action].suffix[1];
5238   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5239
5240   sprintf(action_class_token, "[%s]", action_class_name);
5241
5242   return action_class_token;
5243 }
5244 #endif
5245
5246 static void InitArtworkConfig()
5247 {
5248   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5249   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5250   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5251   static char *action_id_suffix[NUM_ACTIONS + 1];
5252   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5253   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5254   static char *level_id_suffix[MAX_LEVELS + 1];
5255   static char *dummy[1] = { NULL };
5256   static char *ignore_generic_tokens[] =
5257   {
5258     "name",
5259     "sort_priority",
5260     NULL
5261   };
5262   static char **ignore_image_tokens;
5263   static char **ignore_sound_tokens;
5264   static char **ignore_music_tokens;
5265   int num_ignore_generic_tokens;
5266   int num_ignore_image_tokens;
5267   int num_ignore_sound_tokens;
5268   int num_ignore_music_tokens;
5269   int i;
5270
5271   /* dynamically determine list of generic tokens to be ignored */
5272   num_ignore_generic_tokens = 0;
5273   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5274     num_ignore_generic_tokens++;
5275
5276   /* dynamically determine list of image tokens to be ignored */
5277   num_ignore_image_tokens = num_ignore_generic_tokens;
5278   for (i = 0; image_config_vars[i].token != NULL; i++)
5279     num_ignore_image_tokens++;
5280   ignore_image_tokens =
5281     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5282   for (i = 0; i < num_ignore_generic_tokens; i++)
5283     ignore_image_tokens[i] = ignore_generic_tokens[i];
5284   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5285     ignore_image_tokens[num_ignore_generic_tokens + i] =
5286       image_config_vars[i].token;
5287   ignore_image_tokens[num_ignore_image_tokens] = NULL;
5288
5289   /* dynamically determine list of sound tokens to be ignored */
5290   num_ignore_sound_tokens = num_ignore_generic_tokens;
5291   ignore_sound_tokens =
5292     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5293   for (i = 0; i < num_ignore_generic_tokens; i++)
5294     ignore_sound_tokens[i] = ignore_generic_tokens[i];
5295   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5296
5297   /* dynamically determine list of music tokens to be ignored */
5298   num_ignore_music_tokens = num_ignore_generic_tokens;
5299   ignore_music_tokens =
5300     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5301   for (i = 0; i < num_ignore_generic_tokens; i++)
5302     ignore_music_tokens[i] = ignore_generic_tokens[i];
5303   ignore_music_tokens[num_ignore_music_tokens] = NULL;
5304
5305   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5306     image_id_prefix[i] = element_info[i].token_name;
5307   for (i = 0; i < NUM_FONTS; i++)
5308     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5309   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5310
5311   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5312     sound_id_prefix[i] = element_info[i].token_name;
5313   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5314     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5315       get_string_in_brackets(element_info[i].class_name);
5316   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5317
5318   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5319     music_id_prefix[i] = music_prefix_info[i].prefix;
5320   music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5321
5322   for (i = 0; i < NUM_ACTIONS; i++)
5323     action_id_suffix[i] = element_action_info[i].suffix;
5324   action_id_suffix[NUM_ACTIONS] = NULL;
5325
5326   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5327     direction_id_suffix[i] = element_direction_info[i].suffix;
5328   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5329
5330   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5331     special_id_suffix[i] = special_suffix_info[i].suffix;
5332   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5333
5334   for (i = 0; i < MAX_LEVELS; i++)
5335     level_id_suffix[i] = get_level_id_suffix(i);
5336   level_id_suffix[MAX_LEVELS] = NULL;
5337
5338   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5339                 image_id_prefix, action_id_suffix, direction_id_suffix,
5340                 special_id_suffix, ignore_image_tokens);
5341   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5342                 sound_id_prefix, action_id_suffix, dummy,
5343                 special_id_suffix, ignore_sound_tokens);
5344   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5345                 music_id_prefix, special_id_suffix, level_id_suffix,
5346                 dummy, ignore_music_tokens);
5347 }
5348
5349 static void InitMixer()
5350 {
5351   OpenAudio();
5352   StartMixer();
5353 }
5354
5355 void InitGfx()
5356 {
5357   char *filename_font_initial = NULL;
5358   char *filename_anim_initial = NULL;
5359   Bitmap *bitmap_font_initial = NULL;
5360   int font_height;
5361   int i, j;
5362
5363   /* determine settings for initial font (for displaying startup messages) */
5364   for (i = 0; image_config[i].token != NULL; i++)
5365   {
5366     for (j = 0; j < NUM_INITIAL_FONTS; j++)
5367     {
5368       char font_token[128];
5369       int len_font_token;
5370
5371       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5372       len_font_token = strlen(font_token);
5373
5374       if (strEqual(image_config[i].token, font_token))
5375         filename_font_initial = image_config[i].value;
5376       else if (strlen(image_config[i].token) > len_font_token &&
5377                strncmp(image_config[i].token, font_token, len_font_token) == 0)
5378       {
5379         if (strEqual(&image_config[i].token[len_font_token], ".x"))
5380           font_initial[j].src_x = atoi(image_config[i].value);
5381         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5382           font_initial[j].src_y = atoi(image_config[i].value);
5383         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5384           font_initial[j].width = atoi(image_config[i].value);
5385         else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5386           font_initial[j].height = atoi(image_config[i].value);
5387       }
5388     }
5389   }
5390
5391   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5392   {
5393     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5394     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5395   }
5396
5397   if (filename_font_initial == NULL)    /* should not happen */
5398     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5399
5400   /* create additional image buffers for double-buffering and cross-fading */
5401   bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5402   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5403   bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5404   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5405
5406   /* initialize screen properties */
5407   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5408                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5409                    bitmap_db_field);
5410   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5411   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5412   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5413
5414   bitmap_font_initial = LoadCustomImage(filename_font_initial);
5415
5416   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5417     font_initial[j].bitmap = bitmap_font_initial;
5418
5419   InitFontGraphicInfo();
5420
5421   font_height = getFontHeight(FC_RED);
5422
5423 #if 1
5424   DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5425 #else
5426   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5427 #endif
5428   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5429   DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5430
5431   DrawInitText("Loading graphics", 120, FC_GREEN);
5432
5433 #if 1
5434 #if 1
5435   /* initialize busy animation with default values */
5436   int parameter[NUM_GFX_ARGS];
5437   for (i = 0; i < NUM_GFX_ARGS; i++)
5438     parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5439                                                image_config_suffix[i].token,
5440                                                image_config_suffix[i].type);
5441 #if 0
5442   for (i = 0; i < NUM_GFX_ARGS; i++)
5443     printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5444 #endif
5445 #endif
5446
5447   /* determine settings for busy animation (when displaying startup messages) */
5448   for (i = 0; image_config[i].token != NULL; i++)
5449   {
5450     char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5451     int len_anim_token = strlen(anim_token);
5452
5453     if (strEqual(image_config[i].token, anim_token))
5454       filename_anim_initial = image_config[i].value;
5455     else if (strlen(image_config[i].token) > len_anim_token &&
5456              strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5457     {
5458 #if 1
5459       for (j = 0; image_config_suffix[j].token != NULL; j++)
5460       {
5461         if (strEqual(&image_config[i].token[len_anim_token],
5462                      image_config_suffix[j].token))
5463           parameter[j] =
5464             get_graphic_parameter_value(image_config[i].value,
5465                                         image_config_suffix[j].token,
5466                                         image_config_suffix[j].type);
5467       }
5468 #else
5469       if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5470         anim_initial.src_x = atoi(image_config[i].value);
5471       else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5472         anim_initial.src_y = atoi(image_config[i].value);
5473       else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5474         anim_initial.width = atoi(image_config[i].value);
5475       else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5476         anim_initial.height = atoi(image_config[i].value);
5477       else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5478         anim_initial.anim_frames = atoi(image_config[i].value);
5479       else if (strEqual(&image_config[i].token[len_anim_token],
5480                         ".frames_per_line"))
5481         anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5482       else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5483         anim_initial.anim_delay = atoi(image_config[i].value);
5484 #endif
5485     }
5486   }
5487
5488   set_graphic_parameters_ext(0, &anim_initial, parameter, NULL);
5489
5490   if (filename_anim_initial == NULL)    /* should not happen */
5491     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5492
5493   anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5494
5495   init.busy.width  = anim_initial.width;
5496   init.busy.height = anim_initial.height;
5497
5498   InitMenuDesignSettings_Static();
5499   InitGfxDrawBusyAnimFunction(DrawInitAnim);
5500 #endif
5501 }
5502
5503 void RedrawBackground()
5504 {
5505   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5506              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5507
5508   redraw_mask = REDRAW_ALL;
5509 }
5510
5511 void InitGfxBackground()
5512 {
5513   int x, y;
5514
5515   fieldbuffer = bitmap_db_field;
5516   SetDrawtoField(DRAW_BACKBUFFER);
5517
5518 #if 1
5519   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5520 #else
5521   RedrawBackground();
5522
5523   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5524   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5525 #endif
5526
5527   for (x = 0; x < MAX_BUF_XSIZE; x++)
5528     for (y = 0; y < MAX_BUF_YSIZE; y++)
5529       redraw[x][y] = 0;
5530   redraw_tiles = 0;
5531   redraw_mask = REDRAW_ALL;
5532 }
5533
5534 static void InitLevelInfo()
5535 {
5536   LoadLevelInfo();                              /* global level info */
5537   LoadLevelSetup_LastSeries();                  /* last played series info */
5538   LoadLevelSetup_SeriesInfo();                  /* last played level info */
5539 }
5540
5541 void InitLevelArtworkInfo()
5542 {
5543   LoadLevelArtworkInfo();
5544 }
5545
5546 static void InitImages()
5547 {
5548   print_timestamp_init("InitImages");
5549
5550   setLevelArtworkDir(artwork.gfx_first);
5551
5552 #if 0
5553   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5554          leveldir_current->identifier,
5555          artwork.gfx_current_identifier,
5556          artwork.gfx_current->identifier,
5557          leveldir_current->graphics_set,
5558          leveldir_current->graphics_path);
5559 #endif
5560
5561   UPDATE_BUSY_STATE();
5562
5563   ReloadCustomImages();
5564   print_timestamp_time("ReloadCustomImages");
5565
5566   UPDATE_BUSY_STATE();
5567
5568   LoadCustomElementDescriptions();
5569   print_timestamp_time("LoadCustomElementDescriptions");
5570
5571   UPDATE_BUSY_STATE();
5572
5573   LoadMenuDesignSettings();
5574   print_timestamp_time("LoadMenuDesignSettings");
5575
5576   UPDATE_BUSY_STATE();
5577
5578   ReinitializeGraphics();
5579   print_timestamp_time("ReinitializeGraphics");
5580
5581   UPDATE_BUSY_STATE();
5582
5583   print_timestamp_done("InitImages");
5584 }
5585
5586 static void InitSound(char *identifier)
5587 {
5588   print_timestamp_init("InitSound");
5589
5590   if (identifier == NULL)
5591     identifier = artwork.snd_current->identifier;
5592
5593   /* set artwork path to send it to the sound server process */
5594   setLevelArtworkDir(artwork.snd_first);
5595
5596   InitReloadCustomSounds(identifier);
5597   print_timestamp_time("InitReloadCustomSounds");
5598
5599   ReinitializeSounds();
5600   print_timestamp_time("ReinitializeSounds");
5601
5602   print_timestamp_done("InitSound");
5603 }
5604
5605 static void InitMusic(char *identifier)
5606 {
5607   print_timestamp_init("InitMusic");
5608
5609   if (identifier == NULL)
5610     identifier = artwork.mus_current->identifier;
5611
5612   /* set artwork path to send it to the sound server process */
5613   setLevelArtworkDir(artwork.mus_first);
5614
5615   InitReloadCustomMusic(identifier);
5616   print_timestamp_time("InitReloadCustomMusic");
5617
5618   ReinitializeMusic();
5619   print_timestamp_time("ReinitializeMusic");
5620
5621   print_timestamp_done("InitMusic");
5622 }
5623
5624 void InitNetworkServer()
5625 {
5626 #if defined(NETWORK_AVALIABLE)
5627   int nr_wanted;
5628 #endif
5629
5630   if (!options.network)
5631     return;
5632
5633 #if defined(NETWORK_AVALIABLE)
5634   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5635
5636   if (!ConnectToServer(options.server_host, options.server_port))
5637     Error(ERR_EXIT, "cannot connect to network game server");
5638
5639   SendToServer_PlayerName(setup.player_name);
5640   SendToServer_ProtocolVersion();
5641
5642   if (nr_wanted)
5643     SendToServer_NrWanted(nr_wanted);
5644 #endif
5645 }
5646
5647 static char *getNewArtworkIdentifier(int type)
5648 {
5649   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5650   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5651   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5652   static boolean initialized[3] = { FALSE, FALSE, FALSE };
5653   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5654   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5655   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5656   char *leveldir_identifier = leveldir_current->identifier;
5657 #if 1
5658   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5659   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5660 #else
5661   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5662 #endif
5663   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5664   char *artwork_current_identifier;
5665   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
5666
5667   /* leveldir_current may be invalid (level group, parent link) */
5668   if (!validLevelSeries(leveldir_current))
5669     return NULL;
5670
5671   /* 1st step: determine artwork set to be activated in descending order:
5672      --------------------------------------------------------------------
5673      1. setup artwork (when configured to override everything else)
5674      2. artwork set configured in "levelinfo.conf" of current level set
5675         (artwork in level directory will have priority when loading later)
5676      3. artwork in level directory (stored in artwork sub-directory)
5677      4. setup artwork (currently configured in setup menu) */
5678
5679   if (setup_override_artwork)
5680     artwork_current_identifier = setup_artwork_set;
5681   else if (leveldir_artwork_set != NULL)
5682     artwork_current_identifier = leveldir_artwork_set;
5683   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5684     artwork_current_identifier = leveldir_identifier;
5685   else
5686     artwork_current_identifier = setup_artwork_set;
5687
5688
5689   /* 2nd step: check if it is really needed to reload artwork set
5690      ------------------------------------------------------------ */
5691
5692 #if 0
5693   if (type == ARTWORK_TYPE_GRAPHICS)
5694     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5695            artwork_new_identifier,
5696            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5697            artwork_current_identifier,
5698            leveldir_current->graphics_set,
5699            leveldir_current->identifier);
5700 #endif
5701
5702   /* ---------- reload if level set and also artwork set has changed ------- */
5703   if (leveldir_current_identifier[type] != leveldir_identifier &&
5704       (last_has_level_artwork_set[type] || has_level_artwork_set))
5705     artwork_new_identifier = artwork_current_identifier;
5706
5707   leveldir_current_identifier[type] = leveldir_identifier;
5708   last_has_level_artwork_set[type] = has_level_artwork_set;
5709
5710 #if 0
5711   if (type == ARTWORK_TYPE_GRAPHICS)
5712     printf("::: 1: '%s'\n", artwork_new_identifier);
5713 #endif
5714
5715   /* ---------- reload if "override artwork" setting has changed ----------- */
5716   if (last_override_level_artwork[type] != setup_override_artwork)
5717     artwork_new_identifier = artwork_current_identifier;
5718
5719   last_override_level_artwork[type] = setup_override_artwork;
5720
5721 #if 0
5722   if (type == ARTWORK_TYPE_GRAPHICS)
5723     printf("::: 2: '%s'\n", artwork_new_identifier);
5724 #endif
5725
5726   /* ---------- reload if current artwork identifier has changed ----------- */
5727   if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5728                 artwork_current_identifier))
5729     artwork_new_identifier = artwork_current_identifier;
5730
5731   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5732
5733 #if 0
5734   if (type == ARTWORK_TYPE_GRAPHICS)
5735     printf("::: 3: '%s'\n", artwork_new_identifier);
5736 #endif
5737
5738   /* ---------- do not reload directly after starting ---------------------- */
5739   if (!initialized[type])
5740     artwork_new_identifier = NULL;
5741
5742   initialized[type] = TRUE;
5743
5744 #if 0
5745   if (type == ARTWORK_TYPE_GRAPHICS)
5746     printf("::: 4: '%s'\n", artwork_new_identifier);
5747 #endif
5748
5749 #if 0
5750   if (type == ARTWORK_TYPE_GRAPHICS)
5751     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5752            artwork.gfx_current_identifier, artwork_current_identifier,
5753            artwork.gfx_current->identifier, leveldir_current->graphics_set,
5754            artwork_new_identifier);
5755 #endif
5756
5757   return artwork_new_identifier;
5758 }
5759
5760 void ReloadCustomArtwork(int force_reload)
5761 {
5762   int last_game_status = game_status;   /* save current game status */
5763   char *gfx_new_identifier;
5764   char *snd_new_identifier;
5765   char *mus_new_identifier;
5766   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5767   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5768   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5769   boolean reload_needed;
5770
5771   force_reload_gfx |= AdjustGraphicsForEMC();
5772
5773   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5774   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5775   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5776
5777   reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5778                    snd_new_identifier != NULL || force_reload_snd ||
5779                    mus_new_identifier != NULL || force_reload_mus);
5780
5781   if (!reload_needed)
5782     return;
5783
5784   print_timestamp_init("ReloadCustomArtwork");
5785
5786   game_status = GAME_MODE_LOADING;
5787
5788   FadeOut(REDRAW_ALL);
5789
5790 #if 1
5791   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5792 #else
5793   ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5794 #endif
5795   print_timestamp_time("ClearRectangle");
5796
5797 #if 0
5798   printf("::: fading in ... %d\n", fading.fade_mode);
5799 #endif
5800   FadeIn(REDRAW_ALL);
5801 #if 0
5802   printf("::: done\n");
5803 #endif
5804
5805   if (gfx_new_identifier != NULL || force_reload_gfx)
5806   {
5807 #if 0
5808     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5809            artwork.gfx_current_identifier,
5810            gfx_new_identifier,
5811            artwork.gfx_current->identifier,
5812            leveldir_current->graphics_set);
5813 #endif
5814
5815     InitImages();
5816     print_timestamp_time("InitImages");
5817   }
5818
5819   if (snd_new_identifier != NULL || force_reload_snd)
5820   {
5821     InitSound(snd_new_identifier);
5822     print_timestamp_time("InitSound");
5823   }
5824
5825   if (mus_new_identifier != NULL || force_reload_mus)
5826   {
5827     InitMusic(mus_new_identifier);
5828     print_timestamp_time("InitMusic");
5829   }
5830
5831   game_status = last_game_status;       /* restore current game status */
5832
5833 #if 0
5834   printf("::: FadeOut @ ReloadCustomArtwork ...\n");
5835 #endif
5836   FadeOut(REDRAW_ALL);
5837 #if 0
5838   printf("::: FadeOut @ ReloadCustomArtwork done\n");
5839 #endif
5840
5841   RedrawBackground();
5842
5843   /* force redraw of (open or closed) door graphics */
5844   SetDoorState(DOOR_OPEN_ALL);
5845   CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5846
5847 #if 1
5848 #if 1
5849   FadeSetEnterScreen();
5850   FadeSkipNextFadeOut();
5851   // FadeSetDisabled();
5852 #else
5853   FadeSkipNext();
5854 #endif
5855 #else
5856   fading = fading_none;
5857 #endif
5858
5859   print_timestamp_done("ReloadCustomArtwork");
5860 }
5861
5862 void KeyboardAutoRepeatOffUnlessAutoplay()
5863 {
5864   if (global.autoplay_leveldir == NULL)
5865     KeyboardAutoRepeatOff();
5866 }
5867
5868
5869 /* ========================================================================= */
5870 /* OpenAll()                                                                 */
5871 /* ========================================================================= */
5872
5873 void OpenAll()
5874 {
5875   print_timestamp_init("OpenAll");
5876
5877   game_status = GAME_MODE_LOADING;
5878
5879   InitGlobal();                 /* initialize some global variables */
5880
5881   if (options.execute_command)
5882     Execute_Command(options.execute_command);
5883
5884   if (options.serveronly)
5885   {
5886 #if defined(PLATFORM_UNIX)
5887     NetworkServer(options.server_port, options.serveronly);
5888 #else
5889     Error(ERR_WARN, "networking only supported in Unix version");
5890 #endif
5891
5892     exit(0);                    /* never reached, server loops forever */
5893   }
5894
5895   InitSetup();
5896
5897   InitGameInfo();
5898   InitPlayerInfo();
5899   InitArtworkInfo();            /* needed before loading gfx, sound & music */
5900   InitArtworkConfig();          /* needed before forking sound child process */
5901   InitMixer();
5902
5903   InitCounter();
5904
5905   InitRND(NEW_RANDOMIZE);
5906   InitSimpleRandom(NEW_RANDOMIZE);
5907
5908   InitJoysticks();
5909
5910   print_timestamp_time("[pre-video]");
5911
5912   InitVideoDisplay();
5913   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5914
5915   InitEventFilter(FilterMouseMotionEvents);
5916
5917   InitElementPropertiesStatic();
5918   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5919
5920   print_timestamp_time("[post-video]");
5921
5922   InitGfx();
5923
5924   print_timestamp_time("InitGfx");
5925
5926   InitLevelInfo();
5927   print_timestamp_time("InitLevelInfo");
5928
5929   InitLevelArtworkInfo();
5930   print_timestamp_time("InitLevelArtworkInfo");
5931
5932   InitImages();                 /* needs to know current level directory */
5933   print_timestamp_time("InitImages");
5934
5935   InitSound(NULL);              /* needs to know current level directory */
5936   print_timestamp_time("InitSound");
5937
5938   InitMusic(NULL);              /* needs to know current level directory */
5939   print_timestamp_time("InitMusic");
5940
5941   InitGfxBackground();
5942
5943 #if 1
5944   em_open_all();
5945 #endif
5946
5947   if (global.autoplay_leveldir)
5948   {
5949     AutoPlayTape();
5950     return;
5951   }
5952   else if (global.convert_leveldir)
5953   {
5954     ConvertLevels();
5955     return;
5956   }
5957
5958   game_status = GAME_MODE_MAIN;
5959
5960 #if 1
5961   FadeSetEnterScreen();
5962   if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5963     FadeSkipNextFadeOut();
5964   // FadeSetDisabled();
5965 #else
5966   fading = fading_none;
5967 #endif
5968
5969   print_timestamp_time("[post-artwork]");
5970
5971   print_timestamp_done("OpenAll");
5972
5973   DrawMainMenu();
5974
5975   InitNetworkServer();
5976 }
5977
5978 void CloseAllAndExit(int exit_value)
5979 {
5980   StopSounds();
5981   FreeAllSounds();
5982   FreeAllMusic();
5983   CloseAudio();         /* called after freeing sounds (needed for SDL) */
5984
5985 #if 1
5986   em_close_all();
5987 #endif
5988
5989   FreeAllImages();
5990
5991 #if defined(TARGET_SDL)
5992   if (network_server)   /* terminate network server */
5993     SDL_KillThread(server_thread);
5994 #endif
5995
5996   CloseVideoDisplay();
5997   ClosePlatformDependentStuff();
5998
5999   if (exit_value != 0)
6000     NotifyUserAboutErrorFile();
6001
6002   exit(exit_value);
6003 }