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