rnd-20140515-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   /* use image size as default values for width and height for these images */
1757   static int full_size_graphics[] =
1758   {
1759     IMG_GLOBAL_BORDER,
1760     IMG_GLOBAL_DOOR,
1761
1762     IMG_BACKGROUND_ENVELOPE_1,
1763     IMG_BACKGROUND_ENVELOPE_2,
1764     IMG_BACKGROUND_ENVELOPE_3,
1765     IMG_BACKGROUND_ENVELOPE_4,
1766     IMG_BACKGROUND_REQUEST,
1767
1768     IMG_BACKGROUND,
1769     IMG_BACKGROUND_TITLE_INITIAL,
1770     IMG_BACKGROUND_TITLE,
1771     IMG_BACKGROUND_MAIN,
1772     IMG_BACKGROUND_LEVELS,
1773     IMG_BACKGROUND_LEVELNR,
1774     IMG_BACKGROUND_SCORES,
1775     IMG_BACKGROUND_EDITOR,
1776     IMG_BACKGROUND_INFO,
1777     IMG_BACKGROUND_INFO_ELEMENTS,
1778     IMG_BACKGROUND_INFO_MUSIC,
1779     IMG_BACKGROUND_INFO_CREDITS,
1780     IMG_BACKGROUND_INFO_PROGRAM,
1781     IMG_BACKGROUND_INFO_VERSION,
1782     IMG_BACKGROUND_INFO_LEVELSET,
1783     IMG_BACKGROUND_SETUP,
1784     IMG_BACKGROUND_PLAYING,
1785     IMG_BACKGROUND_DOOR,
1786     IMG_BACKGROUND_TAPE,
1787     IMG_BACKGROUND_PANEL,
1788     IMG_BACKGROUND_PALETTE,
1789     IMG_BACKGROUND_TOOLBOX,
1790
1791     IMG_TITLESCREEN_INITIAL_1,
1792     IMG_TITLESCREEN_INITIAL_2,
1793     IMG_TITLESCREEN_INITIAL_3,
1794     IMG_TITLESCREEN_INITIAL_4,
1795     IMG_TITLESCREEN_INITIAL_5,
1796     IMG_TITLESCREEN_1,
1797     IMG_TITLESCREEN_2,
1798     IMG_TITLESCREEN_3,
1799     IMG_TITLESCREEN_4,
1800     IMG_TITLESCREEN_5,
1801
1802     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1803     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1804     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1805     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1806     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1807     IMG_BACKGROUND_TITLEMESSAGE_1,
1808     IMG_BACKGROUND_TITLEMESSAGE_2,
1809     IMG_BACKGROUND_TITLEMESSAGE_3,
1810     IMG_BACKGROUND_TITLEMESSAGE_4,
1811     IMG_BACKGROUND_TITLEMESSAGE_5,
1812
1813     -1
1814   };
1815
1816   checked_free(graphic_info);
1817
1818   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1819
1820 #if 1
1821   /* initialize "use_image_size" flag with default value */
1822   for (i = 0; i < num_images; i++)
1823     graphic_info[i].use_image_size = FALSE;
1824
1825   /* initialize "use_image_size" flag from static configuration above */
1826   for (i = 0; full_size_graphics[i] != -1; i++)
1827     graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1828 #endif
1829
1830   /* first set all graphic paramaters ... */
1831   for (i = 0; i < num_images; i++)
1832     set_graphic_parameters(i);
1833
1834   /* ... then copy these parameters for cloned graphics */
1835   for (i = 0; i < num_images; i++)
1836     if (graphic_info[i].clone_from != -1)
1837       set_cloned_graphic_parameters(i);
1838
1839   for (i = 0; i < num_images; i++)
1840   {
1841     Bitmap *src_bitmap;
1842     int src_x, src_y;
1843     int width, height;
1844     int first_frame, last_frame;
1845     int src_bitmap_width, src_bitmap_height;
1846
1847     /* now check if no animation frames are outside of the loaded image */
1848
1849     if (graphic_info[i].bitmap == NULL)
1850       continue;         /* skip check for optional images that are undefined */
1851
1852     /* get image size (this can differ from the standard element tile size!) */
1853     width  = graphic_info[i].width;
1854     height = graphic_info[i].height;
1855
1856     /* get final bitmap size (with scaling, but without small images) */
1857     src_bitmap_width  = graphic_info[i].src_image_width;
1858     src_bitmap_height = graphic_info[i].src_image_height;
1859
1860     /* check if first animation frame is inside specified bitmap */
1861
1862     first_frame = 0;
1863     getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1864
1865 #if 1
1866     /* this avoids calculating wrong start position for out-of-bounds frame */
1867     src_x = graphic_info[i].src_x;
1868     src_y = graphic_info[i].src_y;
1869 #endif
1870
1871     if (src_x < 0 || src_y < 0 ||
1872         src_x + width  > src_bitmap_width ||
1873         src_y + height > src_bitmap_height)
1874     {
1875       Error(ERR_INFO_LINE, "-");
1876       Error(ERR_INFO, "warning: error found in config file:");
1877       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1878       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1879       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1880       Error(ERR_INFO,
1881             "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1882             src_x, src_y, src_bitmap_width, src_bitmap_height);
1883       Error(ERR_INFO, "custom graphic rejected for this element/action");
1884
1885       if (i == fallback_graphic)
1886         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1887
1888       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1889       Error(ERR_INFO_LINE, "-");
1890
1891       graphic_info[i] = graphic_info[fallback_graphic];
1892     }
1893
1894     /* check if last animation frame is inside specified bitmap */
1895
1896     last_frame = graphic_info[i].anim_frames - 1;
1897     getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1898
1899     if (src_x < 0 || src_y < 0 ||
1900         src_x + width  > src_bitmap_width ||
1901         src_y + height > src_bitmap_height)
1902     {
1903       Error(ERR_INFO_LINE, "-");
1904       Error(ERR_INFO, "warning: error found in config file:");
1905       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1906       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1907       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1908       Error(ERR_INFO,
1909             "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1910             last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1911       Error(ERR_INFO, "::: %d, %d", width, height);
1912       Error(ERR_INFO, "custom graphic rejected for this element/action");
1913
1914       if (i == fallback_graphic)
1915         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1916
1917       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1918       Error(ERR_INFO_LINE, "-");
1919
1920       graphic_info[i] = graphic_info[fallback_graphic];
1921     }
1922   }
1923 }
1924
1925 static void InitGraphicCompatibilityInfo()
1926 {
1927   struct FileInfo *fi_global_door =
1928     getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1929   int num_images = getImageListSize();
1930   int i;
1931
1932   /* the following compatibility handling is needed for the following case:
1933      versions up to 3.3.0.0 used one large bitmap "global.door" for various
1934      graphics mainly used for door and panel graphics, like editor, tape and
1935      in-game buttons with hard-coded bitmap positions and button sizes; as
1936      these graphics now have individual definitions, redefining "global.door"
1937      to change all these graphics at once like before does not work anymore
1938      (because all those individual definitions still have their default values);
1939      to solve this, remap all those individual definitions that are not
1940      redefined to the new bitmap of "global.door" if it was redefined */
1941
1942   /* special compatibility handling if image "global.door" was redefined */
1943   if (fi_global_door->redefined)
1944   {
1945     for (i = 0; i < num_images; i++)
1946     {
1947       struct FileInfo *fi = getImageListEntryFromImageID(i);
1948
1949       /* process only those images that still use the default settings */
1950       if (!fi->redefined)
1951       {
1952         /* process all images which default to same image as "global.door" */
1953         if (strEqual(fi->default_filename, fi_global_door->default_filename))
1954         {
1955           // printf("::: special treatment needed for token '%s'\n", fi->token);
1956
1957           graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1958         }
1959       }
1960     }
1961   }
1962
1963 #if 1
1964   InitGraphicCompatibilityInfo_Doors();
1965 #endif
1966
1967 #if 0
1968   struct
1969   {
1970     int graphic;
1971     int *width, *height;
1972     boolean right_wing;
1973   }
1974   doors[] =
1975   {
1976     { IMG_DOOR_1_WING_LEFT,     &door_1.width,  &door_1.height, FALSE   },
1977     { IMG_DOOR_1_WING_RIGHT,    &door_1.width,  &door_1.height, TRUE    },
1978     { IMG_DOOR_2_WING_LEFT,     &door_2.width,  &door_2.height, FALSE   },
1979     { IMG_DOOR_2_WING_RIGHT,    &door_2.width,  &door_2.height, TRUE    },
1980
1981     { 0,                        NULL,           NULL,           FALSE   }
1982   };
1983
1984   for (i = 0; doors[i].graphic != 0; i++)
1985   {
1986     int graphic = doors[i].graphic;
1987     int *width  = doors[i].width;
1988     int *height = doors[i].height;
1989     boolean right_wing = doors[i].right_wing;
1990
1991     struct FileInfo *fi = getImageListEntryFromImageID(graphic);
1992     struct GraphicInfo *g = &graphic_info[graphic];
1993
1994     if (!fi->redefined)
1995     {
1996       if (*width != -1)
1997       {
1998         // correct start position for right wing of "standard" door graphic
1999         if (right_wing)
2000           g->src_x += g->width - *width;
2001
2002         g->width = *width;
2003       }
2004
2005       if (*height != -1)
2006         g->height = *height;
2007     }
2008   }
2009 #endif
2010
2011 #if 0
2012   for (i = 0; i < num_images; i++)
2013   {
2014     struct FileInfo *fi = getImageListEntryFromImageID(i);
2015
2016     if (i == IMG_GLOBAL_DOOR)
2017     {
2018       printf("::: %s, %s, %d\n",
2019              fi->default_filename,
2020              fi->filename,
2021              fi->redefined);
2022     }
2023   }
2024 #endif
2025 }
2026
2027 static void InitElementSoundInfo()
2028 {
2029   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
2030   int num_property_mappings = getSoundListPropertyMappingSize();
2031   int i, j, act;
2032
2033   /* set values to -1 to identify later as "uninitialized" values */
2034   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2035     for (act = 0; act < NUM_ACTIONS; act++)
2036       element_info[i].sound[act] = -1;
2037
2038   /* initialize element/sound mapping from static configuration */
2039   for (i = 0; element_to_sound[i].element > -1; i++)
2040   {
2041     int element      = element_to_sound[i].element;
2042     int action       = element_to_sound[i].action;
2043     int sound        = element_to_sound[i].sound;
2044     boolean is_class = element_to_sound[i].is_class;
2045
2046     if (action < 0)
2047       action = ACTION_DEFAULT;
2048
2049     if (!is_class)
2050       element_info[element].sound[action] = sound;
2051     else
2052       for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2053         if (strEqual(element_info[j].class_name,
2054                      element_info[element].class_name))
2055           element_info[j].sound[action] = sound;
2056   }
2057
2058   /* initialize element class/sound mapping from dynamic configuration */
2059   for (i = 0; i < num_property_mappings; i++)
2060   {
2061     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2062     int action        = property_mapping[i].ext1_index;
2063     int sound         = property_mapping[i].artwork_index;
2064
2065     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2066       continue;
2067
2068     if (action < 0)
2069       action = ACTION_DEFAULT;
2070
2071     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2072       if (strEqual(element_info[j].class_name,
2073                    element_info[element_class].class_name))
2074         element_info[j].sound[action] = sound;
2075   }
2076
2077   /* initialize element/sound mapping from dynamic configuration */
2078   for (i = 0; i < num_property_mappings; i++)
2079   {
2080     int element = property_mapping[i].base_index;
2081     int action  = property_mapping[i].ext1_index;
2082     int sound   = property_mapping[i].artwork_index;
2083
2084     if (element >= MAX_NUM_ELEMENTS)
2085       continue;
2086
2087     if (action < 0)
2088       action = ACTION_DEFAULT;
2089
2090     element_info[element].sound[action] = sound;
2091   }
2092
2093   /* now set all '-1' values to element specific default values */
2094   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2095   {
2096     for (act = 0; act < NUM_ACTIONS; act++)
2097     {
2098       /* generic default action sound (defined by "[default]" directive) */
2099       int default_action_sound = element_info[EL_DEFAULT].sound[act];
2100
2101       /* look for special default action sound (classic game specific) */
2102       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2103         default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2104       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2105         default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2106       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2107         default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2108
2109       /* !!! there's no such thing as a "default action sound" !!! */
2110 #if 0
2111       /* look for element specific default sound (independent from action) */
2112       if (element_info[i].sound[ACTION_DEFAULT] != -1)
2113         default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2114 #endif
2115
2116 #if 1
2117       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2118       /* !!! make this better !!! */
2119       if (i == EL_EMPTY_SPACE)
2120         default_action_sound = element_info[EL_DEFAULT].sound[act];
2121 #endif
2122
2123       /* no sound for this specific action -- use default action sound */
2124       if (element_info[i].sound[act] == -1)
2125         element_info[i].sound[act] = default_action_sound;
2126     }
2127   }
2128
2129   /* copy sound settings to some elements that are only stored in level file
2130      in native R'n'D levels, but are used by game engine in native EM levels */
2131   for (i = 0; copy_properties[i][0] != -1; i++)
2132     for (j = 1; j <= 4; j++)
2133       for (act = 0; act < NUM_ACTIONS; act++)
2134         element_info[copy_properties[i][j]].sound[act] =
2135           element_info[copy_properties[i][0]].sound[act];
2136 }
2137
2138 static void InitGameModeSoundInfo()
2139 {
2140   int i;
2141
2142   /* set values to -1 to identify later as "uninitialized" values */
2143   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2144     menu.sound[i] = -1;
2145
2146   /* initialize gamemode/sound mapping from static configuration */
2147   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2148   {
2149     int gamemode = gamemode_to_sound[i].gamemode;
2150     int sound    = gamemode_to_sound[i].sound;
2151
2152     if (gamemode < 0)
2153       gamemode = GAME_MODE_DEFAULT;
2154
2155     menu.sound[gamemode] = sound;
2156   }
2157
2158   /* now set all '-1' values to levelset specific default values */
2159   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2160     if (menu.sound[i] == -1)
2161       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2162
2163 #if 0
2164   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2165     if (menu.sound[i] != -1)
2166       printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2167 #endif
2168 }
2169
2170 static void set_sound_parameters(int sound, char **parameter_raw)
2171 {
2172   int parameter[NUM_SND_ARGS];
2173   int i;
2174
2175   /* get integer values from string parameters */
2176   for (i = 0; i < NUM_SND_ARGS; i++)
2177     parameter[i] =
2178       get_parameter_value(parameter_raw[i],
2179                           sound_config_suffix[i].token,
2180                           sound_config_suffix[i].type);
2181
2182   /* explicit loop mode setting in configuration overrides default value */
2183   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2184     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2185
2186   /* sound volume to change the original volume when loading the sound file */
2187   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2188
2189   /* sound priority to give certain sounds a higher or lower priority */
2190   sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2191 }
2192
2193 static void InitSoundInfo()
2194 {
2195   int *sound_effect_properties;
2196   int num_sounds = getSoundListSize();
2197   int i, j;
2198
2199   checked_free(sound_info);
2200
2201   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2202   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2203
2204   /* initialize sound effect for all elements to "no sound" */
2205   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2206     for (j = 0; j < NUM_ACTIONS; j++)
2207       element_info[i].sound[j] = SND_UNDEFINED;
2208
2209   for (i = 0; i < num_sounds; i++)
2210   {
2211     struct FileInfo *sound = getSoundListEntry(i);
2212     int len_effect_text = strlen(sound->token);
2213
2214     sound_effect_properties[i] = ACTION_OTHER;
2215     sound_info[i].loop = FALSE;         /* default: play sound only once */
2216
2217 #if 0
2218     printf("::: sound %d: '%s'\n", i, sound->token);
2219 #endif
2220
2221     /* determine all loop sounds and identify certain sound classes */
2222
2223     for (j = 0; element_action_info[j].suffix; j++)
2224     {
2225       int len_action_text = strlen(element_action_info[j].suffix);
2226
2227       if (len_action_text < len_effect_text &&
2228           strEqual(&sound->token[len_effect_text - len_action_text],
2229                    element_action_info[j].suffix))
2230       {
2231         sound_effect_properties[i] = element_action_info[j].value;
2232         sound_info[i].loop = element_action_info[j].is_loop_sound;
2233
2234         break;
2235       }
2236     }
2237
2238     /* associate elements and some selected sound actions */
2239
2240     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2241     {
2242       if (element_info[j].class_name)
2243       {
2244         int len_class_text = strlen(element_info[j].class_name);
2245
2246         if (len_class_text + 1 < len_effect_text &&
2247             strncmp(sound->token,
2248                     element_info[j].class_name, len_class_text) == 0 &&
2249             sound->token[len_class_text] == '.')
2250         {
2251           int sound_action_value = sound_effect_properties[i];
2252
2253           element_info[j].sound[sound_action_value] = i;
2254         }
2255       }
2256     }
2257
2258     set_sound_parameters(i, sound->parameter);
2259   }
2260
2261   free(sound_effect_properties);
2262 }
2263
2264 static void InitGameModeMusicInfo()
2265 {
2266   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2267   int num_property_mappings = getMusicListPropertyMappingSize();
2268   int default_levelset_music = -1;
2269   int i;
2270
2271   /* set values to -1 to identify later as "uninitialized" values */
2272   for (i = 0; i < MAX_LEVELS; i++)
2273     levelset.music[i] = -1;
2274   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2275     menu.music[i] = -1;
2276
2277   /* initialize gamemode/music mapping from static configuration */
2278   for (i = 0; gamemode_to_music[i].music > -1; i++)
2279   {
2280     int gamemode = gamemode_to_music[i].gamemode;
2281     int music    = gamemode_to_music[i].music;
2282
2283 #if 0
2284     printf("::: gamemode == %d, music == %d\n", gamemode, music);
2285 #endif
2286
2287     if (gamemode < 0)
2288       gamemode = GAME_MODE_DEFAULT;
2289
2290     menu.music[gamemode] = music;
2291   }
2292
2293   /* initialize gamemode/music mapping from dynamic configuration */
2294   for (i = 0; i < num_property_mappings; i++)
2295   {
2296     int prefix   = property_mapping[i].base_index;
2297     int gamemode = property_mapping[i].ext1_index;
2298     int level    = property_mapping[i].ext2_index;
2299     int music    = property_mapping[i].artwork_index;
2300
2301 #if 0
2302     printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2303            prefix, gamemode, level, music);
2304 #endif
2305
2306     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2307       continue;
2308
2309     if (gamemode < 0)
2310       gamemode = GAME_MODE_DEFAULT;
2311
2312     /* level specific music only allowed for in-game music */
2313     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2314       gamemode = GAME_MODE_PLAYING;
2315
2316     if (level == -1)
2317     {
2318       level = 0;
2319       default_levelset_music = music;
2320     }
2321
2322     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2323       levelset.music[level] = music;
2324     if (gamemode != GAME_MODE_PLAYING)
2325       menu.music[gamemode] = music;
2326   }
2327
2328   /* now set all '-1' values to menu specific default values */
2329   /* (undefined values of "levelset.music[]" might stay at "-1" to
2330      allow dynamic selection of music files from music directory!) */
2331   for (i = 0; i < MAX_LEVELS; i++)
2332     if (levelset.music[i] == -1)
2333       levelset.music[i] = default_levelset_music;
2334   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2335     if (menu.music[i] == -1)
2336       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2337
2338 #if 0
2339   for (i = 0; i < MAX_LEVELS; i++)
2340     if (levelset.music[i] != -1)
2341       printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2342   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2343     if (menu.music[i] != -1)
2344       printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2345 #endif
2346 }
2347
2348 static void set_music_parameters(int music, char **parameter_raw)
2349 {
2350   int parameter[NUM_MUS_ARGS];
2351   int i;
2352
2353   /* get integer values from string parameters */
2354   for (i = 0; i < NUM_MUS_ARGS; i++)
2355     parameter[i] =
2356       get_parameter_value(parameter_raw[i],
2357                           music_config_suffix[i].token,
2358                           music_config_suffix[i].type);
2359
2360   /* explicit loop mode setting in configuration overrides default value */
2361   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2362     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2363 }
2364
2365 static void InitMusicInfo()
2366 {
2367   int num_music = getMusicListSize();
2368   int i, j;
2369
2370   checked_free(music_info);
2371
2372   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2373
2374   for (i = 0; i < num_music; i++)
2375   {
2376     struct FileInfo *music = getMusicListEntry(i);
2377     int len_music_text = strlen(music->token);
2378
2379     music_info[i].loop = TRUE;          /* default: play music in loop mode */
2380
2381     /* determine all loop music */
2382
2383     for (j = 0; music_prefix_info[j].prefix; j++)
2384     {
2385       int len_prefix_text = strlen(music_prefix_info[j].prefix);
2386
2387       if (len_prefix_text < len_music_text &&
2388           strncmp(music->token,
2389                   music_prefix_info[j].prefix, len_prefix_text) == 0)
2390       {
2391         music_info[i].loop = music_prefix_info[j].is_loop_music;
2392
2393         break;
2394       }
2395     }
2396
2397     set_music_parameters(i, music->parameter);
2398   }
2399 }
2400
2401 static void ReinitializeGraphics()
2402 {
2403   print_timestamp_init("ReinitializeGraphics");
2404
2405   InitGraphicInfo();                    /* graphic properties mapping */
2406   print_timestamp_time("InitGraphicInfo");
2407   InitElementGraphicInfo();             /* element game graphic mapping */
2408   print_timestamp_time("InitElementGraphicInfo");
2409   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
2410   print_timestamp_time("InitElementSpecialGraphicInfo");
2411
2412   InitElementSmallImages();             /* scale elements to all needed sizes */
2413   print_timestamp_time("InitElementSmallImages");
2414   InitScaledImages();                   /* scale all other images, if needed */
2415   print_timestamp_time("InitScaledImages");
2416   InitFontGraphicInfo();                /* initialize text drawing functions */
2417   print_timestamp_time("InitFontGraphicInfo");
2418
2419   InitGraphicInfo_EM();                 /* graphic mapping for EM engine */
2420   print_timestamp_time("InitGraphicInfo_EM");
2421
2422   InitGraphicCompatibilityInfo();
2423   print_timestamp_time("InitGraphicCompatibilityInfo");
2424
2425   SetMainBackgroundImage(IMG_BACKGROUND);
2426   print_timestamp_time("SetMainBackgroundImage");
2427   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2428   print_timestamp_time("SetDoorBackgroundImage");
2429
2430   InitGadgets();
2431   print_timestamp_time("InitGadgets");
2432   InitToons();
2433   print_timestamp_time("InitToons");
2434   InitDoors();
2435   print_timestamp_time("InitDoors");
2436
2437   print_timestamp_done("ReinitializeGraphics");
2438 }
2439
2440 static void ReinitializeSounds()
2441 {
2442   InitSoundInfo();              /* sound properties mapping */
2443   InitElementSoundInfo();       /* element game sound mapping */
2444   InitGameModeSoundInfo();      /* game mode sound mapping */
2445
2446   InitPlayLevelSound();         /* internal game sound settings */
2447 }
2448
2449 static void ReinitializeMusic()
2450 {
2451   InitMusicInfo();              /* music properties mapping */
2452   InitGameModeMusicInfo();      /* game mode music mapping */
2453 }
2454
2455 static int get_special_property_bit(int element, int property_bit_nr)
2456 {
2457   struct PropertyBitInfo
2458   {
2459     int element;
2460     int bit_nr;
2461   };
2462
2463   static struct PropertyBitInfo pb_can_move_into_acid[] =
2464   {
2465     /* the player may be able fall into acid when gravity is activated */
2466     { EL_PLAYER_1,              0       },
2467     { EL_PLAYER_2,              0       },
2468     { EL_PLAYER_3,              0       },
2469     { EL_PLAYER_4,              0       },
2470     { EL_SP_MURPHY,             0       },
2471     { EL_SOKOBAN_FIELD_PLAYER,  0       },
2472
2473     /* all elements that can move may be able to also move into acid */
2474     { EL_BUG,                   1       },
2475     { EL_BUG_LEFT,              1       },
2476     { EL_BUG_RIGHT,             1       },
2477     { EL_BUG_UP,                1       },
2478     { EL_BUG_DOWN,              1       },
2479     { EL_SPACESHIP,             2       },
2480     { EL_SPACESHIP_LEFT,        2       },
2481     { EL_SPACESHIP_RIGHT,       2       },
2482     { EL_SPACESHIP_UP,          2       },
2483     { EL_SPACESHIP_DOWN,        2       },
2484     { EL_BD_BUTTERFLY,          3       },
2485     { EL_BD_BUTTERFLY_LEFT,     3       },
2486     { EL_BD_BUTTERFLY_RIGHT,    3       },
2487     { EL_BD_BUTTERFLY_UP,       3       },
2488     { EL_BD_BUTTERFLY_DOWN,     3       },
2489     { EL_BD_FIREFLY,            4       },
2490     { EL_BD_FIREFLY_LEFT,       4       },
2491     { EL_BD_FIREFLY_RIGHT,      4       },
2492     { EL_BD_FIREFLY_UP,         4       },
2493     { EL_BD_FIREFLY_DOWN,       4       },
2494     { EL_YAMYAM,                5       },
2495     { EL_YAMYAM_LEFT,           5       },
2496     { EL_YAMYAM_RIGHT,          5       },
2497     { EL_YAMYAM_UP,             5       },
2498     { EL_YAMYAM_DOWN,           5       },
2499     { EL_DARK_YAMYAM,           6       },
2500     { EL_ROBOT,                 7       },
2501     { EL_PACMAN,                8       },
2502     { EL_PACMAN_LEFT,           8       },
2503     { EL_PACMAN_RIGHT,          8       },
2504     { EL_PACMAN_UP,             8       },
2505     { EL_PACMAN_DOWN,           8       },
2506     { EL_MOLE,                  9       },
2507     { EL_MOLE_LEFT,             9       },
2508     { EL_MOLE_RIGHT,            9       },
2509     { EL_MOLE_UP,               9       },
2510     { EL_MOLE_DOWN,             9       },
2511     { EL_PENGUIN,               10      },
2512     { EL_PIG,                   11      },
2513     { EL_DRAGON,                12      },
2514     { EL_SATELLITE,             13      },
2515     { EL_SP_SNIKSNAK,           14      },
2516     { EL_SP_ELECTRON,           15      },
2517     { EL_BALLOON,               16      },
2518     { EL_SPRING,                17      },
2519     { EL_EMC_ANDROID,           18      },
2520
2521     { -1,                       -1      },
2522   };
2523
2524   static struct PropertyBitInfo pb_dont_collide_with[] =
2525   {
2526     { EL_SP_SNIKSNAK,           0       },
2527     { EL_SP_ELECTRON,           1       },
2528
2529     { -1,                       -1      },
2530   };
2531
2532   static struct
2533   {
2534     int bit_nr;
2535     struct PropertyBitInfo *pb_info;
2536   } pb_definition[] =
2537   {
2538     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
2539     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
2540
2541     { -1,                       NULL                    },
2542   };
2543
2544   struct PropertyBitInfo *pb_info = NULL;
2545   int i;
2546
2547   for (i = 0; pb_definition[i].bit_nr != -1; i++)
2548     if (pb_definition[i].bit_nr == property_bit_nr)
2549       pb_info = pb_definition[i].pb_info;
2550
2551   if (pb_info == NULL)
2552     return -1;
2553
2554   for (i = 0; pb_info[i].element != -1; i++)
2555     if (pb_info[i].element == element)
2556       return pb_info[i].bit_nr;
2557
2558   return -1;
2559 }
2560
2561 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2562                          boolean property_value)
2563 {
2564   int bit_nr = get_special_property_bit(element, property_bit_nr);
2565
2566   if (bit_nr > -1)
2567   {
2568     if (property_value)
2569       *bitfield |=  (1 << bit_nr);
2570     else
2571       *bitfield &= ~(1 << bit_nr);
2572   }
2573 }
2574
2575 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2576 {
2577   int bit_nr = get_special_property_bit(element, property_bit_nr);
2578
2579   if (bit_nr > -1)
2580     return ((*bitfield & (1 << bit_nr)) != 0);
2581
2582   return FALSE;
2583 }
2584
2585 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2586 {
2587   static int group_nr;
2588   static struct ElementGroupInfo *group;
2589   struct ElementGroupInfo *actual_group = element_info[group_element].group;
2590   int i;
2591
2592   if (actual_group == NULL)                     /* not yet initialized */
2593     return;
2594
2595   if (recursion_depth > NUM_GROUP_ELEMENTS)     /* recursion too deep */
2596   {
2597     Error(ERR_WARN, "recursion too deep when resolving group element %d",
2598           group_element - EL_GROUP_START + 1);
2599
2600     /* replace element which caused too deep recursion by question mark */
2601     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2602
2603     return;
2604   }
2605
2606   if (recursion_depth == 0)                     /* initialization */
2607   {
2608     group = actual_group;
2609     group_nr = GROUP_NR(group_element);
2610
2611     group->num_elements_resolved = 0;
2612     group->choice_pos = 0;
2613
2614     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2615       element_info[i].in_group[group_nr] = FALSE;
2616   }
2617
2618   for (i = 0; i < actual_group->num_elements; i++)
2619   {
2620     int element = actual_group->element[i];
2621
2622     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2623       break;
2624
2625     if (IS_GROUP_ELEMENT(element))
2626       ResolveGroupElementExt(element, recursion_depth + 1);
2627     else
2628     {
2629       group->element_resolved[group->num_elements_resolved++] = element;
2630       element_info[element].in_group[group_nr] = TRUE;
2631     }
2632   }
2633 }
2634
2635 void ResolveGroupElement(int group_element)
2636 {
2637   ResolveGroupElementExt(group_element, 0);
2638 }
2639
2640 void InitElementPropertiesStatic()
2641 {
2642   static boolean clipboard_elements_initialized = FALSE;
2643
2644   static int ep_diggable[] =
2645   {
2646     EL_SAND,
2647     EL_SP_BASE,
2648     EL_SP_BUGGY_BASE,
2649     EL_SP_BUGGY_BASE_ACTIVATING,
2650     EL_TRAP,
2651     EL_INVISIBLE_SAND,
2652     EL_INVISIBLE_SAND_ACTIVE,
2653     EL_EMC_GRASS,
2654
2655     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2656     /* (if amoeba can grow into anything diggable, maybe keep these out) */
2657 #if 0
2658     EL_LANDMINE,
2659     EL_DC_LANDMINE,
2660     EL_TRAP_ACTIVE,
2661     EL_SP_BUGGY_BASE_ACTIVE,
2662     EL_EMC_PLANT,
2663 #endif
2664
2665     -1
2666   };
2667
2668   static int ep_collectible_only[] =
2669   {
2670     EL_BD_DIAMOND,
2671     EL_EMERALD,
2672     EL_DIAMOND,
2673     EL_EMERALD_YELLOW,
2674     EL_EMERALD_RED,
2675     EL_EMERALD_PURPLE,
2676     EL_KEY_1,
2677     EL_KEY_2,
2678     EL_KEY_3,
2679     EL_KEY_4,
2680     EL_EM_KEY_1,
2681     EL_EM_KEY_2,
2682     EL_EM_KEY_3,
2683     EL_EM_KEY_4,
2684     EL_EMC_KEY_5,
2685     EL_EMC_KEY_6,
2686     EL_EMC_KEY_7,
2687     EL_EMC_KEY_8,
2688     EL_DYNAMITE,
2689     EL_EM_DYNAMITE,
2690     EL_DYNABOMB_INCREASE_NUMBER,
2691     EL_DYNABOMB_INCREASE_SIZE,
2692     EL_DYNABOMB_INCREASE_POWER,
2693     EL_SP_INFOTRON,
2694     EL_SP_DISK_RED,
2695     EL_PEARL,
2696     EL_CRYSTAL,
2697     EL_DC_KEY_WHITE,
2698     EL_SHIELD_NORMAL,
2699     EL_SHIELD_DEADLY,
2700     EL_EXTRA_TIME,
2701     EL_ENVELOPE_1,
2702     EL_ENVELOPE_2,
2703     EL_ENVELOPE_3,
2704     EL_ENVELOPE_4,
2705     EL_SPEED_PILL,
2706     EL_EMC_LENSES,
2707     EL_EMC_MAGNIFIER,
2708
2709 #if 0
2710     /* !!! handle separately !!! */
2711     EL_DC_LANDMINE,     /* deadly when running into, but can be snapped */
2712 #endif
2713
2714     -1
2715   };
2716
2717   static int ep_dont_run_into[] =
2718   {
2719     /* same elements as in 'ep_dont_touch' */
2720     EL_BUG,
2721     EL_SPACESHIP,
2722     EL_BD_BUTTERFLY,
2723     EL_BD_FIREFLY,
2724
2725     /* same elements as in 'ep_dont_collide_with' */
2726     EL_YAMYAM,
2727     EL_DARK_YAMYAM,
2728     EL_ROBOT,
2729     EL_PACMAN,
2730     EL_SP_SNIKSNAK,
2731     EL_SP_ELECTRON,
2732
2733     /* new elements */
2734     EL_AMOEBA_DROP,
2735     EL_ACID,
2736
2737     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2738 #if 1
2739     EL_LANDMINE,
2740     EL_DC_LANDMINE,
2741     EL_TRAP_ACTIVE,
2742     EL_SP_BUGGY_BASE_ACTIVE,
2743     EL_EMC_PLANT,
2744 #endif
2745
2746     -1
2747   };
2748
2749   static int ep_dont_collide_with[] =
2750   {
2751     /* same elements as in 'ep_dont_touch' */
2752     EL_BUG,
2753     EL_SPACESHIP,
2754     EL_BD_BUTTERFLY,
2755     EL_BD_FIREFLY,
2756
2757     /* new elements */
2758     EL_YAMYAM,
2759     EL_DARK_YAMYAM,
2760     EL_ROBOT,
2761     EL_PACMAN,
2762     EL_SP_SNIKSNAK,
2763     EL_SP_ELECTRON,
2764
2765     -1
2766   };
2767
2768   static int ep_dont_touch[] =
2769   {
2770     EL_BUG,
2771     EL_SPACESHIP,
2772     EL_BD_BUTTERFLY,
2773     EL_BD_FIREFLY,
2774
2775     -1
2776   };
2777
2778   static int ep_indestructible[] =
2779   {
2780     EL_STEELWALL,
2781     EL_ACID,
2782     EL_ACID_POOL_TOPLEFT,
2783     EL_ACID_POOL_TOPRIGHT,
2784     EL_ACID_POOL_BOTTOMLEFT,
2785     EL_ACID_POOL_BOTTOM,
2786     EL_ACID_POOL_BOTTOMRIGHT,
2787     EL_SP_HARDWARE_GRAY,
2788     EL_SP_HARDWARE_GREEN,
2789     EL_SP_HARDWARE_BLUE,
2790     EL_SP_HARDWARE_RED,
2791     EL_SP_HARDWARE_YELLOW,
2792     EL_SP_HARDWARE_BASE_1,
2793     EL_SP_HARDWARE_BASE_2,
2794     EL_SP_HARDWARE_BASE_3,
2795     EL_SP_HARDWARE_BASE_4,
2796     EL_SP_HARDWARE_BASE_5,
2797     EL_SP_HARDWARE_BASE_6,
2798     EL_INVISIBLE_STEELWALL,
2799     EL_INVISIBLE_STEELWALL_ACTIVE,
2800     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2801     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2802     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2803     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2804     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2805     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2806     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2807     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2808     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2809     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2810     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2811     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2812     EL_LIGHT_SWITCH,
2813     EL_LIGHT_SWITCH_ACTIVE,
2814     EL_SIGN_EXCLAMATION,
2815     EL_SIGN_RADIOACTIVITY,
2816     EL_SIGN_STOP,
2817     EL_SIGN_WHEELCHAIR,
2818     EL_SIGN_PARKING,
2819     EL_SIGN_NO_ENTRY,
2820     EL_SIGN_UNUSED_1,
2821     EL_SIGN_GIVE_WAY,
2822     EL_SIGN_ENTRY_FORBIDDEN,
2823     EL_SIGN_EMERGENCY_EXIT,
2824     EL_SIGN_YIN_YANG,
2825     EL_SIGN_UNUSED_2,
2826     EL_SIGN_SPERMS,
2827     EL_SIGN_BULLET,
2828     EL_SIGN_HEART,
2829     EL_SIGN_CROSS,
2830     EL_SIGN_FRANKIE,
2831     EL_STEEL_EXIT_CLOSED,
2832     EL_STEEL_EXIT_OPEN,
2833     EL_STEEL_EXIT_OPENING,
2834     EL_STEEL_EXIT_CLOSING,
2835     EL_EM_STEEL_EXIT_CLOSED,
2836     EL_EM_STEEL_EXIT_OPEN,
2837     EL_EM_STEEL_EXIT_OPENING,
2838     EL_EM_STEEL_EXIT_CLOSING,
2839     EL_DC_STEELWALL_1_LEFT,
2840     EL_DC_STEELWALL_1_RIGHT,
2841     EL_DC_STEELWALL_1_TOP,
2842     EL_DC_STEELWALL_1_BOTTOM,
2843     EL_DC_STEELWALL_1_HORIZONTAL,
2844     EL_DC_STEELWALL_1_VERTICAL,
2845     EL_DC_STEELWALL_1_TOPLEFT,
2846     EL_DC_STEELWALL_1_TOPRIGHT,
2847     EL_DC_STEELWALL_1_BOTTOMLEFT,
2848     EL_DC_STEELWALL_1_BOTTOMRIGHT,
2849     EL_DC_STEELWALL_1_TOPLEFT_2,
2850     EL_DC_STEELWALL_1_TOPRIGHT_2,
2851     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2852     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2853     EL_DC_STEELWALL_2_LEFT,
2854     EL_DC_STEELWALL_2_RIGHT,
2855     EL_DC_STEELWALL_2_TOP,
2856     EL_DC_STEELWALL_2_BOTTOM,
2857     EL_DC_STEELWALL_2_HORIZONTAL,
2858     EL_DC_STEELWALL_2_VERTICAL,
2859     EL_DC_STEELWALL_2_MIDDLE,
2860     EL_DC_STEELWALL_2_SINGLE,
2861     EL_STEELWALL_SLIPPERY,
2862     EL_EMC_STEELWALL_1,
2863     EL_EMC_STEELWALL_2,
2864     EL_EMC_STEELWALL_3,
2865     EL_EMC_STEELWALL_4,
2866     EL_CRYSTAL,
2867     EL_GATE_1,
2868     EL_GATE_2,
2869     EL_GATE_3,
2870     EL_GATE_4,
2871     EL_GATE_1_GRAY,
2872     EL_GATE_2_GRAY,
2873     EL_GATE_3_GRAY,
2874     EL_GATE_4_GRAY,
2875     EL_GATE_1_GRAY_ACTIVE,
2876     EL_GATE_2_GRAY_ACTIVE,
2877     EL_GATE_3_GRAY_ACTIVE,
2878     EL_GATE_4_GRAY_ACTIVE,
2879     EL_EM_GATE_1,
2880     EL_EM_GATE_2,
2881     EL_EM_GATE_3,
2882     EL_EM_GATE_4,
2883     EL_EM_GATE_1_GRAY,
2884     EL_EM_GATE_2_GRAY,
2885     EL_EM_GATE_3_GRAY,
2886     EL_EM_GATE_4_GRAY,
2887     EL_EM_GATE_1_GRAY_ACTIVE,
2888     EL_EM_GATE_2_GRAY_ACTIVE,
2889     EL_EM_GATE_3_GRAY_ACTIVE,
2890     EL_EM_GATE_4_GRAY_ACTIVE,
2891     EL_EMC_GATE_5,
2892     EL_EMC_GATE_6,
2893     EL_EMC_GATE_7,
2894     EL_EMC_GATE_8,
2895     EL_EMC_GATE_5_GRAY,
2896     EL_EMC_GATE_6_GRAY,
2897     EL_EMC_GATE_7_GRAY,
2898     EL_EMC_GATE_8_GRAY,
2899     EL_EMC_GATE_5_GRAY_ACTIVE,
2900     EL_EMC_GATE_6_GRAY_ACTIVE,
2901     EL_EMC_GATE_7_GRAY_ACTIVE,
2902     EL_EMC_GATE_8_GRAY_ACTIVE,
2903     EL_DC_GATE_WHITE,
2904     EL_DC_GATE_WHITE_GRAY,
2905     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2906     EL_DC_GATE_FAKE_GRAY,
2907     EL_SWITCHGATE_OPEN,
2908     EL_SWITCHGATE_OPENING,
2909     EL_SWITCHGATE_CLOSED,
2910     EL_SWITCHGATE_CLOSING,
2911 #if 1
2912     EL_DC_SWITCHGATE_SWITCH_UP,
2913     EL_DC_SWITCHGATE_SWITCH_DOWN,
2914 #endif
2915     EL_TIMEGATE_OPEN,
2916     EL_TIMEGATE_OPENING,
2917     EL_TIMEGATE_CLOSED,
2918     EL_TIMEGATE_CLOSING,
2919 #if 1
2920     EL_DC_TIMEGATE_SWITCH,
2921     EL_DC_TIMEGATE_SWITCH_ACTIVE,
2922 #endif
2923     EL_TUBE_ANY,
2924     EL_TUBE_VERTICAL,
2925     EL_TUBE_HORIZONTAL,
2926     EL_TUBE_VERTICAL_LEFT,
2927     EL_TUBE_VERTICAL_RIGHT,
2928     EL_TUBE_HORIZONTAL_UP,
2929     EL_TUBE_HORIZONTAL_DOWN,
2930     EL_TUBE_LEFT_UP,
2931     EL_TUBE_LEFT_DOWN,
2932     EL_TUBE_RIGHT_UP,
2933     EL_TUBE_RIGHT_DOWN,
2934     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2935     EL_EXPANDABLE_STEELWALL_VERTICAL,
2936     EL_EXPANDABLE_STEELWALL_ANY,
2937
2938     -1
2939   };
2940
2941   static int ep_slippery[] =
2942   {
2943     EL_WALL_SLIPPERY,
2944     EL_BD_WALL,
2945     EL_ROCK,
2946     EL_BD_ROCK,
2947     EL_EMERALD,
2948     EL_BD_DIAMOND,
2949     EL_EMERALD_YELLOW,
2950     EL_EMERALD_RED,
2951     EL_EMERALD_PURPLE,
2952     EL_DIAMOND,
2953     EL_BOMB,
2954     EL_NUT,
2955     EL_ROBOT_WHEEL_ACTIVE,
2956     EL_ROBOT_WHEEL,
2957     EL_TIME_ORB_FULL,
2958     EL_TIME_ORB_EMPTY,
2959     EL_LAMP_ACTIVE,
2960     EL_LAMP,
2961     EL_ACID_POOL_TOPLEFT,
2962     EL_ACID_POOL_TOPRIGHT,
2963     EL_SATELLITE,
2964     EL_SP_ZONK,
2965     EL_SP_INFOTRON,
2966     EL_SP_CHIP_SINGLE,
2967     EL_SP_CHIP_LEFT,
2968     EL_SP_CHIP_RIGHT,
2969     EL_SP_CHIP_TOP,
2970     EL_SP_CHIP_BOTTOM,
2971     EL_SPEED_PILL,
2972     EL_STEELWALL_SLIPPERY,
2973     EL_PEARL,
2974     EL_CRYSTAL,
2975     EL_EMC_WALL_SLIPPERY_1,
2976     EL_EMC_WALL_SLIPPERY_2,
2977     EL_EMC_WALL_SLIPPERY_3,
2978     EL_EMC_WALL_SLIPPERY_4,
2979     EL_EMC_MAGIC_BALL,
2980     EL_EMC_MAGIC_BALL_ACTIVE,
2981
2982     -1
2983   };
2984
2985   static int ep_can_change[] =
2986   {
2987     -1
2988   };
2989
2990   static int ep_can_move[] =
2991   {
2992     /* same elements as in 'pb_can_move_into_acid' */
2993     EL_BUG,
2994     EL_SPACESHIP,
2995     EL_BD_BUTTERFLY,
2996     EL_BD_FIREFLY,
2997     EL_YAMYAM,
2998     EL_DARK_YAMYAM,
2999     EL_ROBOT,
3000     EL_PACMAN,
3001     EL_MOLE,
3002     EL_PENGUIN,
3003     EL_PIG,
3004     EL_DRAGON,
3005     EL_SATELLITE,
3006     EL_SP_SNIKSNAK,
3007     EL_SP_ELECTRON,
3008     EL_BALLOON,
3009     EL_SPRING,
3010     EL_EMC_ANDROID,
3011
3012     -1
3013   };
3014
3015   static int ep_can_fall[] =
3016   {
3017     EL_ROCK,
3018     EL_BD_ROCK,
3019     EL_EMERALD,
3020     EL_BD_DIAMOND,
3021     EL_EMERALD_YELLOW,
3022     EL_EMERALD_RED,
3023     EL_EMERALD_PURPLE,
3024     EL_DIAMOND,
3025     EL_BOMB,
3026     EL_NUT,
3027     EL_AMOEBA_DROP,
3028     EL_QUICKSAND_FULL,
3029     EL_QUICKSAND_FAST_FULL,
3030     EL_MAGIC_WALL_FULL,
3031     EL_BD_MAGIC_WALL_FULL,
3032     EL_DC_MAGIC_WALL_FULL,
3033     EL_TIME_ORB_FULL,
3034     EL_TIME_ORB_EMPTY,
3035     EL_SP_ZONK,
3036     EL_SP_INFOTRON,
3037     EL_SP_DISK_ORANGE,
3038     EL_PEARL,
3039     EL_CRYSTAL,
3040     EL_SPRING,
3041     EL_DX_SUPABOMB,
3042
3043     -1
3044   };
3045
3046   static int ep_can_smash_player[] =
3047   {
3048     EL_ROCK,
3049     EL_BD_ROCK,
3050     EL_EMERALD,
3051     EL_BD_DIAMOND,
3052     EL_EMERALD_YELLOW,
3053     EL_EMERALD_RED,
3054     EL_EMERALD_PURPLE,
3055     EL_DIAMOND,
3056     EL_BOMB,
3057     EL_NUT,
3058     EL_AMOEBA_DROP,
3059     EL_TIME_ORB_FULL,
3060     EL_TIME_ORB_EMPTY,
3061     EL_SP_ZONK,
3062     EL_SP_INFOTRON,
3063     EL_SP_DISK_ORANGE,
3064     EL_PEARL,
3065     EL_CRYSTAL,
3066     EL_SPRING,
3067     EL_DX_SUPABOMB,
3068
3069     -1
3070   };
3071
3072   static int ep_can_smash_enemies[] =
3073   {
3074     EL_ROCK,
3075     EL_BD_ROCK,
3076     EL_SP_ZONK,
3077
3078     -1
3079   };
3080
3081   static int ep_can_smash_everything[] =
3082   {
3083     EL_ROCK,
3084     EL_BD_ROCK,
3085     EL_SP_ZONK,
3086
3087     -1
3088   };
3089
3090   static int ep_explodes_by_fire[] =
3091   {
3092     /* same elements as in 'ep_explodes_impact' */
3093     EL_BOMB,
3094     EL_SP_DISK_ORANGE,
3095     EL_DX_SUPABOMB,
3096
3097     /* same elements as in 'ep_explodes_smashed' */
3098     EL_SATELLITE,
3099     EL_PIG,
3100     EL_DRAGON,
3101     EL_MOLE,
3102
3103     /* new elements */
3104     EL_DYNAMITE,
3105     EL_DYNAMITE_ACTIVE,
3106     EL_EM_DYNAMITE,
3107     EL_EM_DYNAMITE_ACTIVE,
3108     EL_DYNABOMB_PLAYER_1_ACTIVE,
3109     EL_DYNABOMB_PLAYER_2_ACTIVE,
3110     EL_DYNABOMB_PLAYER_3_ACTIVE,
3111     EL_DYNABOMB_PLAYER_4_ACTIVE,
3112     EL_DYNABOMB_INCREASE_NUMBER,
3113     EL_DYNABOMB_INCREASE_SIZE,
3114     EL_DYNABOMB_INCREASE_POWER,
3115     EL_SP_DISK_RED_ACTIVE,
3116     EL_BUG,
3117     EL_PENGUIN,
3118     EL_SP_DISK_RED,
3119     EL_SP_DISK_YELLOW,
3120     EL_SP_SNIKSNAK,
3121     EL_SP_ELECTRON,
3122 #if 0
3123     EL_BLACK_ORB,
3124 #endif
3125
3126     -1
3127   };
3128
3129   static int ep_explodes_smashed[] =
3130   {
3131     /* same elements as in 'ep_explodes_impact' */
3132     EL_BOMB,
3133     EL_SP_DISK_ORANGE,
3134     EL_DX_SUPABOMB,
3135
3136     /* new elements */
3137     EL_SATELLITE,
3138     EL_PIG,
3139     EL_DRAGON,
3140     EL_MOLE,
3141
3142     -1
3143   };
3144
3145   static int ep_explodes_impact[] =
3146   {
3147     EL_BOMB,
3148     EL_SP_DISK_ORANGE,
3149     EL_DX_SUPABOMB,
3150
3151     -1
3152   };
3153
3154   static int ep_walkable_over[] =
3155   {
3156     EL_EMPTY_SPACE,
3157     EL_SP_EMPTY_SPACE,
3158     EL_SOKOBAN_FIELD_EMPTY,
3159     EL_EXIT_OPEN,
3160     EL_EM_EXIT_OPEN,
3161 #if 1
3162     EL_EM_EXIT_OPENING,
3163 #endif
3164     EL_SP_EXIT_OPEN,
3165     EL_SP_EXIT_OPENING,
3166     EL_STEEL_EXIT_OPEN,
3167     EL_EM_STEEL_EXIT_OPEN,
3168 #if 1
3169     EL_EM_STEEL_EXIT_OPENING,
3170 #endif
3171     EL_GATE_1,
3172     EL_GATE_2,
3173     EL_GATE_3,
3174     EL_GATE_4,
3175     EL_GATE_1_GRAY,
3176     EL_GATE_2_GRAY,
3177     EL_GATE_3_GRAY,
3178     EL_GATE_4_GRAY,
3179     EL_GATE_1_GRAY_ACTIVE,
3180     EL_GATE_2_GRAY_ACTIVE,
3181     EL_GATE_3_GRAY_ACTIVE,
3182     EL_GATE_4_GRAY_ACTIVE,
3183     EL_PENGUIN,
3184     EL_PIG,
3185     EL_DRAGON,
3186
3187     -1
3188   };
3189
3190   static int ep_walkable_inside[] =
3191   {
3192     EL_TUBE_ANY,
3193     EL_TUBE_VERTICAL,
3194     EL_TUBE_HORIZONTAL,
3195     EL_TUBE_VERTICAL_LEFT,
3196     EL_TUBE_VERTICAL_RIGHT,
3197     EL_TUBE_HORIZONTAL_UP,
3198     EL_TUBE_HORIZONTAL_DOWN,
3199     EL_TUBE_LEFT_UP,
3200     EL_TUBE_LEFT_DOWN,
3201     EL_TUBE_RIGHT_UP,
3202     EL_TUBE_RIGHT_DOWN,
3203
3204     -1
3205   };
3206
3207   static int ep_walkable_under[] =
3208   {
3209     -1
3210   };
3211
3212   static int ep_passable_over[] =
3213   {
3214     EL_EM_GATE_1,
3215     EL_EM_GATE_2,
3216     EL_EM_GATE_3,
3217     EL_EM_GATE_4,
3218     EL_EM_GATE_1_GRAY,
3219     EL_EM_GATE_2_GRAY,
3220     EL_EM_GATE_3_GRAY,
3221     EL_EM_GATE_4_GRAY,
3222     EL_EM_GATE_1_GRAY_ACTIVE,
3223     EL_EM_GATE_2_GRAY_ACTIVE,
3224     EL_EM_GATE_3_GRAY_ACTIVE,
3225     EL_EM_GATE_4_GRAY_ACTIVE,
3226     EL_EMC_GATE_5,
3227     EL_EMC_GATE_6,
3228     EL_EMC_GATE_7,
3229     EL_EMC_GATE_8,
3230     EL_EMC_GATE_5_GRAY,
3231     EL_EMC_GATE_6_GRAY,
3232     EL_EMC_GATE_7_GRAY,
3233     EL_EMC_GATE_8_GRAY,
3234     EL_EMC_GATE_5_GRAY_ACTIVE,
3235     EL_EMC_GATE_6_GRAY_ACTIVE,
3236     EL_EMC_GATE_7_GRAY_ACTIVE,
3237     EL_EMC_GATE_8_GRAY_ACTIVE,
3238     EL_DC_GATE_WHITE,
3239     EL_DC_GATE_WHITE_GRAY,
3240     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3241     EL_SWITCHGATE_OPEN,
3242     EL_TIMEGATE_OPEN,
3243
3244     -1
3245   };
3246
3247   static int ep_passable_inside[] =
3248   {
3249     EL_SP_PORT_LEFT,
3250     EL_SP_PORT_RIGHT,
3251     EL_SP_PORT_UP,
3252     EL_SP_PORT_DOWN,
3253     EL_SP_PORT_HORIZONTAL,
3254     EL_SP_PORT_VERTICAL,
3255     EL_SP_PORT_ANY,
3256     EL_SP_GRAVITY_PORT_LEFT,
3257     EL_SP_GRAVITY_PORT_RIGHT,
3258     EL_SP_GRAVITY_PORT_UP,
3259     EL_SP_GRAVITY_PORT_DOWN,
3260     EL_SP_GRAVITY_ON_PORT_LEFT,
3261     EL_SP_GRAVITY_ON_PORT_RIGHT,
3262     EL_SP_GRAVITY_ON_PORT_UP,
3263     EL_SP_GRAVITY_ON_PORT_DOWN,
3264     EL_SP_GRAVITY_OFF_PORT_LEFT,
3265     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3266     EL_SP_GRAVITY_OFF_PORT_UP,
3267     EL_SP_GRAVITY_OFF_PORT_DOWN,
3268
3269     -1
3270   };
3271
3272   static int ep_passable_under[] =
3273   {
3274     -1
3275   };
3276
3277   static int ep_droppable[] =
3278   {
3279     -1
3280   };
3281
3282   static int ep_explodes_1x1_old[] =
3283   {
3284     -1
3285   };
3286
3287   static int ep_pushable[] =
3288   {
3289     EL_ROCK,
3290     EL_BOMB,
3291     EL_DX_SUPABOMB,
3292     EL_NUT,
3293     EL_TIME_ORB_EMPTY,
3294     EL_SP_ZONK,
3295     EL_SP_DISK_ORANGE,
3296     EL_SPRING,
3297     EL_BD_ROCK,
3298     EL_SOKOBAN_OBJECT,
3299     EL_SOKOBAN_FIELD_FULL,
3300     EL_SATELLITE,
3301     EL_SP_DISK_YELLOW,
3302     EL_BALLOON,
3303     EL_EMC_ANDROID,
3304
3305     -1
3306   };
3307
3308   static int ep_explodes_cross_old[] =
3309   {
3310     -1
3311   };
3312
3313   static int ep_protected[] =
3314   {
3315     /* same elements as in 'ep_walkable_inside' */
3316     EL_TUBE_ANY,
3317     EL_TUBE_VERTICAL,
3318     EL_TUBE_HORIZONTAL,
3319     EL_TUBE_VERTICAL_LEFT,
3320     EL_TUBE_VERTICAL_RIGHT,
3321     EL_TUBE_HORIZONTAL_UP,
3322     EL_TUBE_HORIZONTAL_DOWN,
3323     EL_TUBE_LEFT_UP,
3324     EL_TUBE_LEFT_DOWN,
3325     EL_TUBE_RIGHT_UP,
3326     EL_TUBE_RIGHT_DOWN,
3327
3328     /* same elements as in 'ep_passable_over' */
3329     EL_EM_GATE_1,
3330     EL_EM_GATE_2,
3331     EL_EM_GATE_3,
3332     EL_EM_GATE_4,
3333     EL_EM_GATE_1_GRAY,
3334     EL_EM_GATE_2_GRAY,
3335     EL_EM_GATE_3_GRAY,
3336     EL_EM_GATE_4_GRAY,
3337     EL_EM_GATE_1_GRAY_ACTIVE,
3338     EL_EM_GATE_2_GRAY_ACTIVE,
3339     EL_EM_GATE_3_GRAY_ACTIVE,
3340     EL_EM_GATE_4_GRAY_ACTIVE,
3341     EL_EMC_GATE_5,
3342     EL_EMC_GATE_6,
3343     EL_EMC_GATE_7,
3344     EL_EMC_GATE_8,
3345     EL_EMC_GATE_5_GRAY,
3346     EL_EMC_GATE_6_GRAY,
3347     EL_EMC_GATE_7_GRAY,
3348     EL_EMC_GATE_8_GRAY,
3349     EL_EMC_GATE_5_GRAY_ACTIVE,
3350     EL_EMC_GATE_6_GRAY_ACTIVE,
3351     EL_EMC_GATE_7_GRAY_ACTIVE,
3352     EL_EMC_GATE_8_GRAY_ACTIVE,
3353     EL_DC_GATE_WHITE,
3354     EL_DC_GATE_WHITE_GRAY,
3355     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3356     EL_SWITCHGATE_OPEN,
3357     EL_TIMEGATE_OPEN,
3358
3359     /* same elements as in 'ep_passable_inside' */
3360     EL_SP_PORT_LEFT,
3361     EL_SP_PORT_RIGHT,
3362     EL_SP_PORT_UP,
3363     EL_SP_PORT_DOWN,
3364     EL_SP_PORT_HORIZONTAL,
3365     EL_SP_PORT_VERTICAL,
3366     EL_SP_PORT_ANY,
3367     EL_SP_GRAVITY_PORT_LEFT,
3368     EL_SP_GRAVITY_PORT_RIGHT,
3369     EL_SP_GRAVITY_PORT_UP,
3370     EL_SP_GRAVITY_PORT_DOWN,
3371     EL_SP_GRAVITY_ON_PORT_LEFT,
3372     EL_SP_GRAVITY_ON_PORT_RIGHT,
3373     EL_SP_GRAVITY_ON_PORT_UP,
3374     EL_SP_GRAVITY_ON_PORT_DOWN,
3375     EL_SP_GRAVITY_OFF_PORT_LEFT,
3376     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3377     EL_SP_GRAVITY_OFF_PORT_UP,
3378     EL_SP_GRAVITY_OFF_PORT_DOWN,
3379
3380     -1
3381   };
3382
3383   static int ep_throwable[] =
3384   {
3385     -1
3386   };
3387
3388   static int ep_can_explode[] =
3389   {
3390     /* same elements as in 'ep_explodes_impact' */
3391     EL_BOMB,
3392     EL_SP_DISK_ORANGE,
3393     EL_DX_SUPABOMB,
3394
3395     /* same elements as in 'ep_explodes_smashed' */
3396     EL_SATELLITE,
3397     EL_PIG,
3398     EL_DRAGON,
3399     EL_MOLE,
3400
3401     /* elements that can explode by explosion or by dragonfire */
3402     EL_DYNAMITE,
3403     EL_DYNAMITE_ACTIVE,
3404     EL_EM_DYNAMITE,
3405     EL_EM_DYNAMITE_ACTIVE,
3406     EL_DYNABOMB_PLAYER_1_ACTIVE,
3407     EL_DYNABOMB_PLAYER_2_ACTIVE,
3408     EL_DYNABOMB_PLAYER_3_ACTIVE,
3409     EL_DYNABOMB_PLAYER_4_ACTIVE,
3410     EL_DYNABOMB_INCREASE_NUMBER,
3411     EL_DYNABOMB_INCREASE_SIZE,
3412     EL_DYNABOMB_INCREASE_POWER,
3413     EL_SP_DISK_RED_ACTIVE,
3414     EL_BUG,
3415     EL_PENGUIN,
3416     EL_SP_DISK_RED,
3417     EL_SP_DISK_YELLOW,
3418     EL_SP_SNIKSNAK,
3419     EL_SP_ELECTRON,
3420
3421     /* elements that can explode only by explosion */
3422     EL_BLACK_ORB,
3423
3424     -1
3425   };
3426
3427   static int ep_gravity_reachable[] =
3428   {
3429     EL_SAND,
3430     EL_SP_BASE,
3431     EL_TRAP,
3432     EL_INVISIBLE_SAND,
3433     EL_INVISIBLE_SAND_ACTIVE,
3434     EL_SP_PORT_LEFT,
3435     EL_SP_PORT_RIGHT,
3436     EL_SP_PORT_UP,
3437     EL_SP_PORT_DOWN,
3438     EL_SP_PORT_HORIZONTAL,
3439     EL_SP_PORT_VERTICAL,
3440     EL_SP_PORT_ANY,
3441     EL_SP_GRAVITY_PORT_LEFT,
3442     EL_SP_GRAVITY_PORT_RIGHT,
3443     EL_SP_GRAVITY_PORT_UP,
3444     EL_SP_GRAVITY_PORT_DOWN,
3445     EL_SP_GRAVITY_ON_PORT_LEFT,
3446     EL_SP_GRAVITY_ON_PORT_RIGHT,
3447     EL_SP_GRAVITY_ON_PORT_UP,
3448     EL_SP_GRAVITY_ON_PORT_DOWN,
3449     EL_SP_GRAVITY_OFF_PORT_LEFT,
3450     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3451     EL_SP_GRAVITY_OFF_PORT_UP,
3452     EL_SP_GRAVITY_OFF_PORT_DOWN,
3453     EL_EMC_GRASS,
3454
3455     -1
3456   };
3457
3458   static int ep_player[] =
3459   {
3460     EL_PLAYER_1,
3461     EL_PLAYER_2,
3462     EL_PLAYER_3,
3463     EL_PLAYER_4,
3464     EL_SP_MURPHY,
3465     EL_SOKOBAN_FIELD_PLAYER,
3466     EL_TRIGGER_PLAYER,
3467
3468     -1
3469   };
3470
3471   static int ep_can_pass_magic_wall[] =
3472   {
3473     EL_ROCK,
3474     EL_BD_ROCK,
3475     EL_EMERALD,
3476     EL_BD_DIAMOND,
3477     EL_EMERALD_YELLOW,
3478     EL_EMERALD_RED,
3479     EL_EMERALD_PURPLE,
3480     EL_DIAMOND,
3481
3482     -1
3483   };
3484
3485   static int ep_can_pass_dc_magic_wall[] =
3486   {
3487     EL_ROCK,
3488     EL_BD_ROCK,
3489     EL_EMERALD,
3490     EL_BD_DIAMOND,
3491     EL_EMERALD_YELLOW,
3492     EL_EMERALD_RED,
3493     EL_EMERALD_PURPLE,
3494     EL_DIAMOND,
3495     EL_PEARL,
3496     EL_CRYSTAL,
3497
3498     -1
3499   };
3500
3501   static int ep_switchable[] =
3502   {
3503     EL_ROBOT_WHEEL,
3504     EL_SP_TERMINAL,
3505     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3506     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3507     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3508     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3509     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3510     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3511     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3512     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3513     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3514     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3515     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3516     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3517     EL_SWITCHGATE_SWITCH_UP,
3518     EL_SWITCHGATE_SWITCH_DOWN,
3519     EL_DC_SWITCHGATE_SWITCH_UP,
3520     EL_DC_SWITCHGATE_SWITCH_DOWN,
3521     EL_LIGHT_SWITCH,
3522     EL_LIGHT_SWITCH_ACTIVE,
3523     EL_TIMEGATE_SWITCH,
3524     EL_DC_TIMEGATE_SWITCH,
3525     EL_BALLOON_SWITCH_LEFT,
3526     EL_BALLOON_SWITCH_RIGHT,
3527     EL_BALLOON_SWITCH_UP,
3528     EL_BALLOON_SWITCH_DOWN,
3529     EL_BALLOON_SWITCH_ANY,
3530     EL_BALLOON_SWITCH_NONE,
3531     EL_LAMP,
3532     EL_TIME_ORB_FULL,
3533     EL_EMC_MAGIC_BALL_SWITCH,
3534     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3535
3536     -1
3537   };
3538
3539   static int ep_bd_element[] =
3540   {
3541     EL_EMPTY,
3542     EL_SAND,
3543     EL_WALL_SLIPPERY,
3544     EL_BD_WALL,
3545     EL_ROCK,
3546     EL_BD_ROCK,
3547     EL_BD_DIAMOND,
3548     EL_BD_MAGIC_WALL,
3549     EL_EXIT_CLOSED,
3550     EL_EXIT_OPEN,
3551     EL_STEELWALL,
3552     EL_PLAYER_1,
3553     EL_PLAYER_2,
3554     EL_PLAYER_3,
3555     EL_PLAYER_4,
3556     EL_BD_FIREFLY,
3557     EL_BD_FIREFLY_1,
3558     EL_BD_FIREFLY_2,
3559     EL_BD_FIREFLY_3,
3560     EL_BD_FIREFLY_4,
3561     EL_BD_BUTTERFLY,
3562     EL_BD_BUTTERFLY_1,
3563     EL_BD_BUTTERFLY_2,
3564     EL_BD_BUTTERFLY_3,
3565     EL_BD_BUTTERFLY_4,
3566     EL_BD_AMOEBA,
3567     EL_CHAR_QUESTION,
3568     EL_UNKNOWN,
3569
3570     -1
3571   };
3572
3573   static int ep_sp_element[] =
3574   {
3575     /* should always be valid */
3576     EL_EMPTY,
3577
3578     /* standard classic Supaplex elements */
3579     EL_SP_EMPTY,
3580     EL_SP_ZONK,
3581     EL_SP_BASE,
3582     EL_SP_MURPHY,
3583     EL_SP_INFOTRON,
3584     EL_SP_CHIP_SINGLE,
3585     EL_SP_HARDWARE_GRAY,
3586     EL_SP_EXIT_CLOSED,
3587     EL_SP_EXIT_OPEN,
3588     EL_SP_DISK_ORANGE,
3589     EL_SP_PORT_RIGHT,
3590     EL_SP_PORT_DOWN,
3591     EL_SP_PORT_LEFT,
3592     EL_SP_PORT_UP,
3593     EL_SP_GRAVITY_PORT_RIGHT,
3594     EL_SP_GRAVITY_PORT_DOWN,
3595     EL_SP_GRAVITY_PORT_LEFT,
3596     EL_SP_GRAVITY_PORT_UP,
3597     EL_SP_SNIKSNAK,
3598     EL_SP_DISK_YELLOW,
3599     EL_SP_TERMINAL,
3600     EL_SP_DISK_RED,
3601     EL_SP_PORT_VERTICAL,
3602     EL_SP_PORT_HORIZONTAL,
3603     EL_SP_PORT_ANY,
3604     EL_SP_ELECTRON,
3605     EL_SP_BUGGY_BASE,
3606     EL_SP_CHIP_LEFT,
3607     EL_SP_CHIP_RIGHT,
3608     EL_SP_HARDWARE_BASE_1,
3609     EL_SP_HARDWARE_GREEN,
3610     EL_SP_HARDWARE_BLUE,
3611     EL_SP_HARDWARE_RED,
3612     EL_SP_HARDWARE_YELLOW,
3613     EL_SP_HARDWARE_BASE_2,
3614     EL_SP_HARDWARE_BASE_3,
3615     EL_SP_HARDWARE_BASE_4,
3616     EL_SP_HARDWARE_BASE_5,
3617     EL_SP_HARDWARE_BASE_6,
3618     EL_SP_CHIP_TOP,
3619     EL_SP_CHIP_BOTTOM,
3620
3621     /* additional elements that appeared in newer Supaplex levels */
3622     EL_INVISIBLE_WALL,
3623
3624     /* additional gravity port elements (not switching, but setting gravity) */
3625     EL_SP_GRAVITY_ON_PORT_LEFT,
3626     EL_SP_GRAVITY_ON_PORT_RIGHT,
3627     EL_SP_GRAVITY_ON_PORT_UP,
3628     EL_SP_GRAVITY_ON_PORT_DOWN,
3629     EL_SP_GRAVITY_OFF_PORT_LEFT,
3630     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3631     EL_SP_GRAVITY_OFF_PORT_UP,
3632     EL_SP_GRAVITY_OFF_PORT_DOWN,
3633
3634     /* more than one Murphy in a level results in an inactive clone */
3635     EL_SP_MURPHY_CLONE,
3636
3637     /* runtime Supaplex elements */
3638     EL_SP_DISK_RED_ACTIVE,
3639     EL_SP_TERMINAL_ACTIVE,
3640     EL_SP_BUGGY_BASE_ACTIVATING,
3641     EL_SP_BUGGY_BASE_ACTIVE,
3642     EL_SP_EXIT_OPENING,
3643     EL_SP_EXIT_CLOSING,
3644
3645     -1
3646   };
3647
3648   static int ep_sb_element[] =
3649   {
3650     EL_EMPTY,
3651     EL_STEELWALL,
3652     EL_SOKOBAN_OBJECT,
3653     EL_SOKOBAN_FIELD_EMPTY,
3654     EL_SOKOBAN_FIELD_FULL,
3655     EL_SOKOBAN_FIELD_PLAYER,
3656     EL_PLAYER_1,
3657     EL_PLAYER_2,
3658     EL_PLAYER_3,
3659     EL_PLAYER_4,
3660     EL_INVISIBLE_STEELWALL,
3661
3662     -1
3663   };
3664
3665   static int ep_gem[] =
3666   {
3667     EL_BD_DIAMOND,
3668     EL_EMERALD,
3669     EL_EMERALD_YELLOW,
3670     EL_EMERALD_RED,
3671     EL_EMERALD_PURPLE,
3672     EL_DIAMOND,
3673
3674     -1
3675   };
3676
3677   static int ep_food_dark_yamyam[] =
3678   {
3679     EL_SAND,
3680     EL_BUG,
3681     EL_SPACESHIP,
3682     EL_BD_BUTTERFLY,
3683     EL_BD_FIREFLY,
3684     EL_YAMYAM,
3685     EL_ROBOT,
3686     EL_PACMAN,
3687     EL_AMOEBA_DROP,
3688     EL_AMOEBA_DEAD,
3689     EL_AMOEBA_WET,
3690     EL_AMOEBA_DRY,
3691     EL_AMOEBA_FULL,
3692     EL_BD_AMOEBA,
3693     EL_EMERALD,
3694     EL_BD_DIAMOND,
3695     EL_EMERALD_YELLOW,
3696     EL_EMERALD_RED,
3697     EL_EMERALD_PURPLE,
3698     EL_DIAMOND,
3699     EL_PEARL,
3700     EL_CRYSTAL,
3701
3702     -1
3703   };
3704
3705   static int ep_food_penguin[] =
3706   {
3707     EL_EMERALD,
3708     EL_BD_DIAMOND,
3709     EL_EMERALD_YELLOW,
3710     EL_EMERALD_RED,
3711     EL_EMERALD_PURPLE,
3712     EL_DIAMOND,
3713     EL_PEARL,
3714     EL_CRYSTAL,
3715
3716     -1
3717   };
3718
3719   static int ep_food_pig[] =
3720   {
3721     EL_EMERALD,
3722     EL_BD_DIAMOND,
3723     EL_EMERALD_YELLOW,
3724     EL_EMERALD_RED,
3725     EL_EMERALD_PURPLE,
3726     EL_DIAMOND,
3727
3728     -1
3729   };
3730
3731   static int ep_historic_wall[] =
3732   {
3733     EL_STEELWALL,
3734     EL_GATE_1,
3735     EL_GATE_2,
3736     EL_GATE_3,
3737     EL_GATE_4,
3738     EL_GATE_1_GRAY,
3739     EL_GATE_2_GRAY,
3740     EL_GATE_3_GRAY,
3741     EL_GATE_4_GRAY,
3742     EL_GATE_1_GRAY_ACTIVE,
3743     EL_GATE_2_GRAY_ACTIVE,
3744     EL_GATE_3_GRAY_ACTIVE,
3745     EL_GATE_4_GRAY_ACTIVE,
3746     EL_EM_GATE_1,
3747     EL_EM_GATE_2,
3748     EL_EM_GATE_3,
3749     EL_EM_GATE_4,
3750     EL_EM_GATE_1_GRAY,
3751     EL_EM_GATE_2_GRAY,
3752     EL_EM_GATE_3_GRAY,
3753     EL_EM_GATE_4_GRAY,
3754     EL_EM_GATE_1_GRAY_ACTIVE,
3755     EL_EM_GATE_2_GRAY_ACTIVE,
3756     EL_EM_GATE_3_GRAY_ACTIVE,
3757     EL_EM_GATE_4_GRAY_ACTIVE,
3758     EL_EXIT_CLOSED,
3759     EL_EXIT_OPENING,
3760     EL_EXIT_OPEN,
3761     EL_WALL,
3762     EL_WALL_SLIPPERY,
3763     EL_EXPANDABLE_WALL,
3764     EL_EXPANDABLE_WALL_HORIZONTAL,
3765     EL_EXPANDABLE_WALL_VERTICAL,
3766     EL_EXPANDABLE_WALL_ANY,
3767     EL_EXPANDABLE_WALL_GROWING,
3768     EL_BD_EXPANDABLE_WALL,
3769     EL_BD_WALL,
3770     EL_SP_CHIP_SINGLE,
3771     EL_SP_CHIP_LEFT,
3772     EL_SP_CHIP_RIGHT,
3773     EL_SP_CHIP_TOP,
3774     EL_SP_CHIP_BOTTOM,
3775     EL_SP_HARDWARE_GRAY,
3776     EL_SP_HARDWARE_GREEN,
3777     EL_SP_HARDWARE_BLUE,
3778     EL_SP_HARDWARE_RED,
3779     EL_SP_HARDWARE_YELLOW,
3780     EL_SP_HARDWARE_BASE_1,
3781     EL_SP_HARDWARE_BASE_2,
3782     EL_SP_HARDWARE_BASE_3,
3783     EL_SP_HARDWARE_BASE_4,
3784     EL_SP_HARDWARE_BASE_5,
3785     EL_SP_HARDWARE_BASE_6,
3786     EL_SP_TERMINAL,
3787     EL_SP_TERMINAL_ACTIVE,
3788     EL_SP_EXIT_CLOSED,
3789     EL_SP_EXIT_OPEN,
3790     EL_INVISIBLE_STEELWALL,
3791     EL_INVISIBLE_STEELWALL_ACTIVE,
3792     EL_INVISIBLE_WALL,
3793     EL_INVISIBLE_WALL_ACTIVE,
3794     EL_STEELWALL_SLIPPERY,
3795     EL_EMC_STEELWALL_1,
3796     EL_EMC_STEELWALL_2,
3797     EL_EMC_STEELWALL_3,
3798     EL_EMC_STEELWALL_4,
3799     EL_EMC_WALL_1,
3800     EL_EMC_WALL_2,
3801     EL_EMC_WALL_3,
3802     EL_EMC_WALL_4,
3803     EL_EMC_WALL_5,
3804     EL_EMC_WALL_6,
3805     EL_EMC_WALL_7,
3806     EL_EMC_WALL_8,
3807
3808     -1
3809   };
3810
3811   static int ep_historic_solid[] =
3812   {
3813     EL_WALL,
3814     EL_EXPANDABLE_WALL,
3815     EL_EXPANDABLE_WALL_HORIZONTAL,
3816     EL_EXPANDABLE_WALL_VERTICAL,
3817     EL_EXPANDABLE_WALL_ANY,
3818     EL_BD_EXPANDABLE_WALL,
3819     EL_BD_WALL,
3820     EL_WALL_SLIPPERY,
3821     EL_EXIT_CLOSED,
3822     EL_EXIT_OPENING,
3823     EL_EXIT_OPEN,
3824     EL_AMOEBA_DEAD,
3825     EL_AMOEBA_WET,
3826     EL_AMOEBA_DRY,
3827     EL_AMOEBA_FULL,
3828     EL_BD_AMOEBA,
3829     EL_QUICKSAND_EMPTY,
3830     EL_QUICKSAND_FULL,
3831     EL_QUICKSAND_FILLING,
3832     EL_QUICKSAND_EMPTYING,
3833     EL_MAGIC_WALL,
3834     EL_MAGIC_WALL_ACTIVE,
3835     EL_MAGIC_WALL_EMPTYING,
3836     EL_MAGIC_WALL_FILLING,
3837     EL_MAGIC_WALL_FULL,
3838     EL_MAGIC_WALL_DEAD,
3839     EL_BD_MAGIC_WALL,
3840     EL_BD_MAGIC_WALL_ACTIVE,
3841     EL_BD_MAGIC_WALL_EMPTYING,
3842     EL_BD_MAGIC_WALL_FULL,
3843     EL_BD_MAGIC_WALL_FILLING,
3844     EL_BD_MAGIC_WALL_DEAD,
3845     EL_GAME_OF_LIFE,
3846     EL_BIOMAZE,
3847     EL_SP_CHIP_SINGLE,
3848     EL_SP_CHIP_LEFT,
3849     EL_SP_CHIP_RIGHT,
3850     EL_SP_CHIP_TOP,
3851     EL_SP_CHIP_BOTTOM,
3852     EL_SP_TERMINAL,
3853     EL_SP_TERMINAL_ACTIVE,
3854     EL_SP_EXIT_CLOSED,
3855     EL_SP_EXIT_OPEN,
3856     EL_INVISIBLE_WALL,
3857     EL_INVISIBLE_WALL_ACTIVE,
3858     EL_SWITCHGATE_SWITCH_UP,
3859     EL_SWITCHGATE_SWITCH_DOWN,
3860     EL_DC_SWITCHGATE_SWITCH_UP,
3861     EL_DC_SWITCHGATE_SWITCH_DOWN,
3862     EL_TIMEGATE_SWITCH,
3863     EL_TIMEGATE_SWITCH_ACTIVE,
3864     EL_DC_TIMEGATE_SWITCH,
3865     EL_DC_TIMEGATE_SWITCH_ACTIVE,
3866     EL_EMC_WALL_1,
3867     EL_EMC_WALL_2,
3868     EL_EMC_WALL_3,
3869     EL_EMC_WALL_4,
3870     EL_EMC_WALL_5,
3871     EL_EMC_WALL_6,
3872     EL_EMC_WALL_7,
3873     EL_EMC_WALL_8,
3874     EL_WALL_PEARL,
3875     EL_WALL_CRYSTAL,
3876
3877     /* the following elements are a direct copy of "indestructible" elements,
3878        except "EL_ACID", which is "indestructible", but not "solid"! */
3879 #if 0
3880     EL_ACID,
3881 #endif
3882     EL_STEELWALL,
3883     EL_ACID_POOL_TOPLEFT,
3884     EL_ACID_POOL_TOPRIGHT,
3885     EL_ACID_POOL_BOTTOMLEFT,
3886     EL_ACID_POOL_BOTTOM,
3887     EL_ACID_POOL_BOTTOMRIGHT,
3888     EL_SP_HARDWARE_GRAY,
3889     EL_SP_HARDWARE_GREEN,
3890     EL_SP_HARDWARE_BLUE,
3891     EL_SP_HARDWARE_RED,
3892     EL_SP_HARDWARE_YELLOW,
3893     EL_SP_HARDWARE_BASE_1,
3894     EL_SP_HARDWARE_BASE_2,
3895     EL_SP_HARDWARE_BASE_3,
3896     EL_SP_HARDWARE_BASE_4,
3897     EL_SP_HARDWARE_BASE_5,
3898     EL_SP_HARDWARE_BASE_6,
3899     EL_INVISIBLE_STEELWALL,
3900     EL_INVISIBLE_STEELWALL_ACTIVE,
3901     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3902     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3903     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3904     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3905     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3906     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3907     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3908     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3909     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3910     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3911     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3912     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3913     EL_LIGHT_SWITCH,
3914     EL_LIGHT_SWITCH_ACTIVE,
3915     EL_SIGN_EXCLAMATION,
3916     EL_SIGN_RADIOACTIVITY,
3917     EL_SIGN_STOP,
3918     EL_SIGN_WHEELCHAIR,
3919     EL_SIGN_PARKING,
3920     EL_SIGN_NO_ENTRY,
3921     EL_SIGN_UNUSED_1,
3922     EL_SIGN_GIVE_WAY,
3923     EL_SIGN_ENTRY_FORBIDDEN,
3924     EL_SIGN_EMERGENCY_EXIT,
3925     EL_SIGN_YIN_YANG,
3926     EL_SIGN_UNUSED_2,
3927     EL_SIGN_SPERMS,
3928     EL_SIGN_BULLET,
3929     EL_SIGN_HEART,
3930     EL_SIGN_CROSS,
3931     EL_SIGN_FRANKIE,
3932     EL_STEEL_EXIT_CLOSED,
3933     EL_STEEL_EXIT_OPEN,
3934     EL_DC_STEELWALL_1_LEFT,
3935     EL_DC_STEELWALL_1_RIGHT,
3936     EL_DC_STEELWALL_1_TOP,
3937     EL_DC_STEELWALL_1_BOTTOM,
3938     EL_DC_STEELWALL_1_HORIZONTAL,
3939     EL_DC_STEELWALL_1_VERTICAL,
3940     EL_DC_STEELWALL_1_TOPLEFT,
3941     EL_DC_STEELWALL_1_TOPRIGHT,
3942     EL_DC_STEELWALL_1_BOTTOMLEFT,
3943     EL_DC_STEELWALL_1_BOTTOMRIGHT,
3944     EL_DC_STEELWALL_1_TOPLEFT_2,
3945     EL_DC_STEELWALL_1_TOPRIGHT_2,
3946     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3947     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3948     EL_DC_STEELWALL_2_LEFT,
3949     EL_DC_STEELWALL_2_RIGHT,
3950     EL_DC_STEELWALL_2_TOP,
3951     EL_DC_STEELWALL_2_BOTTOM,
3952     EL_DC_STEELWALL_2_HORIZONTAL,
3953     EL_DC_STEELWALL_2_VERTICAL,
3954     EL_DC_STEELWALL_2_MIDDLE,
3955     EL_DC_STEELWALL_2_SINGLE,
3956     EL_STEELWALL_SLIPPERY,
3957     EL_EMC_STEELWALL_1,
3958     EL_EMC_STEELWALL_2,
3959     EL_EMC_STEELWALL_3,
3960     EL_EMC_STEELWALL_4,
3961     EL_CRYSTAL,
3962     EL_GATE_1,
3963     EL_GATE_2,
3964     EL_GATE_3,
3965     EL_GATE_4,
3966     EL_GATE_1_GRAY,
3967     EL_GATE_2_GRAY,
3968     EL_GATE_3_GRAY,
3969     EL_GATE_4_GRAY,
3970     EL_GATE_1_GRAY_ACTIVE,
3971     EL_GATE_2_GRAY_ACTIVE,
3972     EL_GATE_3_GRAY_ACTIVE,
3973     EL_GATE_4_GRAY_ACTIVE,
3974     EL_EM_GATE_1,
3975     EL_EM_GATE_2,
3976     EL_EM_GATE_3,
3977     EL_EM_GATE_4,
3978     EL_EM_GATE_1_GRAY,
3979     EL_EM_GATE_2_GRAY,
3980     EL_EM_GATE_3_GRAY,
3981     EL_EM_GATE_4_GRAY,
3982     EL_EM_GATE_1_GRAY_ACTIVE,
3983     EL_EM_GATE_2_GRAY_ACTIVE,
3984     EL_EM_GATE_3_GRAY_ACTIVE,
3985     EL_EM_GATE_4_GRAY_ACTIVE,
3986     EL_SWITCHGATE_OPEN,
3987     EL_SWITCHGATE_OPENING,
3988     EL_SWITCHGATE_CLOSED,
3989     EL_SWITCHGATE_CLOSING,
3990     EL_TIMEGATE_OPEN,
3991     EL_TIMEGATE_OPENING,
3992     EL_TIMEGATE_CLOSED,
3993     EL_TIMEGATE_CLOSING,
3994     EL_TUBE_ANY,
3995     EL_TUBE_VERTICAL,
3996     EL_TUBE_HORIZONTAL,
3997     EL_TUBE_VERTICAL_LEFT,
3998     EL_TUBE_VERTICAL_RIGHT,
3999     EL_TUBE_HORIZONTAL_UP,
4000     EL_TUBE_HORIZONTAL_DOWN,
4001     EL_TUBE_LEFT_UP,
4002     EL_TUBE_LEFT_DOWN,
4003     EL_TUBE_RIGHT_UP,
4004     EL_TUBE_RIGHT_DOWN,
4005
4006     -1
4007   };
4008
4009   static int ep_classic_enemy[] =
4010   {
4011     EL_BUG,
4012     EL_SPACESHIP,
4013     EL_BD_BUTTERFLY,
4014     EL_BD_FIREFLY,
4015
4016     EL_YAMYAM,
4017     EL_DARK_YAMYAM,
4018     EL_ROBOT,
4019     EL_PACMAN,
4020     EL_SP_SNIKSNAK,
4021     EL_SP_ELECTRON,
4022
4023     -1
4024   };
4025
4026   static int ep_belt[] =
4027   {
4028     EL_CONVEYOR_BELT_1_LEFT,
4029     EL_CONVEYOR_BELT_1_MIDDLE,
4030     EL_CONVEYOR_BELT_1_RIGHT,
4031     EL_CONVEYOR_BELT_2_LEFT,
4032     EL_CONVEYOR_BELT_2_MIDDLE,
4033     EL_CONVEYOR_BELT_2_RIGHT,
4034     EL_CONVEYOR_BELT_3_LEFT,
4035     EL_CONVEYOR_BELT_3_MIDDLE,
4036     EL_CONVEYOR_BELT_3_RIGHT,
4037     EL_CONVEYOR_BELT_4_LEFT,
4038     EL_CONVEYOR_BELT_4_MIDDLE,
4039     EL_CONVEYOR_BELT_4_RIGHT,
4040
4041     -1
4042   };
4043
4044   static int ep_belt_active[] =
4045   {
4046     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
4047     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
4048     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
4049     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
4050     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
4051     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
4052     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
4053     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
4054     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
4055     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
4056     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
4057     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
4058
4059     -1
4060   };
4061
4062   static int ep_belt_switch[] =
4063   {
4064     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4065     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4066     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4067     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4068     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4069     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4070     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4071     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4072     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4073     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4074     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4075     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4076
4077     -1
4078   };
4079
4080   static int ep_tube[] =
4081   {
4082     EL_TUBE_LEFT_UP,
4083     EL_TUBE_LEFT_DOWN,
4084     EL_TUBE_RIGHT_UP,
4085     EL_TUBE_RIGHT_DOWN,
4086     EL_TUBE_HORIZONTAL,
4087     EL_TUBE_HORIZONTAL_UP,
4088     EL_TUBE_HORIZONTAL_DOWN,
4089     EL_TUBE_VERTICAL,
4090     EL_TUBE_VERTICAL_LEFT,
4091     EL_TUBE_VERTICAL_RIGHT,
4092     EL_TUBE_ANY,
4093
4094     -1
4095   };
4096
4097   static int ep_acid_pool[] =
4098   {
4099     EL_ACID_POOL_TOPLEFT,
4100     EL_ACID_POOL_TOPRIGHT,
4101     EL_ACID_POOL_BOTTOMLEFT,
4102     EL_ACID_POOL_BOTTOM,
4103     EL_ACID_POOL_BOTTOMRIGHT,
4104
4105     -1
4106   };
4107
4108   static int ep_keygate[] =
4109   {
4110     EL_GATE_1,
4111     EL_GATE_2,
4112     EL_GATE_3,
4113     EL_GATE_4,
4114     EL_GATE_1_GRAY,
4115     EL_GATE_2_GRAY,
4116     EL_GATE_3_GRAY,
4117     EL_GATE_4_GRAY,
4118     EL_GATE_1_GRAY_ACTIVE,
4119     EL_GATE_2_GRAY_ACTIVE,
4120     EL_GATE_3_GRAY_ACTIVE,
4121     EL_GATE_4_GRAY_ACTIVE,
4122     EL_EM_GATE_1,
4123     EL_EM_GATE_2,
4124     EL_EM_GATE_3,
4125     EL_EM_GATE_4,
4126     EL_EM_GATE_1_GRAY,
4127     EL_EM_GATE_2_GRAY,
4128     EL_EM_GATE_3_GRAY,
4129     EL_EM_GATE_4_GRAY,
4130     EL_EM_GATE_1_GRAY_ACTIVE,
4131     EL_EM_GATE_2_GRAY_ACTIVE,
4132     EL_EM_GATE_3_GRAY_ACTIVE,
4133     EL_EM_GATE_4_GRAY_ACTIVE,
4134     EL_EMC_GATE_5,
4135     EL_EMC_GATE_6,
4136     EL_EMC_GATE_7,
4137     EL_EMC_GATE_8,
4138     EL_EMC_GATE_5_GRAY,
4139     EL_EMC_GATE_6_GRAY,
4140     EL_EMC_GATE_7_GRAY,
4141     EL_EMC_GATE_8_GRAY,
4142     EL_EMC_GATE_5_GRAY_ACTIVE,
4143     EL_EMC_GATE_6_GRAY_ACTIVE,
4144     EL_EMC_GATE_7_GRAY_ACTIVE,
4145     EL_EMC_GATE_8_GRAY_ACTIVE,
4146     EL_DC_GATE_WHITE,
4147     EL_DC_GATE_WHITE_GRAY,
4148     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4149
4150     -1
4151   };
4152
4153   static int ep_amoeboid[] =
4154   {
4155     EL_AMOEBA_DEAD,
4156     EL_AMOEBA_WET,
4157     EL_AMOEBA_DRY,
4158     EL_AMOEBA_FULL,
4159     EL_BD_AMOEBA,
4160     EL_EMC_DRIPPER,
4161
4162     -1
4163   };
4164
4165   static int ep_amoebalive[] =
4166   {
4167     EL_AMOEBA_WET,
4168     EL_AMOEBA_DRY,
4169     EL_AMOEBA_FULL,
4170     EL_BD_AMOEBA,
4171     EL_EMC_DRIPPER,
4172
4173     -1
4174   };
4175
4176   static int ep_has_editor_content[] =
4177   {
4178     EL_PLAYER_1,
4179     EL_PLAYER_2,
4180     EL_PLAYER_3,
4181     EL_PLAYER_4,
4182     EL_SOKOBAN_FIELD_PLAYER,
4183     EL_SP_MURPHY,
4184     EL_YAMYAM,
4185     EL_YAMYAM_LEFT,
4186     EL_YAMYAM_RIGHT,
4187     EL_YAMYAM_UP,
4188     EL_YAMYAM_DOWN,
4189     EL_AMOEBA_WET,
4190     EL_AMOEBA_DRY,
4191     EL_AMOEBA_FULL,
4192     EL_BD_AMOEBA,
4193     EL_EMC_MAGIC_BALL,
4194     EL_EMC_ANDROID,
4195
4196     -1
4197   };
4198
4199   static int ep_can_turn_each_move[] =
4200   {
4201     /* !!! do something with this one !!! */
4202     -1
4203   };
4204
4205   static int ep_can_grow[] =
4206   {
4207     EL_BD_AMOEBA,
4208     EL_AMOEBA_DROP,
4209     EL_AMOEBA_WET,
4210     EL_AMOEBA_DRY,
4211     EL_AMOEBA_FULL,
4212     EL_GAME_OF_LIFE,
4213     EL_BIOMAZE,
4214     EL_EMC_DRIPPER,
4215
4216     -1
4217   };
4218
4219   static int ep_active_bomb[] =
4220   {
4221     EL_DYNAMITE_ACTIVE,
4222     EL_EM_DYNAMITE_ACTIVE,
4223     EL_DYNABOMB_PLAYER_1_ACTIVE,
4224     EL_DYNABOMB_PLAYER_2_ACTIVE,
4225     EL_DYNABOMB_PLAYER_3_ACTIVE,
4226     EL_DYNABOMB_PLAYER_4_ACTIVE,
4227     EL_SP_DISK_RED_ACTIVE,
4228
4229     -1
4230   };
4231
4232   static int ep_inactive[] =
4233   {
4234     EL_EMPTY,
4235     EL_SAND,
4236     EL_WALL,
4237     EL_BD_WALL,
4238     EL_WALL_SLIPPERY,
4239     EL_STEELWALL,
4240     EL_AMOEBA_DEAD,
4241     EL_QUICKSAND_EMPTY,
4242     EL_QUICKSAND_FAST_EMPTY,
4243     EL_STONEBLOCK,
4244     EL_ROBOT_WHEEL,
4245     EL_KEY_1,
4246     EL_KEY_2,
4247     EL_KEY_3,
4248     EL_KEY_4,
4249     EL_EM_KEY_1,
4250     EL_EM_KEY_2,
4251     EL_EM_KEY_3,
4252     EL_EM_KEY_4,
4253     EL_EMC_KEY_5,
4254     EL_EMC_KEY_6,
4255     EL_EMC_KEY_7,
4256     EL_EMC_KEY_8,
4257     EL_GATE_1,
4258     EL_GATE_2,
4259     EL_GATE_3,
4260     EL_GATE_4,
4261     EL_GATE_1_GRAY,
4262     EL_GATE_2_GRAY,
4263     EL_GATE_3_GRAY,
4264     EL_GATE_4_GRAY,
4265     EL_GATE_1_GRAY_ACTIVE,
4266     EL_GATE_2_GRAY_ACTIVE,
4267     EL_GATE_3_GRAY_ACTIVE,
4268     EL_GATE_4_GRAY_ACTIVE,
4269     EL_EM_GATE_1,
4270     EL_EM_GATE_2,
4271     EL_EM_GATE_3,
4272     EL_EM_GATE_4,
4273     EL_EM_GATE_1_GRAY,
4274     EL_EM_GATE_2_GRAY,
4275     EL_EM_GATE_3_GRAY,
4276     EL_EM_GATE_4_GRAY,
4277     EL_EM_GATE_1_GRAY_ACTIVE,
4278     EL_EM_GATE_2_GRAY_ACTIVE,
4279     EL_EM_GATE_3_GRAY_ACTIVE,
4280     EL_EM_GATE_4_GRAY_ACTIVE,
4281     EL_EMC_GATE_5,
4282     EL_EMC_GATE_6,
4283     EL_EMC_GATE_7,
4284     EL_EMC_GATE_8,
4285     EL_EMC_GATE_5_GRAY,
4286     EL_EMC_GATE_6_GRAY,
4287     EL_EMC_GATE_7_GRAY,
4288     EL_EMC_GATE_8_GRAY,
4289     EL_EMC_GATE_5_GRAY_ACTIVE,
4290     EL_EMC_GATE_6_GRAY_ACTIVE,
4291     EL_EMC_GATE_7_GRAY_ACTIVE,
4292     EL_EMC_GATE_8_GRAY_ACTIVE,
4293     EL_DC_GATE_WHITE,
4294     EL_DC_GATE_WHITE_GRAY,
4295     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4296     EL_DC_GATE_FAKE_GRAY,
4297     EL_DYNAMITE,
4298     EL_EM_DYNAMITE,
4299     EL_INVISIBLE_STEELWALL,
4300     EL_INVISIBLE_WALL,
4301     EL_INVISIBLE_SAND,
4302     EL_LAMP,
4303     EL_LAMP_ACTIVE,
4304     EL_WALL_EMERALD,
4305     EL_WALL_DIAMOND,
4306     EL_WALL_BD_DIAMOND,
4307     EL_WALL_EMERALD_YELLOW,
4308     EL_DYNABOMB_INCREASE_NUMBER,
4309     EL_DYNABOMB_INCREASE_SIZE,
4310     EL_DYNABOMB_INCREASE_POWER,
4311 #if 0
4312     EL_SOKOBAN_OBJECT,
4313 #endif
4314     EL_SOKOBAN_FIELD_EMPTY,
4315     EL_SOKOBAN_FIELD_FULL,
4316     EL_WALL_EMERALD_RED,
4317     EL_WALL_EMERALD_PURPLE,
4318     EL_ACID_POOL_TOPLEFT,
4319     EL_ACID_POOL_TOPRIGHT,
4320     EL_ACID_POOL_BOTTOMLEFT,
4321     EL_ACID_POOL_BOTTOM,
4322     EL_ACID_POOL_BOTTOMRIGHT,
4323     EL_MAGIC_WALL,
4324     EL_MAGIC_WALL_DEAD,
4325     EL_BD_MAGIC_WALL,
4326     EL_BD_MAGIC_WALL_DEAD,
4327     EL_DC_MAGIC_WALL,
4328     EL_DC_MAGIC_WALL_DEAD,
4329     EL_AMOEBA_TO_DIAMOND,
4330     EL_BLOCKED,
4331     EL_SP_EMPTY,
4332     EL_SP_BASE,
4333     EL_SP_PORT_RIGHT,
4334     EL_SP_PORT_DOWN,
4335     EL_SP_PORT_LEFT,
4336     EL_SP_PORT_UP,
4337     EL_SP_GRAVITY_PORT_RIGHT,
4338     EL_SP_GRAVITY_PORT_DOWN,
4339     EL_SP_GRAVITY_PORT_LEFT,
4340     EL_SP_GRAVITY_PORT_UP,
4341     EL_SP_PORT_HORIZONTAL,
4342     EL_SP_PORT_VERTICAL,
4343     EL_SP_PORT_ANY,
4344     EL_SP_DISK_RED,
4345 #if 0
4346     EL_SP_DISK_YELLOW,
4347 #endif
4348     EL_SP_CHIP_SINGLE,
4349     EL_SP_CHIP_LEFT,
4350     EL_SP_CHIP_RIGHT,
4351     EL_SP_CHIP_TOP,
4352     EL_SP_CHIP_BOTTOM,
4353     EL_SP_HARDWARE_GRAY,
4354     EL_SP_HARDWARE_GREEN,
4355     EL_SP_HARDWARE_BLUE,
4356     EL_SP_HARDWARE_RED,
4357     EL_SP_HARDWARE_YELLOW,
4358     EL_SP_HARDWARE_BASE_1,
4359     EL_SP_HARDWARE_BASE_2,
4360     EL_SP_HARDWARE_BASE_3,
4361     EL_SP_HARDWARE_BASE_4,
4362     EL_SP_HARDWARE_BASE_5,
4363     EL_SP_HARDWARE_BASE_6,
4364     EL_SP_GRAVITY_ON_PORT_LEFT,
4365     EL_SP_GRAVITY_ON_PORT_RIGHT,
4366     EL_SP_GRAVITY_ON_PORT_UP,
4367     EL_SP_GRAVITY_ON_PORT_DOWN,
4368     EL_SP_GRAVITY_OFF_PORT_LEFT,
4369     EL_SP_GRAVITY_OFF_PORT_RIGHT,
4370     EL_SP_GRAVITY_OFF_PORT_UP,
4371     EL_SP_GRAVITY_OFF_PORT_DOWN,
4372     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4373     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4374     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4375     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4376     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4377     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4378     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4379     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4380     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4381     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4382     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4383     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4384     EL_SIGN_EXCLAMATION,
4385     EL_SIGN_RADIOACTIVITY,
4386     EL_SIGN_STOP,
4387     EL_SIGN_WHEELCHAIR,
4388     EL_SIGN_PARKING,
4389     EL_SIGN_NO_ENTRY,
4390     EL_SIGN_UNUSED_1,
4391     EL_SIGN_GIVE_WAY,
4392     EL_SIGN_ENTRY_FORBIDDEN,
4393     EL_SIGN_EMERGENCY_EXIT,
4394     EL_SIGN_YIN_YANG,
4395     EL_SIGN_UNUSED_2,
4396     EL_SIGN_SPERMS,
4397     EL_SIGN_BULLET,
4398     EL_SIGN_HEART,
4399     EL_SIGN_CROSS,
4400     EL_SIGN_FRANKIE,
4401     EL_DC_STEELWALL_1_LEFT,
4402     EL_DC_STEELWALL_1_RIGHT,
4403     EL_DC_STEELWALL_1_TOP,
4404     EL_DC_STEELWALL_1_BOTTOM,
4405     EL_DC_STEELWALL_1_HORIZONTAL,
4406     EL_DC_STEELWALL_1_VERTICAL,
4407     EL_DC_STEELWALL_1_TOPLEFT,
4408     EL_DC_STEELWALL_1_TOPRIGHT,
4409     EL_DC_STEELWALL_1_BOTTOMLEFT,
4410     EL_DC_STEELWALL_1_BOTTOMRIGHT,
4411     EL_DC_STEELWALL_1_TOPLEFT_2,
4412     EL_DC_STEELWALL_1_TOPRIGHT_2,
4413     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4414     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4415     EL_DC_STEELWALL_2_LEFT,
4416     EL_DC_STEELWALL_2_RIGHT,
4417     EL_DC_STEELWALL_2_TOP,
4418     EL_DC_STEELWALL_2_BOTTOM,
4419     EL_DC_STEELWALL_2_HORIZONTAL,
4420     EL_DC_STEELWALL_2_VERTICAL,
4421     EL_DC_STEELWALL_2_MIDDLE,
4422     EL_DC_STEELWALL_2_SINGLE,
4423     EL_STEELWALL_SLIPPERY,
4424     EL_EMC_STEELWALL_1,
4425     EL_EMC_STEELWALL_2,
4426     EL_EMC_STEELWALL_3,
4427     EL_EMC_STEELWALL_4,
4428     EL_EMC_WALL_SLIPPERY_1,
4429     EL_EMC_WALL_SLIPPERY_2,
4430     EL_EMC_WALL_SLIPPERY_3,
4431     EL_EMC_WALL_SLIPPERY_4,
4432     EL_EMC_WALL_1,
4433     EL_EMC_WALL_2,
4434     EL_EMC_WALL_3,
4435     EL_EMC_WALL_4,
4436     EL_EMC_WALL_5,
4437     EL_EMC_WALL_6,
4438     EL_EMC_WALL_7,
4439     EL_EMC_WALL_8,
4440     EL_EMC_WALL_9,
4441     EL_EMC_WALL_10,
4442     EL_EMC_WALL_11,
4443     EL_EMC_WALL_12,
4444     EL_EMC_WALL_13,
4445     EL_EMC_WALL_14,
4446     EL_EMC_WALL_15,
4447     EL_EMC_WALL_16,
4448
4449     -1
4450   };
4451
4452   static int ep_em_slippery_wall[] =
4453   {
4454     -1
4455   };
4456
4457   static int ep_gfx_crumbled[] =
4458   {
4459     EL_SAND,
4460     EL_LANDMINE,
4461     EL_DC_LANDMINE,
4462     EL_TRAP,
4463     EL_TRAP_ACTIVE,
4464
4465     -1
4466   };
4467
4468   static int ep_editor_cascade_active[] =
4469   {
4470     EL_INTERNAL_CASCADE_BD_ACTIVE,
4471     EL_INTERNAL_CASCADE_EM_ACTIVE,
4472     EL_INTERNAL_CASCADE_EMC_ACTIVE,
4473     EL_INTERNAL_CASCADE_RND_ACTIVE,
4474     EL_INTERNAL_CASCADE_SB_ACTIVE,
4475     EL_INTERNAL_CASCADE_SP_ACTIVE,
4476     EL_INTERNAL_CASCADE_DC_ACTIVE,
4477     EL_INTERNAL_CASCADE_DX_ACTIVE,
4478     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4479     EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4480     EL_INTERNAL_CASCADE_CE_ACTIVE,
4481     EL_INTERNAL_CASCADE_GE_ACTIVE,
4482     EL_INTERNAL_CASCADE_REF_ACTIVE,
4483     EL_INTERNAL_CASCADE_USER_ACTIVE,
4484     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4485
4486     -1
4487   };
4488
4489   static int ep_editor_cascade_inactive[] =
4490   {
4491     EL_INTERNAL_CASCADE_BD,
4492     EL_INTERNAL_CASCADE_EM,
4493     EL_INTERNAL_CASCADE_EMC,
4494     EL_INTERNAL_CASCADE_RND,
4495     EL_INTERNAL_CASCADE_SB,
4496     EL_INTERNAL_CASCADE_SP,
4497     EL_INTERNAL_CASCADE_DC,
4498     EL_INTERNAL_CASCADE_DX,
4499     EL_INTERNAL_CASCADE_CHARS,
4500     EL_INTERNAL_CASCADE_STEEL_CHARS,
4501     EL_INTERNAL_CASCADE_CE,
4502     EL_INTERNAL_CASCADE_GE,
4503     EL_INTERNAL_CASCADE_REF,
4504     EL_INTERNAL_CASCADE_USER,
4505     EL_INTERNAL_CASCADE_DYNAMIC,
4506
4507     -1
4508   };
4509
4510   static int ep_obsolete[] =
4511   {
4512     EL_PLAYER_OBSOLETE,
4513     EL_KEY_OBSOLETE,
4514     EL_EM_KEY_1_FILE_OBSOLETE,
4515     EL_EM_KEY_2_FILE_OBSOLETE,
4516     EL_EM_KEY_3_FILE_OBSOLETE,
4517     EL_EM_KEY_4_FILE_OBSOLETE,
4518     EL_ENVELOPE_OBSOLETE,
4519
4520     -1
4521   };
4522
4523   static struct
4524   {
4525     int *elements;
4526     int property;
4527   } element_properties[] =
4528   {
4529     { ep_diggable,                      EP_DIGGABLE                     },
4530     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
4531     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
4532     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
4533     { ep_dont_touch,                    EP_DONT_TOUCH                   },
4534     { ep_indestructible,                EP_INDESTRUCTIBLE               },
4535     { ep_slippery,                      EP_SLIPPERY                     },
4536     { ep_can_change,                    EP_CAN_CHANGE                   },
4537     { ep_can_move,                      EP_CAN_MOVE                     },
4538     { ep_can_fall,                      EP_CAN_FALL                     },
4539     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
4540     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
4541     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
4542     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
4543     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
4544     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
4545     { ep_walkable_over,                 EP_WALKABLE_OVER                },
4546     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
4547     { ep_walkable_under,                EP_WALKABLE_UNDER               },
4548     { ep_passable_over,                 EP_PASSABLE_OVER                },
4549     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
4550     { ep_passable_under,                EP_PASSABLE_UNDER               },
4551     { ep_droppable,                     EP_DROPPABLE                    },
4552     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
4553     { ep_pushable,                      EP_PUSHABLE                     },
4554     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
4555     { ep_protected,                     EP_PROTECTED                    },
4556     { ep_throwable,                     EP_THROWABLE                    },
4557     { ep_can_explode,                   EP_CAN_EXPLODE                  },
4558     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
4559
4560     { ep_player,                        EP_PLAYER                       },
4561     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
4562     { ep_can_pass_dc_magic_wall,        EP_CAN_PASS_DC_MAGIC_WALL       },
4563     { ep_switchable,                    EP_SWITCHABLE                   },
4564     { ep_bd_element,                    EP_BD_ELEMENT                   },
4565     { ep_sp_element,                    EP_SP_ELEMENT                   },
4566     { ep_sb_element,                    EP_SB_ELEMENT                   },
4567     { ep_gem,                           EP_GEM                          },
4568     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
4569     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
4570     { ep_food_pig,                      EP_FOOD_PIG                     },
4571     { ep_historic_wall,                 EP_HISTORIC_WALL                },
4572     { ep_historic_solid,                EP_HISTORIC_SOLID               },
4573     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
4574     { ep_belt,                          EP_BELT                         },
4575     { ep_belt_active,                   EP_BELT_ACTIVE                  },
4576     { ep_belt_switch,                   EP_BELT_SWITCH                  },
4577     { ep_tube,                          EP_TUBE                         },
4578     { ep_acid_pool,                     EP_ACID_POOL                    },
4579     { ep_keygate,                       EP_KEYGATE                      },
4580     { ep_amoeboid,                      EP_AMOEBOID                     },
4581     { ep_amoebalive,                    EP_AMOEBALIVE                   },
4582     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
4583     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
4584     { ep_can_grow,                      EP_CAN_GROW                     },
4585     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
4586     { ep_inactive,                      EP_INACTIVE                     },
4587
4588     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
4589
4590     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
4591
4592     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
4593     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
4594
4595     { ep_obsolete,                      EP_OBSOLETE                     },
4596
4597     { NULL,                             -1                              }
4598   };
4599
4600   int i, j, k;
4601
4602   /* always start with reliable default values (element has no properties) */
4603   /* (but never initialize clipboard elements after the very first time) */
4604   /* (to be able to use clipboard elements between several levels) */
4605   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4606     if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4607       for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4608         SET_PROPERTY(i, j, FALSE);
4609
4610   /* set all base element properties from above array definitions */
4611   for (i = 0; element_properties[i].elements != NULL; i++)
4612     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4613       SET_PROPERTY((element_properties[i].elements)[j],
4614                    element_properties[i].property, TRUE);
4615
4616   /* copy properties to some elements that are only stored in level file */
4617   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4618     for (j = 0; copy_properties[j][0] != -1; j++)
4619       if (HAS_PROPERTY(copy_properties[j][0], i))
4620         for (k = 1; k <= 4; k++)
4621           SET_PROPERTY(copy_properties[j][k], i, TRUE);
4622
4623   /* set static element properties that are not listed in array definitions */
4624   for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4625     SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4626
4627   clipboard_elements_initialized = TRUE;
4628 }
4629
4630 void InitElementPropertiesEngine(int engine_version)
4631 {
4632   static int no_wall_properties[] =
4633   {
4634     EP_DIGGABLE,
4635     EP_COLLECTIBLE_ONLY,
4636     EP_DONT_RUN_INTO,
4637     EP_DONT_COLLIDE_WITH,
4638     EP_CAN_MOVE,
4639     EP_CAN_FALL,
4640     EP_CAN_SMASH_PLAYER,
4641     EP_CAN_SMASH_ENEMIES,
4642     EP_CAN_SMASH_EVERYTHING,
4643     EP_PUSHABLE,
4644
4645     EP_PLAYER,
4646     EP_GEM,
4647     EP_FOOD_DARK_YAMYAM,
4648     EP_FOOD_PENGUIN,
4649     EP_BELT,
4650     EP_BELT_ACTIVE,
4651     EP_TUBE,
4652     EP_AMOEBOID,
4653     EP_AMOEBALIVE,
4654     EP_ACTIVE_BOMB,
4655
4656     EP_ACCESSIBLE,
4657
4658     -1
4659   };
4660
4661   int i, j;
4662
4663   /* important: after initialization in InitElementPropertiesStatic(), the
4664      elements are not again initialized to a default value; therefore all
4665      changes have to make sure that they leave the element with a defined
4666      property (which means that conditional property changes must be set to
4667      a reliable default value before) */
4668
4669   /* resolve group elements */
4670   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4671     ResolveGroupElement(EL_GROUP_START + i);
4672
4673   /* set all special, combined or engine dependent element properties */
4674   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4675   {
4676     /* do not change (already initialized) clipboard elements here */
4677     if (IS_CLIPBOARD_ELEMENT(i))
4678       continue;
4679
4680     /* ---------- INACTIVE ------------------------------------------------- */
4681     SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4682                                    i <= EL_CHAR_END) ||
4683                                   (i >= EL_STEEL_CHAR_START &&
4684                                    i <= EL_STEEL_CHAR_END)));
4685
4686     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4687     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4688                                   IS_WALKABLE_INSIDE(i) ||
4689                                   IS_WALKABLE_UNDER(i)));
4690
4691     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4692                                   IS_PASSABLE_INSIDE(i) ||
4693                                   IS_PASSABLE_UNDER(i)));
4694
4695     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4696                                          IS_PASSABLE_OVER(i)));
4697
4698     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4699                                            IS_PASSABLE_INSIDE(i)));
4700
4701     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4702                                           IS_PASSABLE_UNDER(i)));
4703
4704     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4705                                     IS_PASSABLE(i)));
4706
4707     /* ---------- COLLECTIBLE ---------------------------------------------- */
4708     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4709                                      IS_DROPPABLE(i) ||
4710                                      IS_THROWABLE(i)));
4711
4712     /* ---------- SNAPPABLE ------------------------------------------------ */
4713     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4714                                    IS_COLLECTIBLE(i) ||
4715                                    IS_SWITCHABLE(i) ||
4716                                    i == EL_BD_ROCK));
4717
4718     /* ---------- WALL ----------------------------------------------------- */
4719     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
4720
4721     for (j = 0; no_wall_properties[j] != -1; j++)
4722       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4723           i >= EL_FIRST_RUNTIME_UNREAL)
4724         SET_PROPERTY(i, EP_WALL, FALSE);
4725
4726     if (IS_HISTORIC_WALL(i))
4727       SET_PROPERTY(i, EP_WALL, TRUE);
4728
4729     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4730     if (engine_version < VERSION_IDENT(2,2,0,0))
4731       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4732     else
4733       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4734                                              !IS_DIGGABLE(i) &&
4735                                              !IS_COLLECTIBLE(i)));
4736
4737     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4738     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4739       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4740     else
4741       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4742                                             IS_INDESTRUCTIBLE(i)));
4743
4744     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4745     if (i == EL_FLAMES)
4746       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4747     else if (engine_version < VERSION_IDENT(2,2,0,0))
4748       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4749     else
4750       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4751                                            (!IS_WALKABLE(i) ||
4752                                             IS_PROTECTED(i))));
4753
4754     if (IS_CUSTOM_ELEMENT(i))
4755     {
4756       /* these are additional properties which are initially false when set */
4757
4758       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4759       if (DONT_TOUCH(i))
4760         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4761       if (DONT_COLLIDE_WITH(i))
4762         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4763
4764       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4765       if (CAN_SMASH_EVERYTHING(i))
4766         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4767       if (CAN_SMASH_ENEMIES(i))
4768         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4769     }
4770
4771     /* ---------- CAN_SMASH ------------------------------------------------ */
4772     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4773                                    CAN_SMASH_ENEMIES(i) ||
4774                                    CAN_SMASH_EVERYTHING(i)));
4775
4776     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4777     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4778                                              EXPLODES_BY_FIRE(i)));
4779
4780     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4781     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4782                                              EXPLODES_SMASHED(i)));
4783
4784     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4785     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4786                                             EXPLODES_IMPACT(i)));
4787
4788     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4789     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4790
4791     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4792     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4793                                                   i == EL_BLACK_ORB));
4794
4795     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4796     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4797                                               CAN_MOVE(i) ||
4798                                               IS_CUSTOM_ELEMENT(i)));
4799
4800     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4801     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4802                                                  i == EL_SP_ELECTRON));
4803
4804     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4805     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4806       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4807                    getMoveIntoAcidProperty(&level, i));
4808
4809     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4810     if (MAYBE_DONT_COLLIDE_WITH(i))
4811       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4812                    getDontCollideWithProperty(&level, i));
4813
4814     /* ---------- SP_PORT -------------------------------------------------- */
4815     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4816                                  IS_PASSABLE_INSIDE(i)));
4817
4818     /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4819     for (j = 0; j < level.num_android_clone_elements; j++)
4820       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4821                    (i != EL_EMPTY &&
4822                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4823
4824     /* ---------- CAN_CHANGE ----------------------------------------------- */
4825     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
4826     for (j = 0; j < element_info[i].num_change_pages; j++)
4827       if (element_info[i].change_page[j].can_change)
4828         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4829
4830     /* ---------- HAS_ACTION ----------------------------------------------- */
4831     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      /* default: has no action */
4832     for (j = 0; j < element_info[i].num_change_pages; j++)
4833       if (element_info[i].change_page[j].has_action)
4834         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4835
4836     /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4837     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4838                                                   HAS_ACTION(i)));
4839
4840     /* ---------- GFX_CRUMBLED --------------------------------------------- */
4841 #if 1
4842     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4843                  element_info[i].crumbled[ACTION_DEFAULT] !=
4844                  element_info[i].graphic[ACTION_DEFAULT]);
4845 #else
4846     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4847     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4848                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4849 #endif
4850
4851     /* ---------- EDITOR_CASCADE ------------------------------------------- */
4852     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4853                                         IS_EDITOR_CASCADE_INACTIVE(i)));
4854   }
4855
4856   /* dynamically adjust element properties according to game engine version */
4857   {
4858     static int ep_em_slippery_wall[] =
4859     {
4860       EL_WALL,
4861       EL_STEELWALL,
4862       EL_EXPANDABLE_WALL,
4863       EL_EXPANDABLE_WALL_HORIZONTAL,
4864       EL_EXPANDABLE_WALL_VERTICAL,
4865       EL_EXPANDABLE_WALL_ANY,
4866       EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4867       EL_EXPANDABLE_STEELWALL_VERTICAL,
4868       EL_EXPANDABLE_STEELWALL_ANY,
4869       EL_EXPANDABLE_STEELWALL_GROWING,
4870       -1
4871     };
4872
4873     static int ep_em_explodes_by_fire[] =
4874     {
4875       EL_EM_DYNAMITE,
4876       EL_EM_DYNAMITE_ACTIVE,
4877       EL_MOLE,
4878       -1
4879     };
4880
4881     /* special EM style gems behaviour */
4882     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4883       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4884                    level.em_slippery_gems);
4885
4886     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4887     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4888                  (level.em_slippery_gems &&
4889                   engine_version > VERSION_IDENT(2,0,1,0)));
4890
4891     /* special EM style explosion behaviour regarding chain reactions */
4892     for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4893       SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4894                    level.em_explodes_by_fire);
4895   }
4896
4897   /* this is needed because some graphics depend on element properties */
4898   if (game_status == GAME_MODE_PLAYING)
4899     InitElementGraphicInfo();
4900 }
4901
4902 void InitElementPropertiesAfterLoading(int engine_version)
4903 {
4904   int i;
4905
4906   /* set some other uninitialized values of custom elements in older levels */
4907   if (engine_version < VERSION_IDENT(3,1,0,0))
4908   {
4909     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4910     {
4911       int element = EL_CUSTOM_START + i;
4912
4913       element_info[element].access_direction = MV_ALL_DIRECTIONS;
4914
4915       element_info[element].explosion_delay = 17;
4916       element_info[element].ignition_delay = 8;
4917     }
4918   }
4919 }
4920
4921 void InitElementPropertiesGfxElement()
4922 {
4923   int i;
4924
4925   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4926   {
4927     struct ElementInfo *ei = &element_info[i];
4928
4929     ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4930   }
4931 }
4932
4933 static void InitGlobal()
4934 {
4935   int graphic;
4936   int i;
4937
4938   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4939   {
4940     /* check if element_name_info entry defined for each element in "main.h" */
4941     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4942       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4943
4944     element_info[i].token_name = element_name_info[i].token_name;
4945     element_info[i].class_name = element_name_info[i].class_name;
4946     element_info[i].editor_description= element_name_info[i].editor_description;
4947
4948 #if 0
4949     printf("%04d: %s\n", i, element_name_info[i].token_name);
4950 #endif
4951   }
4952
4953   /* create hash from image config list */
4954   image_config_hash = newSetupFileHash();
4955   for (i = 0; image_config[i].token != NULL; i++)
4956     setHashEntry(image_config_hash,
4957                  image_config[i].token,
4958                  image_config[i].value);
4959
4960   /* create hash from element token list */
4961   element_token_hash = newSetupFileHash();
4962   for (i = 0; element_name_info[i].token_name != NULL; i++)
4963     setHashEntry(element_token_hash,
4964                  element_name_info[i].token_name,
4965                  int2str(i, 0));
4966
4967   /* create hash from graphic token list */
4968   graphic_token_hash = newSetupFileHash();
4969   for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4970     if (strSuffix(image_config[i].value, ".png") ||
4971         strSuffix(image_config[i].value, ".pcx") ||
4972         strSuffix(image_config[i].value, ".wav") ||
4973         strEqual(image_config[i].value, UNDEFINED_FILENAME))
4974       setHashEntry(graphic_token_hash,
4975                    image_config[i].token,
4976                    int2str(graphic++, 0));
4977
4978   /* create hash from font token list */
4979   font_token_hash = newSetupFileHash();
4980   for (i = 0; font_info[i].token_name != NULL; i++)
4981     setHashEntry(font_token_hash,
4982                  font_info[i].token_name,
4983                  int2str(i, 0));
4984
4985   /* always start with reliable default values (all elements) */
4986   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4987     ActiveElement[i] = i;
4988
4989   /* now add all entries that have an active state (active elements) */
4990   for (i = 0; element_with_active_state[i].element != -1; i++)
4991   {
4992     int element = element_with_active_state[i].element;
4993     int element_active = element_with_active_state[i].element_active;
4994
4995     ActiveElement[element] = element_active;
4996   }
4997
4998   /* always start with reliable default values (all buttons) */
4999   for (i = 0; i < NUM_IMAGE_FILES; i++)
5000     ActiveButton[i] = i;
5001
5002   /* now add all entries that have an active state (active buttons) */
5003   for (i = 0; button_with_active_state[i].button != -1; i++)
5004   {
5005     int button = button_with_active_state[i].button;
5006     int button_active = button_with_active_state[i].button_active;
5007
5008     ActiveButton[button] = button_active;
5009   }
5010
5011   /* always start with reliable default values (all fonts) */
5012   for (i = 0; i < NUM_FONTS; i++)
5013     ActiveFont[i] = i;
5014
5015   /* now add all entries that have an active state (active fonts) */
5016   for (i = 0; font_with_active_state[i].font_nr != -1; i++)
5017   {
5018     int font = font_with_active_state[i].font_nr;
5019     int font_active = font_with_active_state[i].font_nr_active;
5020
5021     ActiveFont[font] = font_active;
5022   }
5023
5024   global.autoplay_leveldir = NULL;
5025   global.convert_leveldir = NULL;
5026   global.create_images_dir = NULL;
5027
5028   global.frames_per_second = 0;
5029   global.fps_slowdown = FALSE;
5030   global.fps_slowdown_factor = 1;
5031
5032   global.border_status = GAME_MODE_MAIN;
5033 #if 0
5034   global.fading_status = GAME_MODE_MAIN;
5035   global.fading_type = TYPE_ENTER_MENU;
5036 #endif
5037
5038   global.use_envelope_request = FALSE;
5039 }
5040
5041 void Execute_Command(char *command)
5042 {
5043   int i;
5044
5045   if (strEqual(command, "print graphicsinfo.conf"))
5046   {
5047     printf("# You can configure additional/alternative image files here.\n");
5048     printf("# (The entries below are default and therefore commented out.)\n");
5049     printf("\n");
5050     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
5051     printf("\n");
5052     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5053     printf("\n");
5054
5055     for (i = 0; image_config[i].token != NULL; i++)
5056       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
5057                                               image_config[i].value));
5058
5059     exit(0);
5060   }
5061   else if (strEqual(command, "print soundsinfo.conf"))
5062   {
5063     printf("# You can configure additional/alternative sound files here.\n");
5064     printf("# (The entries below are default and therefore commented out.)\n");
5065     printf("\n");
5066     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5067     printf("\n");
5068     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5069     printf("\n");
5070
5071     for (i = 0; sound_config[i].token != NULL; i++)
5072       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5073                                               sound_config[i].value));
5074
5075     exit(0);
5076   }
5077   else if (strEqual(command, "print musicinfo.conf"))
5078   {
5079     printf("# You can configure additional/alternative music files here.\n");
5080     printf("# (The entries below are default and therefore commented out.)\n");
5081     printf("\n");
5082     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5083     printf("\n");
5084     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5085     printf("\n");
5086
5087     for (i = 0; music_config[i].token != NULL; i++)
5088       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
5089                                               music_config[i].value));
5090
5091     exit(0);
5092   }
5093   else if (strEqual(command, "print editorsetup.conf"))
5094   {
5095     printf("# You can configure your personal editor element list here.\n");
5096     printf("# (The entries below are default and therefore commented out.)\n");
5097     printf("\n");
5098
5099     /* this is needed to be able to check element list for cascade elements */
5100     InitElementPropertiesStatic();
5101     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5102
5103     PrintEditorElementList();
5104
5105     exit(0);
5106   }
5107   else if (strEqual(command, "print helpanim.conf"))
5108   {
5109     printf("# You can configure different element help animations here.\n");
5110     printf("# (The entries below are default and therefore commented out.)\n");
5111     printf("\n");
5112
5113     for (i = 0; helpanim_config[i].token != NULL; i++)
5114     {
5115       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5116                                               helpanim_config[i].value));
5117
5118       if (strEqual(helpanim_config[i].token, "end"))
5119         printf("#\n");
5120     }
5121
5122     exit(0);
5123   }
5124   else if (strEqual(command, "print helptext.conf"))
5125   {
5126     printf("# You can configure different element help text here.\n");
5127     printf("# (The entries below are default and therefore commented out.)\n");
5128     printf("\n");
5129
5130     for (i = 0; helptext_config[i].token != NULL; i++)
5131       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5132                                               helptext_config[i].value));
5133
5134     exit(0);
5135   }
5136   else if (strPrefix(command, "dump level "))
5137   {
5138     char *filename = &command[11];
5139
5140     if (!fileExists(filename))
5141       Error(ERR_EXIT, "cannot open file '%s'", filename);
5142
5143     LoadLevelFromFilename(&level, filename);
5144     DumpLevel(&level);
5145
5146     exit(0);
5147   }
5148   else if (strPrefix(command, "dump tape "))
5149   {
5150     char *filename = &command[10];
5151
5152     if (!fileExists(filename))
5153       Error(ERR_EXIT, "cannot open file '%s'", filename);
5154
5155     LoadTapeFromFilename(filename);
5156     DumpTape(&tape);
5157
5158     exit(0);
5159   }
5160   else if (strPrefix(command, "autoplay "))
5161   {
5162     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5163
5164     while (*str_ptr != '\0')                    /* continue parsing string */
5165     {
5166       /* cut leading whitespace from string, replace it by string terminator */
5167       while (*str_ptr == ' ' || *str_ptr == '\t')
5168         *str_ptr++ = '\0';
5169
5170       if (*str_ptr == '\0')                     /* end of string reached */
5171         break;
5172
5173       if (global.autoplay_leveldir == NULL)     /* read level set string */
5174       {
5175         global.autoplay_leveldir = str_ptr;
5176         global.autoplay_all = TRUE;             /* default: play all tapes */
5177
5178         for (i = 0; i < MAX_TAPES_PER_SET; i++)
5179           global.autoplay_level[i] = FALSE;
5180       }
5181       else                                      /* read level number string */
5182       {
5183         int level_nr = atoi(str_ptr);           /* get level_nr value */
5184
5185         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5186           global.autoplay_level[level_nr] = TRUE;
5187
5188         global.autoplay_all = FALSE;
5189       }
5190
5191       /* advance string pointer to the next whitespace (or end of string) */
5192       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5193         str_ptr++;
5194     }
5195   }
5196   else if (strPrefix(command, "convert "))
5197   {
5198     char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5199     char *str_ptr = strchr(str_copy, ' ');
5200
5201     global.convert_leveldir = str_copy;
5202     global.convert_level_nr = -1;
5203
5204     if (str_ptr != NULL)                        /* level number follows */
5205     {
5206       *str_ptr++ = '\0';                        /* terminate leveldir string */
5207       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
5208     }
5209   }
5210   else if (strPrefix(command, "create images "))
5211   {
5212 #if defined(TARGET_SDL)
5213     global.create_images_dir = getStringCopy(&command[14]);
5214
5215     if (access(global.create_images_dir, W_OK) != 0)
5216       Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5217             global.create_images_dir);
5218 #else
5219     Error(ERR_EXIT, "command only available for SDL target");
5220 #endif
5221   }
5222
5223 #if DEBUG
5224 #if defined(TARGET_SDL2)
5225   else if (strEqual(command, "SDL_ListModes"))
5226   {
5227     SDL_Init(SDL_INIT_VIDEO);
5228
5229     int num_displays = SDL_GetNumVideoDisplays();
5230
5231     // check if there are any displays available
5232     if (num_displays < 0)
5233     {
5234       printf("No displays available: %s\n", SDL_GetError());
5235
5236       exit(-1);
5237     }
5238
5239     for (i = 0; i < num_displays; i++)
5240     {
5241       int num_modes = SDL_GetNumDisplayModes(i);
5242       int j;
5243
5244       printf("Available display modes for display %d:\n", i);
5245
5246       // check if there are any display modes available for this display
5247       if (num_modes < 0)
5248       {
5249         printf("No display modes available for display %d: %s\n",
5250                i, SDL_GetError());
5251
5252         exit(-1);
5253       }
5254
5255       for (j = 0; j < num_modes; j++)
5256       {
5257         SDL_DisplayMode mode;
5258
5259         if (SDL_GetDisplayMode(i, j, &mode) < 0)
5260         {
5261           printf("Cannot get display mode %d for display %d: %s\n",
5262                  j, i, SDL_GetError());
5263
5264           exit(-1);
5265         }
5266
5267         printf("- %d x %d\n", mode.w, mode.h);
5268       }
5269     }
5270
5271     exit(0);
5272   }
5273 #elif defined(TARGET_SDL)
5274   else if (strEqual(command, "SDL_ListModes"))
5275   {
5276     SDL_Rect **modes;
5277     int i;
5278
5279     SDL_Init(SDL_INIT_VIDEO);
5280
5281     /* get available fullscreen/hardware modes */
5282     modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5283
5284     /* check if there are any modes available */
5285     if (modes == NULL)
5286     {
5287       printf("No modes available!\n");
5288
5289       exit(-1);
5290     }
5291
5292     /* check if our resolution is restricted */
5293     if (modes == (SDL_Rect **)-1)
5294     {
5295       printf("All resolutions available.\n");
5296     }
5297     else
5298     {
5299       printf("Available display modes:\n");
5300
5301       for (i = 0; modes[i]; i++)
5302         printf("- %d x %d\n", modes[i]->w, modes[i]->h);
5303     }
5304
5305     exit(0);
5306   }
5307 #endif
5308 #endif
5309
5310   else
5311   {
5312     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5313   }
5314 }
5315
5316 static void InitSetup()
5317 {
5318   LoadSetup();                                  /* global setup info */
5319
5320   /* set some options from setup file */
5321
5322   if (setup.options.verbose)
5323     options.verbose = TRUE;
5324 }
5325
5326 static void InitGameInfo()
5327 {
5328   game.restart_level = FALSE;
5329 }
5330
5331 static void InitPlayerInfo()
5332 {
5333   int i;
5334
5335   /* choose default local player */
5336   local_player = &stored_player[0];
5337
5338   for (i = 0; i < MAX_PLAYERS; i++)
5339     stored_player[i].connected = FALSE;
5340
5341   local_player->connected = TRUE;
5342 }
5343
5344 static void InitArtworkInfo()
5345 {
5346   LoadArtworkInfo();
5347 }
5348
5349 static char *get_string_in_brackets(char *string)
5350 {
5351   char *string_in_brackets = checked_malloc(strlen(string) + 3);
5352
5353   sprintf(string_in_brackets, "[%s]", string);
5354
5355   return string_in_brackets;
5356 }
5357
5358 static char *get_level_id_suffix(int id_nr)
5359 {
5360   char *id_suffix = checked_malloc(1 + 3 + 1);
5361
5362   if (id_nr < 0 || id_nr > 999)
5363     id_nr = 0;
5364
5365   sprintf(id_suffix, ".%03d", id_nr);
5366
5367   return id_suffix;
5368 }
5369
5370 #if 0
5371 static char *get_element_class_token(int element)
5372 {
5373   char *element_class_name = element_info[element].class_name;
5374   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5375
5376   sprintf(element_class_token, "[%s]", element_class_name);
5377
5378   return element_class_token;
5379 }
5380
5381 static char *get_action_class_token(int action)
5382 {
5383   char *action_class_name = &element_action_info[action].suffix[1];
5384   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5385
5386   sprintf(action_class_token, "[%s]", action_class_name);
5387
5388   return action_class_token;
5389 }
5390 #endif
5391
5392 static void InitArtworkConfig()
5393 {
5394   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5395   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5396   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5397   static char *action_id_suffix[NUM_ACTIONS + 1];
5398   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5399   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5400   static char *level_id_suffix[MAX_LEVELS + 1];
5401   static char *dummy[1] = { NULL };
5402   static char *ignore_generic_tokens[] =
5403   {
5404     "name",
5405     "sort_priority",
5406     NULL
5407   };
5408   static char **ignore_image_tokens;
5409   static char **ignore_sound_tokens;
5410   static char **ignore_music_tokens;
5411   int num_ignore_generic_tokens;
5412   int num_ignore_image_tokens;
5413   int num_ignore_sound_tokens;
5414   int num_ignore_music_tokens;
5415   int i;
5416
5417   /* dynamically determine list of generic tokens to be ignored */
5418   num_ignore_generic_tokens = 0;
5419   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5420     num_ignore_generic_tokens++;
5421
5422   /* dynamically determine list of image tokens to be ignored */
5423   num_ignore_image_tokens = num_ignore_generic_tokens;
5424   for (i = 0; image_config_vars[i].token != NULL; i++)
5425     num_ignore_image_tokens++;
5426   ignore_image_tokens =
5427     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5428   for (i = 0; i < num_ignore_generic_tokens; i++)
5429     ignore_image_tokens[i] = ignore_generic_tokens[i];
5430   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5431     ignore_image_tokens[num_ignore_generic_tokens + i] =
5432       image_config_vars[i].token;
5433   ignore_image_tokens[num_ignore_image_tokens] = NULL;
5434
5435   /* dynamically determine list of sound tokens to be ignored */
5436   num_ignore_sound_tokens = num_ignore_generic_tokens;
5437   ignore_sound_tokens =
5438     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5439   for (i = 0; i < num_ignore_generic_tokens; i++)
5440     ignore_sound_tokens[i] = ignore_generic_tokens[i];
5441   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5442
5443   /* dynamically determine list of music tokens to be ignored */
5444   num_ignore_music_tokens = num_ignore_generic_tokens;
5445   ignore_music_tokens =
5446     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5447   for (i = 0; i < num_ignore_generic_tokens; i++)
5448     ignore_music_tokens[i] = ignore_generic_tokens[i];
5449   ignore_music_tokens[num_ignore_music_tokens] = NULL;
5450
5451   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5452     image_id_prefix[i] = element_info[i].token_name;
5453   for (i = 0; i < NUM_FONTS; i++)
5454     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5455   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5456
5457   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5458     sound_id_prefix[i] = element_info[i].token_name;
5459   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5460     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5461       get_string_in_brackets(element_info[i].class_name);
5462   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5463
5464   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5465     music_id_prefix[i] = music_prefix_info[i].prefix;
5466   music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5467
5468   for (i = 0; i < NUM_ACTIONS; i++)
5469     action_id_suffix[i] = element_action_info[i].suffix;
5470   action_id_suffix[NUM_ACTIONS] = NULL;
5471
5472   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5473     direction_id_suffix[i] = element_direction_info[i].suffix;
5474   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5475
5476   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5477     special_id_suffix[i] = special_suffix_info[i].suffix;
5478   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5479
5480   for (i = 0; i < MAX_LEVELS; i++)
5481     level_id_suffix[i] = get_level_id_suffix(i);
5482   level_id_suffix[MAX_LEVELS] = NULL;
5483
5484   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5485                 image_id_prefix, action_id_suffix, direction_id_suffix,
5486                 special_id_suffix, ignore_image_tokens);
5487   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5488                 sound_id_prefix, action_id_suffix, dummy,
5489                 special_id_suffix, ignore_sound_tokens);
5490   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5491                 music_id_prefix, special_id_suffix, level_id_suffix,
5492                 dummy, ignore_music_tokens);
5493 }
5494
5495 static void InitMixer()
5496 {
5497   OpenAudio();
5498
5499   StartMixer();
5500 }
5501
5502 void InitGfxBuffers()
5503 {
5504   /* create additional image buffers for double-buffering and cross-fading */
5505   ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5506   ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5507   ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5508   ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5509 #if 0
5510   ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5511 #endif
5512   ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5513   ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5514   ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5515
5516   /* initialize screen properties */
5517   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5518                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5519                    bitmap_db_field);
5520   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5521   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5522   InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5523   InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5524   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5525   InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5526
5527   InitGfxBuffers_EM();
5528   InitGfxBuffers_SP();
5529 }
5530
5531 void InitGfx()
5532 {
5533   struct GraphicInfo *graphic_info_last = graphic_info;
5534   char *filename_font_initial = NULL;
5535   char *filename_anim_initial = NULL;
5536   Bitmap *bitmap_font_initial = NULL;
5537   int font_height;
5538   int i, j;
5539
5540   /* determine settings for initial font (for displaying startup messages) */
5541   for (i = 0; image_config[i].token != NULL; i++)
5542   {
5543     for (j = 0; j < NUM_INITIAL_FONTS; j++)
5544     {
5545       char font_token[128];
5546       int len_font_token;
5547
5548       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5549       len_font_token = strlen(font_token);
5550
5551       if (strEqual(image_config[i].token, font_token))
5552         filename_font_initial = image_config[i].value;
5553       else if (strlen(image_config[i].token) > len_font_token &&
5554                strncmp(image_config[i].token, font_token, len_font_token) == 0)
5555       {
5556         if (strEqual(&image_config[i].token[len_font_token], ".x"))
5557           font_initial[j].src_x = atoi(image_config[i].value);
5558         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5559           font_initial[j].src_y = atoi(image_config[i].value);
5560         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5561           font_initial[j].width = atoi(image_config[i].value);
5562         else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5563           font_initial[j].height = atoi(image_config[i].value);
5564       }
5565     }
5566   }
5567
5568   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5569   {
5570     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5571     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5572   }
5573
5574   if (filename_font_initial == NULL)    /* should not happen */
5575     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5576
5577   InitGfxBuffers();
5578   InitGfxCustomArtworkInfo();
5579
5580   bitmap_font_initial = LoadCustomImage(filename_font_initial);
5581
5582   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5583     font_initial[j].bitmap = bitmap_font_initial;
5584
5585   InitFontGraphicInfo();
5586
5587   font_height = getFontHeight(FC_RED);
5588
5589 #if 0
5590   DrawInitTextAlways(getWindowTitleString(), 20, FC_YELLOW);
5591 #else
5592   DrawInitTextAlways(getProgramInitString(), 20, FC_YELLOW);
5593 #endif
5594   DrawInitTextAlways(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5595   DrawInitTextAlways(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height,
5596                      FC_RED);
5597
5598   DrawInitTextAlways("Loading graphics", 120, FC_GREEN);
5599
5600 #if 1
5601 #if 1
5602   /* initialize busy animation with default values */
5603   int parameter[NUM_GFX_ARGS];
5604   for (i = 0; i < NUM_GFX_ARGS; i++)
5605     parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5606                                                image_config_suffix[i].token,
5607                                                image_config_suffix[i].type);
5608 #if 0
5609   for (i = 0; i < NUM_GFX_ARGS; i++)
5610     printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5611 #endif
5612 #endif
5613
5614   /* determine settings for busy animation (when displaying startup messages) */
5615   for (i = 0; image_config[i].token != NULL; i++)
5616   {
5617     char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5618     int len_anim_token = strlen(anim_token);
5619
5620     if (strEqual(image_config[i].token, anim_token))
5621       filename_anim_initial = image_config[i].value;
5622     else if (strlen(image_config[i].token) > len_anim_token &&
5623              strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5624     {
5625 #if 1
5626       for (j = 0; image_config_suffix[j].token != NULL; j++)
5627       {
5628         if (strEqual(&image_config[i].token[len_anim_token],
5629                      image_config_suffix[j].token))
5630           parameter[j] =
5631             get_graphic_parameter_value(image_config[i].value,
5632                                         image_config_suffix[j].token,
5633                                         image_config_suffix[j].type);
5634       }
5635 #else
5636       if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5637         anim_initial.src_x = atoi(image_config[i].value);
5638       else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5639         anim_initial.src_y = atoi(image_config[i].value);
5640       else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5641         anim_initial.width = atoi(image_config[i].value);
5642       else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5643         anim_initial.height = atoi(image_config[i].value);
5644       else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5645         anim_initial.anim_frames = atoi(image_config[i].value);
5646       else if (strEqual(&image_config[i].token[len_anim_token],
5647                         ".frames_per_line"))
5648         anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5649       else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5650         anim_initial.anim_delay = atoi(image_config[i].value);
5651 #endif
5652     }
5653   }
5654
5655 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
5656   filename_anim_initial = "loading.pcx";
5657
5658   parameter[GFX_ARG_X] = 0;
5659   parameter[GFX_ARG_Y] = 0;
5660   parameter[GFX_ARG_WIDTH] = 128;
5661   parameter[GFX_ARG_HEIGHT] = 40;
5662   parameter[GFX_ARG_FRAMES] = 32;
5663   parameter[GFX_ARG_DELAY] = 4;
5664   parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
5665 #endif
5666
5667   if (filename_anim_initial == NULL)    /* should not happen */
5668     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5669
5670   anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5671
5672   graphic_info = &anim_initial;         /* graphic == 0 => anim_initial */
5673
5674   set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
5675
5676 #if 0
5677   printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
5678          graphic_info[0].anim_frames_per_line,
5679          get_scaled_graphic_width(0),
5680          graphic_info[0].width,
5681          getOriginalImageWidthFromImageID(0),
5682          graphic_info[0].scale_up_factor);
5683 #endif
5684
5685   graphic_info = graphic_info_last;
5686
5687   init.busy.width  = anim_initial.width;
5688   init.busy.height = anim_initial.height;
5689
5690   InitMenuDesignSettings_Static();
5691   InitGfxDrawBusyAnimFunction(DrawInitAnim);
5692
5693   /* use copy of busy animation to prevent change while reloading artwork */
5694   init_last = init;
5695 #endif
5696 }
5697
5698 void RedrawBackground()
5699 {
5700   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5701              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5702
5703   redraw_mask = REDRAW_ALL;
5704 }
5705
5706 void InitGfxBackground()
5707 {
5708   int x, y;
5709
5710   fieldbuffer = bitmap_db_field;
5711   SetDrawtoField(DRAW_BACKBUFFER);
5712
5713 #if 1
5714   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5715 #else
5716   RedrawBackground();
5717
5718   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5719   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5720 #endif
5721
5722   for (x = 0; x < MAX_BUF_XSIZE; x++)
5723     for (y = 0; y < MAX_BUF_YSIZE; y++)
5724       redraw[x][y] = 0;
5725   redraw_tiles = 0;
5726   redraw_mask = REDRAW_ALL;
5727 }
5728
5729 static void InitLevelInfo()
5730 {
5731   LoadLevelInfo();                              /* global level info */
5732   LoadLevelSetup_LastSeries();                  /* last played series info */
5733   LoadLevelSetup_SeriesInfo();                  /* last played level info */
5734 }
5735
5736 static void InitLevelArtworkInfo()
5737 {
5738   LoadLevelArtworkInfo();
5739 }
5740
5741 static void InitImages()
5742 {
5743   print_timestamp_init("InitImages");
5744
5745 #if 0
5746   printf("::: leveldir_current->identifier == '%s'\n",
5747          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5748   printf("::: leveldir_current->graphics_path == '%s'\n",
5749          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5750   printf("::: leveldir_current->graphics_set == '%s'\n",
5751          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5752   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5753          leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5754 #endif
5755
5756   setLevelArtworkDir(artwork.gfx_first);
5757
5758 #if 0
5759   printf("::: leveldir_current->identifier == '%s'\n",
5760          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5761   printf("::: leveldir_current->graphics_path == '%s'\n",
5762          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5763   printf("::: leveldir_current->graphics_set == '%s'\n",
5764          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5765   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5766          leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5767 #endif
5768
5769 #if 0
5770   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5771          leveldir_current->identifier,
5772          artwork.gfx_current_identifier,
5773          artwork.gfx_current->identifier,
5774          leveldir_current->graphics_set,
5775          leveldir_current->graphics_path);
5776 #endif
5777
5778   UPDATE_BUSY_STATE();
5779
5780   ReloadCustomImages();
5781   print_timestamp_time("ReloadCustomImages");
5782
5783   UPDATE_BUSY_STATE();
5784
5785   LoadCustomElementDescriptions();
5786   print_timestamp_time("LoadCustomElementDescriptions");
5787
5788   UPDATE_BUSY_STATE();
5789
5790   LoadMenuDesignSettings();
5791   print_timestamp_time("LoadMenuDesignSettings");
5792
5793   UPDATE_BUSY_STATE();
5794
5795   ReinitializeGraphics();
5796   print_timestamp_time("ReinitializeGraphics");
5797
5798   UPDATE_BUSY_STATE();
5799
5800   print_timestamp_done("InitImages");
5801 }
5802
5803 static void InitSound(char *identifier)
5804 {
5805   print_timestamp_init("InitSound");
5806
5807   if (identifier == NULL)
5808     identifier = artwork.snd_current->identifier;
5809
5810   /* set artwork path to send it to the sound server process */
5811   setLevelArtworkDir(artwork.snd_first);
5812
5813   InitReloadCustomSounds(identifier);
5814   print_timestamp_time("InitReloadCustomSounds");
5815
5816   ReinitializeSounds();
5817   print_timestamp_time("ReinitializeSounds");
5818
5819   print_timestamp_done("InitSound");
5820 }
5821
5822 static void InitMusic(char *identifier)
5823 {
5824   print_timestamp_init("InitMusic");
5825
5826   if (identifier == NULL)
5827     identifier = artwork.mus_current->identifier;
5828
5829   /* set artwork path to send it to the sound server process */
5830   setLevelArtworkDir(artwork.mus_first);
5831
5832   InitReloadCustomMusic(identifier);
5833   print_timestamp_time("InitReloadCustomMusic");
5834
5835   ReinitializeMusic();
5836   print_timestamp_time("ReinitializeMusic");
5837
5838   print_timestamp_done("InitMusic");
5839 }
5840
5841 void InitNetworkServer()
5842 {
5843 #if defined(NETWORK_AVALIABLE)
5844   int nr_wanted;
5845 #endif
5846
5847   if (!options.network)
5848     return;
5849
5850 #if defined(NETWORK_AVALIABLE)
5851   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5852
5853   if (!ConnectToServer(options.server_host, options.server_port))
5854     Error(ERR_EXIT, "cannot connect to network game server");
5855
5856   SendToServer_PlayerName(setup.player_name);
5857   SendToServer_ProtocolVersion();
5858
5859   if (nr_wanted)
5860     SendToServer_NrWanted(nr_wanted);
5861 #endif
5862 }
5863
5864 static boolean CheckArtworkConfigForCustomElements(char *filename)
5865 {
5866   SetupFileHash *setup_file_hash;
5867   boolean redefined_ce_found = FALSE;
5868
5869   /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5870
5871   if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5872   {
5873     BEGIN_HASH_ITERATION(setup_file_hash, itr)
5874     {
5875       char *token = HASH_ITERATION_TOKEN(itr);
5876
5877       if (strPrefix(token, "custom_"))
5878       {
5879         redefined_ce_found = TRUE;
5880
5881         break;
5882       }
5883     }
5884     END_HASH_ITERATION(setup_file_hash, itr)
5885
5886     freeSetupFileHash(setup_file_hash);
5887   }
5888
5889   return redefined_ce_found;
5890 }
5891
5892 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5893 {
5894   char *filename_base, *filename_local;
5895   boolean redefined_ce_found = FALSE;
5896
5897   setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5898
5899 #if 0
5900   printf("::: leveldir_current->identifier == '%s'\n",
5901          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5902   printf("::: leveldir_current->graphics_path == '%s'\n",
5903          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5904   printf("::: leveldir_current->graphics_set == '%s'\n",
5905          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5906   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5907          leveldir_current == NULL ? "[NULL]" :
5908          LEVELDIR_ARTWORK_SET(leveldir_current, type));
5909 #endif
5910
5911   /* first look for special artwork configured in level series config */
5912   filename_base = getCustomArtworkLevelConfigFilename(type);
5913
5914 #if 0
5915   printf("::: filename_base == '%s'\n", filename_base);
5916 #endif
5917
5918   if (fileExists(filename_base))
5919     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5920
5921   filename_local = getCustomArtworkConfigFilename(type);
5922
5923 #if 0
5924   printf("::: filename_local == '%s'\n", filename_local);
5925 #endif
5926
5927   if (filename_local != NULL && !strEqual(filename_base, filename_local))
5928     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5929
5930 #if 0
5931   printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5932 #endif
5933
5934   return redefined_ce_found;
5935 }
5936
5937 static void InitOverrideArtwork()
5938 {
5939   boolean redefined_ce_found = FALSE;
5940
5941   /* to check if this level set redefines any CEs, do not use overriding */
5942   gfx.override_level_graphics = FALSE;
5943   gfx.override_level_sounds   = FALSE;
5944   gfx.override_level_music    = FALSE;
5945
5946   /* now check if this level set has definitions for custom elements */
5947   if (setup.override_level_graphics == AUTO ||
5948       setup.override_level_sounds   == AUTO ||
5949       setup.override_level_music    == AUTO)
5950     redefined_ce_found =
5951       (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5952        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5953        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5954
5955 #if 0
5956   printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5957 #endif
5958
5959   if (redefined_ce_found)
5960   {
5961     /* this level set has CE definitions: change "AUTO" to "FALSE" */
5962     gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5963     gfx.override_level_sounds   = (setup.override_level_sounds   == TRUE);
5964     gfx.override_level_music    = (setup.override_level_music    == TRUE);
5965   }
5966   else
5967   {
5968     /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5969     gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5970     gfx.override_level_sounds   = (setup.override_level_sounds   != FALSE);
5971     gfx.override_level_music    = (setup.override_level_music    != FALSE);
5972   }
5973
5974 #if 0
5975   printf("::: => %d, %d, %d\n",
5976          gfx.override_level_graphics,
5977          gfx.override_level_sounds,
5978          gfx.override_level_music);
5979 #endif
5980 }
5981
5982 static char *getNewArtworkIdentifier(int type)
5983 {
5984   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5985   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5986   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5987   static boolean initialized[3] = { FALSE, FALSE, FALSE };
5988   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5989 #if 1
5990   boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5991 #else
5992   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5993 #endif
5994   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5995   char *leveldir_identifier = leveldir_current->identifier;
5996 #if 1
5997   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5998   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5999 #else
6000   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
6001 #endif
6002   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6003   char *artwork_current_identifier;
6004   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
6005
6006   /* leveldir_current may be invalid (level group, parent link) */
6007   if (!validLevelSeries(leveldir_current))
6008     return NULL;
6009
6010   /* 1st step: determine artwork set to be activated in descending order:
6011      --------------------------------------------------------------------
6012      1. setup artwork (when configured to override everything else)
6013      2. artwork set configured in "levelinfo.conf" of current level set
6014         (artwork in level directory will have priority when loading later)
6015      3. artwork in level directory (stored in artwork sub-directory)
6016      4. setup artwork (currently configured in setup menu) */
6017
6018   if (setup_override_artwork)
6019     artwork_current_identifier = setup_artwork_set;
6020   else if (leveldir_artwork_set != NULL)
6021     artwork_current_identifier = leveldir_artwork_set;
6022   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
6023     artwork_current_identifier = leveldir_identifier;
6024   else
6025     artwork_current_identifier = setup_artwork_set;
6026
6027
6028   /* 2nd step: check if it is really needed to reload artwork set
6029      ------------------------------------------------------------ */
6030
6031 #if 0
6032   if (type == ARTWORK_TYPE_GRAPHICS)
6033     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
6034            artwork_new_identifier,
6035            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6036            artwork_current_identifier,
6037            leveldir_current->graphics_set,
6038            leveldir_current->identifier);
6039 #endif
6040
6041   /* ---------- reload if level set and also artwork set has changed ------- */
6042   if (leveldir_current_identifier[type] != leveldir_identifier &&
6043       (last_has_level_artwork_set[type] || has_level_artwork_set))
6044     artwork_new_identifier = artwork_current_identifier;
6045
6046   leveldir_current_identifier[type] = leveldir_identifier;
6047   last_has_level_artwork_set[type] = has_level_artwork_set;
6048
6049 #if 0
6050   if (type == ARTWORK_TYPE_GRAPHICS)
6051     printf("::: 1: '%s'\n", artwork_new_identifier);
6052 #endif
6053
6054   /* ---------- reload if "override artwork" setting has changed ----------- */
6055   if (last_override_level_artwork[type] != setup_override_artwork)
6056     artwork_new_identifier = artwork_current_identifier;
6057
6058   last_override_level_artwork[type] = setup_override_artwork;
6059
6060 #if 0
6061   if (type == ARTWORK_TYPE_GRAPHICS)
6062     printf("::: 2: '%s'\n", artwork_new_identifier);
6063 #endif
6064
6065   /* ---------- reload if current artwork identifier has changed ----------- */
6066   if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
6067                 artwork_current_identifier))
6068     artwork_new_identifier = artwork_current_identifier;
6069
6070   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
6071
6072 #if 0
6073   if (type == ARTWORK_TYPE_GRAPHICS)
6074     printf("::: 3: '%s'\n", artwork_new_identifier);
6075 #endif
6076
6077   /* ---------- do not reload directly after starting ---------------------- */
6078   if (!initialized[type])
6079     artwork_new_identifier = NULL;
6080
6081   initialized[type] = TRUE;
6082
6083 #if 0
6084   if (type == ARTWORK_TYPE_GRAPHICS)
6085     printf("::: 4: '%s'\n", artwork_new_identifier);
6086 #endif
6087
6088 #if 0
6089   if (type == ARTWORK_TYPE_GRAPHICS)
6090     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
6091            artwork.gfx_current_identifier, artwork_current_identifier,
6092            artwork.gfx_current->identifier, leveldir_current->graphics_set,
6093            artwork_new_identifier);
6094 #endif
6095
6096   return artwork_new_identifier;
6097 }
6098
6099 void ReloadCustomArtwork(int force_reload)
6100 {
6101   int last_game_status = game_status;   /* save current game status */
6102   char *gfx_new_identifier;
6103   char *snd_new_identifier;
6104   char *mus_new_identifier;
6105   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6106   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6107   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6108   boolean reload_needed;
6109
6110   InitOverrideArtwork();
6111
6112   force_reload_gfx |= AdjustGraphicsForEMC();
6113
6114   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6115   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6116   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6117
6118   reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6119                    snd_new_identifier != NULL || force_reload_snd ||
6120                    mus_new_identifier != NULL || force_reload_mus);
6121
6122   if (!reload_needed)
6123     return;
6124
6125   print_timestamp_init("ReloadCustomArtwork");
6126
6127   game_status = GAME_MODE_LOADING;
6128
6129   FadeOut(REDRAW_ALL);
6130
6131 #if 1
6132   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6133 #else
6134   ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
6135 #endif
6136   print_timestamp_time("ClearRectangle");
6137
6138 #if 0
6139   printf("::: fading in ... %d\n", fading.fade_mode);
6140 #endif
6141   FadeIn(REDRAW_ALL);
6142 #if 0
6143   printf("::: done\n");
6144 #endif
6145
6146   if (gfx_new_identifier != NULL || force_reload_gfx)
6147   {
6148 #if 0
6149     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
6150            artwork.gfx_current_identifier,
6151            gfx_new_identifier,
6152            artwork.gfx_current->identifier,
6153            leveldir_current->graphics_set);
6154 #endif
6155
6156     InitImages();
6157     print_timestamp_time("InitImages");
6158   }
6159
6160   if (snd_new_identifier != NULL || force_reload_snd)
6161   {
6162     InitSound(snd_new_identifier);
6163     print_timestamp_time("InitSound");
6164   }
6165
6166   if (mus_new_identifier != NULL || force_reload_mus)
6167   {
6168     InitMusic(mus_new_identifier);
6169     print_timestamp_time("InitMusic");
6170   }
6171
6172   game_status = last_game_status;       /* restore current game status */
6173
6174   init_last = init;                     /* switch to new busy animation */
6175
6176 #if 0
6177   printf("::: ----------------DELAY 1 ...\n");
6178   Delay(3000);
6179 #endif
6180
6181 #if 0
6182   printf("::: FadeOut @ ReloadCustomArtwork ...\n");
6183 #endif
6184   FadeOut(REDRAW_ALL);
6185 #if 0
6186   printf("::: FadeOut @ ReloadCustomArtwork done\n");
6187 #endif
6188
6189   RedrawBackground();
6190
6191   /* force redraw of (open or closed) door graphics */
6192   SetDoorState(DOOR_OPEN_ALL);
6193   CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6194
6195 #if 1
6196 #if 1
6197 #if 1
6198   FadeSetEnterScreen();
6199   FadeSkipNextFadeOut();
6200   // FadeSetDisabled();
6201 #else
6202   FadeSkipNext();
6203 #endif
6204 #else
6205   fading = fading_none;
6206 #endif
6207 #endif
6208
6209 #if 0
6210   redraw_mask = REDRAW_ALL;
6211 #endif
6212
6213   print_timestamp_done("ReloadCustomArtwork");
6214
6215   LimitScreenUpdates(FALSE);
6216 }
6217
6218 void KeyboardAutoRepeatOffUnlessAutoplay()
6219 {
6220   if (global.autoplay_leveldir == NULL)
6221     KeyboardAutoRepeatOff();
6222 }
6223
6224 void DisplayExitMessage(char *format, va_list ap)
6225 {
6226   // check if draw buffer and fonts for exit message are already available
6227   if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6228     return;
6229
6230   int font_1 = FC_RED;
6231   int font_2 = FC_YELLOW;
6232   int font_3 = FC_BLUE;
6233   int font_width = getFontWidth(font_2);
6234   int font_height = getFontHeight(font_2);
6235   int sx = SX;
6236   int sy = SY;
6237   int sxsize = WIN_XSIZE - 2 * sx;
6238   int sysize = WIN_YSIZE - 2 * sy;
6239   int line_length = sxsize / font_width;
6240   int max_lines = sysize / font_height;
6241   int num_lines_printed;
6242
6243   gfx.sx = sx;
6244   gfx.sy = sy;
6245   gfx.sxsize = sxsize;
6246   gfx.sysize = sysize;
6247
6248   sy = 20;
6249
6250   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6251
6252   DrawTextSCentered(sy, font_1, "Fatal error:");
6253   sy += 3 * font_height;;
6254
6255   num_lines_printed =
6256     DrawTextBufferVA(sx, sy, format, ap, font_2,
6257                      line_length, line_length, max_lines,
6258                      0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6259   sy += (num_lines_printed + 3) * font_height;
6260
6261   DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6262   sy += 3 * font_height;
6263
6264   num_lines_printed =
6265     DrawTextBuffer(sx, sy, program.error_filename, font_2,
6266                    line_length, line_length, max_lines,
6267                    0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6268
6269   DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6270
6271   redraw_mask = REDRAW_ALL;
6272
6273   BackToFront();
6274
6275   /* deactivate toons on error message screen */
6276   setup.toons = FALSE;
6277
6278   WaitForEventToContinue();
6279 }
6280
6281
6282 /* ========================================================================= */
6283 /* OpenAll()                                                                 */
6284 /* ========================================================================= */
6285
6286 void OpenAll()
6287 {
6288   print_timestamp_init("OpenAll");
6289
6290   game_status = GAME_MODE_LOADING;
6291
6292 #if 1
6293   InitCounter();
6294 #endif
6295
6296   InitGlobal();                 /* initialize some global variables */
6297
6298   print_timestamp_time("[init global stuff]");
6299
6300   if (options.execute_command)
6301     Execute_Command(options.execute_command);
6302
6303   if (options.serveronly)
6304   {
6305 #if defined(PLATFORM_UNIX)
6306     NetworkServer(options.server_port, options.serveronly);
6307 #else
6308     Error(ERR_WARN, "networking only supported in Unix version");
6309 #endif
6310
6311     exit(0);                    /* never reached, server loops forever */
6312   }
6313
6314   InitSetup();
6315
6316   print_timestamp_time("[init setup/config stuff (1)]");
6317
6318   InitGameInfo();
6319   print_timestamp_time("[init setup/config stuff (2)]");
6320   InitPlayerInfo();
6321   print_timestamp_time("[init setup/config stuff (3)]");
6322   InitArtworkInfo();            /* needed before loading gfx, sound & music */
6323   print_timestamp_time("[init setup/config stuff (4)]");
6324   InitArtworkConfig();          /* needed before forking sound child process */
6325   print_timestamp_time("[init setup/config stuff (5)]");
6326   InitMixer();
6327   print_timestamp_time("[init setup/config stuff (6)]");
6328
6329 #if 0
6330   InitCounter();
6331 #endif
6332
6333   InitRND(NEW_RANDOMIZE);
6334   InitSimpleRandom(NEW_RANDOMIZE);
6335
6336   InitJoysticks();
6337
6338   print_timestamp_time("[init setup/config stuff]");
6339
6340   InitVideoDisplay();
6341   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6342
6343   InitEventFilter(FilterEvents);
6344
6345   print_timestamp_time("[init video stuff]");
6346
6347   InitElementPropertiesStatic();
6348   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6349   InitElementPropertiesGfxElement();
6350
6351   print_timestamp_time("[init element properties stuff]");
6352
6353   InitGfx();
6354
6355   print_timestamp_time("InitGfx");
6356
6357   InitLevelInfo();
6358   print_timestamp_time("InitLevelInfo");
6359
6360   InitLevelArtworkInfo();
6361   print_timestamp_time("InitLevelArtworkInfo");
6362
6363   InitOverrideArtwork();        /* needs to know current level directory */
6364   print_timestamp_time("InitOverrideArtwork");
6365
6366   InitImages();                 /* needs to know current level directory */
6367   print_timestamp_time("InitImages");
6368
6369   InitSound(NULL);              /* needs to know current level directory */
6370   print_timestamp_time("InitSound");
6371
6372   InitMusic(NULL);              /* needs to know current level directory */
6373   print_timestamp_time("InitMusic");
6374
6375   InitGfxBackground();
6376
6377 #if 1
6378   em_open_all();
6379 #endif
6380
6381 #if 1
6382   sp_open_all();
6383 #endif
6384
6385   if (global.autoplay_leveldir)
6386   {
6387     AutoPlayTape();
6388     return;
6389   }
6390   else if (global.convert_leveldir)
6391   {
6392     ConvertLevels();
6393     return;
6394   }
6395   else if (global.create_images_dir)
6396   {
6397     CreateLevelSketchImages();
6398     return;
6399   }
6400
6401   game_status = GAME_MODE_MAIN;
6402
6403 #if 1
6404   FadeSetEnterScreen();
6405   if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6406     FadeSkipNextFadeOut();
6407   // FadeSetDisabled();
6408 #else
6409   fading = fading_none;
6410 #endif
6411
6412   print_timestamp_time("[post-artwork]");
6413
6414   print_timestamp_done("OpenAll");
6415
6416   DrawMainMenu();
6417
6418   InitNetworkServer();
6419
6420 #if 0
6421   Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6422         SDL_GetBasePath());
6423   Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6424         SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6425 #if defined(PLATFORM_ANDROID)
6426   Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6427         SDL_AndroidGetInternalStoragePath());
6428   Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6429         SDL_AndroidGetExternalStoragePath());
6430   Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6431         (SDL_AndroidGetExternalStorageState() ==
6432          SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6433          SDL_AndroidGetExternalStorageState() ==
6434          SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6435 #endif
6436 #endif
6437 }
6438
6439 void CloseAllAndExit(int exit_value)
6440 {
6441   StopSounds();
6442   FreeAllSounds();
6443   FreeAllMusic();
6444   CloseAudio();         /* called after freeing sounds (needed for SDL) */
6445
6446 #if 1
6447   em_close_all();
6448 #endif
6449
6450 #if 1
6451   sp_close_all();
6452 #endif
6453
6454   FreeAllImages();
6455
6456 #if defined(TARGET_SDL)
6457 #if defined(TARGET_SDL2)
6458   // !!! TODO !!!
6459   // set a flag to tell the network server thread to quit and wait for it
6460   // using SDL_WaitThread()
6461 #else
6462   if (network_server)   /* terminate network server */
6463     SDL_KillThread(server_thread);
6464 #endif
6465 #endif
6466
6467   CloseVideoDisplay();
6468   ClosePlatformDependentStuff();
6469
6470   if (exit_value != 0)
6471   {
6472     /* fall back to default level set (current set may have caused an error) */
6473     SaveLevelSetup_LastSeries_Deactivate();
6474
6475     /* tell user where to find error log file which may contain more details */
6476     // (error notification now directly displayed on screen inside R'n'D
6477     // NotifyUserAboutErrorFile();      /* currently only works for Windows */
6478   }
6479
6480   exit(exit_value);
6481 }