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