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