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