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