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