rnd-20030402-1-src
[rocksndiamonds.git] / src / init.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 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
28 #include "conf_e2g.c"   /* include auto-generated data structure definitions */
29 #include "conf_esg.c"   /* include auto-generated data structure definitions */
30 #include "conf_e2s.c"   /* include auto-generated data structure definitions */
31 #include "conf_fnt.c"   /* include auto-generated data structure definitions */
32
33
34 #define CONFIG_TOKEN_FONT_INITIAL               "font.initial"
35
36
37 struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
38
39
40 static void InitTileClipmasks()
41 {
42 #if 0
43 #if defined(TARGET_X11)
44   XGCValues clip_gc_values;
45   unsigned long clip_gc_valuemask;
46
47 #if defined(TARGET_X11_NATIVE)
48
49 #if 0
50   GC copy_clipmask_gc;
51
52   static struct
53   {
54     int start;
55     int count;
56   }
57   tile_needs_clipping[] =
58   {
59     { GFX_SPIELER1_UP, 4 },
60     { GFX_SPIELER1_DOWN, 4 },
61     { GFX_SPIELER1_LEFT, 4 },
62     { GFX_SPIELER1_RIGHT, 4 },
63     { GFX_SPIELER1_PUSH_LEFT, 4 },
64     { GFX_SPIELER1_PUSH_RIGHT, 4 },
65     { GFX_SPIELER2_UP, 4 },
66     { GFX_SPIELER2_DOWN, 4 },
67     { GFX_SPIELER2_LEFT, 4 },
68     { GFX_SPIELER2_RIGHT, 4 },
69     { GFX_SPIELER2_PUSH_LEFT, 4 },
70     { GFX_SPIELER2_PUSH_RIGHT, 4 },
71     { GFX_SPIELER3_UP, 4 },
72     { GFX_SPIELER3_DOWN, 4 },
73     { GFX_SPIELER3_LEFT, 4 },
74     { GFX_SPIELER3_RIGHT, 4 },
75     { GFX_SPIELER3_PUSH_LEFT, 4 },
76     { GFX_SPIELER3_PUSH_RIGHT, 4 },
77     { GFX_SPIELER4_UP, 4 },
78     { GFX_SPIELER4_DOWN, 4 },
79     { GFX_SPIELER4_LEFT, 4 },
80     { GFX_SPIELER4_RIGHT, 4 },
81     { GFX_SPIELER4_PUSH_LEFT, 4 },
82     { GFX_SPIELER4_PUSH_RIGHT, 4 },
83     { GFX_SP_MURPHY, 1 },
84     { GFX_MURPHY_GO_LEFT, 3 },
85     { GFX_MURPHY_GO_RIGHT, 3 },
86     { GFX_MURPHY_SNAP_UP, 1 },
87     { GFX_MURPHY_SNAP_DOWN, 1 },
88     { GFX_MURPHY_SNAP_RIGHT, 1 },
89     { GFX_MURPHY_SNAP_LEFT, 1 },
90     { GFX_MURPHY_PUSH_RIGHT, 1 },
91     { GFX_MURPHY_PUSH_LEFT, 1 },
92     { GFX_GEBLUBBER, 4 },
93     { GFX_DYNAMIT, 7 },
94     { GFX_DYNABOMB, 4 },
95     { GFX_EXPLOSION, 8 },
96     { GFX_SOKOBAN_OBJEKT, 1 },
97     { GFX_FUNKELN_BLAU, 3 },
98     { GFX_FUNKELN_WEISS, 3 },
99     { GFX2_SHIELD_PASSIVE, 3 },
100     { GFX2_SHIELD_ACTIVE, 3 },
101     { -1, 0 }
102   };
103 #endif
104
105 #endif /* TARGET_X11_NATIVE */
106 #endif /* TARGET_X11 */
107
108   int i;
109
110   /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
111   for (i=0; i<NUM_TILES; i++)
112     tile_clipmask[i] = None;
113
114 #if defined(TARGET_X11)
115   /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
116      often very slow when preparing a masked XCopyArea() for big Pixmaps.
117      To prevent this, create small (tile-sized) mask Pixmaps which will then
118      be set much faster with XSetClipOrigin() and speed things up a lot. */
119
120   clip_gc_values.graphics_exposures = False;
121   clip_gc_valuemask = GCGraphicsExposures;
122   tile_clip_gc = XCreateGC(display, window->drawable,
123                            clip_gc_valuemask, &clip_gc_values);
124
125 #if 0
126   for (i=0; i<NUM_BITMAPS; i++)
127   {
128     if (pix[i]->clip_mask)
129     {
130       clip_gc_values.graphics_exposures = False;
131       clip_gc_values.clip_mask = pix[i]->clip_mask;
132       clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
133       pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
134                                          clip_gc_valuemask, &clip_gc_values);
135     }
136   }
137 #endif
138
139 #if defined(TARGET_X11_NATIVE)
140
141 #if 0
142   /* create graphic context structures needed for clipping */
143   clip_gc_values.graphics_exposures = False;
144   clip_gc_valuemask = GCGraphicsExposures;
145   copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
146                                clip_gc_valuemask, &clip_gc_values);
147
148   /* create only those clipping Pixmaps we really need */
149   for (i=0; tile_needs_clipping[i].start>=0; i++)
150   {
151     int j;
152
153     for (j=0; j<tile_needs_clipping[i].count; j++)
154     {
155       int tile = tile_needs_clipping[i].start + j;
156       int graphic = tile;
157       int src_x, src_y;
158       Bitmap *src_bitmap;
159       Pixmap src_pixmap;
160
161       getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
162       src_pixmap = src_bitmap->clip_mask;
163
164       tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
165                                           TILEX, TILEY, 1);
166
167       XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
168                 src_x, src_y, TILEX, TILEY, 0, 0);
169     }
170   }
171
172   XFreeGC(display, copy_clipmask_gc);
173 #endif
174
175 #endif /* TARGET_X11_NATIVE */
176 #endif /* TARGET_X11 */
177 #endif
178 }
179
180 void FreeTileClipmasks()
181 {
182 #if 0
183 #if defined(TARGET_X11)
184   int i;
185
186   for (i=0; i<NUM_TILES; i++)
187   {
188     if (tile_clipmask[i] != None)
189     {
190       XFreePixmap(display, tile_clipmask[i]);
191       tile_clipmask[i] = None;
192     }
193   }
194
195   if (tile_clip_gc)
196     XFreeGC(display, tile_clip_gc);
197   tile_clip_gc = None;
198
199 #if 0
200   for (i=0; i<NUM_BITMAPS; i++)
201   {
202     if (pix[i] != NULL && pix[i]->stored_clip_gc)
203     {
204       XFreeGC(display, pix[i]->stored_clip_gc);
205       pix[i]->stored_clip_gc = None;
206     }
207   }
208 #endif
209
210 #endif /* TARGET_X11 */
211 #endif
212 }
213
214 void FreeGadgets()
215 {
216   FreeLevelEditorGadgets();
217   FreeGameButtons();
218   FreeTapeButtons();
219   FreeToolButtons();
220   FreeScreenGadgets();
221 }
222
223 void InitGadgets()
224 {
225   static boolean gadgets_initialized = FALSE;
226
227   if (gadgets_initialized)
228     FreeGadgets();
229
230   CreateLevelEditorGadgets();
231   CreateGameButtons();
232   CreateTapeButtons();
233   CreateToolButtons();
234   CreateScreenGadgets();
235
236   gadgets_initialized = TRUE;
237 }
238
239 void InitElementSmallImages()
240 {
241   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
242   int num_property_mappings = getImageListPropertyMappingSize();
243   int i;
244
245   /* initialize normal images from static configuration */
246   for (i=0; element_to_graphic[i].element > -1; i++)
247     CreateImageWithSmallImages(element_to_graphic[i].graphic);
248
249   /* initialize special images from static configuration */
250   for (i=0; element_to_special_graphic[i].element > -1; i++)
251     CreateImageWithSmallImages(element_to_special_graphic[i].graphic);
252
253   /* initialize images from dynamic configuration */
254   for (i=0; i < num_property_mappings; i++)
255     if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
256       CreateImageWithSmallImages(property_mapping[i].artwork_index);
257 }
258
259 static int getFontBitmapID(int font_nr)
260 {
261   int special = -1;
262
263   if (game_status == MAINMENU || game_status == TYPENAME)
264     special = GFX_SPECIAL_ARG_MAIN;
265   else if (game_status == CHOOSELEVEL)
266     special = GFX_SPECIAL_ARG_LEVELS;
267   else if (game_status == HALLOFFAME)
268     special = GFX_SPECIAL_ARG_SCORES;
269   else if (game_status == LEVELED)
270     special = GFX_SPECIAL_ARG_EDITOR;
271   else if (game_status == HELPSCREEN)
272     special = GFX_SPECIAL_ARG_INFO;
273   else if (game_status == SETUP)
274     special = GFX_SPECIAL_ARG_SETUP;
275   else if (game_status == PSEUDO_PREVIEW)
276     special = GFX_SPECIAL_ARG_PREVIEW;
277   else if (game_status == PLAYING || game_status == PSEUDO_DOOR)
278     special = GFX_SPECIAL_ARG_DOOR;
279
280   if (special != -1)
281     return font_info[font_nr].special_bitmap_id[special];
282   else
283     return font_nr;
284 }
285
286 void InitFontGraphicInfo()
287 {
288   static struct FontBitmapInfo *font_bitmap_info = NULL;
289   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
290   int num_property_mappings = getImageListPropertyMappingSize();
291   int num_font_bitmaps = NUM_FONTS;
292   int i, j;
293
294   if (graphic_info == NULL)             /* still at startup phase */
295   {
296     InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
297
298     return;
299   }
300
301   /* ---------- initialize font graphic definitions ---------- */
302
303   /* always start with reliable default values (normal font graphics) */
304   for (i=0; i < NUM_FONTS; i++)
305     font_info[i].graphic = FONT_INITIAL_1;
306
307   /* initialize normal font/graphic mapping from static configuration */
308   for (i=0; font_to_graphic[i].font_nr > -1; i++)
309   {
310     int font_nr = font_to_graphic[i].font_nr;
311     int special = font_to_graphic[i].special;
312     int graphic = font_to_graphic[i].graphic;
313
314     if (special != -1)
315       continue;
316
317     font_info[font_nr].graphic = graphic;
318   }
319
320   /* always start with reliable default values (special font graphics) */
321   for (i=0; i < NUM_FONTS; i++)
322   {
323     for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
324     {
325       font_info[i].special_graphic[j] = font_info[i].graphic;
326       font_info[i].special_bitmap_id[j] = i;
327     }
328   }
329
330   /* initialize special font/graphic mapping from static configuration */
331   for (i=0; font_to_graphic[i].font_nr > -1; i++)
332   {
333     int font_nr = font_to_graphic[i].font_nr;
334     int special = font_to_graphic[i].special;
335     int graphic = font_to_graphic[i].graphic;
336
337     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
338     {
339       font_info[font_nr].special_graphic[special] = graphic;
340       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
341       num_font_bitmaps++;
342     }
343   }
344
345   /* initialize special element/graphic mapping from dynamic configuration */
346   for (i=0; i < num_property_mappings; i++)
347   {
348     int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
349     int special = property_mapping[i].ext3_index;
350     int graphic = property_mapping[i].artwork_index;
351
352     if (font_nr < 0)
353       continue;
354
355     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
356     {
357       font_info[font_nr].special_graphic[special] = graphic;
358       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
359       num_font_bitmaps++;
360     }
361   }
362
363   /* ---------- initialize font bitmap array ---------- */
364
365   if (font_bitmap_info != NULL)
366     free(font_bitmap_info);
367
368   font_bitmap_info =
369     checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
370
371   /* ---------- initialize font bitmap definitions ---------- */
372
373   for (i=0; i < NUM_FONTS; i++)
374   {
375     if (i < NUM_INITIAL_FONTS)
376     {
377       font_bitmap_info[i] = font_initial[i];
378       continue;
379     }
380
381     for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
382     {
383       int font_bitmap_id = font_info[i].special_bitmap_id[j];
384       int graphic = font_info[i].special_graphic[j];
385
386       /* copy font relevant information from graphics information */
387       font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
388       font_bitmap_info[font_bitmap_id].src_x  = graphic_info[graphic].src_x;
389       font_bitmap_info[font_bitmap_id].src_y  = graphic_info[graphic].src_y;
390       font_bitmap_info[font_bitmap_id].width  = graphic_info[graphic].width;
391       font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
392       font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
393       font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
394     }
395   }
396
397   InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
398 }
399
400 void InitElementGraphicInfo()
401 {
402   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
403   int num_property_mappings = getImageListPropertyMappingSize();
404   int i, act, dir;
405
406   /* set values to -1 to identify later as "uninitialized" values */
407   for (i=0; i<MAX_NUM_ELEMENTS; i++)
408   {
409     for (act=0; act<NUM_ACTIONS; act++)
410     {
411       element_info[i].graphic[act] = -1;
412
413       for (dir=0; dir<NUM_DIRECTIONS; dir++)
414         element_info[i].direction_graphic[act][dir] = -1;
415     }
416   }
417
418   /* initialize normal element/graphic mapping from static configuration */
419   for (i=0; element_to_graphic[i].element > -1; i++)
420   {
421     int element   = element_to_graphic[i].element;
422     int action    = element_to_graphic[i].action;
423     int direction = element_to_graphic[i].direction;
424     int graphic   = element_to_graphic[i].graphic;
425
426     if (graphic_info[graphic].bitmap == NULL)
427       continue;
428
429     if (action < 0)
430       action = ACTION_DEFAULT;
431
432     if (direction > -1)
433       element_info[element].direction_graphic[action][direction] = graphic;
434     else
435       element_info[element].graphic[action] = graphic;
436   }
437
438   /* initialize normal element/graphic mapping from dynamic configuration */
439   for (i=0; i < num_property_mappings; i++)
440   {
441     int element   = property_mapping[i].base_index;
442     int action    = property_mapping[i].ext1_index;
443     int direction = property_mapping[i].ext2_index;
444     int special   = property_mapping[i].ext3_index;
445     int graphic   = property_mapping[i].artwork_index;
446
447     if (graphic_info[graphic].bitmap == NULL)
448       continue;
449
450     if (element >= MAX_NUM_ELEMENTS || special != -1)
451       continue;
452
453     if (action < 0)
454       action = ACTION_DEFAULT;
455
456     if (direction > -1)
457       element_info[element].direction_graphic[action][direction] = graphic;
458     else
459       element_info[element].graphic[action] = graphic;
460   }
461
462   /* now set all '-1' values to element specific default values */
463   for (i=0; i<MAX_NUM_ELEMENTS; i++)
464   {
465     int default_action_graphic = element_info[i].graphic[ACTION_DEFAULT];
466     int default_action_direction_graphic[NUM_DIRECTIONS];
467
468     if (default_action_graphic == -1)
469       default_action_graphic = IMG_CHAR_QUESTION;
470
471     for (dir=0; dir<NUM_DIRECTIONS; dir++)
472     {
473       default_action_direction_graphic[dir] =
474         element_info[i].direction_graphic[ACTION_DEFAULT][dir];
475
476       if (default_action_direction_graphic[dir] == -1)
477         default_action_direction_graphic[dir] = default_action_graphic;
478     }
479
480     for (act=0; act<NUM_ACTIONS; act++)
481     {
482       boolean act_empty = (act == ACTION_DIGGING ||
483                            act == ACTION_SNAPPING ||
484                            act == ACTION_COLLECTING);
485
486       for (dir=0; dir<NUM_DIRECTIONS; dir++)
487       {
488         int default_direction_graphic = element_info[i].graphic[act];
489
490         /* no graphic for current action -- use default direction graphic */
491         if (default_direction_graphic == -1)
492           default_direction_graphic =
493             (act_empty ? IMG_EMPTY : default_action_direction_graphic[dir]);
494
495         if (element_info[i].direction_graphic[act][dir] == -1)
496           element_info[i].direction_graphic[act][dir] =
497             default_direction_graphic;
498       }
499
500       /* no graphic for this specific action -- use default action graphic */
501       if (element_info[i].graphic[act] == -1)
502         element_info[i].graphic[act] =
503           (act_empty ? IMG_EMPTY : default_action_graphic);
504     }
505   }
506
507 #if 0
508 #if DEBUG
509   if (options.verbose)
510   {
511     for (i=0; i<MAX_NUM_ELEMENTS; i++)
512       if (element_info[i].graphic[ACTION_DEFAULT] == IMG_CHAR_QUESTION &&
513           i != EL_CHAR_QUESTION)
514         Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
515               element_info[i].token_name, i);
516   }
517 #endif
518 #endif
519 }
520
521 void InitElementSpecialGraphicInfo()
522 {
523   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
524   int num_property_mappings = getImageListPropertyMappingSize();
525   int i, j;
526
527   /* always start with reliable default values */
528   for (i=0; i < MAX_NUM_ELEMENTS; i++)
529     for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
530       element_info[i].special_graphic[j] =
531         element_info[i].graphic[ACTION_DEFAULT];
532
533   /* initialize special element/graphic mapping from static configuration */
534   for (i=0; element_to_special_graphic[i].element > -1; i++)
535   {
536     int element = element_to_special_graphic[i].element;
537     int special = element_to_special_graphic[i].special;
538     int graphic = element_to_special_graphic[i].graphic;
539     boolean base_redefined = getImageListEntry(el2img(element))->redefined;
540     boolean special_redefined = getImageListEntry(graphic)->redefined;
541
542     if (base_redefined && !special_redefined)
543       continue;
544
545     element_info[element].special_graphic[special] = graphic;
546   }
547
548   /* initialize special element/graphic mapping from dynamic configuration */
549   for (i=0; i < num_property_mappings; i++)
550   {
551     int element = property_mapping[i].base_index;
552     int special = property_mapping[i].ext3_index;
553     int graphic = property_mapping[i].artwork_index;
554
555     if (element >= MAX_NUM_ELEMENTS)
556       continue;
557
558     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
559       element_info[element].special_graphic[special] = graphic;
560   }
561 }
562
563 static void set_graphic_parameters(int graphic, char **parameter_raw)
564 {
565   Bitmap *src_bitmap = getBitmapFromImageID(graphic);
566   int num_xtiles = (src_bitmap ? src_bitmap->width          : TILEX) / TILEX;
567   int num_ytiles = (src_bitmap ? src_bitmap->height * 2 / 3 : TILEY) / TILEY;
568   int parameter[NUM_GFX_ARGS];
569   int i;
570
571   /* get integer values from string parameters */
572   for (i=0; i < NUM_GFX_ARGS; i++)
573     parameter[i] =
574       get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
575                           image_config_suffix[i].type);
576
577   graphic_info[graphic].bitmap = src_bitmap;
578
579   /* start with reliable default values */
580   graphic_info[graphic].src_x = 0;
581   graphic_info[graphic].src_y = 0;
582   graphic_info[graphic].width = TILEX;
583   graphic_info[graphic].height = TILEY;
584   graphic_info[graphic].offset_x = 0;   /* one or both of these values ... */
585   graphic_info[graphic].offset_y = 0;   /* ... will be corrected later */
586
587   /* optional x and y tile position of animation frame sequence */
588   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
589     graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
590   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
591     graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
592
593   /* optional x and y pixel position of animation frame sequence */
594   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
595     graphic_info[graphic].src_x = parameter[GFX_ARG_X];
596   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
597     graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
598
599   /* optional width and height of each animation frame */
600   if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
601     graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
602   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
603     graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
604
605   /* correct x or y offset dependant of vertical or horizontal frame order */
606   if (parameter[GFX_ARG_VERTICAL])      /* frames are ordered vertically */
607   {
608     if (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE)
609       graphic_info[graphic].offset_y = parameter[GFX_ARG_OFFSET];
610     else
611       graphic_info[graphic].offset_y = graphic_info[graphic].height;
612   }
613   else                                  /* frames are ordered horizontally */
614   {
615     if (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE)
616       graphic_info[graphic].offset_x = parameter[GFX_ARG_OFFSET];
617     else
618       graphic_info[graphic].offset_x = graphic_info[graphic].width;
619   }
620
621   /* optionally, the x and y offset of frames can be specified directly */
622   if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
623     graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
624   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
625     graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
626
627   /* automatically determine correct number of frames, if not defined */
628   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
629     graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
630   else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
631     graphic_info[graphic].anim_frames = num_xtiles;
632   else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
633     graphic_info[graphic].anim_frames = num_ytiles;
634   else
635     graphic_info[graphic].anim_frames = 1;
636
637   graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
638   if (graphic_info[graphic].anim_delay == 0)    /* delay must be at least 1 */
639     graphic_info[graphic].anim_delay = 1;
640
641   if (parameter[GFX_ARG_ANIM_MODE] != ANIM_NONE)
642     graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
643   else if (graphic_info[graphic].anim_frames > 1)
644     graphic_info[graphic].anim_mode = ANIM_LOOP;
645
646   /* automatically determine correct start frame, if not defined */
647   if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
648     graphic_info[graphic].anim_start_frame = 0;
649   else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
650     graphic_info[graphic].anim_start_frame =
651       graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
652   else
653     graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
654
655   /* animation synchronized with global frame counter, not move position */
656   graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
657
658   /* this is only used for toon animations */
659   graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
660   graphic_info[graphic].step_delay  = parameter[GFX_ARG_STEP_DELAY];
661
662   /* this is only used for drawing font characters */
663   graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
664   graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
665 }
666
667 static void InitGraphicInfo()
668 {
669   int fallback_graphic = IMG_CHAR_EXCLAM;
670   struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
671   Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
672   int num_images = getImageListSize();
673   int i;
674
675 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
676   static boolean clipmasks_initialized = FALSE;
677   Pixmap src_pixmap;
678   XGCValues clip_gc_values;
679   unsigned long clip_gc_valuemask;
680   GC copy_clipmask_gc = None;
681 #endif
682
683   if (graphic_info != NULL)
684     free(graphic_info);
685
686   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
687
688 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
689   if (clipmasks_initialized)
690   {
691     for (i=0; i<num_images; i++)
692     {
693       if (graphic_info[i].clip_mask)
694         XFreePixmap(display, graphic_info[i].clip_mask);
695       if (graphic_info[i].clip_gc)
696         XFreeGC(display, graphic_info[i].clip_gc);
697
698       graphic_info[i].clip_mask = None;
699       graphic_info[i].clip_gc = None;
700     }
701   }
702 #endif
703
704   for (i=0; i<num_images; i++)
705   {
706     struct FileInfo *image = getImageListEntry(i);
707     Bitmap *src_bitmap;
708     int src_x, src_y;
709     int first_frame, last_frame;
710
711     set_graphic_parameters(i, image->parameter);
712
713     /* now check if no animation frames are outside of the loaded image */
714
715     if (graphic_info[i].bitmap == NULL)
716       continue;         /* skip check for optional images that are undefined */
717
718     first_frame = 0;
719     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
720     if (src_x < 0 || src_y < 0 ||
721         src_x + TILEX > src_bitmap->width ||
722         src_y + TILEY > src_bitmap->height)
723     {
724       Error(ERR_RETURN_LINE, "-");
725       Error(ERR_RETURN, "warning: error found in config file:");
726       Error(ERR_RETURN, "- config file: '%s'",
727             getImageConfigFilename());
728       Error(ERR_RETURN, "- config token: '%s'",
729             getTokenFromImageID(i));
730       Error(ERR_RETURN, "- image file: '%s'",
731             src_bitmap->source_filename);
732       Error(ERR_RETURN,
733             "error: first animation frame out of bounds (%d, %d)",
734             src_x, src_y);
735       Error(ERR_RETURN, "custom graphic rejected for this element/action");
736
737       if (i == fallback_graphic)
738         Error(ERR_EXIT, "fatal error: no fallback graphic available");
739
740       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
741       Error(ERR_RETURN_LINE, "-");
742
743       set_graphic_parameters(i, fallback_image->default_parameter);
744       graphic_info[i].bitmap = fallback_bitmap;
745     }
746
747     last_frame = graphic_info[i].anim_frames - 1;
748     getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
749     if (src_x < 0 || src_y < 0 ||
750         src_x + TILEX > src_bitmap->width ||
751         src_y + TILEY > src_bitmap->height)
752     {
753       Error(ERR_RETURN_LINE, "-");
754       Error(ERR_RETURN, "warning: error found in config file:");
755       Error(ERR_RETURN, "- config file: '%s'",
756             getImageConfigFilename());
757       Error(ERR_RETURN, "- config token: '%s'",
758             getTokenFromImageID(i));
759       Error(ERR_RETURN, "- image file: '%s'",
760             src_bitmap->source_filename);
761       Error(ERR_RETURN,
762             "error: last animation frame (%d) out of bounds (%d, %d)",
763             last_frame, src_x, src_y);
764       Error(ERR_RETURN, "custom graphic rejected for this element/action");
765
766       if (i == fallback_graphic)
767         Error(ERR_EXIT, "fatal error: no fallback graphic available");
768
769       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
770       Error(ERR_RETURN_LINE, "-");
771
772       set_graphic_parameters(i, fallback_image->default_parameter);
773       graphic_info[i].bitmap = fallback_bitmap;
774     }
775
776 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
777     /* currently we need only a tile clip mask from the first frame */
778     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
779
780     if (copy_clipmask_gc == None)
781     {
782       clip_gc_values.graphics_exposures = False;
783       clip_gc_valuemask = GCGraphicsExposures;
784       copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
785                                    clip_gc_valuemask, &clip_gc_values);
786     }
787
788     graphic_info[i].clip_mask =
789       XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
790
791     src_pixmap = src_bitmap->clip_mask;
792     XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
793               copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
794
795     clip_gc_values.graphics_exposures = False;
796     clip_gc_values.clip_mask = graphic_info[i].clip_mask;
797     clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
798
799     graphic_info[i].clip_gc =
800       XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
801 #endif
802   }
803
804 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
805   if (copy_clipmask_gc)
806     XFreeGC(display, copy_clipmask_gc);
807
808   clipmasks_initialized = TRUE;
809 #endif
810 }
811
812 static void InitElementSoundInfo()
813 {
814   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
815   int num_property_mappings = getSoundListPropertyMappingSize();
816   int i, j, act;
817
818   /* set values to -1 to identify later as "uninitialized" values */
819   for (i=0; i < MAX_NUM_ELEMENTS; i++)
820     for (act=0; act < NUM_ACTIONS; act++)
821       element_info[i].sound[act] = -1;
822
823   /* initialize element/sound mapping from static configuration */
824   for (i=0; element_to_sound[i].element > -1; i++)
825   {
826     int element      = element_to_sound[i].element;
827     int action       = element_to_sound[i].action;
828     int sound        = element_to_sound[i].sound;
829     boolean is_class = element_to_sound[i].is_class;
830
831     if (action < 0)
832       action = ACTION_DEFAULT;
833
834     if (!is_class)
835       element_info[element].sound[action] = sound;
836     else
837       for (j=0; j < MAX_NUM_ELEMENTS; j++)
838         if (strcmp(element_info[j].class_name,
839                    element_info[element].class_name) == 0)
840           element_info[j].sound[action] = sound;
841   }
842
843   /* initialize element/sound mapping from dynamic configuration */
844   for (i=0; i < num_property_mappings; i++)
845   {
846     int element = property_mapping[i].base_index;
847     int action  = property_mapping[i].ext1_index;
848     int sound   = property_mapping[i].artwork_index;
849
850     if (element >= MAX_NUM_ELEMENTS)
851       continue;
852
853     if (action < 0)
854       action = ACTION_DEFAULT;
855
856     element_info[element].sound[action] = sound;
857   }
858
859   /* initialize element class/sound mapping from dynamic configuration */
860   for (i=0; i < num_property_mappings; i++)
861   {
862     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
863     int action        = property_mapping[i].ext1_index;
864     int sound         = property_mapping[i].artwork_index;
865
866     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
867       continue;
868
869     if (action < 0)
870       action = ACTION_DEFAULT;
871
872     for (j=0; j < MAX_NUM_ELEMENTS; j++)
873       if (strcmp(element_info[j].class_name,
874                  element_info[element_class].class_name) == 0)
875         element_info[j].sound[action] = sound;
876   }
877
878   /* now set all '-1' values to element specific default values */
879   for (i=0; i<MAX_NUM_ELEMENTS; i++)
880   {
881     int default_action_sound = element_info[i].sound[ACTION_DEFAULT];
882
883     for (act=0; act < NUM_ACTIONS; act++)
884     {
885       /* no sound for this specific action -- use default action sound */
886       if (element_info[i].sound[act] == -1)
887         element_info[i].sound[act] = default_action_sound;
888     }
889   }
890 }
891
892 static void set_sound_parameters(int sound, char **parameter_raw)
893 {
894   int parameter[NUM_SND_ARGS];
895   int i;
896
897   /* get integer values from string parameters */
898   for (i=0; i < NUM_SND_ARGS; i++)
899     parameter[i] =
900       get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
901                           sound_config_suffix[i].type);
902
903   /* explicit loop mode setting in configuration overrides default value */
904   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
905     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
906 }
907
908 static void InitSoundInfo()
909 {
910   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
911   int num_property_mappings = getSoundListPropertyMappingSize();
912   int *sound_effect_properties;
913   int num_sounds = getSoundListSize();
914   int i, j;
915
916   if (sound_info != NULL)
917     free(sound_info);
918
919   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
920   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
921
922   /* initialize sound effect for all elements to "no sound" */
923   for (i=0; i<MAX_NUM_ELEMENTS; i++)
924     for (j=0; j<NUM_ACTIONS; j++)
925       element_info[i].sound[j] = SND_UNDEFINED;
926
927   for (i=0; i<num_sounds; i++)
928   {
929     struct FileInfo *sound = getSoundListEntry(i);
930     int len_effect_text = strlen(sound->token);
931
932     sound_effect_properties[i] = ACTION_OTHER;
933     sound_info[i].loop = FALSE;
934
935     /* determine all loop sounds and identify certain sound classes */
936
937     for (j=0; element_action_info[j].suffix; j++)
938     {
939       int len_action_text = strlen(element_action_info[j].suffix);
940
941       if (len_action_text < len_effect_text &&
942           strcmp(&sound->token[len_effect_text - len_action_text],
943                  element_action_info[j].suffix) == 0)
944       {
945         sound_effect_properties[i] = element_action_info[j].value;
946
947         if (element_action_info[j].is_loop_sound)
948           sound_info[i].loop = TRUE;
949       }
950     }
951
952     /* associate elements and some selected sound actions */
953
954     for (j=0; j<MAX_NUM_ELEMENTS; j++)
955     {
956       if (element_info[j].class_name)
957       {
958         int len_class_text = strlen(element_info[j].class_name);
959
960         if (len_class_text + 1 < len_effect_text &&
961             strncmp(sound->token,
962                     element_info[j].class_name, len_class_text) == 0 &&
963             sound->token[len_class_text] == '.')
964         {
965           int sound_action_value = sound_effect_properties[i];
966
967           element_info[j].sound[sound_action_value] = i;
968         }
969       }
970     }
971
972     set_sound_parameters(i, sound->parameter);
973   }
974
975   free(sound_effect_properties);
976
977   /* initialize element/sound mapping from dynamic configuration */
978   for (i=0; i < num_property_mappings; i++)
979   {
980     int element   = property_mapping[i].base_index;
981     int action    = property_mapping[i].ext1_index;
982     int sound     = property_mapping[i].artwork_index;
983
984     if (action < 0)
985       action = ACTION_DEFAULT;
986
987     element_info[element].sound[action] = sound;
988   }
989
990 #if 0
991   /* TEST ONLY */
992   {
993     int element = EL_CUSTOM_11;
994     int j = 0;
995
996     while (element_action_info[j].suffix)
997     {
998       printf("element %d, sound action '%s'  == %d\n",
999              element, element_action_info[j].suffix,
1000              element_info[element].sound[j]);
1001       j++;
1002     }
1003   }
1004
1005   PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
1006 #endif
1007
1008 #if 0
1009   /* TEST ONLY */
1010   {
1011     int element = EL_SAND;
1012     int sound_action = ACTION_DIGGING;
1013     int j = 0;
1014
1015     while (element_action_info[j].suffix)
1016     {
1017       if (element_action_info[j].value == sound_action)
1018         printf("element %d, sound action '%s'  == %d\n",
1019                element, element_action_info[j].suffix,
1020                element_info[element].sound[sound_action]);
1021       j++;
1022     }
1023   }
1024 #endif
1025 }
1026
1027 static void ReinitializeGraphics()
1028 {
1029   InitGraphicInfo();                    /* graphic properties mapping */
1030   InitElementGraphicInfo();             /* element game graphic mapping */
1031   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
1032
1033   InitElementSmallImages();             /* create editor and preview images */
1034   InitFontGraphicInfo();                /* initialize text drawing functions */
1035
1036   SetMainBackgroundImage(IMG_BACKGROUND);
1037   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1038
1039   InitGadgets();
1040   InitToons();
1041 }
1042
1043 static void ReinitializeSounds()
1044 {
1045   InitSoundInfo();              /* sound properties mapping */
1046   InitElementSoundInfo();       /* element game sound mapping */
1047
1048 #if 1
1049   InitElementSoundInfo();       /* element game sound mapping */
1050 #endif
1051
1052   InitPlaySoundLevel();         /* internal game sound settings */
1053 }
1054
1055 static void ReinitializeMusic()
1056 {
1057   /* currently nothing to do */
1058 }
1059
1060 void InitElementProperties()
1061 {
1062   int i, j;
1063
1064   static int ep_amoebalive[] =
1065   {
1066     EL_AMOEBA_WET,
1067     EL_AMOEBA_DRY,
1068     EL_AMOEBA_FULL,
1069     EL_BD_AMOEBA
1070   };
1071   static int ep_amoebalive_num = SIZEOF_ARRAY_INT(ep_amoebalive);
1072
1073   static int ep_amoeboid[] =
1074   {
1075     EL_AMOEBA_DEAD,
1076     EL_AMOEBA_WET,
1077     EL_AMOEBA_DRY,
1078     EL_AMOEBA_FULL,
1079     EL_BD_AMOEBA
1080   };
1081   static int ep_amoeboid_num = SIZEOF_ARRAY_INT(ep_amoeboid);
1082
1083   static int ep_schluessel[] =
1084   {
1085     EL_KEY_1,
1086     EL_KEY_2,
1087     EL_KEY_3,
1088     EL_KEY_4,
1089     EL_EM_KEY_1,
1090     EL_EM_KEY_2,
1091     EL_EM_KEY_3,
1092     EL_EM_KEY_4
1093   };
1094   static int ep_schluessel_num = SIZEOF_ARRAY_INT(ep_schluessel);
1095
1096   static int ep_pforte[] =
1097   {
1098     EL_GATE_1,
1099     EL_GATE_2,
1100     EL_GATE_3,
1101     EL_GATE_4,
1102     EL_GATE_1_GRAY,
1103     EL_GATE_2_GRAY,
1104     EL_GATE_3_GRAY,
1105     EL_GATE_4_GRAY,
1106     EL_EM_GATE_1,
1107     EL_EM_GATE_2,
1108     EL_EM_GATE_3,
1109     EL_EM_GATE_4,
1110     EL_EM_GATE_1_GRAY,
1111     EL_EM_GATE_2_GRAY,
1112     EL_EM_GATE_3_GRAY,
1113     EL_EM_GATE_4_GRAY,
1114     EL_SWITCHGATE_OPEN,
1115     EL_SWITCHGATE_OPENING,
1116     EL_SWITCHGATE_CLOSED,
1117     EL_SWITCHGATE_CLOSING,
1118     EL_TIMEGATE_OPEN,
1119     EL_TIMEGATE_OPENING,
1120     EL_TIMEGATE_CLOSED,
1121     EL_TIMEGATE_CLOSING,
1122     EL_TUBE_ANY,
1123     EL_TUBE_VERTICAL,
1124     EL_TUBE_HORIZONTAL,
1125     EL_TUBE_VERTICAL_LEFT,
1126     EL_TUBE_VERTICAL_RIGHT,
1127     EL_TUBE_HORIZONTAL_UP,
1128     EL_TUBE_HORIZONTAL_DOWN,
1129     EL_TUBE_LEFT_UP,
1130     EL_TUBE_LEFT_DOWN,
1131     EL_TUBE_RIGHT_UP,
1132     EL_TUBE_RIGHT_DOWN
1133   };
1134   static int ep_pforte_num = SIZEOF_ARRAY_INT(ep_pforte);
1135
1136   static int ep_solid[] =
1137   {
1138     EL_WALL,
1139     EL_EXPANDABLE_WALL,
1140     EL_EXPANDABLE_WALL_HORIZONTAL,
1141     EL_EXPANDABLE_WALL_VERTICAL,
1142     EL_EXPANDABLE_WALL_ANY,
1143     EL_BD_WALL,
1144     EL_WALL_CRUMBLED,
1145     EL_EXIT_CLOSED,
1146     EL_EXIT_OPENING,
1147     EL_EXIT_OPEN,
1148     EL_AMOEBA_DEAD,
1149     EL_AMOEBA_WET,
1150     EL_AMOEBA_DRY,
1151     EL_AMOEBA_FULL,
1152     EL_BD_AMOEBA,
1153     EL_QUICKSAND_EMPTY,
1154     EL_QUICKSAND_FULL,
1155     EL_QUICKSAND_FILLING,
1156     EL_QUICKSAND_EMPTYING,
1157     EL_MAGIC_WALL,
1158     EL_MAGIC_WALL_ACTIVE,
1159     EL_MAGIC_WALL_EMPTYING,
1160     EL_MAGIC_WALL_FILLING,
1161     EL_MAGIC_WALL_FULL,
1162     EL_MAGIC_WALL_DEAD,
1163     EL_BD_MAGIC_WALL,
1164     EL_BD_MAGIC_WALL_ACTIVE,
1165     EL_BD_MAGIC_WALL_EMPTYING,
1166     EL_BD_MAGIC_WALL_FULL,
1167     EL_BD_MAGIC_WALL_FILLING,
1168     EL_BD_MAGIC_WALL_DEAD,
1169     EL_GAME_OF_LIFE,
1170     EL_BIOMAZE,
1171     EL_SP_CHIP_SINGLE,
1172     EL_SP_CHIP_LEFT,
1173     EL_SP_CHIP_RIGHT,
1174     EL_SP_CHIP_TOP,
1175     EL_SP_CHIP_BOTTOM,
1176     EL_SP_TERMINAL,
1177     EL_SP_TERMINAL_ACTIVE,
1178     EL_SP_EXIT_CLOSED,
1179     EL_SP_EXIT_OPEN,
1180     EL_INVISIBLE_WALL,
1181     EL_INVISIBLE_WALL_ACTIVE,
1182     EL_SWITCHGATE_SWITCH_UP,
1183     EL_SWITCHGATE_SWITCH_DOWN,
1184     EL_TIMEGATE_SWITCH,
1185     EL_TIMEGATE_SWITCH_ACTIVE,
1186     EL_EMC_WALL_1,
1187     EL_EMC_WALL_2,
1188     EL_EMC_WALL_3,
1189     EL_EMC_WALL_4,
1190     EL_EMC_WALL_5,
1191     EL_EMC_WALL_6,
1192     EL_EMC_WALL_7,
1193     EL_EMC_WALL_8,
1194     EL_WALL_PEARL,
1195     EL_WALL_CRYSTAL,
1196
1197     /* the following elements are a direct copy of "indestructible" elements,
1198        except "EL_ACID", which is "indestructible", but not "solid"! */
1199 #if 0
1200     EL_ACID,
1201 #endif
1202     EL_STEELWALL,
1203     EL_ACID_POOL_TOPLEFT,
1204     EL_ACID_POOL_TOPRIGHT,
1205     EL_ACID_POOL_BOTTOMLEFT,
1206     EL_ACID_POOL_BOTTOM,
1207     EL_ACID_POOL_BOTTOMRIGHT,
1208     EL_SP_HARDWARE_GRAY,
1209     EL_SP_HARDWARE_GREEN,
1210     EL_SP_HARDWARE_BLUE,
1211     EL_SP_HARDWARE_RED,
1212     EL_SP_HARDWARE_YELLOW,
1213     EL_SP_HARDWARE_BASE_1,
1214     EL_SP_HARDWARE_BASE_2,
1215     EL_SP_HARDWARE_BASE_3,
1216     EL_SP_HARDWARE_BASE_4,
1217     EL_SP_HARDWARE_BASE_5,
1218     EL_SP_HARDWARE_BASE_6,
1219     EL_INVISIBLE_STEELWALL,
1220     EL_INVISIBLE_STEELWALL_ACTIVE,
1221     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1222     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1223     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1224     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1225     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1226     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1227     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1228     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1229     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1230     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1231     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1232     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1233     EL_LIGHT_SWITCH,
1234     EL_LIGHT_SWITCH_ACTIVE,
1235     EL_SIGN_EXCLAMATION,
1236     EL_SIGN_RADIOACTIVITY,
1237     EL_SIGN_STOP,
1238     EL_SIGN_WHEELCHAIR,
1239     EL_SIGN_PARKING,
1240     EL_SIGN_ONEWAY,
1241     EL_SIGN_HEART,
1242     EL_SIGN_TRIANGLE,
1243     EL_SIGN_ROUND,
1244     EL_SIGN_EXIT,
1245     EL_SIGN_YINYANG,
1246     EL_SIGN_OTHER,
1247     EL_STEELWALL_SLANTED,
1248     EL_EMC_STEELWALL_1,
1249     EL_EMC_STEELWALL_2,
1250     EL_EMC_STEELWALL_3,
1251     EL_EMC_STEELWALL_4,
1252     EL_CRYSTAL,
1253     EL_GATE_1,
1254     EL_GATE_2,
1255     EL_GATE_3,
1256     EL_GATE_4,
1257     EL_GATE_1_GRAY,
1258     EL_GATE_2_GRAY,
1259     EL_GATE_3_GRAY,
1260     EL_GATE_4_GRAY,
1261     EL_EM_GATE_1,
1262     EL_EM_GATE_2,
1263     EL_EM_GATE_3,
1264     EL_EM_GATE_4,
1265     EL_EM_GATE_1_GRAY,
1266     EL_EM_GATE_2_GRAY,
1267     EL_EM_GATE_3_GRAY,
1268     EL_EM_GATE_4_GRAY,
1269     EL_SWITCHGATE_OPEN,
1270     EL_SWITCHGATE_OPENING,
1271     EL_SWITCHGATE_CLOSED,
1272     EL_SWITCHGATE_CLOSING,
1273     EL_TIMEGATE_OPEN,
1274     EL_TIMEGATE_OPENING,
1275     EL_TIMEGATE_CLOSED,
1276     EL_TIMEGATE_CLOSING,
1277     EL_TUBE_ANY,
1278     EL_TUBE_VERTICAL,
1279     EL_TUBE_HORIZONTAL,
1280     EL_TUBE_VERTICAL_LEFT,
1281     EL_TUBE_VERTICAL_RIGHT,
1282     EL_TUBE_HORIZONTAL_UP,
1283     EL_TUBE_HORIZONTAL_DOWN,
1284     EL_TUBE_LEFT_UP,
1285     EL_TUBE_LEFT_DOWN,
1286     EL_TUBE_RIGHT_UP,
1287     EL_TUBE_RIGHT_DOWN
1288   };
1289   static int ep_solid_num = SIZEOF_ARRAY_INT(ep_solid);
1290
1291   static int ep_indestructible[] =
1292   {
1293     EL_STEELWALL,
1294     EL_ACID,
1295     EL_ACID_POOL_TOPLEFT,
1296     EL_ACID_POOL_TOPRIGHT,
1297     EL_ACID_POOL_BOTTOMLEFT,
1298     EL_ACID_POOL_BOTTOM,
1299     EL_ACID_POOL_BOTTOMRIGHT,
1300     EL_SP_HARDWARE_GRAY,
1301     EL_SP_HARDWARE_GREEN,
1302     EL_SP_HARDWARE_BLUE,
1303     EL_SP_HARDWARE_RED,
1304     EL_SP_HARDWARE_YELLOW,
1305     EL_SP_HARDWARE_BASE_1,
1306     EL_SP_HARDWARE_BASE_2,
1307     EL_SP_HARDWARE_BASE_3,
1308     EL_SP_HARDWARE_BASE_4,
1309     EL_SP_HARDWARE_BASE_5,
1310     EL_SP_HARDWARE_BASE_6,
1311     EL_INVISIBLE_STEELWALL,
1312     EL_INVISIBLE_STEELWALL_ACTIVE,
1313     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1314     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1315     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1316     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1317     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1318     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1319     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1320     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1321     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1322     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1323     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1324     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1325     EL_LIGHT_SWITCH,
1326     EL_LIGHT_SWITCH_ACTIVE,
1327     EL_SIGN_EXCLAMATION,
1328     EL_SIGN_RADIOACTIVITY,
1329     EL_SIGN_STOP,
1330     EL_SIGN_WHEELCHAIR,
1331     EL_SIGN_PARKING,
1332     EL_SIGN_ONEWAY,
1333     EL_SIGN_HEART,
1334     EL_SIGN_TRIANGLE,
1335     EL_SIGN_ROUND,
1336     EL_SIGN_EXIT,
1337     EL_SIGN_YINYANG,
1338     EL_SIGN_OTHER,
1339     EL_STEELWALL_SLANTED,
1340     EL_EMC_STEELWALL_1,
1341     EL_EMC_STEELWALL_2,
1342     EL_EMC_STEELWALL_3,
1343     EL_EMC_STEELWALL_4,
1344     EL_CRYSTAL,
1345     EL_GATE_1,
1346     EL_GATE_2,
1347     EL_GATE_3,
1348     EL_GATE_4,
1349     EL_GATE_1_GRAY,
1350     EL_GATE_2_GRAY,
1351     EL_GATE_3_GRAY,
1352     EL_GATE_4_GRAY,
1353     EL_EM_GATE_1,
1354     EL_EM_GATE_2,
1355     EL_EM_GATE_3,
1356     EL_EM_GATE_4,
1357     EL_EM_GATE_1_GRAY,
1358     EL_EM_GATE_2_GRAY,
1359     EL_EM_GATE_3_GRAY,
1360     EL_EM_GATE_4_GRAY,
1361     EL_SWITCHGATE_OPEN,
1362     EL_SWITCHGATE_OPENING,
1363     EL_SWITCHGATE_CLOSED,
1364     EL_SWITCHGATE_CLOSING,
1365     EL_TIMEGATE_OPEN,
1366     EL_TIMEGATE_OPENING,
1367     EL_TIMEGATE_CLOSED,
1368     EL_TIMEGATE_CLOSING,
1369     EL_TUBE_ANY,
1370     EL_TUBE_VERTICAL,
1371     EL_TUBE_HORIZONTAL,
1372     EL_TUBE_VERTICAL_LEFT,
1373     EL_TUBE_VERTICAL_RIGHT,
1374     EL_TUBE_HORIZONTAL_UP,
1375     EL_TUBE_HORIZONTAL_DOWN,
1376     EL_TUBE_LEFT_UP,
1377     EL_TUBE_LEFT_DOWN,
1378     EL_TUBE_RIGHT_UP,
1379     EL_TUBE_RIGHT_DOWN
1380   };
1381   static int ep_indestructible_num = SIZEOF_ARRAY_INT(ep_indestructible);
1382
1383   static int ep_slippery[] =
1384   {
1385     EL_WALL_CRUMBLED,
1386     EL_BD_WALL,
1387     EL_ROCK,
1388     EL_BD_ROCK,
1389     EL_EMERALD,
1390     EL_BD_DIAMOND,
1391     EL_EMERALD_YELLOW,
1392     EL_EMERALD_RED,
1393     EL_EMERALD_PURPLE,
1394     EL_DIAMOND,
1395     EL_BOMB,
1396     EL_NUT,
1397     EL_ROBOT_WHEEL_ACTIVE,
1398     EL_ROBOT_WHEEL,
1399     EL_TIME_ORB_FULL,
1400     EL_TIME_ORB_EMPTY,
1401     EL_LAMP_ACTIVE,
1402     EL_LAMP,
1403     EL_ACID_POOL_TOPLEFT,
1404     EL_ACID_POOL_TOPRIGHT,
1405     EL_SATELLITE,
1406     EL_SP_ZONK,
1407     EL_SP_INFOTRON,
1408     EL_SP_CHIP_SINGLE,
1409     EL_SP_CHIP_LEFT,
1410     EL_SP_CHIP_RIGHT,
1411     EL_SP_CHIP_TOP,
1412     EL_SP_CHIP_BOTTOM,
1413     EL_SPEED_PILL,
1414     EL_STEELWALL_SLANTED,
1415     EL_PEARL,
1416     EL_CRYSTAL
1417   };
1418   static int ep_slippery_num = SIZEOF_ARRAY_INT(ep_slippery);
1419
1420   static int ep_enemy[] =
1421   {
1422     EL_BUG,
1423     EL_SPACESHIP,
1424     EL_BD_BUTTERFLY,
1425     EL_BD_FIREFLY,
1426     EL_YAMYAM,
1427     EL_DARK_YAMYAM,
1428     EL_ROBOT,
1429     EL_PACMAN,
1430     EL_SP_SNIKSNAK,
1431     EL_SP_ELECTRON
1432   };
1433   static int ep_enemy_num = SIZEOF_ARRAY_INT(ep_enemy);
1434
1435   static int ep_mauer[] =
1436   {
1437     EL_STEELWALL,
1438     EL_GATE_1,
1439     EL_GATE_2,
1440     EL_GATE_3,
1441     EL_GATE_4,
1442     EL_GATE_1_GRAY,
1443     EL_GATE_2_GRAY,
1444     EL_GATE_3_GRAY,
1445     EL_GATE_4_GRAY,
1446     EL_EM_GATE_1,
1447     EL_EM_GATE_2,
1448     EL_EM_GATE_3,
1449     EL_EM_GATE_4,
1450     EL_EM_GATE_1_GRAY,
1451     EL_EM_GATE_2_GRAY,
1452     EL_EM_GATE_3_GRAY,
1453     EL_EM_GATE_4_GRAY,
1454     EL_EXIT_CLOSED,
1455     EL_EXIT_OPENING,
1456     EL_EXIT_OPEN,
1457     EL_WALL,
1458     EL_WALL_CRUMBLED,
1459     EL_EXPANDABLE_WALL,
1460     EL_EXPANDABLE_WALL_HORIZONTAL,
1461     EL_EXPANDABLE_WALL_VERTICAL,
1462     EL_EXPANDABLE_WALL_ANY,
1463     EL_EXPANDABLE_WALL_GROWING,
1464     EL_BD_WALL,
1465     EL_SP_CHIP_SINGLE,
1466     EL_SP_CHIP_LEFT,
1467     EL_SP_CHIP_RIGHT,
1468     EL_SP_CHIP_TOP,
1469     EL_SP_CHIP_BOTTOM,
1470     EL_SP_HARDWARE_GRAY,
1471     EL_SP_HARDWARE_GREEN,
1472     EL_SP_HARDWARE_BLUE,
1473     EL_SP_HARDWARE_RED,
1474     EL_SP_HARDWARE_YELLOW,
1475     EL_SP_HARDWARE_BASE_1,
1476     EL_SP_HARDWARE_BASE_2,
1477     EL_SP_HARDWARE_BASE_3,
1478     EL_SP_HARDWARE_BASE_4,
1479     EL_SP_HARDWARE_BASE_5,
1480     EL_SP_HARDWARE_BASE_6,
1481     EL_SP_TERMINAL,
1482     EL_SP_TERMINAL_ACTIVE,
1483     EL_SP_EXIT_CLOSED,
1484     EL_SP_EXIT_OPEN,
1485     EL_INVISIBLE_STEELWALL,
1486     EL_INVISIBLE_STEELWALL_ACTIVE,
1487     EL_INVISIBLE_WALL,
1488     EL_INVISIBLE_WALL_ACTIVE,
1489     EL_STEELWALL_SLANTED,
1490     EL_EMC_STEELWALL_1,
1491     EL_EMC_STEELWALL_2,
1492     EL_EMC_STEELWALL_3,
1493     EL_EMC_STEELWALL_4,
1494     EL_EMC_WALL_1,
1495     EL_EMC_WALL_2,
1496     EL_EMC_WALL_3,
1497     EL_EMC_WALL_4,
1498     EL_EMC_WALL_5,
1499     EL_EMC_WALL_6,
1500     EL_EMC_WALL_7,
1501     EL_EMC_WALL_8
1502   };
1503   static int ep_mauer_num = SIZEOF_ARRAY_INT(ep_mauer);
1504
1505   static int ep_can_fall[] =
1506   {
1507     EL_ROCK,
1508     EL_BD_ROCK,
1509     EL_EMERALD,
1510     EL_BD_DIAMOND,
1511     EL_EMERALD_YELLOW,
1512     EL_EMERALD_RED,
1513     EL_EMERALD_PURPLE,
1514     EL_DIAMOND,
1515     EL_BOMB,
1516     EL_NUT,
1517     EL_AMOEBA_DROP,
1518     EL_QUICKSAND_FULL,
1519     EL_MAGIC_WALL_FULL,
1520     EL_BD_MAGIC_WALL_FULL,
1521     EL_TIME_ORB_FULL,
1522     EL_TIME_ORB_EMPTY,
1523     EL_SP_ZONK,
1524     EL_SP_INFOTRON,
1525     EL_SP_DISK_ORANGE,
1526     EL_PEARL,
1527     EL_CRYSTAL,
1528     EL_SPRING,
1529     EL_DX_SUPABOMB
1530   };
1531   static int ep_can_fall_num = SIZEOF_ARRAY_INT(ep_can_fall);
1532
1533   static int ep_can_smash[] =
1534   {
1535     EL_ROCK,
1536     EL_BD_ROCK,
1537     EL_EMERALD,
1538     EL_BD_DIAMOND,
1539     EL_EMERALD_YELLOW,
1540     EL_EMERALD_RED,
1541     EL_EMERALD_PURPLE,
1542     EL_DIAMOND,
1543     EL_BOMB,
1544     EL_NUT,
1545     EL_AMOEBA_DROP,
1546     EL_TIME_ORB_FULL,
1547     EL_TIME_ORB_EMPTY,
1548     EL_SP_ZONK,
1549     EL_SP_INFOTRON,
1550     EL_SP_DISK_ORANGE,
1551     EL_PEARL,
1552     EL_CRYSTAL,
1553     EL_SPRING,
1554     EL_DX_SUPABOMB
1555   };
1556   static int ep_can_smash_num = SIZEOF_ARRAY_INT(ep_can_smash);
1557
1558   static int ep_can_change[] =
1559   {
1560     EL_ROCK,
1561     EL_BD_ROCK,
1562     EL_EMERALD,
1563     EL_BD_DIAMOND,
1564     EL_EMERALD_YELLOW,
1565     EL_EMERALD_RED,
1566     EL_EMERALD_PURPLE,
1567     EL_DIAMOND
1568   };
1569   static int ep_can_change_num = SIZEOF_ARRAY_INT(ep_can_change);
1570
1571   static int ep_can_move[] =
1572   {
1573     EL_BUG,
1574     EL_SPACESHIP,
1575     EL_BD_BUTTERFLY,
1576     EL_BD_FIREFLY,
1577     EL_YAMYAM,
1578     EL_DARK_YAMYAM,
1579     EL_ROBOT,
1580     EL_PACMAN,
1581     EL_MOLE,
1582     EL_PENGUIN,
1583     EL_PIG,
1584     EL_DRAGON,
1585     EL_SATELLITE,
1586     EL_SP_SNIKSNAK,
1587     EL_SP_ELECTRON,
1588     EL_BALLOON,
1589     EL_SPRING
1590   };
1591   static int ep_can_move_num = SIZEOF_ARRAY_INT(ep_can_move);
1592
1593   static int ep_could_move[] =
1594   {
1595     EL_BUG_RIGHT,
1596     EL_BUG_UP,
1597     EL_BUG_LEFT,
1598     EL_BUG_DOWN,
1599     EL_SPACESHIP_RIGHT,
1600     EL_SPACESHIP_UP,
1601     EL_SPACESHIP_LEFT,
1602     EL_SPACESHIP_DOWN,
1603     EL_BD_BUTTERFLY_RIGHT,
1604     EL_BD_BUTTERFLY_UP,
1605     EL_BD_BUTTERFLY_LEFT,
1606     EL_BD_BUTTERFLY_DOWN,
1607     EL_BD_FIREFLY_RIGHT,
1608     EL_BD_FIREFLY_UP,
1609     EL_BD_FIREFLY_LEFT,
1610     EL_BD_FIREFLY_DOWN,
1611     EL_PACMAN_RIGHT,
1612     EL_PACMAN_UP,
1613     EL_PACMAN_LEFT,
1614     EL_PACMAN_DOWN
1615   };
1616   static int ep_could_move_num = SIZEOF_ARRAY_INT(ep_could_move);
1617
1618   static int ep_dont_touch[] =
1619   {
1620     EL_BUG,
1621     EL_SPACESHIP,
1622     EL_BD_BUTTERFLY,
1623     EL_BD_FIREFLY
1624   };
1625   static int ep_dont_touch_num = SIZEOF_ARRAY_INT(ep_dont_touch);
1626
1627   static int ep_dont_go_to[] =
1628   {
1629     EL_BUG,
1630     EL_SPACESHIP,
1631     EL_BD_BUTTERFLY,
1632     EL_BD_FIREFLY,
1633     EL_YAMYAM,
1634     EL_DARK_YAMYAM,
1635     EL_ROBOT,
1636     EL_PACMAN,
1637     EL_AMOEBA_DROP,
1638     EL_ACID,
1639     EL_SP_SNIKSNAK,
1640     EL_SP_ELECTRON,
1641     EL_SP_BUGGY_BASE_ACTIVE,
1642     EL_TRAP_ACTIVE,
1643     EL_LANDMINE
1644   };
1645   static int ep_dont_go_to_num = SIZEOF_ARRAY_INT(ep_dont_go_to);
1646
1647   static int ep_mampf2[] =
1648   {
1649     EL_SAND,
1650     EL_BUG,
1651     EL_SPACESHIP,
1652     EL_BD_BUTTERFLY,
1653     EL_BD_FIREFLY,
1654     EL_YAMYAM,
1655     EL_ROBOT,
1656     EL_PACMAN,
1657     EL_AMOEBA_DROP,
1658     EL_AMOEBA_DEAD,
1659     EL_AMOEBA_WET,
1660     EL_AMOEBA_DRY,
1661     EL_AMOEBA_FULL,
1662     EL_BD_AMOEBA,
1663     EL_EMERALD,
1664     EL_BD_DIAMOND,
1665     EL_EMERALD_YELLOW,
1666     EL_EMERALD_RED,
1667     EL_EMERALD_PURPLE,
1668     EL_DIAMOND,
1669     EL_PEARL,
1670     EL_CRYSTAL
1671   };
1672   static int ep_mampf2_num = SIZEOF_ARRAY_INT(ep_mampf2);
1673
1674   static int ep_bd_element[] =
1675   {
1676     EL_EMPTY,
1677     EL_SAND,
1678     EL_WALL_CRUMBLED,
1679     EL_BD_WALL,
1680     EL_ROCK,
1681     EL_BD_ROCK,
1682     EL_BD_DIAMOND,
1683     EL_BD_MAGIC_WALL,
1684     EL_EXIT_CLOSED,
1685     EL_EXIT_OPEN,
1686     EL_STEELWALL,
1687     EL_PLAYER_1,
1688     EL_BD_FIREFLY,
1689     EL_BD_FIREFLY_1,
1690     EL_BD_FIREFLY_2,
1691     EL_BD_FIREFLY_3,
1692     EL_BD_FIREFLY_4,
1693     EL_BD_BUTTERFLY,
1694     EL_BD_BUTTERFLY_1,
1695     EL_BD_BUTTERFLY_2,
1696     EL_BD_BUTTERFLY_3,
1697     EL_BD_BUTTERFLY_4,
1698     EL_BD_AMOEBA,
1699     EL_CHAR_QUESTION
1700   };
1701   static int ep_bd_element_num = SIZEOF_ARRAY_INT(ep_bd_element);
1702
1703   static int ep_sb_element[] =
1704   {
1705     EL_EMPTY,
1706     EL_STEELWALL,
1707     EL_SOKOBAN_OBJECT,
1708     EL_SOKOBAN_FIELD_EMPTY,
1709     EL_SOKOBAN_FIELD_FULL,
1710     EL_PLAYER_1,
1711     EL_INVISIBLE_STEELWALL
1712   };
1713   static int ep_sb_element_num = SIZEOF_ARRAY_INT(ep_sb_element);
1714
1715   static int ep_gem[] =
1716   {
1717     EL_EMERALD,
1718     EL_BD_DIAMOND,
1719     EL_EMERALD_YELLOW,
1720     EL_EMERALD_RED,
1721     EL_EMERALD_PURPLE,
1722     EL_DIAMOND
1723   };
1724   static int ep_gem_num = SIZEOF_ARRAY_INT(ep_gem);
1725
1726   static int ep_inactive[] =
1727   {
1728     EL_EMPTY,
1729     EL_SAND,
1730     EL_WALL,
1731     EL_BD_WALL,
1732     EL_WALL_CRUMBLED,
1733     EL_STEELWALL,
1734     EL_AMOEBA_DEAD,
1735     EL_QUICKSAND_EMPTY,
1736     EL_STONEBLOCK,
1737     EL_ROBOT_WHEEL,
1738     EL_KEY_1,
1739     EL_KEY_2,
1740     EL_KEY_3,
1741     EL_KEY_4,
1742     EL_EM_KEY_1,
1743     EL_EM_KEY_2,
1744     EL_EM_KEY_3,
1745     EL_EM_KEY_4,
1746     EL_GATE_1,
1747     EL_GATE_2,
1748     EL_GATE_3,
1749     EL_GATE_4,
1750     EL_GATE_1_GRAY,
1751     EL_GATE_2_GRAY,
1752     EL_GATE_3_GRAY,
1753     EL_GATE_4_GRAY,
1754     EL_EM_GATE_1,
1755     EL_EM_GATE_2,
1756     EL_EM_GATE_3,
1757     EL_EM_GATE_4,
1758     EL_EM_GATE_1_GRAY,
1759     EL_EM_GATE_2_GRAY,
1760     EL_EM_GATE_3_GRAY,
1761     EL_EM_GATE_4_GRAY,
1762     EL_DYNAMITE,
1763     EL_INVISIBLE_STEELWALL,
1764     EL_INVISIBLE_WALL,
1765     EL_INVISIBLE_SAND,
1766     EL_LAMP,
1767     EL_LAMP_ACTIVE,
1768     EL_WALL_EMERALD,
1769     EL_WALL_DIAMOND,
1770     EL_WALL_BD_DIAMOND,
1771     EL_WALL_EMERALD_YELLOW,
1772     EL_DYNABOMB_INCREASE_NUMBER,
1773     EL_DYNABOMB_INCREASE_SIZE,
1774     EL_DYNABOMB_INCREASE_POWER,
1775     EL_SOKOBAN_OBJECT,
1776     EL_SOKOBAN_FIELD_EMPTY,
1777     EL_SOKOBAN_FIELD_FULL,
1778     EL_WALL_EMERALD_RED,
1779     EL_WALL_EMERALD_PURPLE,
1780     EL_ACID_POOL_TOPLEFT,
1781     EL_ACID_POOL_TOPRIGHT,
1782     EL_ACID_POOL_BOTTOMLEFT,
1783     EL_ACID_POOL_BOTTOM,
1784     EL_ACID_POOL_BOTTOMRIGHT,
1785     EL_MAGIC_WALL,
1786     EL_MAGIC_WALL_DEAD,
1787     EL_BD_MAGIC_WALL,
1788     EL_BD_MAGIC_WALL_DEAD,
1789     EL_AMOEBA_TO_DIAMOND,
1790     EL_BLOCKED,
1791     EL_SP_EMPTY,
1792     EL_SP_BASE,
1793     EL_SP_PORT_RIGHT,
1794     EL_SP_PORT_DOWN,
1795     EL_SP_PORT_LEFT,
1796     EL_SP_PORT_UP,
1797     EL_SP_GRAVITY_PORT_RIGHT,
1798     EL_SP_GRAVITY_PORT_DOWN,
1799     EL_SP_GRAVITY_PORT_LEFT,
1800     EL_SP_GRAVITY_PORT_UP,
1801     EL_SP_PORT_HORIZONTAL,
1802     EL_SP_PORT_VERTICAL,
1803     EL_SP_PORT_ANY,
1804     EL_SP_DISK_RED,
1805     EL_SP_DISK_YELLOW,
1806     EL_SP_CHIP_SINGLE,
1807     EL_SP_CHIP_LEFT,
1808     EL_SP_CHIP_RIGHT,
1809     EL_SP_CHIP_TOP,
1810     EL_SP_CHIP_BOTTOM,
1811     EL_SP_HARDWARE_GRAY,
1812     EL_SP_HARDWARE_GREEN,
1813     EL_SP_HARDWARE_BLUE,
1814     EL_SP_HARDWARE_RED,
1815     EL_SP_HARDWARE_YELLOW,
1816     EL_SP_HARDWARE_BASE_1,
1817     EL_SP_HARDWARE_BASE_2,
1818     EL_SP_HARDWARE_BASE_3,
1819     EL_SP_HARDWARE_BASE_4,
1820     EL_SP_HARDWARE_BASE_5,
1821     EL_SP_HARDWARE_BASE_6,
1822     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1823     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1824     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1825     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1826     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1827     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1828     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1829     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1830     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1831     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1832     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1833     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1834     EL_SIGN_EXCLAMATION,
1835     EL_SIGN_RADIOACTIVITY,
1836     EL_SIGN_STOP,
1837     EL_SIGN_WHEELCHAIR,
1838     EL_SIGN_PARKING,
1839     EL_SIGN_ONEWAY,
1840     EL_SIGN_HEART,
1841     EL_SIGN_TRIANGLE,
1842     EL_SIGN_ROUND,
1843     EL_SIGN_EXIT,
1844     EL_SIGN_YINYANG,
1845     EL_SIGN_OTHER,
1846     EL_STEELWALL_SLANTED,
1847     EL_EMC_STEELWALL_1,
1848     EL_EMC_STEELWALL_2,
1849     EL_EMC_STEELWALL_3,
1850     EL_EMC_STEELWALL_4,
1851     EL_EMC_WALL_1,
1852     EL_EMC_WALL_2,
1853     EL_EMC_WALL_3,
1854     EL_EMC_WALL_4,
1855     EL_EMC_WALL_5,
1856     EL_EMC_WALL_6,
1857     EL_EMC_WALL_7,
1858     EL_EMC_WALL_8
1859   };
1860   static int ep_inactive_num = SIZEOF_ARRAY_INT(ep_inactive);
1861
1862   static int ep_explosive[] =
1863   {
1864     EL_BOMB,
1865     EL_DYNAMITE_ACTIVE,
1866     EL_DYNAMITE,
1867     EL_DYNABOMB_PLAYER_1_ACTIVE,
1868     EL_DYNABOMB_PLAYER_2_ACTIVE,
1869     EL_DYNABOMB_PLAYER_3_ACTIVE,
1870     EL_DYNABOMB_PLAYER_4_ACTIVE,
1871     EL_DYNABOMB_INCREASE_NUMBER,
1872     EL_DYNABOMB_INCREASE_SIZE,
1873     EL_DYNABOMB_INCREASE_POWER,
1874     EL_SP_DISK_RED_ACTIVE,
1875     EL_BUG,
1876     EL_MOLE,
1877     EL_PENGUIN,
1878     EL_PIG,
1879     EL_DRAGON,
1880     EL_SATELLITE,
1881     EL_SP_DISK_RED,
1882     EL_SP_DISK_ORANGE,
1883     EL_SP_DISK_YELLOW,
1884     EL_SP_SNIKSNAK,
1885     EL_SP_ELECTRON,
1886     EL_DX_SUPABOMB
1887   };
1888   static int ep_explosive_num = SIZEOF_ARRAY_INT(ep_explosive);
1889
1890   static int ep_mampf3[] =
1891   {
1892     EL_EMERALD,
1893     EL_BD_DIAMOND,
1894     EL_EMERALD_YELLOW,
1895     EL_EMERALD_RED,
1896     EL_EMERALD_PURPLE,
1897     EL_DIAMOND,
1898     EL_PEARL,
1899     EL_CRYSTAL
1900   };
1901   static int ep_mampf3_num = SIZEOF_ARRAY_INT(ep_mampf3);
1902
1903   static int ep_pushable[] =
1904   {
1905     EL_ROCK,
1906     EL_BD_ROCK,
1907     EL_BOMB,
1908     EL_NUT,
1909     EL_TIME_ORB_EMPTY,
1910     EL_SOKOBAN_FIELD_FULL,
1911     EL_SOKOBAN_OBJECT,
1912     EL_SATELLITE,
1913     EL_SP_ZONK,
1914     EL_SP_DISK_ORANGE,
1915     EL_SP_DISK_YELLOW,
1916     EL_BALLOON,
1917     EL_SPRING,
1918     EL_DX_SUPABOMB
1919   };
1920   static int ep_pushable_num = SIZEOF_ARRAY_INT(ep_pushable);
1921
1922   static int ep_player[] =
1923   {
1924     EL_PLAYER_1,
1925     EL_PLAYER_2,
1926     EL_PLAYER_3,
1927     EL_PLAYER_4
1928   };
1929   static int ep_player_num = SIZEOF_ARRAY_INT(ep_player);
1930
1931   static int ep_has_content[] =
1932   {
1933     EL_YAMYAM,
1934     EL_AMOEBA_WET,
1935     EL_AMOEBA_DRY,
1936     EL_AMOEBA_FULL,
1937     EL_BD_AMOEBA
1938   };
1939   static int ep_has_content_num = SIZEOF_ARRAY_INT(ep_has_content);
1940
1941   static int ep_eatable[] =
1942   {
1943     EL_SAND,
1944     EL_SP_BASE,
1945     EL_SP_BUGGY_BASE,
1946     EL_SP_BUGGY_BASE_ACTIVATING,
1947     EL_TRAP,
1948     EL_INVISIBLE_SAND,
1949     EL_INVISIBLE_SAND_ACTIVE
1950   };
1951   static int ep_eatable_num = SIZEOF_ARRAY_INT(ep_eatable);
1952
1953   static int ep_sp_element[] =
1954   {
1955     EL_SP_EMPTY,
1956     EL_SP_ZONK,
1957     EL_SP_BASE,
1958     EL_SP_MURPHY,
1959     EL_SP_INFOTRON,
1960     EL_SP_CHIP_SINGLE,
1961     EL_SP_HARDWARE_GRAY,
1962     EL_SP_EXIT_CLOSED,
1963     EL_SP_EXIT_OPEN,
1964     EL_SP_DISK_ORANGE,
1965     EL_SP_PORT_RIGHT,
1966     EL_SP_PORT_DOWN,
1967     EL_SP_PORT_LEFT,
1968     EL_SP_PORT_UP,
1969     EL_SP_GRAVITY_PORT_RIGHT,
1970     EL_SP_GRAVITY_PORT_DOWN,
1971     EL_SP_GRAVITY_PORT_LEFT,
1972     EL_SP_GRAVITY_PORT_UP,
1973     EL_SP_SNIKSNAK,
1974     EL_SP_DISK_YELLOW,
1975     EL_SP_TERMINAL,
1976     EL_SP_DISK_RED,
1977     EL_SP_PORT_VERTICAL,
1978     EL_SP_PORT_HORIZONTAL,
1979     EL_SP_PORT_ANY,
1980     EL_SP_ELECTRON,
1981     EL_SP_BUGGY_BASE,
1982     EL_SP_CHIP_LEFT,
1983     EL_SP_CHIP_RIGHT,
1984     EL_SP_HARDWARE_BASE_1,
1985     EL_SP_HARDWARE_GREEN,
1986     EL_SP_HARDWARE_BLUE,
1987     EL_SP_HARDWARE_RED,
1988     EL_SP_HARDWARE_YELLOW,
1989     EL_SP_HARDWARE_BASE_2,
1990     EL_SP_HARDWARE_BASE_3,
1991     EL_SP_HARDWARE_BASE_4,
1992     EL_SP_HARDWARE_BASE_5,
1993     EL_SP_HARDWARE_BASE_6,
1994     EL_SP_CHIP_TOP,
1995     EL_SP_CHIP_BOTTOM,
1996     /* additional elements that appeared in newer Supaplex levels */
1997     EL_INVISIBLE_WALL,
1998     /* more than one murphy in a level results in an inactive clone */
1999     EL_SP_MURPHY_CLONE
2000   };
2001   static int ep_sp_element_num = SIZEOF_ARRAY_INT(ep_sp_element);
2002
2003   static int ep_quick_gate[] =
2004   {
2005     EL_EM_GATE_1,
2006     EL_EM_GATE_2,
2007     EL_EM_GATE_3,
2008     EL_EM_GATE_4,
2009     EL_EM_GATE_1_GRAY,
2010     EL_EM_GATE_2_GRAY,
2011     EL_EM_GATE_3_GRAY,
2012     EL_EM_GATE_4_GRAY,
2013     EL_SP_PORT_LEFT,
2014     EL_SP_PORT_RIGHT,
2015     EL_SP_PORT_UP,
2016     EL_SP_PORT_DOWN,
2017     EL_SP_GRAVITY_PORT_LEFT,
2018     EL_SP_GRAVITY_PORT_RIGHT,
2019     EL_SP_GRAVITY_PORT_UP,
2020     EL_SP_GRAVITY_PORT_DOWN,
2021     EL_SP_PORT_HORIZONTAL,
2022     EL_SP_PORT_VERTICAL,
2023     EL_SP_PORT_ANY,
2024     EL_SWITCHGATE_OPEN,
2025     EL_TIMEGATE_OPEN
2026   };
2027   static int ep_quick_gate_num = SIZEOF_ARRAY_INT(ep_quick_gate);
2028
2029   static int ep_over_player[] =
2030   {
2031     EL_SP_PORT_LEFT,
2032     EL_SP_PORT_RIGHT,
2033     EL_SP_PORT_UP,
2034     EL_SP_PORT_DOWN,
2035     EL_SP_GRAVITY_PORT_LEFT,
2036     EL_SP_GRAVITY_PORT_RIGHT,
2037     EL_SP_GRAVITY_PORT_UP,
2038     EL_SP_GRAVITY_PORT_DOWN,
2039     EL_SP_PORT_HORIZONTAL,
2040     EL_SP_PORT_VERTICAL,
2041     EL_SP_PORT_ANY,
2042     EL_TUBE_ANY,
2043     EL_TUBE_VERTICAL,
2044     EL_TUBE_HORIZONTAL,
2045     EL_TUBE_VERTICAL_LEFT,
2046     EL_TUBE_VERTICAL_RIGHT,
2047     EL_TUBE_HORIZONTAL_UP,
2048     EL_TUBE_HORIZONTAL_DOWN,
2049     EL_TUBE_LEFT_UP,
2050     EL_TUBE_LEFT_DOWN,
2051     EL_TUBE_RIGHT_UP,
2052     EL_TUBE_RIGHT_DOWN
2053   };
2054   static int ep_over_player_num = SIZEOF_ARRAY_INT(ep_over_player);
2055
2056   static int ep_active_bomb[] =
2057   {
2058     EL_DYNAMITE_ACTIVE,
2059     EL_DYNABOMB_PLAYER_1_ACTIVE,
2060     EL_DYNABOMB_PLAYER_2_ACTIVE,
2061     EL_DYNABOMB_PLAYER_3_ACTIVE,
2062     EL_DYNABOMB_PLAYER_4_ACTIVE,
2063     EL_SP_DISK_RED_ACTIVE
2064   };
2065   static int ep_active_bomb_num = SIZEOF_ARRAY_INT(ep_active_bomb);
2066
2067   static int ep_belt[] =
2068   {
2069     EL_CONVEYOR_BELT_1_LEFT,
2070     EL_CONVEYOR_BELT_1_MIDDLE,
2071     EL_CONVEYOR_BELT_1_RIGHT,
2072     EL_CONVEYOR_BELT_2_LEFT,
2073     EL_CONVEYOR_BELT_2_MIDDLE,
2074     EL_CONVEYOR_BELT_2_RIGHT,
2075     EL_CONVEYOR_BELT_3_LEFT,
2076     EL_CONVEYOR_BELT_3_MIDDLE,
2077     EL_CONVEYOR_BELT_3_RIGHT,
2078     EL_CONVEYOR_BELT_4_LEFT,
2079     EL_CONVEYOR_BELT_4_MIDDLE,
2080     EL_CONVEYOR_BELT_4_RIGHT,
2081   };
2082   static int ep_belt_num = SIZEOF_ARRAY_INT(ep_belt);
2083
2084   static int ep_belt_active[] =
2085   {
2086     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
2087     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
2088     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
2089     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
2090     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
2091     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
2092     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
2093     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
2094     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
2095     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
2096     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
2097     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
2098   };
2099   static int ep_belt_active_num = SIZEOF_ARRAY_INT(ep_belt_active);
2100
2101   static int ep_belt_switch[] =
2102   {
2103     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2104     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2105     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2106     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2107     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2108     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2109     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2110     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2111     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2112     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2113     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2114     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2115   };
2116   static int ep_belt_switch_num = SIZEOF_ARRAY_INT(ep_belt_switch);
2117
2118   static int ep_tube[] =
2119   {
2120     EL_TUBE_ANY,
2121     EL_TUBE_VERTICAL,
2122     EL_TUBE_HORIZONTAL,
2123     EL_TUBE_VERTICAL_LEFT,
2124     EL_TUBE_VERTICAL_RIGHT,
2125     EL_TUBE_HORIZONTAL_UP,
2126     EL_TUBE_HORIZONTAL_DOWN,
2127     EL_TUBE_LEFT_UP,
2128     EL_TUBE_LEFT_DOWN,
2129     EL_TUBE_RIGHT_UP,
2130     EL_TUBE_RIGHT_DOWN
2131   };
2132   static int ep_tube_num = SIZEOF_ARRAY_INT(ep_tube);
2133
2134   static int ep_em_slippery_wall[] =
2135   {
2136   };
2137   static int ep_em_slippery_wall_num = SIZEOF_ARRAY_INT(ep_em_slippery_wall);
2138
2139   static int ep_can_be_crumbled[] =
2140   {
2141     EL_SAND,
2142     EL_LANDMINE,
2143     EL_TRAP,
2144     EL_TRAP_ACTIVE
2145   };
2146   static int ep_can_be_crumbled_num = SIZEOF_ARRAY_INT(ep_can_be_crumbled);
2147
2148   static long ep1_bit[] =
2149   {
2150     EP_BIT_AMOEBALIVE,
2151     EP_BIT_AMOEBOID,
2152     EP_BIT_SCHLUESSEL,
2153     EP_BIT_PFORTE,
2154     EP_BIT_SOLID,
2155     EP_BIT_INDESTRUCTIBLE,
2156     EP_BIT_SLIPPERY,
2157     EP_BIT_ENEMY,
2158     EP_BIT_MAUER,
2159     EP_BIT_CAN_FALL,
2160     EP_BIT_CAN_SMASH,
2161     EP_BIT_CAN_CHANGE,
2162     EP_BIT_CAN_MOVE,
2163     EP_BIT_COULD_MOVE,
2164     EP_BIT_DONT_TOUCH,
2165     EP_BIT_DONT_GO_TO,
2166     EP_BIT_MAMPF2,
2167     EP_BIT_BD_ELEMENT,
2168     EP_BIT_SB_ELEMENT,
2169     EP_BIT_GEM,
2170     EP_BIT_INACTIVE,
2171     EP_BIT_EXPLOSIVE,
2172     EP_BIT_MAMPF3,
2173     EP_BIT_PUSHABLE,
2174     EP_BIT_PLAYER,
2175     EP_BIT_HAS_CONTENT,
2176     EP_BIT_EATABLE,
2177     EP_BIT_SP_ELEMENT,
2178     EP_BIT_QUICK_GATE,
2179     EP_BIT_OVER_PLAYER,
2180     EP_BIT_ACTIVE_BOMB
2181   };
2182   static long ep2_bit[] =
2183   {
2184     EP_BIT_BELT,
2185     EP_BIT_BELT_ACTIVE,
2186     EP_BIT_BELT_SWITCH,
2187     EP_BIT_TUBE,
2188     EP_BIT_EM_SLIPPERY_WALL,
2189     EP_BIT_CAN_BE_CRUMBLED
2190   };
2191   static int *ep1_array[] =
2192   {
2193     ep_amoebalive,
2194     ep_amoeboid,
2195     ep_schluessel,
2196     ep_pforte,
2197     ep_solid,
2198     ep_indestructible,
2199     ep_slippery,
2200     ep_enemy,
2201     ep_mauer,
2202     ep_can_fall,
2203     ep_can_smash,
2204     ep_can_change,
2205     ep_can_move,
2206     ep_could_move,
2207     ep_dont_touch,
2208     ep_dont_go_to,
2209     ep_mampf2,
2210     ep_bd_element,
2211     ep_sb_element,
2212     ep_gem,
2213     ep_inactive,
2214     ep_explosive,
2215     ep_mampf3,
2216     ep_pushable,
2217     ep_player,
2218     ep_has_content,
2219     ep_eatable,
2220     ep_sp_element,
2221     ep_quick_gate,
2222     ep_over_player,
2223     ep_active_bomb
2224   };
2225   static int *ep2_array[] =
2226   {
2227     ep_belt,
2228     ep_belt_active,
2229     ep_belt_switch,
2230     ep_tube,
2231     ep_em_slippery_wall,
2232     ep_can_be_crumbled
2233   };
2234   static int *ep1_num[] =
2235   {
2236     &ep_amoebalive_num,
2237     &ep_amoeboid_num,
2238     &ep_schluessel_num,
2239     &ep_pforte_num,
2240     &ep_solid_num,
2241     &ep_indestructible_num,
2242     &ep_slippery_num,
2243     &ep_enemy_num,
2244     &ep_mauer_num,
2245     &ep_can_fall_num,
2246     &ep_can_smash_num,
2247     &ep_can_change_num,
2248     &ep_can_move_num,
2249     &ep_could_move_num,
2250     &ep_dont_touch_num,
2251     &ep_dont_go_to_num,
2252     &ep_mampf2_num,
2253     &ep_bd_element_num,
2254     &ep_sb_element_num,
2255     &ep_gem_num,
2256     &ep_inactive_num,
2257     &ep_explosive_num,
2258     &ep_mampf3_num,
2259     &ep_pushable_num,
2260     &ep_player_num,
2261     &ep_has_content_num,
2262     &ep_eatable_num,
2263     &ep_sp_element_num,
2264     &ep_quick_gate_num,
2265     &ep_over_player_num,
2266     &ep_active_bomb_num
2267   };
2268   static int *ep2_num[] =
2269   {
2270     &ep_belt_num,
2271     &ep_belt_active_num,
2272     &ep_belt_switch_num,
2273     &ep_tube_num,
2274     &ep_em_slippery_wall_num,
2275     &ep_can_be_crumbled_num
2276   };
2277   static int num_properties1 = SIZEOF_ARRAY(ep1_num, int *);
2278   static int num_properties2 = SIZEOF_ARRAY(ep2_num, int *);
2279
2280   for (i=0; i<MAX_NUM_ELEMENTS; i++)
2281   {
2282     Properties1[i] = 0;
2283     Properties2[i] = 0;
2284   }
2285
2286   for (i=0; i<num_properties1; i++)
2287     for (j=0; j<*(ep1_num[i]); j++)
2288       Properties1[(ep1_array[i])[j]] |= ep1_bit[i];
2289   for (i=0; i<num_properties2; i++)
2290     for (j=0; j<*(ep2_num[i]); j++)
2291       Properties2[(ep2_array[i])[j]] |= ep2_bit[i];
2292
2293   for (i=EL_CHAR_START; i<=EL_CHAR_END; i++)
2294     Properties1[i] |= (EP_BIT_CHAR | EP_BIT_INACTIVE);
2295 }
2296
2297 static void InitGlobal()
2298 {
2299   global.autoplay_leveldir = NULL;
2300
2301   global.frames_per_second = 0;
2302   global.fps_slowdown = FALSE;
2303   global.fps_slowdown_factor = 1;
2304 }
2305
2306 void Execute_Command(char *command)
2307 {
2308   if (strcmp(command, "print graphicsinfo.conf") == 0)
2309   {
2310     int i;
2311
2312     printf("# You can configure additional/alternative image files here.\n");
2313     printf("# (The images below are default and therefore commented out.)\n");
2314     printf("\n");
2315     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
2316     printf("\n");
2317     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2318     printf("\n");
2319
2320     for (i=0; image_config[i].token != NULL; i++)
2321       printf("# %s\n",
2322              getFormattedSetupEntry(image_config[i].token,
2323                                     image_config[i].value));
2324
2325     exit(0);
2326   }
2327   else if (strcmp(command, "print soundsinfo.conf") == 0)
2328   {
2329     int i;
2330
2331     printf("# You can configure additional/alternative sound files here.\n");
2332     printf("# (The sounds below are default and therefore commented out.)\n");
2333     printf("\n");
2334     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
2335     printf("\n");
2336     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2337     printf("\n");
2338
2339     for (i=0; sound_config[i].token != NULL; i++)
2340       printf("# %s\n",
2341              getFormattedSetupEntry(sound_config[i].token,
2342                                     sound_config[i].value));
2343
2344     exit(0);
2345   }
2346   else if (strcmp(command, "print musicinfo.conf") == 0)
2347   {
2348     printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
2349     printf("\n");
2350     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
2351     printf("\n");
2352     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
2353
2354     exit(0);
2355   }
2356   else if (strncmp(command, "dump level ", 11) == 0)
2357   {
2358     char *filename = &command[11];
2359
2360     if (access(filename, F_OK) != 0)
2361       Error(ERR_EXIT, "cannot open file '%s'", filename);
2362
2363     LoadLevelFromFilename(filename);
2364     DumpLevel(&level);
2365
2366     exit(0);
2367   }
2368   else if (strncmp(command, "dump tape ", 10) == 0)
2369   {
2370     char *filename = &command[10];
2371
2372     if (access(filename, F_OK) != 0)
2373       Error(ERR_EXIT, "cannot open file '%s'", filename);
2374
2375     LoadTapeFromFilename(filename);
2376     DumpTape(&tape);
2377
2378     exit(0);
2379   }
2380   else if (strncmp(command, "autoplay ", 9) == 0)
2381   {
2382     char *str_copy = getStringCopy(&command[9]);
2383     char *str_ptr = strchr(str_copy, ' ');
2384
2385     global.autoplay_leveldir = str_copy;
2386     global.autoplay_level_nr = -1;
2387
2388     if (str_ptr != NULL)
2389     {
2390       *str_ptr++ = '\0';                        /* terminate leveldir string */
2391       global.autoplay_level_nr = atoi(str_ptr); /* get level_nr value */
2392     }
2393   }
2394   else
2395   {
2396     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
2397   }
2398 }
2399
2400 static void InitSetup()
2401 {
2402   LoadSetup();                                  /* global setup info */
2403
2404   /* set some options from setup file */
2405
2406   if (setup.options.verbose)
2407     options.verbose = TRUE;
2408 }
2409
2410 static void InitPlayerInfo()
2411 {
2412   int i;
2413
2414   /* choose default local player */
2415   local_player = &stored_player[0];
2416
2417   for (i=0; i<MAX_PLAYERS; i++)
2418     stored_player[i].connected = FALSE;
2419
2420   local_player->connected = TRUE;
2421 }
2422
2423 static void InitArtworkInfo()
2424 {
2425   LoadArtworkInfo();
2426 }
2427
2428 static char *get_element_class_token(int element)
2429 {
2430   char *element_class_name = element_info[element].class_name;
2431   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
2432
2433   sprintf(element_class_token, "[%s]", element_class_name);
2434
2435   return element_class_token;
2436 }
2437
2438 static void InitArtworkConfig()
2439 {
2440   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
2441   static char *sound_id_prefix[MAX_NUM_ELEMENTS + MAX_NUM_ELEMENTS + 1];
2442   static char *action_id_suffix[NUM_ACTIONS + 1];
2443   static char *direction_id_suffix[NUM_DIRECTIONS + 1];
2444   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
2445   static char *dummy[1] = { NULL };
2446   static char *ignore_image_tokens[] =
2447   {
2448     "name",
2449     "sort_priority",
2450     "global.num_toons",
2451     "menu.draw_xoffset",
2452     "menu.draw_yoffset",
2453     "menu.draw_xoffset.MAIN",
2454     "menu.draw_yoffset.MAIN",
2455     "door.step_offset",
2456     "door.step_delay",
2457     NULL
2458   };
2459   static char *ignore_sound_tokens[] =
2460   {
2461     "name",
2462     "sort_priority",
2463     NULL
2464   };
2465   int i;
2466
2467   for (i=0; i<MAX_NUM_ELEMENTS; i++)
2468     image_id_prefix[i] = element_info[i].token_name;
2469   for (i=0; i<NUM_FONTS; i++)
2470     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
2471   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
2472
2473   for (i=0; i<MAX_NUM_ELEMENTS; i++)
2474     sound_id_prefix[i] = element_info[i].token_name;
2475   for (i=0; i<MAX_NUM_ELEMENTS; i++)
2476     sound_id_prefix[MAX_NUM_ELEMENTS + i] = get_element_class_token(i);
2477   sound_id_prefix[MAX_NUM_ELEMENTS + MAX_NUM_ELEMENTS] = NULL;
2478
2479   for (i=0; i<NUM_ACTIONS; i++)
2480     action_id_suffix[i] = element_action_info[i].suffix;
2481   action_id_suffix[NUM_ACTIONS] = NULL;
2482
2483   for (i=0; i<NUM_DIRECTIONS; i++)
2484     direction_id_suffix[i] = element_direction_info[i].suffix;
2485   direction_id_suffix[NUM_DIRECTIONS] = NULL;
2486
2487   for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
2488     special_id_suffix[i] = special_suffix_info[i].suffix;
2489   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
2490
2491   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
2492                 image_id_prefix, action_id_suffix, direction_id_suffix,
2493                 special_id_suffix, ignore_image_tokens);
2494   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
2495                 sound_id_prefix, action_id_suffix, dummy,
2496                 special_id_suffix, ignore_sound_tokens);
2497 }
2498
2499 static void InitMixer()
2500 {
2501   OpenAudio();
2502   StartMixer();
2503 }
2504
2505 void InitGfx()
2506 {
2507   char *filename_font_initial = NULL;
2508   Bitmap *bitmap_font_initial = NULL;
2509   int i, j;
2510
2511   /* determine settings for initial font (for displaying startup messages) */
2512   for (i=0; image_config[i].token != NULL; i++)
2513   {
2514     for (j=0; j < NUM_INITIAL_FONTS; j++)
2515     {
2516       char font_token[128];
2517       int len_font_token;
2518
2519       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
2520       len_font_token = strlen(font_token);
2521
2522       if (strcmp(image_config[i].token, font_token) == 0)
2523         filename_font_initial = image_config[i].value;
2524       else if (strlen(image_config[i].token) > len_font_token &&
2525                strncmp(image_config[i].token, font_token, len_font_token) == 0)
2526       {
2527         if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
2528           font_initial[j].src_x = atoi(image_config[i].value);
2529         else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
2530           font_initial[j].src_y = atoi(image_config[i].value);
2531         else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
2532           font_initial[j].width = atoi(image_config[i].value);
2533         else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
2534           font_initial[j].height = atoi(image_config[i].value);
2535       }
2536     }
2537   }
2538
2539   if (filename_font_initial == NULL)    /* should not happen */
2540     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
2541
2542   /* initialize screen properties */
2543   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
2544                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
2545   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
2546   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
2547   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
2548
2549   /* create additional image buffers for double-buffering */
2550   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
2551   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
2552
2553   bitmap_font_initial = LoadCustomImage(filename_font_initial);
2554
2555   for (j=0; j < NUM_INITIAL_FONTS; j++)
2556     font_initial[j].bitmap = bitmap_font_initial;
2557
2558   InitFontGraphicInfo();
2559
2560   DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
2561   DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
2562
2563   DrawInitText("Loading graphics:", 120, FC_GREEN);
2564
2565   InitTileClipmasks();
2566 }
2567
2568 void InitGfxBackground()
2569 {
2570   int x, y;
2571
2572   drawto = backbuffer;
2573   fieldbuffer = bitmap_db_field;
2574   SetDrawtoField(DRAW_BACKBUFFER);
2575
2576   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
2577              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2578   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
2579   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
2580
2581   for (x=0; x<MAX_BUF_XSIZE; x++)
2582     for (y=0; y<MAX_BUF_YSIZE; y++)
2583       redraw[x][y] = 0;
2584   redraw_tiles = 0;
2585   redraw_mask = REDRAW_ALL;
2586 }
2587
2588 static void InitLevelInfo()
2589 {
2590   LoadLevelInfo();                              /* global level info */
2591   LoadLevelSetup_LastSeries();                  /* last played series info */
2592   LoadLevelSetup_SeriesInfo();                  /* last played level info */
2593 }
2594
2595 void InitLevelArtworkInfo()
2596 {
2597   LoadLevelArtworkInfo();
2598 }
2599
2600 static void InitImages()
2601 {
2602   ReloadCustomImages();
2603
2604   LoadCustomElementDescriptions();
2605   LoadSpecialMenuDesignSettings();
2606
2607   ReinitializeGraphics();
2608 }
2609
2610 static void InitSound()
2611 {
2612   InitReloadCustomSounds(artwork.snd_current->identifier);
2613   ReinitializeSounds();
2614 }
2615
2616 static void InitMusic()
2617 {
2618   InitReloadCustomMusic(artwork.mus_current->identifier);
2619   ReinitializeMusic();
2620 }
2621
2622 void InitNetworkServer()
2623 {
2624 #if defined(PLATFORM_UNIX)
2625   int nr_wanted;
2626 #endif
2627
2628   if (!options.network)
2629     return;
2630
2631 #if defined(PLATFORM_UNIX)
2632   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
2633
2634   if (!ConnectToServer(options.server_host, options.server_port))
2635     Error(ERR_EXIT, "cannot connect to network game server");
2636
2637   SendToServer_PlayerName(setup.player_name);
2638   SendToServer_ProtocolVersion();
2639
2640   if (nr_wanted)
2641     SendToServer_NrWanted(nr_wanted);
2642 #endif
2643 }
2644
2645 void ReloadCustomArtwork()
2646 {
2647   static char *leveldir_current_identifier = NULL;
2648   static boolean last_override_level_graphics = FALSE;
2649   static boolean last_override_level_sounds = FALSE;
2650   static boolean last_override_level_music = FALSE;
2651   /* identifier for new artwork; default: artwork configured in setup */
2652   char *gfx_new_identifier = artwork.gfx_current->identifier;
2653   char *snd_new_identifier = artwork.snd_current->identifier;
2654   char *mus_new_identifier = artwork.mus_current->identifier;
2655   boolean redraw_screen = FALSE;
2656
2657   if (leveldir_current_identifier == NULL)
2658     leveldir_current_identifier = leveldir_current->identifier;
2659
2660 #if 0
2661   printf("CURRENT GFX: '%s' ['%s']\n", artwork.gfx_current->identifier,
2662          leveldir_current->graphics_set);
2663   printf("CURRENT LEV: '%s' / '%s'\n", leveldir_current_identifier,
2664          leveldir_current->identifier);
2665 #endif
2666
2667 #if 0
2668   printf("graphics --> '%s' ('%s')\n",
2669          artwork.gfx_current_identifier, artwork.gfx_current->filename);
2670   printf("sounds   --> '%s' ('%s')\n",
2671          artwork.snd_current_identifier, artwork.snd_current->filename);
2672   printf("music    --> '%s' ('%s')\n",
2673          artwork.mus_current_identifier, artwork.mus_current->filename);
2674 #endif
2675
2676   /* leveldir_current may be invalid (level group, parent link) */
2677   if (!validLevelSeries(leveldir_current))
2678     return;
2679
2680   /* when a new level series was selected, check if there was a change
2681      in custom artwork stored in level series directory */
2682   if (leveldir_current_identifier != leveldir_current->identifier)
2683   {
2684     char *identifier_old = leveldir_current_identifier;
2685     char *identifier_new = leveldir_current->identifier;
2686
2687     if (getTreeInfoFromIdentifier(artwork.gfx_first, identifier_old) !=
2688         getTreeInfoFromIdentifier(artwork.gfx_first, identifier_new))
2689       gfx_new_identifier = identifier_new;
2690     if (getTreeInfoFromIdentifier(artwork.snd_first, identifier_old) !=
2691         getTreeInfoFromIdentifier(artwork.snd_first, identifier_new))
2692       snd_new_identifier = identifier_new;
2693     if (getTreeInfoFromIdentifier(artwork.mus_first, identifier_new) !=
2694         getTreeInfoFromIdentifier(artwork.mus_first, identifier_new))
2695       mus_new_identifier = identifier_new;
2696
2697     leveldir_current_identifier = leveldir_current->identifier;
2698   }
2699
2700   /* custom level artwork configured in level series configuration file
2701      always overrides custom level artwork stored in level series directory
2702      and (level independant) custom artwork configured in setup menue */
2703   if (leveldir_current->graphics_set != NULL)
2704     gfx_new_identifier = leveldir_current->graphics_set;
2705   if (leveldir_current->sounds_set != NULL)
2706     snd_new_identifier = leveldir_current->sounds_set;
2707   if (leveldir_current->music_set != NULL)
2708     mus_new_identifier = leveldir_current->music_set;
2709
2710   if (strcmp(artwork.gfx_current_identifier, gfx_new_identifier) != 0 ||
2711       last_override_level_graphics != setup.override_level_graphics)
2712   {
2713 #if 0
2714     printf("RELOADING GRAPHICS '%s' -> '%s' ('%s')\n",
2715            artwork.gfx_current_identifier,
2716            artwork.gfx_current->identifier,
2717            gfx_new_identifier);
2718 #endif
2719
2720     setLevelArtworkDir(artwork.gfx_first);
2721
2722     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
2723
2724     InitImages();
2725
2726     FreeTileClipmasks();
2727     InitTileClipmasks();
2728
2729     artwork.gfx_current_identifier = artwork.gfx_current->identifier;
2730     last_override_level_graphics = setup.override_level_graphics;
2731
2732     redraw_screen = TRUE;
2733   }
2734
2735   if (strcmp(artwork.snd_current_identifier, snd_new_identifier) != 0 ||
2736       last_override_level_sounds != setup.override_level_sounds)
2737   {
2738 #if 0
2739     printf("RELOADING SOUNDS '%s' -> '%s' ('%s')\n",
2740            artwork.snd_current_identifier,
2741            artwork.snd_current->identifier,
2742            snd_new_identifier);
2743 #endif
2744
2745     /* set artwork path to send it to the sound server process */
2746     setLevelArtworkDir(artwork.snd_first);
2747
2748     InitReloadCustomSounds(snd_new_identifier);
2749     ReinitializeSounds();
2750
2751     artwork.snd_current_identifier = artwork.snd_current->identifier;
2752     last_override_level_sounds = setup.override_level_sounds;
2753
2754     redraw_screen = TRUE;
2755   }
2756
2757   if (strcmp(artwork.mus_current_identifier, mus_new_identifier) != 0 ||
2758       last_override_level_music != setup.override_level_music)
2759   {
2760     /* set artwork path to send it to the sound server process */
2761     setLevelArtworkDir(artwork.mus_first);
2762
2763     InitReloadCustomMusic(mus_new_identifier);
2764     ReinitializeMusic();
2765
2766     artwork.mus_current_identifier = artwork.mus_current->identifier;
2767     last_override_level_music = setup.override_level_music;
2768
2769     redraw_screen = TRUE;
2770   }
2771
2772   if (redraw_screen)
2773   {
2774     InitGfxBackground();
2775
2776     /* force redraw of (open or closed) door graphics */
2777     SetDoorState(DOOR_OPEN_ALL);
2778     CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
2779   }
2780 }
2781
2782
2783 /* ========================================================================= */
2784 /* OpenAll()                                                                 */
2785 /* ========================================================================= */
2786
2787 void OpenAll()
2788 {
2789   InitGlobal();         /* initialize some global variables */
2790
2791   if (options.execute_command)
2792     Execute_Command(options.execute_command);
2793
2794   if (options.serveronly)
2795   {
2796 #if defined(PLATFORM_UNIX)
2797     NetworkServer(options.server_port, options.serveronly);
2798 #else
2799     Error(ERR_WARN, "networking only supported in Unix version");
2800 #endif
2801     exit(0);    /* never reached */
2802   }
2803
2804   InitSetup();
2805
2806   InitPlayerInfo();
2807   InitArtworkInfo();            /* needed before loading gfx, sound & music */
2808   InitArtworkConfig();          /* needed before forking sound child process */
2809   InitMixer();
2810
2811   InitCounter();
2812
2813   InitRND(NEW_RANDOMIZE);
2814   InitSimpleRND(NEW_RANDOMIZE);
2815
2816   InitJoysticks();
2817
2818   InitVideoDisplay();
2819   InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
2820                   setup.fullscreen);
2821
2822   InitEventFilter(FilterMouseMotionEvents);
2823
2824   InitElementProperties();
2825
2826   InitGfx();
2827
2828   InitLevelInfo();
2829   InitLevelArtworkInfo();
2830
2831   InitImages();                 /* needs to know current level directory */
2832   InitSound();                  /* needs to know current level directory */
2833   InitMusic();                  /* needs to know current level directory */
2834
2835   InitGfxBackground();
2836
2837   if (global.autoplay_leveldir)
2838   {
2839     AutoPlayTape();
2840     return;
2841   }
2842
2843   game_status = MAINMENU;
2844
2845   DrawMainMenu();
2846
2847   InitNetworkServer();
2848 }
2849
2850 void CloseAllAndExit(int exit_value)
2851 {
2852   StopSounds();
2853   FreeAllSounds();
2854   FreeAllMusic();
2855   CloseAudio();         /* called after freeing sounds (needed for SDL) */
2856
2857   FreeAllImages();
2858   FreeTileClipmasks();
2859
2860   CloseVideoDisplay();
2861   ClosePlatformDependantStuff();
2862
2863   exit(exit_value);
2864 }