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