rnd-20070901-3-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 boolean clipboard_elements_initialized = FALSE;
2609
2610   static int ep_diggable[] =
2611   {
2612     EL_SAND,
2613     EL_SP_BASE,
2614     EL_SP_BUGGY_BASE,
2615     EL_SP_BUGGY_BASE_ACTIVATING,
2616     EL_TRAP,
2617     EL_INVISIBLE_SAND,
2618     EL_INVISIBLE_SAND_ACTIVE,
2619     EL_EMC_GRASS,
2620
2621     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2622     /* (if amoeba can grow into anything diggable, maybe keep these out) */
2623 #if 0
2624     EL_LANDMINE,
2625     EL_DC_LANDMINE,
2626     EL_TRAP_ACTIVE,
2627     EL_SP_BUGGY_BASE_ACTIVE,
2628     EL_EMC_PLANT,
2629 #endif
2630
2631     -1
2632   };
2633
2634   static int ep_collectible_only[] =
2635   {
2636     EL_BD_DIAMOND,
2637     EL_EMERALD,
2638     EL_DIAMOND,
2639     EL_EMERALD_YELLOW,
2640     EL_EMERALD_RED,
2641     EL_EMERALD_PURPLE,
2642     EL_KEY_1,
2643     EL_KEY_2,
2644     EL_KEY_3,
2645     EL_KEY_4,
2646     EL_EM_KEY_1,
2647     EL_EM_KEY_2,
2648     EL_EM_KEY_3,
2649     EL_EM_KEY_4,
2650     EL_EMC_KEY_5,
2651     EL_EMC_KEY_6,
2652     EL_EMC_KEY_7,
2653     EL_EMC_KEY_8,
2654     EL_DYNAMITE,
2655     EL_EM_DYNAMITE,
2656     EL_DYNABOMB_INCREASE_NUMBER,
2657     EL_DYNABOMB_INCREASE_SIZE,
2658     EL_DYNABOMB_INCREASE_POWER,
2659     EL_SP_INFOTRON,
2660     EL_SP_DISK_RED,
2661     EL_PEARL,
2662     EL_CRYSTAL,
2663     EL_DC_KEY_WHITE,
2664     EL_SHIELD_NORMAL,
2665     EL_SHIELD_DEADLY,
2666     EL_EXTRA_TIME,
2667     EL_ENVELOPE_1,
2668     EL_ENVELOPE_2,
2669     EL_ENVELOPE_3,
2670     EL_ENVELOPE_4,
2671     EL_SPEED_PILL,
2672     EL_EMC_LENSES,
2673     EL_EMC_MAGNIFIER,
2674
2675 #if 0
2676     /* !!! handle separately !!! */
2677     EL_DC_LANDMINE,     /* deadly when running into, but can be snapped */
2678 #endif
2679
2680     -1
2681   };
2682
2683   static int ep_dont_run_into[] =
2684   {
2685     /* same elements as in 'ep_dont_touch' */
2686     EL_BUG,
2687     EL_SPACESHIP,
2688     EL_BD_BUTTERFLY,
2689     EL_BD_FIREFLY,
2690
2691     /* same elements as in 'ep_dont_collide_with' */
2692     EL_YAMYAM,
2693     EL_DARK_YAMYAM,
2694     EL_ROBOT,
2695     EL_PACMAN,
2696     EL_SP_SNIKSNAK,
2697     EL_SP_ELECTRON,
2698
2699     /* new elements */
2700     EL_AMOEBA_DROP,
2701     EL_ACID,
2702
2703     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2704 #if 1
2705     EL_LANDMINE,
2706     EL_DC_LANDMINE,
2707     EL_TRAP_ACTIVE,
2708     EL_SP_BUGGY_BASE_ACTIVE,
2709     EL_EMC_PLANT,
2710 #endif
2711
2712     -1
2713   };
2714
2715   static int ep_dont_collide_with[] =
2716   {
2717     /* same elements as in 'ep_dont_touch' */
2718     EL_BUG,
2719     EL_SPACESHIP,
2720     EL_BD_BUTTERFLY,
2721     EL_BD_FIREFLY,
2722
2723     /* new elements */
2724     EL_YAMYAM,
2725     EL_DARK_YAMYAM,
2726     EL_ROBOT,
2727     EL_PACMAN,
2728     EL_SP_SNIKSNAK,
2729     EL_SP_ELECTRON,
2730
2731     -1
2732   };
2733
2734   static int ep_dont_touch[] =
2735   {
2736     EL_BUG,
2737     EL_SPACESHIP,
2738     EL_BD_BUTTERFLY,
2739     EL_BD_FIREFLY,
2740
2741     -1
2742   };
2743
2744   static int ep_indestructible[] =
2745   {
2746     EL_STEELWALL,
2747     EL_ACID,
2748     EL_ACID_POOL_TOPLEFT,
2749     EL_ACID_POOL_TOPRIGHT,
2750     EL_ACID_POOL_BOTTOMLEFT,
2751     EL_ACID_POOL_BOTTOM,
2752     EL_ACID_POOL_BOTTOMRIGHT,
2753     EL_SP_HARDWARE_GRAY,
2754     EL_SP_HARDWARE_GREEN,
2755     EL_SP_HARDWARE_BLUE,
2756     EL_SP_HARDWARE_RED,
2757     EL_SP_HARDWARE_YELLOW,
2758     EL_SP_HARDWARE_BASE_1,
2759     EL_SP_HARDWARE_BASE_2,
2760     EL_SP_HARDWARE_BASE_3,
2761     EL_SP_HARDWARE_BASE_4,
2762     EL_SP_HARDWARE_BASE_5,
2763     EL_SP_HARDWARE_BASE_6,
2764     EL_INVISIBLE_STEELWALL,
2765     EL_INVISIBLE_STEELWALL_ACTIVE,
2766     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2767     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2768     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2769     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2770     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2771     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2772     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2773     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2774     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2775     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2776     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2777     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2778     EL_LIGHT_SWITCH,
2779     EL_LIGHT_SWITCH_ACTIVE,
2780     EL_SIGN_EXCLAMATION,
2781     EL_SIGN_RADIOACTIVITY,
2782     EL_SIGN_STOP,
2783     EL_SIGN_WHEELCHAIR,
2784     EL_SIGN_PARKING,
2785     EL_SIGN_NO_ENTRY,
2786     EL_SIGN_UNUSED_1,
2787     EL_SIGN_GIVE_WAY,
2788     EL_SIGN_ENTRY_FORBIDDEN,
2789     EL_SIGN_EMERGENCY_EXIT,
2790     EL_SIGN_YIN_YANG,
2791     EL_SIGN_UNUSED_2,
2792     EL_SIGN_SPERMS,
2793     EL_SIGN_BULLET,
2794     EL_SIGN_HEART,
2795     EL_SIGN_CROSS,
2796     EL_SIGN_FRANKIE,
2797     EL_STEEL_EXIT_CLOSED,
2798     EL_STEEL_EXIT_OPEN,
2799     EL_EM_STEEL_EXIT_CLOSED,
2800     EL_EM_STEEL_EXIT_OPEN,
2801     EL_DC_STEELWALL_1_LEFT,
2802     EL_DC_STEELWALL_1_RIGHT,
2803     EL_DC_STEELWALL_1_TOP,
2804     EL_DC_STEELWALL_1_BOTTOM,
2805     EL_DC_STEELWALL_1_HORIZONTAL,
2806     EL_DC_STEELWALL_1_VERTICAL,
2807     EL_DC_STEELWALL_1_TOPLEFT,
2808     EL_DC_STEELWALL_1_TOPRIGHT,
2809     EL_DC_STEELWALL_1_BOTTOMLEFT,
2810     EL_DC_STEELWALL_1_BOTTOMRIGHT,
2811     EL_DC_STEELWALL_1_TOPLEFT_2,
2812     EL_DC_STEELWALL_1_TOPRIGHT_2,
2813     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2814     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2815     EL_DC_STEELWALL_2_LEFT,
2816     EL_DC_STEELWALL_2_RIGHT,
2817     EL_DC_STEELWALL_2_TOP,
2818     EL_DC_STEELWALL_2_BOTTOM,
2819     EL_DC_STEELWALL_2_HORIZONTAL,
2820     EL_DC_STEELWALL_2_VERTICAL,
2821     EL_DC_STEELWALL_2_MIDDLE,
2822     EL_DC_STEELWALL_2_SINGLE,
2823     EL_STEELWALL_SLIPPERY,
2824     EL_EMC_STEELWALL_1,
2825     EL_EMC_STEELWALL_2,
2826     EL_EMC_STEELWALL_3,
2827     EL_EMC_STEELWALL_4,
2828     EL_CRYSTAL,
2829     EL_GATE_1,
2830     EL_GATE_2,
2831     EL_GATE_3,
2832     EL_GATE_4,
2833     EL_GATE_1_GRAY,
2834     EL_GATE_2_GRAY,
2835     EL_GATE_3_GRAY,
2836     EL_GATE_4_GRAY,
2837     EL_GATE_1_GRAY_ACTIVE,
2838     EL_GATE_2_GRAY_ACTIVE,
2839     EL_GATE_3_GRAY_ACTIVE,
2840     EL_GATE_4_GRAY_ACTIVE,
2841     EL_EM_GATE_1,
2842     EL_EM_GATE_2,
2843     EL_EM_GATE_3,
2844     EL_EM_GATE_4,
2845     EL_EM_GATE_1_GRAY,
2846     EL_EM_GATE_2_GRAY,
2847     EL_EM_GATE_3_GRAY,
2848     EL_EM_GATE_4_GRAY,
2849     EL_EM_GATE_1_GRAY_ACTIVE,
2850     EL_EM_GATE_2_GRAY_ACTIVE,
2851     EL_EM_GATE_3_GRAY_ACTIVE,
2852     EL_EM_GATE_4_GRAY_ACTIVE,
2853     EL_EMC_GATE_5,
2854     EL_EMC_GATE_6,
2855     EL_EMC_GATE_7,
2856     EL_EMC_GATE_8,
2857     EL_EMC_GATE_5_GRAY,
2858     EL_EMC_GATE_6_GRAY,
2859     EL_EMC_GATE_7_GRAY,
2860     EL_EMC_GATE_8_GRAY,
2861     EL_EMC_GATE_5_GRAY_ACTIVE,
2862     EL_EMC_GATE_6_GRAY_ACTIVE,
2863     EL_EMC_GATE_7_GRAY_ACTIVE,
2864     EL_EMC_GATE_8_GRAY_ACTIVE,
2865     EL_DC_GATE_WHITE,
2866     EL_DC_GATE_WHITE_GRAY,
2867     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2868     EL_DC_GATE_FAKE_GRAY,
2869     EL_SWITCHGATE_OPEN,
2870     EL_SWITCHGATE_OPENING,
2871     EL_SWITCHGATE_CLOSED,
2872     EL_SWITCHGATE_CLOSING,
2873 #if 1
2874     EL_DC_SWITCHGATE_SWITCH_UP,
2875     EL_DC_SWITCHGATE_SWITCH_DOWN,
2876 #endif
2877     EL_TIMEGATE_OPEN,
2878     EL_TIMEGATE_OPENING,
2879     EL_TIMEGATE_CLOSED,
2880     EL_TIMEGATE_CLOSING,
2881 #if 1
2882     EL_DC_TIMEGATE_SWITCH,
2883     EL_DC_TIMEGATE_SWITCH_ACTIVE,
2884 #endif
2885     EL_TUBE_ANY,
2886     EL_TUBE_VERTICAL,
2887     EL_TUBE_HORIZONTAL,
2888     EL_TUBE_VERTICAL_LEFT,
2889     EL_TUBE_VERTICAL_RIGHT,
2890     EL_TUBE_HORIZONTAL_UP,
2891     EL_TUBE_HORIZONTAL_DOWN,
2892     EL_TUBE_LEFT_UP,
2893     EL_TUBE_LEFT_DOWN,
2894     EL_TUBE_RIGHT_UP,
2895     EL_TUBE_RIGHT_DOWN,
2896     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2897     EL_EXPANDABLE_STEELWALL_VERTICAL,
2898     EL_EXPANDABLE_STEELWALL_ANY,
2899
2900     -1
2901   };
2902
2903   static int ep_slippery[] =
2904   {
2905     EL_WALL_SLIPPERY,
2906     EL_BD_WALL,
2907     EL_ROCK,
2908     EL_BD_ROCK,
2909     EL_EMERALD,
2910     EL_BD_DIAMOND,
2911     EL_EMERALD_YELLOW,
2912     EL_EMERALD_RED,
2913     EL_EMERALD_PURPLE,
2914     EL_DIAMOND,
2915     EL_BOMB,
2916     EL_NUT,
2917     EL_ROBOT_WHEEL_ACTIVE,
2918     EL_ROBOT_WHEEL,
2919     EL_TIME_ORB_FULL,
2920     EL_TIME_ORB_EMPTY,
2921     EL_LAMP_ACTIVE,
2922     EL_LAMP,
2923     EL_ACID_POOL_TOPLEFT,
2924     EL_ACID_POOL_TOPRIGHT,
2925     EL_SATELLITE,
2926     EL_SP_ZONK,
2927     EL_SP_INFOTRON,
2928     EL_SP_CHIP_SINGLE,
2929     EL_SP_CHIP_LEFT,
2930     EL_SP_CHIP_RIGHT,
2931     EL_SP_CHIP_TOP,
2932     EL_SP_CHIP_BOTTOM,
2933     EL_SPEED_PILL,
2934     EL_STEELWALL_SLIPPERY,
2935     EL_PEARL,
2936     EL_CRYSTAL,
2937     EL_EMC_WALL_SLIPPERY_1,
2938     EL_EMC_WALL_SLIPPERY_2,
2939     EL_EMC_WALL_SLIPPERY_3,
2940     EL_EMC_WALL_SLIPPERY_4,
2941     EL_EMC_MAGIC_BALL,
2942     EL_EMC_MAGIC_BALL_ACTIVE,
2943
2944     -1
2945   };
2946
2947   static int ep_can_change[] =
2948   {
2949     -1
2950   };
2951
2952   static int ep_can_move[] =
2953   {
2954     /* same elements as in 'pb_can_move_into_acid' */
2955     EL_BUG,
2956     EL_SPACESHIP,
2957     EL_BD_BUTTERFLY,
2958     EL_BD_FIREFLY,
2959     EL_YAMYAM,
2960     EL_DARK_YAMYAM,
2961     EL_ROBOT,
2962     EL_PACMAN,
2963     EL_MOLE,
2964     EL_PENGUIN,
2965     EL_PIG,
2966     EL_DRAGON,
2967     EL_SATELLITE,
2968     EL_SP_SNIKSNAK,
2969     EL_SP_ELECTRON,
2970     EL_BALLOON,
2971     EL_SPRING,
2972     EL_EMC_ANDROID,
2973
2974     -1
2975   };
2976
2977   static int ep_can_fall[] =
2978   {
2979     EL_ROCK,
2980     EL_BD_ROCK,
2981     EL_EMERALD,
2982     EL_BD_DIAMOND,
2983     EL_EMERALD_YELLOW,
2984     EL_EMERALD_RED,
2985     EL_EMERALD_PURPLE,
2986     EL_DIAMOND,
2987     EL_BOMB,
2988     EL_NUT,
2989     EL_AMOEBA_DROP,
2990     EL_QUICKSAND_FULL,
2991     EL_QUICKSAND_FAST_FULL,
2992     EL_MAGIC_WALL_FULL,
2993     EL_BD_MAGIC_WALL_FULL,
2994     EL_DC_MAGIC_WALL_FULL,
2995     EL_TIME_ORB_FULL,
2996     EL_TIME_ORB_EMPTY,
2997     EL_SP_ZONK,
2998     EL_SP_INFOTRON,
2999     EL_SP_DISK_ORANGE,
3000     EL_PEARL,
3001     EL_CRYSTAL,
3002     EL_SPRING,
3003     EL_DX_SUPABOMB,
3004
3005     -1
3006   };
3007
3008   static int ep_can_smash_player[] =
3009   {
3010     EL_ROCK,
3011     EL_BD_ROCK,
3012     EL_EMERALD,
3013     EL_BD_DIAMOND,
3014     EL_EMERALD_YELLOW,
3015     EL_EMERALD_RED,
3016     EL_EMERALD_PURPLE,
3017     EL_DIAMOND,
3018     EL_BOMB,
3019     EL_NUT,
3020     EL_AMOEBA_DROP,
3021     EL_TIME_ORB_FULL,
3022     EL_TIME_ORB_EMPTY,
3023     EL_SP_ZONK,
3024     EL_SP_INFOTRON,
3025     EL_SP_DISK_ORANGE,
3026     EL_PEARL,
3027     EL_CRYSTAL,
3028     EL_SPRING,
3029     EL_DX_SUPABOMB,
3030
3031     -1
3032   };
3033
3034   static int ep_can_smash_enemies[] =
3035   {
3036     EL_ROCK,
3037     EL_BD_ROCK,
3038     EL_SP_ZONK,
3039
3040     -1
3041   };
3042
3043   static int ep_can_smash_everything[] =
3044   {
3045     EL_ROCK,
3046     EL_BD_ROCK,
3047     EL_SP_ZONK,
3048
3049     -1
3050   };
3051
3052   static int ep_explodes_by_fire[] =
3053   {
3054     /* same elements as in 'ep_explodes_impact' */
3055     EL_BOMB,
3056     EL_SP_DISK_ORANGE,
3057     EL_DX_SUPABOMB,
3058
3059     /* same elements as in 'ep_explodes_smashed' */
3060     EL_SATELLITE,
3061     EL_PIG,
3062     EL_DRAGON,
3063     EL_MOLE,
3064
3065     /* new elements */
3066     EL_DYNAMITE,
3067     EL_DYNAMITE_ACTIVE,
3068     EL_EM_DYNAMITE,
3069     EL_EM_DYNAMITE_ACTIVE,
3070     EL_DYNABOMB_PLAYER_1_ACTIVE,
3071     EL_DYNABOMB_PLAYER_2_ACTIVE,
3072     EL_DYNABOMB_PLAYER_3_ACTIVE,
3073     EL_DYNABOMB_PLAYER_4_ACTIVE,
3074     EL_DYNABOMB_INCREASE_NUMBER,
3075     EL_DYNABOMB_INCREASE_SIZE,
3076     EL_DYNABOMB_INCREASE_POWER,
3077     EL_SP_DISK_RED_ACTIVE,
3078     EL_BUG,
3079     EL_PENGUIN,
3080     EL_SP_DISK_RED,
3081     EL_SP_DISK_YELLOW,
3082     EL_SP_SNIKSNAK,
3083     EL_SP_ELECTRON,
3084 #if 0
3085     EL_BLACK_ORB,
3086 #endif
3087
3088     -1
3089   };
3090
3091   static int ep_explodes_smashed[] =
3092   {
3093     /* same elements as in 'ep_explodes_impact' */
3094     EL_BOMB,
3095     EL_SP_DISK_ORANGE,
3096     EL_DX_SUPABOMB,
3097
3098     /* new elements */
3099     EL_SATELLITE,
3100     EL_PIG,
3101     EL_DRAGON,
3102     EL_MOLE,
3103
3104     -1
3105   };
3106
3107   static int ep_explodes_impact[] =
3108   {
3109     EL_BOMB,
3110     EL_SP_DISK_ORANGE,
3111     EL_DX_SUPABOMB,
3112
3113     -1
3114   };
3115
3116   static int ep_walkable_over[] =
3117   {
3118     EL_EMPTY_SPACE,
3119     EL_SP_EMPTY_SPACE,
3120     EL_SOKOBAN_FIELD_EMPTY,
3121     EL_EXIT_OPEN,
3122     EL_EM_EXIT_OPEN,
3123     EL_SP_EXIT_OPEN,
3124     EL_SP_EXIT_OPENING,
3125     EL_STEEL_EXIT_OPEN,
3126     EL_EM_STEEL_EXIT_OPEN,
3127     EL_GATE_1,
3128     EL_GATE_2,
3129     EL_GATE_3,
3130     EL_GATE_4,
3131     EL_GATE_1_GRAY,
3132     EL_GATE_2_GRAY,
3133     EL_GATE_3_GRAY,
3134     EL_GATE_4_GRAY,
3135     EL_GATE_1_GRAY_ACTIVE,
3136     EL_GATE_2_GRAY_ACTIVE,
3137     EL_GATE_3_GRAY_ACTIVE,
3138     EL_GATE_4_GRAY_ACTIVE,
3139     EL_PENGUIN,
3140     EL_PIG,
3141     EL_DRAGON,
3142
3143     -1
3144   };
3145
3146   static int ep_walkable_inside[] =
3147   {
3148     EL_TUBE_ANY,
3149     EL_TUBE_VERTICAL,
3150     EL_TUBE_HORIZONTAL,
3151     EL_TUBE_VERTICAL_LEFT,
3152     EL_TUBE_VERTICAL_RIGHT,
3153     EL_TUBE_HORIZONTAL_UP,
3154     EL_TUBE_HORIZONTAL_DOWN,
3155     EL_TUBE_LEFT_UP,
3156     EL_TUBE_LEFT_DOWN,
3157     EL_TUBE_RIGHT_UP,
3158     EL_TUBE_RIGHT_DOWN,
3159
3160     -1
3161   };
3162
3163   static int ep_walkable_under[] =
3164   {
3165     -1
3166   };
3167
3168   static int ep_passable_over[] =
3169   {
3170     EL_EM_GATE_1,
3171     EL_EM_GATE_2,
3172     EL_EM_GATE_3,
3173     EL_EM_GATE_4,
3174     EL_EM_GATE_1_GRAY,
3175     EL_EM_GATE_2_GRAY,
3176     EL_EM_GATE_3_GRAY,
3177     EL_EM_GATE_4_GRAY,
3178     EL_EM_GATE_1_GRAY_ACTIVE,
3179     EL_EM_GATE_2_GRAY_ACTIVE,
3180     EL_EM_GATE_3_GRAY_ACTIVE,
3181     EL_EM_GATE_4_GRAY_ACTIVE,
3182     EL_EMC_GATE_5,
3183     EL_EMC_GATE_6,
3184     EL_EMC_GATE_7,
3185     EL_EMC_GATE_8,
3186     EL_EMC_GATE_5_GRAY,
3187     EL_EMC_GATE_6_GRAY,
3188     EL_EMC_GATE_7_GRAY,
3189     EL_EMC_GATE_8_GRAY,
3190     EL_EMC_GATE_5_GRAY_ACTIVE,
3191     EL_EMC_GATE_6_GRAY_ACTIVE,
3192     EL_EMC_GATE_7_GRAY_ACTIVE,
3193     EL_EMC_GATE_8_GRAY_ACTIVE,
3194     EL_DC_GATE_WHITE,
3195     EL_DC_GATE_WHITE_GRAY,
3196     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3197     EL_SWITCHGATE_OPEN,
3198     EL_TIMEGATE_OPEN,
3199
3200     -1
3201   };
3202
3203   static int ep_passable_inside[] =
3204   {
3205     EL_SP_PORT_LEFT,
3206     EL_SP_PORT_RIGHT,
3207     EL_SP_PORT_UP,
3208     EL_SP_PORT_DOWN,
3209     EL_SP_PORT_HORIZONTAL,
3210     EL_SP_PORT_VERTICAL,
3211     EL_SP_PORT_ANY,
3212     EL_SP_GRAVITY_PORT_LEFT,
3213     EL_SP_GRAVITY_PORT_RIGHT,
3214     EL_SP_GRAVITY_PORT_UP,
3215     EL_SP_GRAVITY_PORT_DOWN,
3216     EL_SP_GRAVITY_ON_PORT_LEFT,
3217     EL_SP_GRAVITY_ON_PORT_RIGHT,
3218     EL_SP_GRAVITY_ON_PORT_UP,
3219     EL_SP_GRAVITY_ON_PORT_DOWN,
3220     EL_SP_GRAVITY_OFF_PORT_LEFT,
3221     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3222     EL_SP_GRAVITY_OFF_PORT_UP,
3223     EL_SP_GRAVITY_OFF_PORT_DOWN,
3224
3225     -1
3226   };
3227
3228   static int ep_passable_under[] =
3229   {
3230     -1
3231   };
3232
3233   static int ep_droppable[] =
3234   {
3235     -1
3236   };
3237
3238   static int ep_explodes_1x1_old[] =
3239   {
3240     -1
3241   };
3242
3243   static int ep_pushable[] =
3244   {
3245     EL_ROCK,
3246     EL_BOMB,
3247     EL_DX_SUPABOMB,
3248     EL_NUT,
3249     EL_TIME_ORB_EMPTY,
3250     EL_SP_ZONK,
3251     EL_SP_DISK_ORANGE,
3252     EL_SPRING,
3253     EL_BD_ROCK,
3254     EL_SOKOBAN_OBJECT,
3255     EL_SOKOBAN_FIELD_FULL,
3256     EL_SATELLITE,
3257     EL_SP_DISK_YELLOW,
3258     EL_BALLOON,
3259     EL_EMC_ANDROID,
3260
3261     -1
3262   };
3263
3264   static int ep_explodes_cross_old[] =
3265   {
3266     -1
3267   };
3268
3269   static int ep_protected[] =
3270   {
3271     /* same elements as in 'ep_walkable_inside' */
3272     EL_TUBE_ANY,
3273     EL_TUBE_VERTICAL,
3274     EL_TUBE_HORIZONTAL,
3275     EL_TUBE_VERTICAL_LEFT,
3276     EL_TUBE_VERTICAL_RIGHT,
3277     EL_TUBE_HORIZONTAL_UP,
3278     EL_TUBE_HORIZONTAL_DOWN,
3279     EL_TUBE_LEFT_UP,
3280     EL_TUBE_LEFT_DOWN,
3281     EL_TUBE_RIGHT_UP,
3282     EL_TUBE_RIGHT_DOWN,
3283
3284     /* same elements as in 'ep_passable_over' */
3285     EL_EM_GATE_1,
3286     EL_EM_GATE_2,
3287     EL_EM_GATE_3,
3288     EL_EM_GATE_4,
3289     EL_EM_GATE_1_GRAY,
3290     EL_EM_GATE_2_GRAY,
3291     EL_EM_GATE_3_GRAY,
3292     EL_EM_GATE_4_GRAY,
3293     EL_EM_GATE_1_GRAY_ACTIVE,
3294     EL_EM_GATE_2_GRAY_ACTIVE,
3295     EL_EM_GATE_3_GRAY_ACTIVE,
3296     EL_EM_GATE_4_GRAY_ACTIVE,
3297     EL_EMC_GATE_5,
3298     EL_EMC_GATE_6,
3299     EL_EMC_GATE_7,
3300     EL_EMC_GATE_8,
3301     EL_EMC_GATE_5_GRAY,
3302     EL_EMC_GATE_6_GRAY,
3303     EL_EMC_GATE_7_GRAY,
3304     EL_EMC_GATE_8_GRAY,
3305     EL_EMC_GATE_5_GRAY_ACTIVE,
3306     EL_EMC_GATE_6_GRAY_ACTIVE,
3307     EL_EMC_GATE_7_GRAY_ACTIVE,
3308     EL_EMC_GATE_8_GRAY_ACTIVE,
3309     EL_DC_GATE_WHITE,
3310     EL_DC_GATE_WHITE_GRAY,
3311     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3312     EL_SWITCHGATE_OPEN,
3313     EL_TIMEGATE_OPEN,
3314
3315     /* same elements as in 'ep_passable_inside' */
3316     EL_SP_PORT_LEFT,
3317     EL_SP_PORT_RIGHT,
3318     EL_SP_PORT_UP,
3319     EL_SP_PORT_DOWN,
3320     EL_SP_PORT_HORIZONTAL,
3321     EL_SP_PORT_VERTICAL,
3322     EL_SP_PORT_ANY,
3323     EL_SP_GRAVITY_PORT_LEFT,
3324     EL_SP_GRAVITY_PORT_RIGHT,
3325     EL_SP_GRAVITY_PORT_UP,
3326     EL_SP_GRAVITY_PORT_DOWN,
3327     EL_SP_GRAVITY_ON_PORT_LEFT,
3328     EL_SP_GRAVITY_ON_PORT_RIGHT,
3329     EL_SP_GRAVITY_ON_PORT_UP,
3330     EL_SP_GRAVITY_ON_PORT_DOWN,
3331     EL_SP_GRAVITY_OFF_PORT_LEFT,
3332     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3333     EL_SP_GRAVITY_OFF_PORT_UP,
3334     EL_SP_GRAVITY_OFF_PORT_DOWN,
3335
3336     -1
3337   };
3338
3339   static int ep_throwable[] =
3340   {
3341     -1
3342   };
3343
3344   static int ep_can_explode[] =
3345   {
3346     /* same elements as in 'ep_explodes_impact' */
3347     EL_BOMB,
3348     EL_SP_DISK_ORANGE,
3349     EL_DX_SUPABOMB,
3350
3351     /* same elements as in 'ep_explodes_smashed' */
3352     EL_SATELLITE,
3353     EL_PIG,
3354     EL_DRAGON,
3355     EL_MOLE,
3356
3357     /* elements that can explode by explosion or by dragonfire */
3358     EL_DYNAMITE,
3359     EL_DYNAMITE_ACTIVE,
3360     EL_EM_DYNAMITE,
3361     EL_EM_DYNAMITE_ACTIVE,
3362     EL_DYNABOMB_PLAYER_1_ACTIVE,
3363     EL_DYNABOMB_PLAYER_2_ACTIVE,
3364     EL_DYNABOMB_PLAYER_3_ACTIVE,
3365     EL_DYNABOMB_PLAYER_4_ACTIVE,
3366     EL_DYNABOMB_INCREASE_NUMBER,
3367     EL_DYNABOMB_INCREASE_SIZE,
3368     EL_DYNABOMB_INCREASE_POWER,
3369     EL_SP_DISK_RED_ACTIVE,
3370     EL_BUG,
3371     EL_PENGUIN,
3372     EL_SP_DISK_RED,
3373     EL_SP_DISK_YELLOW,
3374     EL_SP_SNIKSNAK,
3375     EL_SP_ELECTRON,
3376
3377     /* elements that can explode only by explosion */
3378     EL_BLACK_ORB,
3379
3380     -1
3381   };
3382
3383   static int ep_gravity_reachable[] =
3384   {
3385     EL_SAND,
3386     EL_SP_BASE,
3387     EL_TRAP,
3388     EL_INVISIBLE_SAND,
3389     EL_INVISIBLE_SAND_ACTIVE,
3390     EL_SP_PORT_LEFT,
3391     EL_SP_PORT_RIGHT,
3392     EL_SP_PORT_UP,
3393     EL_SP_PORT_DOWN,
3394     EL_SP_PORT_HORIZONTAL,
3395     EL_SP_PORT_VERTICAL,
3396     EL_SP_PORT_ANY,
3397     EL_SP_GRAVITY_PORT_LEFT,
3398     EL_SP_GRAVITY_PORT_RIGHT,
3399     EL_SP_GRAVITY_PORT_UP,
3400     EL_SP_GRAVITY_PORT_DOWN,
3401     EL_SP_GRAVITY_ON_PORT_LEFT,
3402     EL_SP_GRAVITY_ON_PORT_RIGHT,
3403     EL_SP_GRAVITY_ON_PORT_UP,
3404     EL_SP_GRAVITY_ON_PORT_DOWN,
3405     EL_SP_GRAVITY_OFF_PORT_LEFT,
3406     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3407     EL_SP_GRAVITY_OFF_PORT_UP,
3408     EL_SP_GRAVITY_OFF_PORT_DOWN,
3409     EL_EMC_GRASS,
3410
3411     -1
3412   };
3413
3414   static int ep_player[] =
3415   {
3416     EL_PLAYER_1,
3417     EL_PLAYER_2,
3418     EL_PLAYER_3,
3419     EL_PLAYER_4,
3420     EL_SP_MURPHY,
3421     EL_SOKOBAN_FIELD_PLAYER,
3422     EL_TRIGGER_PLAYER,
3423
3424     -1
3425   };
3426
3427   static int ep_can_pass_magic_wall[] =
3428   {
3429     EL_ROCK,
3430     EL_BD_ROCK,
3431     EL_EMERALD,
3432     EL_BD_DIAMOND,
3433     EL_EMERALD_YELLOW,
3434     EL_EMERALD_RED,
3435     EL_EMERALD_PURPLE,
3436     EL_DIAMOND,
3437
3438     -1
3439   };
3440
3441   static int ep_can_pass_dc_magic_wall[] =
3442   {
3443     EL_ROCK,
3444     EL_BD_ROCK,
3445     EL_EMERALD,
3446     EL_BD_DIAMOND,
3447     EL_EMERALD_YELLOW,
3448     EL_EMERALD_RED,
3449     EL_EMERALD_PURPLE,
3450     EL_DIAMOND,
3451     EL_PEARL,
3452     EL_CRYSTAL,
3453
3454     -1
3455   };
3456
3457   static int ep_switchable[] =
3458   {
3459     EL_ROBOT_WHEEL,
3460     EL_SP_TERMINAL,
3461     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3462     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3463     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3464     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3465     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3466     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3467     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3468     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3469     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3470     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3471     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3472     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3473     EL_SWITCHGATE_SWITCH_UP,
3474     EL_SWITCHGATE_SWITCH_DOWN,
3475     EL_DC_SWITCHGATE_SWITCH_UP,
3476     EL_DC_SWITCHGATE_SWITCH_DOWN,
3477     EL_LIGHT_SWITCH,
3478     EL_LIGHT_SWITCH_ACTIVE,
3479     EL_TIMEGATE_SWITCH,
3480     EL_DC_TIMEGATE_SWITCH,
3481     EL_BALLOON_SWITCH_LEFT,
3482     EL_BALLOON_SWITCH_RIGHT,
3483     EL_BALLOON_SWITCH_UP,
3484     EL_BALLOON_SWITCH_DOWN,
3485     EL_BALLOON_SWITCH_ANY,
3486     EL_BALLOON_SWITCH_NONE,
3487     EL_LAMP,
3488     EL_TIME_ORB_FULL,
3489     EL_EMC_MAGIC_BALL_SWITCH,
3490     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3491
3492     -1
3493   };
3494
3495   static int ep_bd_element[] =
3496   {
3497     EL_EMPTY,
3498     EL_SAND,
3499     EL_WALL_SLIPPERY,
3500     EL_BD_WALL,
3501     EL_ROCK,
3502     EL_BD_ROCK,
3503     EL_BD_DIAMOND,
3504     EL_BD_MAGIC_WALL,
3505     EL_EXIT_CLOSED,
3506     EL_EXIT_OPEN,
3507     EL_STEELWALL,
3508     EL_PLAYER_1,
3509     EL_PLAYER_2,
3510     EL_PLAYER_3,
3511     EL_PLAYER_4,
3512     EL_BD_FIREFLY,
3513     EL_BD_FIREFLY_1,
3514     EL_BD_FIREFLY_2,
3515     EL_BD_FIREFLY_3,
3516     EL_BD_FIREFLY_4,
3517     EL_BD_BUTTERFLY,
3518     EL_BD_BUTTERFLY_1,
3519     EL_BD_BUTTERFLY_2,
3520     EL_BD_BUTTERFLY_3,
3521     EL_BD_BUTTERFLY_4,
3522     EL_BD_AMOEBA,
3523     EL_CHAR_QUESTION,
3524     EL_UNKNOWN,
3525
3526     -1
3527   };
3528
3529   static int ep_sp_element[] =
3530   {
3531     /* should always be valid */
3532     EL_EMPTY,
3533
3534     /* standard classic Supaplex elements */
3535     EL_SP_EMPTY,
3536     EL_SP_ZONK,
3537     EL_SP_BASE,
3538     EL_SP_MURPHY,
3539     EL_SP_INFOTRON,
3540     EL_SP_CHIP_SINGLE,
3541     EL_SP_HARDWARE_GRAY,
3542     EL_SP_EXIT_CLOSED,
3543     EL_SP_EXIT_OPEN,
3544     EL_SP_DISK_ORANGE,
3545     EL_SP_PORT_RIGHT,
3546     EL_SP_PORT_DOWN,
3547     EL_SP_PORT_LEFT,
3548     EL_SP_PORT_UP,
3549     EL_SP_GRAVITY_PORT_RIGHT,
3550     EL_SP_GRAVITY_PORT_DOWN,
3551     EL_SP_GRAVITY_PORT_LEFT,
3552     EL_SP_GRAVITY_PORT_UP,
3553     EL_SP_SNIKSNAK,
3554     EL_SP_DISK_YELLOW,
3555     EL_SP_TERMINAL,
3556     EL_SP_DISK_RED,
3557     EL_SP_PORT_VERTICAL,
3558     EL_SP_PORT_HORIZONTAL,
3559     EL_SP_PORT_ANY,
3560     EL_SP_ELECTRON,
3561     EL_SP_BUGGY_BASE,
3562     EL_SP_CHIP_LEFT,
3563     EL_SP_CHIP_RIGHT,
3564     EL_SP_HARDWARE_BASE_1,
3565     EL_SP_HARDWARE_GREEN,
3566     EL_SP_HARDWARE_BLUE,
3567     EL_SP_HARDWARE_RED,
3568     EL_SP_HARDWARE_YELLOW,
3569     EL_SP_HARDWARE_BASE_2,
3570     EL_SP_HARDWARE_BASE_3,
3571     EL_SP_HARDWARE_BASE_4,
3572     EL_SP_HARDWARE_BASE_5,
3573     EL_SP_HARDWARE_BASE_6,
3574     EL_SP_CHIP_TOP,
3575     EL_SP_CHIP_BOTTOM,
3576
3577     /* additional elements that appeared in newer Supaplex levels */
3578     EL_INVISIBLE_WALL,
3579
3580     /* additional gravity port elements (not switching, but setting gravity) */
3581     EL_SP_GRAVITY_ON_PORT_LEFT,
3582     EL_SP_GRAVITY_ON_PORT_RIGHT,
3583     EL_SP_GRAVITY_ON_PORT_UP,
3584     EL_SP_GRAVITY_ON_PORT_DOWN,
3585     EL_SP_GRAVITY_OFF_PORT_LEFT,
3586     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3587     EL_SP_GRAVITY_OFF_PORT_UP,
3588     EL_SP_GRAVITY_OFF_PORT_DOWN,
3589
3590     /* more than one Murphy in a level results in an inactive clone */
3591     EL_SP_MURPHY_CLONE,
3592
3593     /* runtime Supaplex elements */
3594     EL_SP_DISK_RED_ACTIVE,
3595     EL_SP_TERMINAL_ACTIVE,
3596     EL_SP_BUGGY_BASE_ACTIVATING,
3597     EL_SP_BUGGY_BASE_ACTIVE,
3598     EL_SP_EXIT_OPENING,
3599     EL_SP_EXIT_CLOSING,
3600
3601     -1
3602   };
3603
3604   static int ep_sb_element[] =
3605   {
3606     EL_EMPTY,
3607     EL_STEELWALL,
3608     EL_SOKOBAN_OBJECT,
3609     EL_SOKOBAN_FIELD_EMPTY,
3610     EL_SOKOBAN_FIELD_FULL,
3611     EL_SOKOBAN_FIELD_PLAYER,
3612     EL_PLAYER_1,
3613     EL_PLAYER_2,
3614     EL_PLAYER_3,
3615     EL_PLAYER_4,
3616     EL_INVISIBLE_STEELWALL,
3617
3618     -1
3619   };
3620
3621   static int ep_gem[] =
3622   {
3623     EL_BD_DIAMOND,
3624     EL_EMERALD,
3625     EL_EMERALD_YELLOW,
3626     EL_EMERALD_RED,
3627     EL_EMERALD_PURPLE,
3628     EL_DIAMOND,
3629
3630     -1
3631   };
3632
3633   static int ep_food_dark_yamyam[] =
3634   {
3635     EL_SAND,
3636     EL_BUG,
3637     EL_SPACESHIP,
3638     EL_BD_BUTTERFLY,
3639     EL_BD_FIREFLY,
3640     EL_YAMYAM,
3641     EL_ROBOT,
3642     EL_PACMAN,
3643     EL_AMOEBA_DROP,
3644     EL_AMOEBA_DEAD,
3645     EL_AMOEBA_WET,
3646     EL_AMOEBA_DRY,
3647     EL_AMOEBA_FULL,
3648     EL_BD_AMOEBA,
3649     EL_EMERALD,
3650     EL_BD_DIAMOND,
3651     EL_EMERALD_YELLOW,
3652     EL_EMERALD_RED,
3653     EL_EMERALD_PURPLE,
3654     EL_DIAMOND,
3655     EL_PEARL,
3656     EL_CRYSTAL,
3657
3658     -1
3659   };
3660
3661   static int ep_food_penguin[] =
3662   {
3663     EL_EMERALD,
3664     EL_BD_DIAMOND,
3665     EL_EMERALD_YELLOW,
3666     EL_EMERALD_RED,
3667     EL_EMERALD_PURPLE,
3668     EL_DIAMOND,
3669     EL_PEARL,
3670     EL_CRYSTAL,
3671
3672     -1
3673   };
3674
3675   static int ep_food_pig[] =
3676   {
3677     EL_EMERALD,
3678     EL_BD_DIAMOND,
3679     EL_EMERALD_YELLOW,
3680     EL_EMERALD_RED,
3681     EL_EMERALD_PURPLE,
3682     EL_DIAMOND,
3683
3684     -1
3685   };
3686
3687   static int ep_historic_wall[] =
3688   {
3689     EL_STEELWALL,
3690     EL_GATE_1,
3691     EL_GATE_2,
3692     EL_GATE_3,
3693     EL_GATE_4,
3694     EL_GATE_1_GRAY,
3695     EL_GATE_2_GRAY,
3696     EL_GATE_3_GRAY,
3697     EL_GATE_4_GRAY,
3698     EL_GATE_1_GRAY_ACTIVE,
3699     EL_GATE_2_GRAY_ACTIVE,
3700     EL_GATE_3_GRAY_ACTIVE,
3701     EL_GATE_4_GRAY_ACTIVE,
3702     EL_EM_GATE_1,
3703     EL_EM_GATE_2,
3704     EL_EM_GATE_3,
3705     EL_EM_GATE_4,
3706     EL_EM_GATE_1_GRAY,
3707     EL_EM_GATE_2_GRAY,
3708     EL_EM_GATE_3_GRAY,
3709     EL_EM_GATE_4_GRAY,
3710     EL_EM_GATE_1_GRAY_ACTIVE,
3711     EL_EM_GATE_2_GRAY_ACTIVE,
3712     EL_EM_GATE_3_GRAY_ACTIVE,
3713     EL_EM_GATE_4_GRAY_ACTIVE,
3714     EL_EXIT_CLOSED,
3715     EL_EXIT_OPENING,
3716     EL_EXIT_OPEN,
3717     EL_WALL,
3718     EL_WALL_SLIPPERY,
3719     EL_EXPANDABLE_WALL,
3720     EL_EXPANDABLE_WALL_HORIZONTAL,
3721     EL_EXPANDABLE_WALL_VERTICAL,
3722     EL_EXPANDABLE_WALL_ANY,
3723     EL_EXPANDABLE_WALL_GROWING,
3724     EL_BD_EXPANDABLE_WALL,
3725     EL_BD_WALL,
3726     EL_SP_CHIP_SINGLE,
3727     EL_SP_CHIP_LEFT,
3728     EL_SP_CHIP_RIGHT,
3729     EL_SP_CHIP_TOP,
3730     EL_SP_CHIP_BOTTOM,
3731     EL_SP_HARDWARE_GRAY,
3732     EL_SP_HARDWARE_GREEN,
3733     EL_SP_HARDWARE_BLUE,
3734     EL_SP_HARDWARE_RED,
3735     EL_SP_HARDWARE_YELLOW,
3736     EL_SP_HARDWARE_BASE_1,
3737     EL_SP_HARDWARE_BASE_2,
3738     EL_SP_HARDWARE_BASE_3,
3739     EL_SP_HARDWARE_BASE_4,
3740     EL_SP_HARDWARE_BASE_5,
3741     EL_SP_HARDWARE_BASE_6,
3742     EL_SP_TERMINAL,
3743     EL_SP_TERMINAL_ACTIVE,
3744     EL_SP_EXIT_CLOSED,
3745     EL_SP_EXIT_OPEN,
3746     EL_INVISIBLE_STEELWALL,
3747     EL_INVISIBLE_STEELWALL_ACTIVE,
3748     EL_INVISIBLE_WALL,
3749     EL_INVISIBLE_WALL_ACTIVE,
3750     EL_STEELWALL_SLIPPERY,
3751     EL_EMC_STEELWALL_1,
3752     EL_EMC_STEELWALL_2,
3753     EL_EMC_STEELWALL_3,
3754     EL_EMC_STEELWALL_4,
3755     EL_EMC_WALL_1,
3756     EL_EMC_WALL_2,
3757     EL_EMC_WALL_3,
3758     EL_EMC_WALL_4,
3759     EL_EMC_WALL_5,
3760     EL_EMC_WALL_6,
3761     EL_EMC_WALL_7,
3762     EL_EMC_WALL_8,
3763
3764     -1
3765   };
3766
3767   static int ep_historic_solid[] =
3768   {
3769     EL_WALL,
3770     EL_EXPANDABLE_WALL,
3771     EL_EXPANDABLE_WALL_HORIZONTAL,
3772     EL_EXPANDABLE_WALL_VERTICAL,
3773     EL_EXPANDABLE_WALL_ANY,
3774     EL_BD_EXPANDABLE_WALL,
3775     EL_BD_WALL,
3776     EL_WALL_SLIPPERY,
3777     EL_EXIT_CLOSED,
3778     EL_EXIT_OPENING,
3779     EL_EXIT_OPEN,
3780     EL_AMOEBA_DEAD,
3781     EL_AMOEBA_WET,
3782     EL_AMOEBA_DRY,
3783     EL_AMOEBA_FULL,
3784     EL_BD_AMOEBA,
3785     EL_QUICKSAND_EMPTY,
3786     EL_QUICKSAND_FULL,
3787     EL_QUICKSAND_FILLING,
3788     EL_QUICKSAND_EMPTYING,
3789     EL_MAGIC_WALL,
3790     EL_MAGIC_WALL_ACTIVE,
3791     EL_MAGIC_WALL_EMPTYING,
3792     EL_MAGIC_WALL_FILLING,
3793     EL_MAGIC_WALL_FULL,
3794     EL_MAGIC_WALL_DEAD,
3795     EL_BD_MAGIC_WALL,
3796     EL_BD_MAGIC_WALL_ACTIVE,
3797     EL_BD_MAGIC_WALL_EMPTYING,
3798     EL_BD_MAGIC_WALL_FULL,
3799     EL_BD_MAGIC_WALL_FILLING,
3800     EL_BD_MAGIC_WALL_DEAD,
3801     EL_GAME_OF_LIFE,
3802     EL_BIOMAZE,
3803     EL_SP_CHIP_SINGLE,
3804     EL_SP_CHIP_LEFT,
3805     EL_SP_CHIP_RIGHT,
3806     EL_SP_CHIP_TOP,
3807     EL_SP_CHIP_BOTTOM,
3808     EL_SP_TERMINAL,
3809     EL_SP_TERMINAL_ACTIVE,
3810     EL_SP_EXIT_CLOSED,
3811     EL_SP_EXIT_OPEN,
3812     EL_INVISIBLE_WALL,
3813     EL_INVISIBLE_WALL_ACTIVE,
3814     EL_SWITCHGATE_SWITCH_UP,
3815     EL_SWITCHGATE_SWITCH_DOWN,
3816     EL_DC_SWITCHGATE_SWITCH_UP,
3817     EL_DC_SWITCHGATE_SWITCH_DOWN,
3818     EL_TIMEGATE_SWITCH,
3819     EL_TIMEGATE_SWITCH_ACTIVE,
3820     EL_DC_TIMEGATE_SWITCH,
3821     EL_DC_TIMEGATE_SWITCH_ACTIVE,
3822     EL_EMC_WALL_1,
3823     EL_EMC_WALL_2,
3824     EL_EMC_WALL_3,
3825     EL_EMC_WALL_4,
3826     EL_EMC_WALL_5,
3827     EL_EMC_WALL_6,
3828     EL_EMC_WALL_7,
3829     EL_EMC_WALL_8,
3830     EL_WALL_PEARL,
3831     EL_WALL_CRYSTAL,
3832
3833     /* the following elements are a direct copy of "indestructible" elements,
3834        except "EL_ACID", which is "indestructible", but not "solid"! */
3835 #if 0
3836     EL_ACID,
3837 #endif
3838     EL_STEELWALL,
3839     EL_ACID_POOL_TOPLEFT,
3840     EL_ACID_POOL_TOPRIGHT,
3841     EL_ACID_POOL_BOTTOMLEFT,
3842     EL_ACID_POOL_BOTTOM,
3843     EL_ACID_POOL_BOTTOMRIGHT,
3844     EL_SP_HARDWARE_GRAY,
3845     EL_SP_HARDWARE_GREEN,
3846     EL_SP_HARDWARE_BLUE,
3847     EL_SP_HARDWARE_RED,
3848     EL_SP_HARDWARE_YELLOW,
3849     EL_SP_HARDWARE_BASE_1,
3850     EL_SP_HARDWARE_BASE_2,
3851     EL_SP_HARDWARE_BASE_3,
3852     EL_SP_HARDWARE_BASE_4,
3853     EL_SP_HARDWARE_BASE_5,
3854     EL_SP_HARDWARE_BASE_6,
3855     EL_INVISIBLE_STEELWALL,
3856     EL_INVISIBLE_STEELWALL_ACTIVE,
3857     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3858     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3859     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3860     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3861     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3862     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3863     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3864     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3865     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3866     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3867     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3868     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3869     EL_LIGHT_SWITCH,
3870     EL_LIGHT_SWITCH_ACTIVE,
3871     EL_SIGN_EXCLAMATION,
3872     EL_SIGN_RADIOACTIVITY,
3873     EL_SIGN_STOP,
3874     EL_SIGN_WHEELCHAIR,
3875     EL_SIGN_PARKING,
3876     EL_SIGN_NO_ENTRY,
3877     EL_SIGN_UNUSED_1,
3878     EL_SIGN_GIVE_WAY,
3879     EL_SIGN_ENTRY_FORBIDDEN,
3880     EL_SIGN_EMERGENCY_EXIT,
3881     EL_SIGN_YIN_YANG,
3882     EL_SIGN_UNUSED_2,
3883     EL_SIGN_SPERMS,
3884     EL_SIGN_BULLET,
3885     EL_SIGN_HEART,
3886     EL_SIGN_CROSS,
3887     EL_SIGN_FRANKIE,
3888     EL_STEEL_EXIT_CLOSED,
3889     EL_STEEL_EXIT_OPEN,
3890     EL_DC_STEELWALL_1_LEFT,
3891     EL_DC_STEELWALL_1_RIGHT,
3892     EL_DC_STEELWALL_1_TOP,
3893     EL_DC_STEELWALL_1_BOTTOM,
3894     EL_DC_STEELWALL_1_HORIZONTAL,
3895     EL_DC_STEELWALL_1_VERTICAL,
3896     EL_DC_STEELWALL_1_TOPLEFT,
3897     EL_DC_STEELWALL_1_TOPRIGHT,
3898     EL_DC_STEELWALL_1_BOTTOMLEFT,
3899     EL_DC_STEELWALL_1_BOTTOMRIGHT,
3900     EL_DC_STEELWALL_1_TOPLEFT_2,
3901     EL_DC_STEELWALL_1_TOPRIGHT_2,
3902     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3903     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3904     EL_DC_STEELWALL_2_LEFT,
3905     EL_DC_STEELWALL_2_RIGHT,
3906     EL_DC_STEELWALL_2_TOP,
3907     EL_DC_STEELWALL_2_BOTTOM,
3908     EL_DC_STEELWALL_2_HORIZONTAL,
3909     EL_DC_STEELWALL_2_VERTICAL,
3910     EL_DC_STEELWALL_2_MIDDLE,
3911     EL_DC_STEELWALL_2_SINGLE,
3912     EL_STEELWALL_SLIPPERY,
3913     EL_EMC_STEELWALL_1,
3914     EL_EMC_STEELWALL_2,
3915     EL_EMC_STEELWALL_3,
3916     EL_EMC_STEELWALL_4,
3917     EL_CRYSTAL,
3918     EL_GATE_1,
3919     EL_GATE_2,
3920     EL_GATE_3,
3921     EL_GATE_4,
3922     EL_GATE_1_GRAY,
3923     EL_GATE_2_GRAY,
3924     EL_GATE_3_GRAY,
3925     EL_GATE_4_GRAY,
3926     EL_GATE_1_GRAY_ACTIVE,
3927     EL_GATE_2_GRAY_ACTIVE,
3928     EL_GATE_3_GRAY_ACTIVE,
3929     EL_GATE_4_GRAY_ACTIVE,
3930     EL_EM_GATE_1,
3931     EL_EM_GATE_2,
3932     EL_EM_GATE_3,
3933     EL_EM_GATE_4,
3934     EL_EM_GATE_1_GRAY,
3935     EL_EM_GATE_2_GRAY,
3936     EL_EM_GATE_3_GRAY,
3937     EL_EM_GATE_4_GRAY,
3938     EL_EM_GATE_1_GRAY_ACTIVE,
3939     EL_EM_GATE_2_GRAY_ACTIVE,
3940     EL_EM_GATE_3_GRAY_ACTIVE,
3941     EL_EM_GATE_4_GRAY_ACTIVE,
3942     EL_SWITCHGATE_OPEN,
3943     EL_SWITCHGATE_OPENING,
3944     EL_SWITCHGATE_CLOSED,
3945     EL_SWITCHGATE_CLOSING,
3946     EL_TIMEGATE_OPEN,
3947     EL_TIMEGATE_OPENING,
3948     EL_TIMEGATE_CLOSED,
3949     EL_TIMEGATE_CLOSING,
3950     EL_TUBE_ANY,
3951     EL_TUBE_VERTICAL,
3952     EL_TUBE_HORIZONTAL,
3953     EL_TUBE_VERTICAL_LEFT,
3954     EL_TUBE_VERTICAL_RIGHT,
3955     EL_TUBE_HORIZONTAL_UP,
3956     EL_TUBE_HORIZONTAL_DOWN,
3957     EL_TUBE_LEFT_UP,
3958     EL_TUBE_LEFT_DOWN,
3959     EL_TUBE_RIGHT_UP,
3960     EL_TUBE_RIGHT_DOWN,
3961
3962     -1
3963   };
3964
3965   static int ep_classic_enemy[] =
3966   {
3967     EL_BUG,
3968     EL_SPACESHIP,
3969     EL_BD_BUTTERFLY,
3970     EL_BD_FIREFLY,
3971
3972     EL_YAMYAM,
3973     EL_DARK_YAMYAM,
3974     EL_ROBOT,
3975     EL_PACMAN,
3976     EL_SP_SNIKSNAK,
3977     EL_SP_ELECTRON,
3978
3979     -1
3980   };
3981
3982   static int ep_belt[] =
3983   {
3984     EL_CONVEYOR_BELT_1_LEFT,
3985     EL_CONVEYOR_BELT_1_MIDDLE,
3986     EL_CONVEYOR_BELT_1_RIGHT,
3987     EL_CONVEYOR_BELT_2_LEFT,
3988     EL_CONVEYOR_BELT_2_MIDDLE,
3989     EL_CONVEYOR_BELT_2_RIGHT,
3990     EL_CONVEYOR_BELT_3_LEFT,
3991     EL_CONVEYOR_BELT_3_MIDDLE,
3992     EL_CONVEYOR_BELT_3_RIGHT,
3993     EL_CONVEYOR_BELT_4_LEFT,
3994     EL_CONVEYOR_BELT_4_MIDDLE,
3995     EL_CONVEYOR_BELT_4_RIGHT,
3996
3997     -1
3998   };
3999
4000   static int ep_belt_active[] =
4001   {
4002     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4003     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4004     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4005     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4006     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4007     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4008     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4009     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4010     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4011     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4012     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4013     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4014
4015     -1
4016   };
4017
4018   static int ep_belt_switch[] =
4019   {
4020     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4021     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4022     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4023     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4024     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4025     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4026     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4027     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4028     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4029     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4030     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4031     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4032
4033     -1
4034   };
4035
4036   static int ep_tube[] =
4037   {
4038     EL_TUBE_LEFT_UP,
4039     EL_TUBE_LEFT_DOWN,
4040     EL_TUBE_RIGHT_UP,
4041     EL_TUBE_RIGHT_DOWN,
4042     EL_TUBE_HORIZONTAL,
4043     EL_TUBE_HORIZONTAL_UP,
4044     EL_TUBE_HORIZONTAL_DOWN,
4045     EL_TUBE_VERTICAL,
4046     EL_TUBE_VERTICAL_LEFT,
4047     EL_TUBE_VERTICAL_RIGHT,
4048     EL_TUBE_ANY,
4049
4050     -1
4051   };
4052
4053   static int ep_acid_pool[] =
4054   {
4055     EL_ACID_POOL_TOPLEFT,
4056     EL_ACID_POOL_TOPRIGHT,
4057     EL_ACID_POOL_BOTTOMLEFT,
4058     EL_ACID_POOL_BOTTOM,
4059     EL_ACID_POOL_BOTTOMRIGHT,
4060
4061     -1
4062   };
4063
4064   static int ep_keygate[] =
4065   {
4066     EL_GATE_1,
4067     EL_GATE_2,
4068     EL_GATE_3,
4069     EL_GATE_4,
4070     EL_GATE_1_GRAY,
4071     EL_GATE_2_GRAY,
4072     EL_GATE_3_GRAY,
4073     EL_GATE_4_GRAY,
4074     EL_GATE_1_GRAY_ACTIVE,
4075     EL_GATE_2_GRAY_ACTIVE,
4076     EL_GATE_3_GRAY_ACTIVE,
4077     EL_GATE_4_GRAY_ACTIVE,
4078     EL_EM_GATE_1,
4079     EL_EM_GATE_2,
4080     EL_EM_GATE_3,
4081     EL_EM_GATE_4,
4082     EL_EM_GATE_1_GRAY,
4083     EL_EM_GATE_2_GRAY,
4084     EL_EM_GATE_3_GRAY,
4085     EL_EM_GATE_4_GRAY,
4086     EL_EM_GATE_1_GRAY_ACTIVE,
4087     EL_EM_GATE_2_GRAY_ACTIVE,
4088     EL_EM_GATE_3_GRAY_ACTIVE,
4089     EL_EM_GATE_4_GRAY_ACTIVE,
4090     EL_EMC_GATE_5,
4091     EL_EMC_GATE_6,
4092     EL_EMC_GATE_7,
4093     EL_EMC_GATE_8,
4094     EL_EMC_GATE_5_GRAY,
4095     EL_EMC_GATE_6_GRAY,
4096     EL_EMC_GATE_7_GRAY,
4097     EL_EMC_GATE_8_GRAY,
4098     EL_EMC_GATE_5_GRAY_ACTIVE,
4099     EL_EMC_GATE_6_GRAY_ACTIVE,
4100     EL_EMC_GATE_7_GRAY_ACTIVE,
4101     EL_EMC_GATE_8_GRAY_ACTIVE,
4102     EL_DC_GATE_WHITE,
4103     EL_DC_GATE_WHITE_GRAY,
4104     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4105
4106     -1
4107   };
4108
4109   static int ep_amoeboid[] =
4110   {
4111     EL_AMOEBA_DEAD,
4112     EL_AMOEBA_WET,
4113     EL_AMOEBA_DRY,
4114     EL_AMOEBA_FULL,
4115     EL_BD_AMOEBA,
4116     EL_EMC_DRIPPER,
4117
4118     -1
4119   };
4120
4121   static int ep_amoebalive[] =
4122   {
4123     EL_AMOEBA_WET,
4124     EL_AMOEBA_DRY,
4125     EL_AMOEBA_FULL,
4126     EL_BD_AMOEBA,
4127     EL_EMC_DRIPPER,
4128
4129     -1
4130   };
4131
4132   static int ep_has_editor_content[] =
4133   {
4134     EL_PLAYER_1,
4135     EL_PLAYER_2,
4136     EL_PLAYER_3,
4137     EL_PLAYER_4,
4138     EL_SP_MURPHY,
4139     EL_YAMYAM,
4140     EL_YAMYAM_LEFT,
4141     EL_YAMYAM_RIGHT,
4142     EL_YAMYAM_UP,
4143     EL_YAMYAM_DOWN,
4144     EL_AMOEBA_WET,
4145     EL_AMOEBA_DRY,
4146     EL_AMOEBA_FULL,
4147     EL_BD_AMOEBA,
4148     EL_EMC_MAGIC_BALL,
4149     EL_EMC_ANDROID,
4150
4151     -1
4152   };
4153
4154   static int ep_can_turn_each_move[] =
4155   {
4156     /* !!! do something with this one !!! */
4157     -1
4158   };
4159
4160   static int ep_can_grow[] =
4161   {
4162     EL_BD_AMOEBA,
4163     EL_AMOEBA_DROP,
4164     EL_AMOEBA_WET,
4165     EL_AMOEBA_DRY,
4166     EL_AMOEBA_FULL,
4167     EL_GAME_OF_LIFE,
4168     EL_BIOMAZE,
4169     EL_EMC_DRIPPER,
4170
4171     -1
4172   };
4173
4174   static int ep_active_bomb[] =
4175   {
4176     EL_DYNAMITE_ACTIVE,
4177     EL_EM_DYNAMITE_ACTIVE,
4178     EL_DYNABOMB_PLAYER_1_ACTIVE,
4179     EL_DYNABOMB_PLAYER_2_ACTIVE,
4180     EL_DYNABOMB_PLAYER_3_ACTIVE,
4181     EL_DYNABOMB_PLAYER_4_ACTIVE,
4182     EL_SP_DISK_RED_ACTIVE,
4183
4184     -1
4185   };
4186
4187   static int ep_inactive[] =
4188   {
4189     EL_EMPTY,
4190     EL_SAND,
4191     EL_WALL,
4192     EL_BD_WALL,
4193     EL_WALL_SLIPPERY,
4194     EL_STEELWALL,
4195     EL_AMOEBA_DEAD,
4196     EL_QUICKSAND_EMPTY,
4197     EL_QUICKSAND_FAST_EMPTY,
4198     EL_STONEBLOCK,
4199     EL_ROBOT_WHEEL,
4200     EL_KEY_1,
4201     EL_KEY_2,
4202     EL_KEY_3,
4203     EL_KEY_4,
4204     EL_EM_KEY_1,
4205     EL_EM_KEY_2,
4206     EL_EM_KEY_3,
4207     EL_EM_KEY_4,
4208     EL_EMC_KEY_5,
4209     EL_EMC_KEY_6,
4210     EL_EMC_KEY_7,
4211     EL_EMC_KEY_8,
4212     EL_GATE_1,
4213     EL_GATE_2,
4214     EL_GATE_3,
4215     EL_GATE_4,
4216     EL_GATE_1_GRAY,
4217     EL_GATE_2_GRAY,
4218     EL_GATE_3_GRAY,
4219     EL_GATE_4_GRAY,
4220     EL_GATE_1_GRAY_ACTIVE,
4221     EL_GATE_2_GRAY_ACTIVE,
4222     EL_GATE_3_GRAY_ACTIVE,
4223     EL_GATE_4_GRAY_ACTIVE,
4224     EL_EM_GATE_1,
4225     EL_EM_GATE_2,
4226     EL_EM_GATE_3,
4227     EL_EM_GATE_4,
4228     EL_EM_GATE_1_GRAY,
4229     EL_EM_GATE_2_GRAY,
4230     EL_EM_GATE_3_GRAY,
4231     EL_EM_GATE_4_GRAY,
4232     EL_EM_GATE_1_GRAY_ACTIVE,
4233     EL_EM_GATE_2_GRAY_ACTIVE,
4234     EL_EM_GATE_3_GRAY_ACTIVE,
4235     EL_EM_GATE_4_GRAY_ACTIVE,
4236     EL_EMC_GATE_5,
4237     EL_EMC_GATE_6,
4238     EL_EMC_GATE_7,
4239     EL_EMC_GATE_8,
4240     EL_EMC_GATE_5_GRAY,
4241     EL_EMC_GATE_6_GRAY,
4242     EL_EMC_GATE_7_GRAY,
4243     EL_EMC_GATE_8_GRAY,
4244     EL_EMC_GATE_5_GRAY_ACTIVE,
4245     EL_EMC_GATE_6_GRAY_ACTIVE,
4246     EL_EMC_GATE_7_GRAY_ACTIVE,
4247     EL_EMC_GATE_8_GRAY_ACTIVE,
4248     EL_DC_GATE_WHITE,
4249     EL_DC_GATE_WHITE_GRAY,
4250     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4251     EL_DC_GATE_FAKE_GRAY,
4252     EL_DYNAMITE,
4253     EL_EM_DYNAMITE,
4254     EL_INVISIBLE_STEELWALL,
4255     EL_INVISIBLE_WALL,
4256     EL_INVISIBLE_SAND,
4257     EL_LAMP,
4258     EL_LAMP_ACTIVE,
4259     EL_WALL_EMERALD,
4260     EL_WALL_DIAMOND,
4261     EL_WALL_BD_DIAMOND,
4262     EL_WALL_EMERALD_YELLOW,
4263     EL_DYNABOMB_INCREASE_NUMBER,
4264     EL_DYNABOMB_INCREASE_SIZE,
4265     EL_DYNABOMB_INCREASE_POWER,
4266 #if 0
4267     EL_SOKOBAN_OBJECT,
4268 #endif
4269     EL_SOKOBAN_FIELD_EMPTY,
4270     EL_SOKOBAN_FIELD_FULL,
4271     EL_WALL_EMERALD_RED,
4272     EL_WALL_EMERALD_PURPLE,
4273     EL_ACID_POOL_TOPLEFT,
4274     EL_ACID_POOL_TOPRIGHT,
4275     EL_ACID_POOL_BOTTOMLEFT,
4276     EL_ACID_POOL_BOTTOM,
4277     EL_ACID_POOL_BOTTOMRIGHT,
4278     EL_MAGIC_WALL,
4279     EL_MAGIC_WALL_DEAD,
4280     EL_BD_MAGIC_WALL,
4281     EL_BD_MAGIC_WALL_DEAD,
4282     EL_DC_MAGIC_WALL,
4283     EL_DC_MAGIC_WALL_DEAD,
4284     EL_AMOEBA_TO_DIAMOND,
4285     EL_BLOCKED,
4286     EL_SP_EMPTY,
4287     EL_SP_BASE,
4288     EL_SP_PORT_RIGHT,
4289     EL_SP_PORT_DOWN,
4290     EL_SP_PORT_LEFT,
4291     EL_SP_PORT_UP,
4292     EL_SP_GRAVITY_PORT_RIGHT,
4293     EL_SP_GRAVITY_PORT_DOWN,
4294     EL_SP_GRAVITY_PORT_LEFT,
4295     EL_SP_GRAVITY_PORT_UP,
4296     EL_SP_PORT_HORIZONTAL,
4297     EL_SP_PORT_VERTICAL,
4298     EL_SP_PORT_ANY,
4299     EL_SP_DISK_RED,
4300 #if 0
4301     EL_SP_DISK_YELLOW,
4302 #endif
4303     EL_SP_CHIP_SINGLE,
4304     EL_SP_CHIP_LEFT,
4305     EL_SP_CHIP_RIGHT,
4306     EL_SP_CHIP_TOP,
4307     EL_SP_CHIP_BOTTOM,
4308     EL_SP_HARDWARE_GRAY,
4309     EL_SP_HARDWARE_GREEN,
4310     EL_SP_HARDWARE_BLUE,
4311     EL_SP_HARDWARE_RED,
4312     EL_SP_HARDWARE_YELLOW,
4313     EL_SP_HARDWARE_BASE_1,
4314     EL_SP_HARDWARE_BASE_2,
4315     EL_SP_HARDWARE_BASE_3,
4316     EL_SP_HARDWARE_BASE_4,
4317     EL_SP_HARDWARE_BASE_5,
4318     EL_SP_HARDWARE_BASE_6,
4319     EL_SP_GRAVITY_ON_PORT_LEFT,
4320     EL_SP_GRAVITY_ON_PORT_RIGHT,
4321     EL_SP_GRAVITY_ON_PORT_UP,
4322     EL_SP_GRAVITY_ON_PORT_DOWN,
4323     EL_SP_GRAVITY_OFF_PORT_LEFT,
4324     EL_SP_GRAVITY_OFF_PORT_RIGHT,
4325     EL_SP_GRAVITY_OFF_PORT_UP,
4326     EL_SP_GRAVITY_OFF_PORT_DOWN,
4327     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4328     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4329     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4330     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4331     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4332     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4333     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4334     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4335     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4336     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4337     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4338     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4339     EL_SIGN_EXCLAMATION,
4340     EL_SIGN_RADIOACTIVITY,
4341     EL_SIGN_STOP,
4342     EL_SIGN_WHEELCHAIR,
4343     EL_SIGN_PARKING,
4344     EL_SIGN_NO_ENTRY,
4345     EL_SIGN_UNUSED_1,
4346     EL_SIGN_GIVE_WAY,
4347     EL_SIGN_ENTRY_FORBIDDEN,
4348     EL_SIGN_EMERGENCY_EXIT,
4349     EL_SIGN_YIN_YANG,
4350     EL_SIGN_UNUSED_2,
4351     EL_SIGN_SPERMS,
4352     EL_SIGN_BULLET,
4353     EL_SIGN_HEART,
4354     EL_SIGN_CROSS,
4355     EL_SIGN_FRANKIE,
4356     EL_DC_STEELWALL_1_LEFT,
4357     EL_DC_STEELWALL_1_RIGHT,
4358     EL_DC_STEELWALL_1_TOP,
4359     EL_DC_STEELWALL_1_BOTTOM,
4360     EL_DC_STEELWALL_1_HORIZONTAL,
4361     EL_DC_STEELWALL_1_VERTICAL,
4362     EL_DC_STEELWALL_1_TOPLEFT,
4363     EL_DC_STEELWALL_1_TOPRIGHT,
4364     EL_DC_STEELWALL_1_BOTTOMLEFT,
4365     EL_DC_STEELWALL_1_BOTTOMRIGHT,
4366     EL_DC_STEELWALL_1_TOPLEFT_2,
4367     EL_DC_STEELWALL_1_TOPRIGHT_2,
4368     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4369     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4370     EL_DC_STEELWALL_2_LEFT,
4371     EL_DC_STEELWALL_2_RIGHT,
4372     EL_DC_STEELWALL_2_TOP,
4373     EL_DC_STEELWALL_2_BOTTOM,
4374     EL_DC_STEELWALL_2_HORIZONTAL,
4375     EL_DC_STEELWALL_2_VERTICAL,
4376     EL_DC_STEELWALL_2_MIDDLE,
4377     EL_DC_STEELWALL_2_SINGLE,
4378     EL_STEELWALL_SLIPPERY,
4379     EL_EMC_STEELWALL_1,
4380     EL_EMC_STEELWALL_2,
4381     EL_EMC_STEELWALL_3,
4382     EL_EMC_STEELWALL_4,
4383     EL_EMC_WALL_SLIPPERY_1,
4384     EL_EMC_WALL_SLIPPERY_2,
4385     EL_EMC_WALL_SLIPPERY_3,
4386     EL_EMC_WALL_SLIPPERY_4,
4387     EL_EMC_WALL_1,
4388     EL_EMC_WALL_2,
4389     EL_EMC_WALL_3,
4390     EL_EMC_WALL_4,
4391     EL_EMC_WALL_5,
4392     EL_EMC_WALL_6,
4393     EL_EMC_WALL_7,
4394     EL_EMC_WALL_8,
4395     EL_EMC_WALL_9,
4396     EL_EMC_WALL_10,
4397     EL_EMC_WALL_11,
4398     EL_EMC_WALL_12,
4399     EL_EMC_WALL_13,
4400     EL_EMC_WALL_14,
4401     EL_EMC_WALL_15,
4402     EL_EMC_WALL_16,
4403
4404     -1
4405   };
4406
4407   static int ep_em_slippery_wall[] =
4408   {
4409     -1
4410   };
4411
4412   static int ep_gfx_crumbled[] =
4413   {
4414     EL_SAND,
4415     EL_LANDMINE,
4416     EL_DC_LANDMINE,
4417     EL_TRAP,
4418     EL_TRAP_ACTIVE,
4419
4420     -1
4421   };
4422
4423   static int ep_editor_cascade_active[] =
4424   {
4425     EL_INTERNAL_CASCADE_BD_ACTIVE,
4426     EL_INTERNAL_CASCADE_EM_ACTIVE,
4427     EL_INTERNAL_CASCADE_EMC_ACTIVE,
4428     EL_INTERNAL_CASCADE_RND_ACTIVE,
4429     EL_INTERNAL_CASCADE_SB_ACTIVE,
4430     EL_INTERNAL_CASCADE_SP_ACTIVE,
4431     EL_INTERNAL_CASCADE_DC_ACTIVE,
4432     EL_INTERNAL_CASCADE_DX_ACTIVE,
4433     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4434     EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4435     EL_INTERNAL_CASCADE_CE_ACTIVE,
4436     EL_INTERNAL_CASCADE_GE_ACTIVE,
4437     EL_INTERNAL_CASCADE_REF_ACTIVE,
4438     EL_INTERNAL_CASCADE_USER_ACTIVE,
4439     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4440
4441     -1
4442   };
4443
4444   static int ep_editor_cascade_inactive[] =
4445   {
4446     EL_INTERNAL_CASCADE_BD,
4447     EL_INTERNAL_CASCADE_EM,
4448     EL_INTERNAL_CASCADE_EMC,
4449     EL_INTERNAL_CASCADE_RND,
4450     EL_INTERNAL_CASCADE_SB,
4451     EL_INTERNAL_CASCADE_SP,
4452     EL_INTERNAL_CASCADE_DC,
4453     EL_INTERNAL_CASCADE_DX,
4454     EL_INTERNAL_CASCADE_CHARS,
4455     EL_INTERNAL_CASCADE_STEEL_CHARS,
4456     EL_INTERNAL_CASCADE_CE,
4457     EL_INTERNAL_CASCADE_GE,
4458     EL_INTERNAL_CASCADE_REF,
4459     EL_INTERNAL_CASCADE_USER,
4460     EL_INTERNAL_CASCADE_DYNAMIC,
4461
4462     -1
4463   };
4464
4465   static int ep_obsolete[] =
4466   {
4467     EL_PLAYER_OBSOLETE,
4468     EL_KEY_OBSOLETE,
4469     EL_EM_KEY_1_FILE_OBSOLETE,
4470     EL_EM_KEY_2_FILE_OBSOLETE,
4471     EL_EM_KEY_3_FILE_OBSOLETE,
4472     EL_EM_KEY_4_FILE_OBSOLETE,
4473     EL_ENVELOPE_OBSOLETE,
4474
4475     -1
4476   };
4477
4478   static struct
4479   {
4480     int *elements;
4481     int property;
4482   } element_properties[] =
4483   {
4484     { ep_diggable,                      EP_DIGGABLE                     },
4485     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
4486     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
4487     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
4488     { ep_dont_touch,                    EP_DONT_TOUCH                   },
4489     { ep_indestructible,                EP_INDESTRUCTIBLE               },
4490     { ep_slippery,                      EP_SLIPPERY                     },
4491     { ep_can_change,                    EP_CAN_CHANGE                   },
4492     { ep_can_move,                      EP_CAN_MOVE                     },
4493     { ep_can_fall,                      EP_CAN_FALL                     },
4494     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
4495     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
4496     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
4497     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
4498     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
4499     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
4500     { ep_walkable_over,                 EP_WALKABLE_OVER                },
4501     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
4502     { ep_walkable_under,                EP_WALKABLE_UNDER               },
4503     { ep_passable_over,                 EP_PASSABLE_OVER                },
4504     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
4505     { ep_passable_under,                EP_PASSABLE_UNDER               },
4506     { ep_droppable,                     EP_DROPPABLE                    },
4507     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
4508     { ep_pushable,                      EP_PUSHABLE                     },
4509     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
4510     { ep_protected,                     EP_PROTECTED                    },
4511     { ep_throwable,                     EP_THROWABLE                    },
4512     { ep_can_explode,                   EP_CAN_EXPLODE                  },
4513     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
4514
4515     { ep_player,                        EP_PLAYER                       },
4516     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
4517     { ep_can_pass_dc_magic_wall,        EP_CAN_PASS_DC_MAGIC_WALL       },
4518     { ep_switchable,                    EP_SWITCHABLE                   },
4519     { ep_bd_element,                    EP_BD_ELEMENT                   },
4520     { ep_sp_element,                    EP_SP_ELEMENT                   },
4521     { ep_sb_element,                    EP_SB_ELEMENT                   },
4522     { ep_gem,                           EP_GEM                          },
4523     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
4524     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
4525     { ep_food_pig,                      EP_FOOD_PIG                     },
4526     { ep_historic_wall,                 EP_HISTORIC_WALL                },
4527     { ep_historic_solid,                EP_HISTORIC_SOLID               },
4528     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
4529     { ep_belt,                          EP_BELT                         },
4530     { ep_belt_active,                   EP_BELT_ACTIVE                  },
4531     { ep_belt_switch,                   EP_BELT_SWITCH                  },
4532     { ep_tube,                          EP_TUBE                         },
4533     { ep_acid_pool,                     EP_ACID_POOL                    },
4534     { ep_keygate,                       EP_KEYGATE                      },
4535     { ep_amoeboid,                      EP_AMOEBOID                     },
4536     { ep_amoebalive,                    EP_AMOEBALIVE                   },
4537     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
4538     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
4539     { ep_can_grow,                      EP_CAN_GROW                     },
4540     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
4541     { ep_inactive,                      EP_INACTIVE                     },
4542
4543     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
4544
4545     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
4546
4547     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
4548     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
4549
4550     { ep_obsolete,                      EP_OBSOLETE                     },
4551
4552     { NULL,                             -1                              }
4553   };
4554
4555   int i, j, k;
4556
4557   /* always start with reliable default values (element has no properties) */
4558   /* (but never initialize clipboard elements after the very first time) */
4559   /* (to be able to use clipboard elements between several levels) */
4560   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4561     if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4562       for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4563         SET_PROPERTY(i, j, FALSE);
4564
4565   /* set all base element properties from above array definitions */
4566   for (i = 0; element_properties[i].elements != NULL; i++)
4567     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4568       SET_PROPERTY((element_properties[i].elements)[j],
4569                    element_properties[i].property, TRUE);
4570
4571   /* copy properties to some elements that are only stored in level file */
4572   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4573     for (j = 0; copy_properties[j][0] != -1; j++)
4574       if (HAS_PROPERTY(copy_properties[j][0], i))
4575         for (k = 1; k <= 4; k++)
4576           SET_PROPERTY(copy_properties[j][k], i, TRUE);
4577
4578   /* set static element properties that are not listed in array definitions */
4579   for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4580     SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4581
4582   clipboard_elements_initialized = TRUE;
4583 }
4584
4585 void InitElementPropertiesEngine(int engine_version)
4586 {
4587   static int no_wall_properties[] =
4588   {
4589     EP_DIGGABLE,
4590     EP_COLLECTIBLE_ONLY,
4591     EP_DONT_RUN_INTO,
4592     EP_DONT_COLLIDE_WITH,
4593     EP_CAN_MOVE,
4594     EP_CAN_FALL,
4595     EP_CAN_SMASH_PLAYER,
4596     EP_CAN_SMASH_ENEMIES,
4597     EP_CAN_SMASH_EVERYTHING,
4598     EP_PUSHABLE,
4599
4600     EP_PLAYER,
4601     EP_GEM,
4602     EP_FOOD_DARK_YAMYAM,
4603     EP_FOOD_PENGUIN,
4604     EP_BELT,
4605     EP_BELT_ACTIVE,
4606     EP_TUBE,
4607     EP_AMOEBOID,
4608     EP_AMOEBALIVE,
4609     EP_ACTIVE_BOMB,
4610
4611     EP_ACCESSIBLE,
4612
4613     -1
4614   };
4615
4616   int i, j;
4617
4618   /* important: after initialization in InitElementPropertiesStatic(), the
4619      elements are not again initialized to a default value; therefore all
4620      changes have to make sure that they leave the element with a defined
4621      property (which means that conditional property changes must be set to
4622      a reliable default value before) */
4623
4624   /* resolve group elements */
4625   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4626     ResolveGroupElement(EL_GROUP_START + i);
4627
4628   /* set all special, combined or engine dependent element properties */
4629   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4630   {
4631     /* do not change (already initialized) clipboard elements here */
4632     if (IS_CLIPBOARD_ELEMENT(i))
4633       continue;
4634
4635     /* ---------- INACTIVE ------------------------------------------------- */
4636     SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4637                                    i <= EL_CHAR_END) ||
4638                                   (i >= EL_STEEL_CHAR_START &&
4639                                    i <= EL_STEEL_CHAR_END)));
4640
4641     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4642     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4643                                   IS_WALKABLE_INSIDE(i) ||
4644                                   IS_WALKABLE_UNDER(i)));
4645
4646     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4647                                   IS_PASSABLE_INSIDE(i) ||
4648                                   IS_PASSABLE_UNDER(i)));
4649
4650     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4651                                          IS_PASSABLE_OVER(i)));
4652
4653     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4654                                            IS_PASSABLE_INSIDE(i)));
4655
4656     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4657                                           IS_PASSABLE_UNDER(i)));
4658
4659     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4660                                     IS_PASSABLE(i)));
4661
4662     /* ---------- COLLECTIBLE ---------------------------------------------- */
4663     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4664                                      IS_DROPPABLE(i) ||
4665                                      IS_THROWABLE(i)));
4666
4667     /* ---------- SNAPPABLE ------------------------------------------------ */
4668     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4669                                    IS_COLLECTIBLE(i) ||
4670                                    IS_SWITCHABLE(i) ||
4671                                    i == EL_BD_ROCK));
4672
4673     /* ---------- WALL ----------------------------------------------------- */
4674     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
4675
4676     for (j = 0; no_wall_properties[j] != -1; j++)
4677       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4678           i >= EL_FIRST_RUNTIME_UNREAL)
4679         SET_PROPERTY(i, EP_WALL, FALSE);
4680
4681     if (IS_HISTORIC_WALL(i))
4682       SET_PROPERTY(i, EP_WALL, TRUE);
4683
4684     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4685     if (engine_version < VERSION_IDENT(2,2,0,0))
4686       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4687     else
4688       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4689                                              !IS_DIGGABLE(i) &&
4690                                              !IS_COLLECTIBLE(i)));
4691
4692     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4693     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4694       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4695     else
4696       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4697                                             IS_INDESTRUCTIBLE(i)));
4698
4699     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4700     if (i == EL_FLAMES)
4701       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4702     else if (engine_version < VERSION_IDENT(2,2,0,0))
4703       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4704     else
4705       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4706                                            (!IS_WALKABLE(i) ||
4707                                             IS_PROTECTED(i))));
4708
4709     if (IS_CUSTOM_ELEMENT(i))
4710     {
4711       /* these are additional properties which are initially false when set */
4712
4713       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4714       if (DONT_TOUCH(i))
4715         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4716       if (DONT_COLLIDE_WITH(i))
4717         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4718
4719       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4720       if (CAN_SMASH_EVERYTHING(i))
4721         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4722       if (CAN_SMASH_ENEMIES(i))
4723         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4724     }
4725
4726     /* ---------- CAN_SMASH ------------------------------------------------ */
4727     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4728                                    CAN_SMASH_ENEMIES(i) ||
4729                                    CAN_SMASH_EVERYTHING(i)));
4730
4731     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4732     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4733                                              EXPLODES_BY_FIRE(i)));
4734
4735     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4736     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4737                                              EXPLODES_SMASHED(i)));
4738
4739     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4740     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4741                                             EXPLODES_IMPACT(i)));
4742
4743     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4744     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4745
4746     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4747     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4748                                                   i == EL_BLACK_ORB));
4749
4750     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4751     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4752                                               CAN_MOVE(i) ||
4753                                               IS_CUSTOM_ELEMENT(i)));
4754
4755     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4756     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4757                                                  i == EL_SP_ELECTRON));
4758
4759     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4760     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4761       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4762                    getMoveIntoAcidProperty(&level, i));
4763
4764     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4765     if (MAYBE_DONT_COLLIDE_WITH(i))
4766       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4767                    getDontCollideWithProperty(&level, i));
4768
4769     /* ---------- SP_PORT -------------------------------------------------- */
4770     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4771                                  IS_PASSABLE_INSIDE(i)));
4772
4773     /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4774     for (j = 0; j < level.num_android_clone_elements; j++)
4775       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4776                    (i != EL_EMPTY &&
4777                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4778
4779     /* ---------- CAN_CHANGE ----------------------------------------------- */
4780     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
4781     for (j = 0; j < element_info[i].num_change_pages; j++)
4782       if (element_info[i].change_page[j].can_change)
4783         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4784
4785     /* ---------- HAS_ACTION ----------------------------------------------- */
4786     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      /* default: has no action */
4787     for (j = 0; j < element_info[i].num_change_pages; j++)
4788       if (element_info[i].change_page[j].has_action)
4789         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4790
4791     /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4792     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4793                                                   HAS_ACTION(i)));
4794
4795     /* ---------- GFX_CRUMBLED --------------------------------------------- */
4796 #if 1
4797     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4798                  element_info[i].crumbled[ACTION_DEFAULT] !=
4799                  element_info[i].graphic[ACTION_DEFAULT]);
4800 #else
4801     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4802     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4803                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4804 #endif
4805
4806     /* ---------- EDITOR_CASCADE ------------------------------------------- */
4807     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4808                                         IS_EDITOR_CASCADE_INACTIVE(i)));
4809   }
4810
4811   /* dynamically adjust element properties according to game engine version */
4812   {
4813     static int ep_em_slippery_wall[] =
4814     {
4815       EL_WALL,
4816       EL_STEELWALL,
4817       EL_EXPANDABLE_WALL,
4818       EL_EXPANDABLE_WALL_HORIZONTAL,
4819       EL_EXPANDABLE_WALL_VERTICAL,
4820       EL_EXPANDABLE_WALL_ANY,
4821       EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4822       EL_EXPANDABLE_STEELWALL_VERTICAL,
4823       EL_EXPANDABLE_STEELWALL_ANY,
4824       EL_EXPANDABLE_STEELWALL_GROWING,
4825       -1
4826     };
4827
4828     /* special EM style gems behaviour */
4829     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4830       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4831                    level.em_slippery_gems);
4832
4833     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4834     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4835                  (level.em_slippery_gems &&
4836                   engine_version > VERSION_IDENT(2,0,1,0)));
4837   }
4838
4839   /* this is needed because some graphics depend on element properties */
4840   if (game_status == GAME_MODE_PLAYING)
4841     InitElementGraphicInfo();
4842 }
4843
4844 void InitElementPropertiesAfterLoading(int engine_version)
4845 {
4846   int i;
4847
4848   /* set some other uninitialized values of custom elements in older levels */
4849   if (engine_version < VERSION_IDENT(3,1,0,0))
4850   {
4851     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4852     {
4853       int element = EL_CUSTOM_START + i;
4854
4855       element_info[element].access_direction = MV_ALL_DIRECTIONS;
4856
4857       element_info[element].explosion_delay = 17;
4858       element_info[element].ignition_delay = 8;
4859     }
4860   }
4861 }
4862
4863 static void InitGlobal()
4864 {
4865   int graphic;
4866   int i;
4867
4868   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4869   {
4870     /* check if element_name_info entry defined for each element in "main.h" */
4871     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4872       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4873
4874     element_info[i].token_name = element_name_info[i].token_name;
4875     element_info[i].class_name = element_name_info[i].class_name;
4876     element_info[i].editor_description= element_name_info[i].editor_description;
4877
4878 #if 0
4879     printf("%04d: %s\n", i, element_name_info[i].token_name);
4880 #endif
4881   }
4882
4883   /* create hash from image config list */
4884   image_config_hash = newSetupFileHash();
4885   for (i = 0; image_config[i].token != NULL; i++)
4886     setHashEntry(image_config_hash,
4887                  image_config[i].token,
4888                  image_config[i].value);
4889
4890   /* create hash from element token list */
4891   element_token_hash = newSetupFileHash();
4892   for (i = 0; element_name_info[i].token_name != NULL; i++)
4893     setHashEntry(element_token_hash,
4894                  element_name_info[i].token_name,
4895                  int2str(i, 0));
4896
4897   /* create hash from graphic token list */
4898   graphic_token_hash = newSetupFileHash();
4899   for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4900     if (strSuffix(image_config[i].value, ".pcx") ||
4901         strSuffix(image_config[i].value, ".wav") ||
4902         strEqual(image_config[i].value, UNDEFINED_FILENAME))
4903       setHashEntry(graphic_token_hash,
4904                    image_config[i].token,
4905                    int2str(graphic++, 0));
4906
4907   /* create hash from font token list */
4908   font_token_hash = newSetupFileHash();
4909   for (i = 0; font_info[i].token_name != NULL; i++)
4910     setHashEntry(font_token_hash,
4911                  font_info[i].token_name,
4912                  int2str(i, 0));
4913
4914   /* always start with reliable default values (all elements) */
4915   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4916     ActiveElement[i] = i;
4917
4918   /* now add all entries that have an active state (active elements) */
4919   for (i = 0; element_with_active_state[i].element != -1; i++)
4920   {
4921     int element = element_with_active_state[i].element;
4922     int element_active = element_with_active_state[i].element_active;
4923
4924     ActiveElement[element] = element_active;
4925   }
4926
4927   /* always start with reliable default values (all buttons) */
4928   for (i = 0; i < NUM_IMAGE_FILES; i++)
4929     ActiveButton[i] = i;
4930
4931   /* now add all entries that have an active state (active buttons) */
4932   for (i = 0; button_with_active_state[i].button != -1; i++)
4933   {
4934     int button = button_with_active_state[i].button;
4935     int button_active = button_with_active_state[i].button_active;
4936
4937     ActiveButton[button] = button_active;
4938   }
4939
4940   /* always start with reliable default values (all fonts) */
4941   for (i = 0; i < NUM_FONTS; i++)
4942     ActiveFont[i] = i;
4943
4944   /* now add all entries that have an active state (active fonts) */
4945   for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4946   {
4947     int font = font_with_active_state[i].font_nr;
4948     int font_active = font_with_active_state[i].font_nr_active;
4949
4950     ActiveFont[font] = font_active;
4951   }
4952
4953   global.autoplay_leveldir = NULL;
4954   global.convert_leveldir = NULL;
4955
4956   global.frames_per_second = 0;
4957   global.fps_slowdown = FALSE;
4958   global.fps_slowdown_factor = 1;
4959
4960   global.border_status = GAME_MODE_MAIN;
4961 #if 0
4962   global.fading_status = GAME_MODE_MAIN;
4963   global.fading_type = TYPE_ENTER_MENU;
4964 #endif
4965 }
4966
4967 void Execute_Command(char *command)
4968 {
4969   int i;
4970
4971   if (strEqual(command, "print graphicsinfo.conf"))
4972   {
4973     printf("# You can configure additional/alternative image files here.\n");
4974     printf("# (The entries below are default and therefore commented out.)\n");
4975     printf("\n");
4976     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4977     printf("\n");
4978     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4979     printf("\n");
4980
4981     for (i = 0; image_config[i].token != NULL; i++)
4982       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4983                                               image_config[i].value));
4984
4985     exit(0);
4986   }
4987   else if (strEqual(command, "print soundsinfo.conf"))
4988   {
4989     printf("# You can configure additional/alternative sound files here.\n");
4990     printf("# (The entries below are default and therefore commented out.)\n");
4991     printf("\n");
4992     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4993     printf("\n");
4994     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4995     printf("\n");
4996
4997     for (i = 0; sound_config[i].token != NULL; i++)
4998       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4999                                               sound_config[i].value));
5000
5001     exit(0);
5002   }
5003   else if (strEqual(command, "print musicinfo.conf"))
5004   {
5005     printf("# You can configure additional/alternative music files here.\n");
5006     printf("# (The entries below are default and therefore commented out.)\n");
5007     printf("\n");
5008     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5009     printf("\n");
5010     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5011     printf("\n");
5012
5013     for (i = 0; music_config[i].token != NULL; i++)
5014       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5015                                               music_config[i].value));
5016
5017     exit(0);
5018   }
5019   else if (strEqual(command, "print editorsetup.conf"))
5020   {
5021     printf("# You can configure your personal editor element list here.\n");
5022     printf("# (The entries below are default and therefore commented out.)\n");
5023     printf("\n");
5024
5025     /* this is needed to be able to check element list for cascade elements */
5026     InitElementPropertiesStatic();
5027     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5028
5029     PrintEditorElementList();
5030
5031     exit(0);
5032   }
5033   else if (strEqual(command, "print helpanim.conf"))
5034   {
5035     printf("# You can configure different element help animations here.\n");
5036     printf("# (The entries below are default and therefore commented out.)\n");
5037     printf("\n");
5038
5039     for (i = 0; helpanim_config[i].token != NULL; i++)
5040     {
5041       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5042                                               helpanim_config[i].value));
5043
5044       if (strEqual(helpanim_config[i].token, "end"))
5045         printf("#\n");
5046     }
5047
5048     exit(0);
5049   }
5050   else if (strEqual(command, "print helptext.conf"))
5051   {
5052     printf("# You can configure different element help text here.\n");
5053     printf("# (The entries below are default and therefore commented out.)\n");
5054     printf("\n");
5055
5056     for (i = 0; helptext_config[i].token != NULL; i++)
5057       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5058                                               helptext_config[i].value));
5059
5060     exit(0);
5061   }
5062   else if (strncmp(command, "dump level ", 11) == 0)
5063   {
5064     char *filename = &command[11];
5065
5066     if (!fileExists(filename))
5067       Error(ERR_EXIT, "cannot open file '%s'", filename);
5068
5069     LoadLevelFromFilename(&level, filename);
5070     DumpLevel(&level);
5071
5072     exit(0);
5073   }
5074   else if (strncmp(command, "dump tape ", 10) == 0)
5075   {
5076     char *filename = &command[10];
5077
5078     if (!fileExists(filename))
5079       Error(ERR_EXIT, "cannot open file '%s'", filename);
5080
5081     LoadTapeFromFilename(filename);
5082     DumpTape(&tape);
5083
5084     exit(0);
5085   }
5086   else if (strncmp(command, "autoplay ", 9) == 0)
5087   {
5088     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5089
5090     while (*str_ptr != '\0')                    /* continue parsing string */
5091     {
5092       /* cut leading whitespace from string, replace it by string terminator */
5093       while (*str_ptr == ' ' || *str_ptr == '\t')
5094         *str_ptr++ = '\0';
5095
5096       if (*str_ptr == '\0')                     /* end of string reached */
5097         break;
5098
5099       if (global.autoplay_leveldir == NULL)     /* read level set string */
5100       {
5101         global.autoplay_leveldir = str_ptr;
5102         global.autoplay_all = TRUE;             /* default: play all tapes */
5103
5104         for (i = 0; i < MAX_TAPES_PER_SET; i++)
5105           global.autoplay_level[i] = FALSE;
5106       }
5107       else                                      /* read level number string */
5108       {
5109         int level_nr = atoi(str_ptr);           /* get level_nr value */
5110
5111         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5112           global.autoplay_level[level_nr] = TRUE;
5113
5114         global.autoplay_all = FALSE;
5115       }
5116
5117       /* advance string pointer to the next whitespace (or end of string) */
5118       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5119         str_ptr++;
5120     }
5121   }
5122   else if (strncmp(command, "convert ", 8) == 0)
5123   {
5124     char *str_copy = getStringCopy(&command[8]);
5125     char *str_ptr = strchr(str_copy, ' ');
5126
5127     global.convert_leveldir = str_copy;
5128     global.convert_level_nr = -1;
5129
5130     if (str_ptr != NULL)                        /* level number follows */
5131     {
5132       *str_ptr++ = '\0';                        /* terminate leveldir string */
5133       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
5134     }
5135   }
5136
5137 #if DEBUG
5138 #if defined(TARGET_SDL)
5139   else if (strEqual(command, "SDL_ListModes"))
5140   {
5141     SDL_Rect **modes;
5142     int i;
5143
5144     SDL_Init(SDL_INIT_VIDEO);
5145
5146     /* get available fullscreen/hardware modes */
5147     modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5148
5149     /* check if there are any modes available */
5150     if (modes == NULL)
5151     {
5152       printf("No modes available!\n");
5153
5154       exit(-1);
5155     }
5156
5157     /* check if our resolution is restricted */
5158     if (modes == (SDL_Rect **)-1)
5159     {
5160       printf("All resolutions available.\n");
5161     }
5162     else
5163     {
5164       printf("Available Modes:\n");
5165
5166       for(i = 0; modes[i]; i++)
5167         printf("  %d x %d\n", modes[i]->w, modes[i]->h);
5168     }
5169
5170     exit(0);
5171   }
5172 #endif
5173 #endif
5174
5175   else
5176   {
5177     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5178   }
5179 }
5180
5181 static void InitSetup()
5182 {
5183   LoadSetup();                                  /* global setup info */
5184
5185   /* set some options from setup file */
5186
5187   if (setup.options.verbose)
5188     options.verbose = TRUE;
5189 }
5190
5191 static void InitGameInfo()
5192 {
5193   game.restart_level = FALSE;
5194 }
5195
5196 static void InitPlayerInfo()
5197 {
5198   int i;
5199
5200   /* choose default local player */
5201   local_player = &stored_player[0];
5202
5203   for (i = 0; i < MAX_PLAYERS; i++)
5204     stored_player[i].connected = FALSE;
5205
5206   local_player->connected = TRUE;
5207 }
5208
5209 static void InitArtworkInfo()
5210 {
5211   LoadArtworkInfo();
5212 }
5213
5214 static char *get_string_in_brackets(char *string)
5215 {
5216   char *string_in_brackets = checked_malloc(strlen(string) + 3);
5217
5218   sprintf(string_in_brackets, "[%s]", string);
5219
5220   return string_in_brackets;
5221 }
5222
5223 static char *get_level_id_suffix(int id_nr)
5224 {
5225   char *id_suffix = checked_malloc(1 + 3 + 1);
5226
5227   if (id_nr < 0 || id_nr > 999)
5228     id_nr = 0;
5229
5230   sprintf(id_suffix, ".%03d", id_nr);
5231
5232   return id_suffix;
5233 }
5234
5235 #if 0
5236 static char *get_element_class_token(int element)
5237 {
5238   char *element_class_name = element_info[element].class_name;
5239   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5240
5241   sprintf(element_class_token, "[%s]", element_class_name);
5242
5243   return element_class_token;
5244 }
5245
5246 static char *get_action_class_token(int action)
5247 {
5248   char *action_class_name = &element_action_info[action].suffix[1];
5249   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5250
5251   sprintf(action_class_token, "[%s]", action_class_name);
5252
5253   return action_class_token;
5254 }
5255 #endif
5256
5257 static void InitArtworkConfig()
5258 {
5259   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5260   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5261   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5262   static char *action_id_suffix[NUM_ACTIONS + 1];
5263   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5264   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5265   static char *level_id_suffix[MAX_LEVELS + 1];
5266   static char *dummy[1] = { NULL };
5267   static char *ignore_generic_tokens[] =
5268   {
5269     "name",
5270     "sort_priority",
5271     NULL
5272   };
5273   static char **ignore_image_tokens;
5274   static char **ignore_sound_tokens;
5275   static char **ignore_music_tokens;
5276   int num_ignore_generic_tokens;
5277   int num_ignore_image_tokens;
5278   int num_ignore_sound_tokens;
5279   int num_ignore_music_tokens;
5280   int i;
5281
5282   /* dynamically determine list of generic tokens to be ignored */
5283   num_ignore_generic_tokens = 0;
5284   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5285     num_ignore_generic_tokens++;
5286
5287   /* dynamically determine list of image tokens to be ignored */
5288   num_ignore_image_tokens = num_ignore_generic_tokens;
5289   for (i = 0; image_config_vars[i].token != NULL; i++)
5290     num_ignore_image_tokens++;
5291   ignore_image_tokens =
5292     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5293   for (i = 0; i < num_ignore_generic_tokens; i++)
5294     ignore_image_tokens[i] = ignore_generic_tokens[i];
5295   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5296     ignore_image_tokens[num_ignore_generic_tokens + i] =
5297       image_config_vars[i].token;
5298   ignore_image_tokens[num_ignore_image_tokens] = NULL;
5299
5300   /* dynamically determine list of sound tokens to be ignored */
5301   num_ignore_sound_tokens = num_ignore_generic_tokens;
5302   ignore_sound_tokens =
5303     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5304   for (i = 0; i < num_ignore_generic_tokens; i++)
5305     ignore_sound_tokens[i] = ignore_generic_tokens[i];
5306   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5307
5308   /* dynamically determine list of music tokens to be ignored */
5309   num_ignore_music_tokens = num_ignore_generic_tokens;
5310   ignore_music_tokens =
5311     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5312   for (i = 0; i < num_ignore_generic_tokens; i++)
5313     ignore_music_tokens[i] = ignore_generic_tokens[i];
5314   ignore_music_tokens[num_ignore_music_tokens] = NULL;
5315
5316   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5317     image_id_prefix[i] = element_info[i].token_name;
5318   for (i = 0; i < NUM_FONTS; i++)
5319     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5320   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5321
5322   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5323     sound_id_prefix[i] = element_info[i].token_name;
5324   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5325     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5326       get_string_in_brackets(element_info[i].class_name);
5327   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5328
5329   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5330     music_id_prefix[i] = music_prefix_info[i].prefix;
5331   music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5332
5333   for (i = 0; i < NUM_ACTIONS; i++)
5334     action_id_suffix[i] = element_action_info[i].suffix;
5335   action_id_suffix[NUM_ACTIONS] = NULL;
5336
5337   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5338     direction_id_suffix[i] = element_direction_info[i].suffix;
5339   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5340
5341   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5342     special_id_suffix[i] = special_suffix_info[i].suffix;
5343   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5344
5345   for (i = 0; i < MAX_LEVELS; i++)
5346     level_id_suffix[i] = get_level_id_suffix(i);
5347   level_id_suffix[MAX_LEVELS] = NULL;
5348
5349   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5350                 image_id_prefix, action_id_suffix, direction_id_suffix,
5351                 special_id_suffix, ignore_image_tokens);
5352   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5353                 sound_id_prefix, action_id_suffix, dummy,
5354                 special_id_suffix, ignore_sound_tokens);
5355   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5356                 music_id_prefix, special_id_suffix, level_id_suffix,
5357                 dummy, ignore_music_tokens);
5358 }
5359
5360 static void InitMixer()
5361 {
5362   OpenAudio();
5363   StartMixer();
5364 }
5365
5366 void InitGfx()
5367 {
5368   char *filename_font_initial = NULL;
5369   char *filename_anim_initial = NULL;
5370   Bitmap *bitmap_font_initial = NULL;
5371   int font_height;
5372   int i, j;
5373
5374   /* determine settings for initial font (for displaying startup messages) */
5375   for (i = 0; image_config[i].token != NULL; i++)
5376   {
5377     for (j = 0; j < NUM_INITIAL_FONTS; j++)
5378     {
5379       char font_token[128];
5380       int len_font_token;
5381
5382       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5383       len_font_token = strlen(font_token);
5384
5385       if (strEqual(image_config[i].token, font_token))
5386         filename_font_initial = image_config[i].value;
5387       else if (strlen(image_config[i].token) > len_font_token &&
5388                strncmp(image_config[i].token, font_token, len_font_token) == 0)
5389       {
5390         if (strEqual(&image_config[i].token[len_font_token], ".x"))
5391           font_initial[j].src_x = atoi(image_config[i].value);
5392         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5393           font_initial[j].src_y = atoi(image_config[i].value);
5394         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5395           font_initial[j].width = atoi(image_config[i].value);
5396         else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5397           font_initial[j].height = atoi(image_config[i].value);
5398       }
5399     }
5400   }
5401
5402   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5403   {
5404     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5405     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5406   }
5407
5408   if (filename_font_initial == NULL)    /* should not happen */
5409     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5410
5411   /* create additional image buffers for double-buffering and cross-fading */
5412   bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5413   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5414   bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5415   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5416
5417   /* initialize screen properties */
5418   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5419                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5420                    bitmap_db_field);
5421   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5422   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5423   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5424
5425   bitmap_font_initial = LoadCustomImage(filename_font_initial);
5426
5427   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5428     font_initial[j].bitmap = bitmap_font_initial;
5429
5430   InitFontGraphicInfo();
5431
5432   font_height = getFontHeight(FC_RED);
5433
5434 #if 1
5435   DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5436 #else
5437   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5438 #endif
5439   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5440   DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5441
5442   DrawInitText("Loading graphics", 120, FC_GREEN);
5443
5444 #if 1
5445 #if 1
5446   /* initialize busy animation with default values */
5447   int parameter[NUM_GFX_ARGS];
5448   for (i = 0; i < NUM_GFX_ARGS; i++)
5449     parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5450                                                image_config_suffix[i].token,
5451                                                image_config_suffix[i].type);
5452 #if 0
5453   for (i = 0; i < NUM_GFX_ARGS; i++)
5454     printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5455 #endif
5456 #endif
5457
5458   /* determine settings for busy animation (when displaying startup messages) */
5459   for (i = 0; image_config[i].token != NULL; i++)
5460   {
5461     char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5462     int len_anim_token = strlen(anim_token);
5463
5464     if (strEqual(image_config[i].token, anim_token))
5465       filename_anim_initial = image_config[i].value;
5466     else if (strlen(image_config[i].token) > len_anim_token &&
5467              strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5468     {
5469 #if 1
5470       for (j = 0; image_config_suffix[j].token != NULL; j++)
5471       {
5472         if (strEqual(&image_config[i].token[len_anim_token],
5473                      image_config_suffix[j].token))
5474           parameter[j] =
5475             get_graphic_parameter_value(image_config[i].value,
5476                                         image_config_suffix[j].token,
5477                                         image_config_suffix[j].type);
5478       }
5479 #else
5480       if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5481         anim_initial.src_x = atoi(image_config[i].value);
5482       else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5483         anim_initial.src_y = atoi(image_config[i].value);
5484       else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5485         anim_initial.width = atoi(image_config[i].value);
5486       else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5487         anim_initial.height = atoi(image_config[i].value);
5488       else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5489         anim_initial.anim_frames = atoi(image_config[i].value);
5490       else if (strEqual(&image_config[i].token[len_anim_token],
5491                         ".frames_per_line"))
5492         anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5493       else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5494         anim_initial.anim_delay = atoi(image_config[i].value);
5495 #endif
5496     }
5497   }
5498
5499   set_graphic_parameters_ext(0, &anim_initial, parameter, NULL);
5500
5501   if (filename_anim_initial == NULL)    /* should not happen */
5502     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5503
5504   anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5505
5506   init.busy.width  = anim_initial.width;
5507   init.busy.height = anim_initial.height;
5508
5509   InitMenuDesignSettings_Static();
5510   InitGfxDrawBusyAnimFunction(DrawInitAnim);
5511 #endif
5512 }
5513
5514 void RedrawBackground()
5515 {
5516   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5517              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5518
5519   redraw_mask = REDRAW_ALL;
5520 }
5521
5522 void InitGfxBackground()
5523 {
5524   int x, y;
5525
5526   fieldbuffer = bitmap_db_field;
5527   SetDrawtoField(DRAW_BACKBUFFER);
5528
5529 #if 1
5530   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5531 #else
5532   RedrawBackground();
5533
5534   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5535   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5536 #endif
5537
5538   for (x = 0; x < MAX_BUF_XSIZE; x++)
5539     for (y = 0; y < MAX_BUF_YSIZE; y++)
5540       redraw[x][y] = 0;
5541   redraw_tiles = 0;
5542   redraw_mask = REDRAW_ALL;
5543 }
5544
5545 static void InitLevelInfo()
5546 {
5547   LoadLevelInfo();                              /* global level info */
5548   LoadLevelSetup_LastSeries();                  /* last played series info */
5549   LoadLevelSetup_SeriesInfo();                  /* last played level info */
5550 }
5551
5552 void InitLevelArtworkInfo()
5553 {
5554   LoadLevelArtworkInfo();
5555 }
5556
5557 static void InitImages()
5558 {
5559   print_timestamp_init("InitImages");
5560
5561   setLevelArtworkDir(artwork.gfx_first);
5562
5563 #if 0
5564   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5565          leveldir_current->identifier,
5566          artwork.gfx_current_identifier,
5567          artwork.gfx_current->identifier,
5568          leveldir_current->graphics_set,
5569          leveldir_current->graphics_path);
5570 #endif
5571
5572   UPDATE_BUSY_STATE();
5573
5574   ReloadCustomImages();
5575   print_timestamp_time("ReloadCustomImages");
5576
5577   UPDATE_BUSY_STATE();
5578
5579   LoadCustomElementDescriptions();
5580   print_timestamp_time("LoadCustomElementDescriptions");
5581
5582   UPDATE_BUSY_STATE();
5583
5584   LoadMenuDesignSettings();
5585   print_timestamp_time("LoadMenuDesignSettings");
5586
5587   UPDATE_BUSY_STATE();
5588
5589   ReinitializeGraphics();
5590   print_timestamp_time("ReinitializeGraphics");
5591
5592   UPDATE_BUSY_STATE();
5593
5594   print_timestamp_done("InitImages");
5595 }
5596
5597 static void InitSound(char *identifier)
5598 {
5599   print_timestamp_init("InitSound");
5600
5601   if (identifier == NULL)
5602     identifier = artwork.snd_current->identifier;
5603
5604   /* set artwork path to send it to the sound server process */
5605   setLevelArtworkDir(artwork.snd_first);
5606
5607   InitReloadCustomSounds(identifier);
5608   print_timestamp_time("InitReloadCustomSounds");
5609
5610   ReinitializeSounds();
5611   print_timestamp_time("ReinitializeSounds");
5612
5613   print_timestamp_done("InitSound");
5614 }
5615
5616 static void InitMusic(char *identifier)
5617 {
5618   print_timestamp_init("InitMusic");
5619
5620   if (identifier == NULL)
5621     identifier = artwork.mus_current->identifier;
5622
5623   /* set artwork path to send it to the sound server process */
5624   setLevelArtworkDir(artwork.mus_first);
5625
5626   InitReloadCustomMusic(identifier);
5627   print_timestamp_time("InitReloadCustomMusic");
5628
5629   ReinitializeMusic();
5630   print_timestamp_time("ReinitializeMusic");
5631
5632   print_timestamp_done("InitMusic");
5633 }
5634
5635 void InitNetworkServer()
5636 {
5637 #if defined(NETWORK_AVALIABLE)
5638   int nr_wanted;
5639 #endif
5640
5641   if (!options.network)
5642     return;
5643
5644 #if defined(NETWORK_AVALIABLE)
5645   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5646
5647   if (!ConnectToServer(options.server_host, options.server_port))
5648     Error(ERR_EXIT, "cannot connect to network game server");
5649
5650   SendToServer_PlayerName(setup.player_name);
5651   SendToServer_ProtocolVersion();
5652
5653   if (nr_wanted)
5654     SendToServer_NrWanted(nr_wanted);
5655 #endif
5656 }
5657
5658 static char *getNewArtworkIdentifier(int type)
5659 {
5660   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5661   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5662   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5663   static boolean initialized[3] = { FALSE, FALSE, FALSE };
5664   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5665   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5666   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5667   char *leveldir_identifier = leveldir_current->identifier;
5668 #if 1
5669   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5670   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5671 #else
5672   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5673 #endif
5674   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5675   char *artwork_current_identifier;
5676   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
5677
5678   /* leveldir_current may be invalid (level group, parent link) */
5679   if (!validLevelSeries(leveldir_current))
5680     return NULL;
5681
5682   /* 1st step: determine artwork set to be activated in descending order:
5683      --------------------------------------------------------------------
5684      1. setup artwork (when configured to override everything else)
5685      2. artwork set configured in "levelinfo.conf" of current level set
5686         (artwork in level directory will have priority when loading later)
5687      3. artwork in level directory (stored in artwork sub-directory)
5688      4. setup artwork (currently configured in setup menu) */
5689
5690   if (setup_override_artwork)
5691     artwork_current_identifier = setup_artwork_set;
5692   else if (leveldir_artwork_set != NULL)
5693     artwork_current_identifier = leveldir_artwork_set;
5694   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5695     artwork_current_identifier = leveldir_identifier;
5696   else
5697     artwork_current_identifier = setup_artwork_set;
5698
5699
5700   /* 2nd step: check if it is really needed to reload artwork set
5701      ------------------------------------------------------------ */
5702
5703 #if 0
5704   if (type == ARTWORK_TYPE_GRAPHICS)
5705     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5706            artwork_new_identifier,
5707            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5708            artwork_current_identifier,
5709            leveldir_current->graphics_set,
5710            leveldir_current->identifier);
5711 #endif
5712
5713   /* ---------- reload if level set and also artwork set has changed ------- */
5714   if (leveldir_current_identifier[type] != leveldir_identifier &&
5715       (last_has_level_artwork_set[type] || has_level_artwork_set))
5716     artwork_new_identifier = artwork_current_identifier;
5717
5718   leveldir_current_identifier[type] = leveldir_identifier;
5719   last_has_level_artwork_set[type] = has_level_artwork_set;
5720
5721 #if 0
5722   if (type == ARTWORK_TYPE_GRAPHICS)
5723     printf("::: 1: '%s'\n", artwork_new_identifier);
5724 #endif
5725
5726   /* ---------- reload if "override artwork" setting has changed ----------- */
5727   if (last_override_level_artwork[type] != setup_override_artwork)
5728     artwork_new_identifier = artwork_current_identifier;
5729
5730   last_override_level_artwork[type] = setup_override_artwork;
5731
5732 #if 0
5733   if (type == ARTWORK_TYPE_GRAPHICS)
5734     printf("::: 2: '%s'\n", artwork_new_identifier);
5735 #endif
5736
5737   /* ---------- reload if current artwork identifier has changed ----------- */
5738   if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5739                 artwork_current_identifier))
5740     artwork_new_identifier = artwork_current_identifier;
5741
5742   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5743
5744 #if 0
5745   if (type == ARTWORK_TYPE_GRAPHICS)
5746     printf("::: 3: '%s'\n", artwork_new_identifier);
5747 #endif
5748
5749   /* ---------- do not reload directly after starting ---------------------- */
5750   if (!initialized[type])
5751     artwork_new_identifier = NULL;
5752
5753   initialized[type] = TRUE;
5754
5755 #if 0
5756   if (type == ARTWORK_TYPE_GRAPHICS)
5757     printf("::: 4: '%s'\n", artwork_new_identifier);
5758 #endif
5759
5760 #if 0
5761   if (type == ARTWORK_TYPE_GRAPHICS)
5762     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5763            artwork.gfx_current_identifier, artwork_current_identifier,
5764            artwork.gfx_current->identifier, leveldir_current->graphics_set,
5765            artwork_new_identifier);
5766 #endif
5767
5768   return artwork_new_identifier;
5769 }
5770
5771 void ReloadCustomArtwork(int force_reload)
5772 {
5773   int last_game_status = game_status;   /* save current game status */
5774   char *gfx_new_identifier;
5775   char *snd_new_identifier;
5776   char *mus_new_identifier;
5777   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5778   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5779   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5780   boolean reload_needed;
5781
5782   force_reload_gfx |= AdjustGraphicsForEMC();
5783
5784   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5785   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5786   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5787
5788   reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5789                    snd_new_identifier != NULL || force_reload_snd ||
5790                    mus_new_identifier != NULL || force_reload_mus);
5791
5792   if (!reload_needed)
5793     return;
5794
5795   print_timestamp_init("ReloadCustomArtwork");
5796
5797   game_status = GAME_MODE_LOADING;
5798
5799   FadeOut(REDRAW_ALL);
5800
5801 #if 1
5802   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5803 #else
5804   ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5805 #endif
5806   print_timestamp_time("ClearRectangle");
5807
5808 #if 0
5809   printf("::: fading in ... %d\n", fading.fade_mode);
5810 #endif
5811   FadeIn(REDRAW_ALL);
5812 #if 0
5813   printf("::: done\n");
5814 #endif
5815
5816   if (gfx_new_identifier != NULL || force_reload_gfx)
5817   {
5818 #if 0
5819     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5820            artwork.gfx_current_identifier,
5821            gfx_new_identifier,
5822            artwork.gfx_current->identifier,
5823            leveldir_current->graphics_set);
5824 #endif
5825
5826     InitImages();
5827     print_timestamp_time("InitImages");
5828   }
5829
5830   if (snd_new_identifier != NULL || force_reload_snd)
5831   {
5832     InitSound(snd_new_identifier);
5833     print_timestamp_time("InitSound");
5834   }
5835
5836   if (mus_new_identifier != NULL || force_reload_mus)
5837   {
5838     InitMusic(mus_new_identifier);
5839     print_timestamp_time("InitMusic");
5840   }
5841
5842   game_status = last_game_status;       /* restore current game status */
5843
5844 #if 0
5845   printf("::: ----------------DELAY 1 ...\n");
5846   Delay(3000);
5847 #endif
5848
5849 #if 0
5850   printf("::: FadeOut @ ReloadCustomArtwork ...\n");
5851 #endif
5852   FadeOut(REDRAW_ALL);
5853 #if 0
5854   printf("::: FadeOut @ ReloadCustomArtwork done\n");
5855 #endif
5856
5857   RedrawBackground();
5858
5859   /* force redraw of (open or closed) door graphics */
5860   SetDoorState(DOOR_OPEN_ALL);
5861   CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5862
5863 #if 1
5864 #if 1
5865 #if 1
5866   FadeSetEnterScreen();
5867   FadeSkipNextFadeOut();
5868   // FadeSetDisabled();
5869 #else
5870   FadeSkipNext();
5871 #endif
5872 #else
5873   fading = fading_none;
5874 #endif
5875 #endif
5876
5877 #if 0
5878   redraw_mask = REDRAW_ALL;
5879 #endif
5880
5881   print_timestamp_done("ReloadCustomArtwork");
5882 }
5883
5884 void KeyboardAutoRepeatOffUnlessAutoplay()
5885 {
5886   if (global.autoplay_leveldir == NULL)
5887     KeyboardAutoRepeatOff();
5888 }
5889
5890
5891 /* ========================================================================= */
5892 /* OpenAll()                                                                 */
5893 /* ========================================================================= */
5894
5895 void OpenAll()
5896 {
5897   print_timestamp_init("OpenAll");
5898
5899   game_status = GAME_MODE_LOADING;
5900
5901   InitGlobal();                 /* initialize some global variables */
5902
5903   if (options.execute_command)
5904     Execute_Command(options.execute_command);
5905
5906   if (options.serveronly)
5907   {
5908 #if defined(PLATFORM_UNIX)
5909     NetworkServer(options.server_port, options.serveronly);
5910 #else
5911     Error(ERR_WARN, "networking only supported in Unix version");
5912 #endif
5913
5914     exit(0);                    /* never reached, server loops forever */
5915   }
5916
5917   InitSetup();
5918
5919   InitGameInfo();
5920   InitPlayerInfo();
5921   InitArtworkInfo();            /* needed before loading gfx, sound & music */
5922   InitArtworkConfig();          /* needed before forking sound child process */
5923   InitMixer();
5924
5925   InitCounter();
5926
5927   InitRND(NEW_RANDOMIZE);
5928   InitSimpleRandom(NEW_RANDOMIZE);
5929
5930   InitJoysticks();
5931
5932   print_timestamp_time("[pre-video]");
5933
5934   InitVideoDisplay();
5935   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5936
5937   InitEventFilter(FilterMouseMotionEvents);
5938
5939   InitElementPropertiesStatic();
5940   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5941
5942   print_timestamp_time("[post-video]");
5943
5944   InitGfx();
5945
5946   print_timestamp_time("InitGfx");
5947
5948   InitLevelInfo();
5949   print_timestamp_time("InitLevelInfo");
5950
5951   InitLevelArtworkInfo();
5952   print_timestamp_time("InitLevelArtworkInfo");
5953
5954   InitImages();                 /* needs to know current level directory */
5955   print_timestamp_time("InitImages");
5956
5957   InitSound(NULL);              /* needs to know current level directory */
5958   print_timestamp_time("InitSound");
5959
5960   InitMusic(NULL);              /* needs to know current level directory */
5961   print_timestamp_time("InitMusic");
5962
5963   InitGfxBackground();
5964
5965 #if 1
5966   em_open_all();
5967 #endif
5968
5969   if (global.autoplay_leveldir)
5970   {
5971     AutoPlayTape();
5972     return;
5973   }
5974   else if (global.convert_leveldir)
5975   {
5976     ConvertLevels();
5977     return;
5978   }
5979
5980   game_status = GAME_MODE_MAIN;
5981
5982 #if 1
5983   FadeSetEnterScreen();
5984   if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5985     FadeSkipNextFadeOut();
5986   // FadeSetDisabled();
5987 #else
5988   fading = fading_none;
5989 #endif
5990
5991   print_timestamp_time("[post-artwork]");
5992
5993   print_timestamp_done("OpenAll");
5994
5995   DrawMainMenu();
5996
5997   InitNetworkServer();
5998 }
5999
6000 void CloseAllAndExit(int exit_value)
6001 {
6002   StopSounds();
6003   FreeAllSounds();
6004   FreeAllMusic();
6005   CloseAudio();         /* called after freeing sounds (needed for SDL) */
6006
6007 #if 1
6008   em_close_all();
6009 #endif
6010
6011   FreeAllImages();
6012
6013 #if defined(TARGET_SDL)
6014   if (network_server)   /* terminate network server */
6015     SDL_KillThread(server_thread);
6016 #endif
6017
6018   CloseVideoDisplay();
6019   ClosePlatformDependentStuff();
6020
6021   if (exit_value != 0)
6022     NotifyUserAboutErrorFile();
6023
6024   exit(exit_value);
6025 }