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