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