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