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