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