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