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