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