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