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