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