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