ce89416c783e356126fcaebdbf1d12326543843d
[rocksndiamonds.git] / src / init.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  init.c                                                  *
12 ***********************************************************/
13
14 #include <signal.h>
15
16 #include "init.h"
17 #include "misc.h"
18 #include "sound.h"
19 #include "screens.h"
20 #include "tools.h"
21 #include "files.h"
22 #include "joystick.h"
23 #include "image.h"
24 #include "network.h"
25 #include "netserv.h"
26
27 struct PictureFileInfo
28 {
29   char *picture_filename;
30   boolean picture_with_mask;
31 };
32
33 struct IconFileInfo
34 {
35   char *picture_filename;
36   char *picturemask_filename;
37 };
38
39 static int sound_process_id = 0;
40
41 static void InitLevelAndPlayerInfo(void);
42 static void InitNetworkServer(void);
43 static void InitDisplay(void);
44 static void InitSound(void);
45 static void InitSoundServer(void);
46 static void InitWindow(int, char **);
47 static void InitGfx(void);
48 static void LoadGfx(int, struct PictureFileInfo *);
49 static void InitElementProperties(void);
50
51 void OpenAll(int argc, char *argv[])
52 {
53   if (options.serveronly)
54   {
55     NetworkServer(options.server_port, options.serveronly);
56
57     /* never reached */
58     exit(0);
59   }
60
61   InitLevelAndPlayerInfo();
62
63   InitCounter();
64   InitSound();
65   InitSoundServer();
66   InitJoysticks();
67   InitRND(NEW_RANDOMIZE);
68
69   signal(SIGINT, CloseAllAndExit);
70   signal(SIGTERM, CloseAllAndExit);
71
72   InitDisplay();
73   InitWindow(argc, argv);
74
75   print_debug("now map window");
76
77   XMapWindow(display, window);
78   XFlush(display);
79
80   print_debug("window mapped");
81
82   print_debug("now init gfx");
83
84   InitGfx();
85
86   print_debug("gfx initialized");
87
88   InitElementProperties();
89
90   DrawMainMenu();
91
92   InitNetworkServer();
93 }
94
95 void InitLevelAndPlayerInfo()
96 {
97   int i;
98
99   /* choose default local player */
100   local_player = &stored_player[0];
101
102   for (i=0; i<MAX_PLAYERS; i++)
103   {
104     stored_player[i].joystick_fd = -1;  /* joystick device closed */
105     stored_player[i].connected = FALSE;
106   }
107
108   local_player->connected = TRUE;
109
110   LoadLevelInfo();                      /* global level info */
111   LoadSetup();                          /* global setup info */
112   LoadLevelSetup();                     /* info about last played level */
113 }
114
115 void InitNetworkServer()
116 {
117 #ifndef MSDOS
118   int nr_wanted;
119 #endif
120
121   if (!options.network)
122     return;
123
124 #ifndef MSDOS
125   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
126
127   if (!ConnectToServer(options.server_host, options.server_port))
128     Error(ERR_EXIT, "cannot connect to network game server");
129
130   SendToServer_PlayerName(setup.player_name);
131   SendToServer_ProtocolVersion();
132
133   if (nr_wanted)
134     SendToServer_NrWanted(nr_wanted);
135 #endif
136 }
137
138 void InitSound()
139 {
140   int i;
141
142   if (sound_status == SOUND_OFF)
143     return;
144
145 #ifndef MSDOS
146   if (access(sound_device_name, W_OK) != 0)
147   {
148     Error(ERR_WARN, "cannot access sound device - no sounds");
149     sound_status = SOUND_OFF;
150     return;
151   }
152
153   if ((sound_device = open(sound_device_name,O_WRONLY))<0)
154   {
155     Error(ERR_WARN, "cannot open sound device - no sounds");
156     sound_status = SOUND_OFF;
157     return;
158   }
159
160   close(sound_device);
161   sound_status = SOUND_AVAILABLE;
162
163 #ifdef VOXWARE
164   sound_loops_allowed = TRUE;
165
166   /*
167   setup.sound_loops_on = TRUE;
168   */
169
170 #endif
171 #else
172   sound_loops_allowed = TRUE;
173
174   /*
175   setup.sound_loops_on = TRUE;
176   */
177
178 #endif
179
180   for(i=0; i<NUM_SOUNDS; i++)
181   {
182 #ifdef MSDOS
183   sprintf(sound_name[i], "%d", i+1);
184 #endif
185     Sound[i].name = sound_name[i];
186     if (!LoadSound(&Sound[i]))
187     {
188       sound_status = SOUND_OFF;
189       return;
190     }
191   }
192 }
193
194 void InitSoundServer()
195 {
196   if (sound_status == SOUND_OFF)
197     return;
198
199 #ifndef MSDOS
200   if (pipe(sound_pipe)<0)
201   {
202     Error(ERR_WARN, "cannot create pipe - no sounds");
203     sound_status = SOUND_OFF;
204     return;
205   }
206
207   if ((sound_process_id = fork()) < 0)
208   {       
209     Error(ERR_WARN, "cannot create sound server process - no sounds");
210     sound_status = SOUND_OFF;
211     return;
212   }
213
214   if (!sound_process_id)        /* we are child */
215   {
216     SoundServer();
217
218     /* never reached */
219     exit(0);
220   }
221   else                          /* we are parent */
222     close(sound_pipe[0]);       /* no reading from pipe needed */
223 #else
224   SoundServer();
225 #endif
226 }
227
228 void InitJoysticks()
229 {
230 #ifndef MSDOS
231   int i;
232 #endif
233
234   if (global_joystick_status == JOYSTICK_OFF)
235     return;
236
237   joystick_status = JOYSTICK_OFF;
238
239 #ifndef MSDOS
240   for (i=0; i<MAX_PLAYERS; i++)
241   {
242     char *device_name = setup.input[i].joy.device_name;
243
244     /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
245     if (stored_player[i].joystick_fd != -1)
246     {
247       close(stored_player[i].joystick_fd);
248       stored_player[i].joystick_fd = -1;
249     }
250
251     if (!setup.input[i].use_joystick)
252       continue;
253
254     if (access(device_name, R_OK) != 0)
255     {
256       Error(ERR_WARN, "cannot access joystick device '%s'", device_name);
257       continue;
258     }
259
260     if ((stored_player[i].joystick_fd = open(device_name, O_RDONLY)) < 0)
261     {
262       Error(ERR_WARN, "cannot open joystick device '%s'", device_name);
263       continue;
264     }
265
266     joystick_status = JOYSTICK_AVAILABLE;
267   }
268 #else
269   joystick_status = JOYSTICK_AVAILABLE;
270 #endif
271 }
272
273 void InitDisplay()
274 {
275 #ifndef MSDOS
276   XVisualInfo vinfo_template, *vinfo;
277   int num_visuals;
278 #endif
279   unsigned int depth;
280
281   /* connect to X server */
282   if (!(display = XOpenDisplay(options.display_name)))
283     Error(ERR_EXIT, "cannot connect to X server %s",
284           XDisplayName(options.display_name));
285
286   screen = DefaultScreen(display);
287   visual = DefaultVisual(display, screen);
288   depth  = DefaultDepth(display, screen);
289   cmap   = DefaultColormap(display, screen);
290
291 #ifndef MSDOS
292   /* look for good enough visual */
293   vinfo_template.screen = screen;
294   vinfo_template.class = (depth == 8 ? PseudoColor : TrueColor);
295   vinfo_template.depth = depth;
296   if ((vinfo = XGetVisualInfo(display, VisualScreenMask | VisualClassMask |
297                               VisualDepthMask, &vinfo_template, &num_visuals)))
298   {
299     visual = vinfo->visual;
300     XFree((void *)vinfo);
301   }
302
303   /* got appropriate visual? */
304   if (depth < 8)
305   {
306     printf("Sorry, displays with less than 8 bits per pixel not supported.\n");
307     exit(-1);
308   }
309   else if ((depth ==8 && visual->class != PseudoColor) ||
310            (depth > 8 && visual->class != TrueColor &&
311             visual->class != DirectColor))
312   {
313     printf("Sorry, cannot get appropriate visual.\n");
314     exit(-1);
315   }
316 #endif
317 }
318
319 void InitWindow(int argc, char *argv[])
320 {
321   unsigned int border_width = 4;
322   XGCValues gc_values;
323   unsigned long gc_valuemask;
324 #ifndef MSDOS
325   XTextProperty windowName, iconName;
326   Pixmap icon_pixmap, iconmask_pixmap;
327   unsigned int icon_width, icon_height;
328   int icon_hot_x, icon_hot_y;
329   char icon_filename[256];
330   XSizeHints size_hints;
331   XWMHints wm_hints;
332   XClassHint class_hints;
333   char *window_name = WINDOWTITLE_STRING;
334   char *icon_name = WINDOWTITLE_STRING;
335   long window_event_mask;
336   Atom proto_atom = None, delete_atom = None;
337 #endif
338   int screen_width, screen_height;
339   int win_xpos = WIN_XPOS, win_ypos = WIN_YPOS;
340   unsigned long pen_fg = WhitePixel(display,screen);
341   unsigned long pen_bg = BlackPixel(display,screen);
342   const int width = WIN_XSIZE, height = WIN_YSIZE;
343
344 #ifndef MSDOS
345   static struct IconFileInfo icon_pic =
346   {
347     "rocks_icon.xbm",
348     "rocks_iconmask.xbm"
349   };
350 #endif
351
352   screen_width = XDisplayWidth(display, screen);
353   screen_height = XDisplayHeight(display, screen);
354
355   win_xpos = (screen_width - width) / 2;
356   win_ypos = (screen_height - height) / 2;
357
358   window = XCreateSimpleWindow(display, RootWindow(display, screen),
359                                win_xpos, win_ypos, width, height, border_width,
360                                pen_fg, pen_bg);
361
362 #ifndef MSDOS
363   proto_atom = XInternAtom(display, "WM_PROTOCOLS", FALSE);
364   delete_atom = XInternAtom(display, "WM_DELETE_WINDOW", FALSE);
365   if ((proto_atom != None) && (delete_atom != None))
366     XChangeProperty(display, window, proto_atom, XA_ATOM, 32,
367                     PropModePrepend, (unsigned char *) &delete_atom, 1);
368
369   sprintf(icon_filename, "%s/%s/%s",
370           options.base_directory, GRAPHICS_DIRECTORY,
371           icon_pic.picture_filename);
372   XReadBitmapFile(display,window,icon_filename,
373                   &icon_width,&icon_height,
374                   &icon_pixmap,&icon_hot_x,&icon_hot_y);
375   if (!icon_pixmap)
376     Error(ERR_EXIT, "cannot read icon bitmap file '%s'", icon_filename);
377
378   sprintf(icon_filename, "%s/%s/%s",
379           options.base_directory, GRAPHICS_DIRECTORY,
380           icon_pic.picturemask_filename);
381   XReadBitmapFile(display,window,icon_filename,
382                   &icon_width,&icon_height,
383                   &iconmask_pixmap,&icon_hot_x,&icon_hot_y);
384   if (!iconmask_pixmap)
385     Error(ERR_EXIT, "cannot read icon bitmap file '%s'", icon_filename);
386
387   size_hints.width  = size_hints.min_width  = size_hints.max_width  = width;
388   size_hints.height = size_hints.min_height = size_hints.max_height = height;
389   size_hints.flags = PSize | PMinSize | PMaxSize;
390
391   if (win_xpos || win_ypos)
392   {
393     size_hints.x = win_xpos;
394     size_hints.y = win_ypos;
395     size_hints.flags |= PPosition;
396   }
397
398   if (!XStringListToTextProperty(&window_name, 1, &windowName))
399     Error(ERR_EXIT, "structure allocation for windowName failed");
400
401   if (!XStringListToTextProperty(&icon_name, 1, &iconName))
402     Error(ERR_EXIT, "structure allocation for iconName failed");
403
404   wm_hints.initial_state = NormalState;
405   wm_hints.input = True;
406   wm_hints.icon_pixmap = icon_pixmap;
407   wm_hints.icon_mask = iconmask_pixmap;
408   wm_hints.flags = StateHint | IconPixmapHint | IconMaskHint | InputHint;
409
410   class_hints.res_name = program_name;
411   class_hints.res_class = "Rocks'n'Diamonds";
412
413   XSetWMProperties(display, window, &windowName, &iconName, 
414                    argv, argc, &size_hints, &wm_hints, 
415                    &class_hints);
416
417   XFree(windowName.value);
418   XFree(iconName.value);
419
420   /* Select event types wanted */
421   window_event_mask = ExposureMask | StructureNotifyMask | FocusChangeMask |
422                       ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
423                       KeyPressMask | KeyReleaseMask;
424   XSelectInput(display, window, window_event_mask);
425 #endif
426
427   /* create GC for drawing with window depth */
428   gc_values.graphics_exposures = False;
429   gc_values.foreground = pen_bg;
430   gc_values.background = pen_bg;
431   gc_valuemask = GCGraphicsExposures | GCForeground | GCBackground;
432   gc = XCreateGC(display, window, gc_valuemask, &gc_values);
433
434
435
436   print_debug("OpenWindow finished");
437 }
438
439 void DrawInitText(char *text, int ypos, int color)
440 {
441   if (display && window && pix[PIX_SMALLFONT])
442   {
443     XFillRectangle(display,window,gc,0,ypos, WIN_XSIZE,FONT2_YSIZE);
444     DrawTextExt(window,gc,(WIN_XSIZE-strlen(text)*FONT2_XSIZE)/2,
445                 ypos,text,FS_SMALL,color);
446     XFlush(display);
447   }
448 }
449
450 void InitGfx()
451 {
452   int i,j;
453   GC copy_clipmask_gc;
454   XGCValues clip_gc_values;
455   unsigned long clip_gc_valuemask;
456
457 #ifdef MSDOS
458   static struct PictureFileInfo pic[NUM_PICTURES] =
459   {
460     { "Screen", TRUE },
461     { "Door",   TRUE },
462     { "Heroes", TRUE },
463     { "Toons",  TRUE },
464     { "Font",   FALSE },
465     { "Font2",  FALSE }
466   }; 
467 #else
468   static struct PictureFileInfo pic[NUM_PICTURES] =
469   {
470     { "RocksScreen",    TRUE },
471     { "RocksDoor",      TRUE },
472     { "RocksHeroes",    TRUE },
473     { "RocksToons",     TRUE },
474     { "RocksFont",      FALSE },
475     { "RocksFont2",     FALSE }
476   }; 
477 #endif
478
479   static struct
480   {
481     int start;
482     int count;
483   }
484   tile_needs_clipping[] =
485   {
486     { GFX_SPIELER1_UP, 4 },
487     { GFX_SPIELER1_DOWN, 4 },
488     { GFX_SPIELER1_LEFT, 4 },
489     { GFX_SPIELER1_RIGHT, 4 },
490     { GFX_SPIELER1_PUSH_LEFT, 4 },
491     { GFX_SPIELER1_PUSH_RIGHT, 4 },
492     { GFX_SPIELER2_UP, 4 },
493     { GFX_SPIELER2_DOWN, 4 },
494     { GFX_SPIELER2_LEFT, 4 },
495     { GFX_SPIELER2_RIGHT, 4 },
496     { GFX_SPIELER2_PUSH_LEFT, 4 },
497     { GFX_SPIELER2_PUSH_RIGHT, 4 },
498     { GFX_SPIELER3_UP, 4 },
499     { GFX_SPIELER3_DOWN, 4 },
500     { GFX_SPIELER3_LEFT, 4 },
501     { GFX_SPIELER3_RIGHT, 4 },
502     { GFX_SPIELER3_PUSH_LEFT, 4 },
503     { GFX_SPIELER3_PUSH_RIGHT, 4 },
504     { GFX_SPIELER4_UP, 4 },
505     { GFX_SPIELER4_DOWN, 4 },
506     { GFX_SPIELER4_LEFT, 4 },
507     { GFX_SPIELER4_RIGHT, 4 },
508     { GFX_SPIELER4_PUSH_LEFT, 4 },
509     { GFX_SPIELER4_PUSH_RIGHT, 4 },
510     { GFX_GEBLUBBER, 4 },
511     { GFX_DYNAMIT, 7 },
512     { GFX_DYNABOMB, 4 },
513     { GFX_EXPLOSION, 8 },
514     { GFX_SOKOBAN_OBJEKT, 1 },
515     { GFX_FUNKELN_BLAU, 3 },
516     { GFX_FUNKELN_WEISS, 3 },
517     { -1, 0 }
518   };
519
520 #if DEBUG_TIMING
521   debug_print_timestamp(0, NULL);       /* initialize timestamp function */
522 #endif
523
524   LoadGfx(PIX_SMALLFONT,&pic[PIX_SMALLFONT]);
525   DrawInitText(WINDOWTITLE_STRING,20,FC_YELLOW);
526   DrawInitText(COPYRIGHT_STRING,50,FC_RED);
527 #ifdef MSDOS
528   DrawInitText("MSDOS version done by Guido Schulz",210,FC_BLUE);
529   rest(200);
530 #endif MSDOS
531   DrawInitText("Loading graphics:",120,FC_GREEN);
532
533   for(i=0; i<NUM_PICTURES; i++)
534     if (i != PIX_SMALLFONT)
535       LoadGfx(i,&pic[i]);
536
537 #if DEBUG_TIMING
538   debug_print_timestamp(0, "SUMMARY LOADING ALL GRAPHICS:");
539 #endif
540
541   pix[PIX_DB_BACK] = XCreatePixmap(display, window,
542                                    WIN_XSIZE,WIN_YSIZE,
543                                    XDefaultDepth(display,screen));
544   pix[PIX_DB_DOOR] = XCreatePixmap(display, window,
545                                    3*DXSIZE,DYSIZE+VYSIZE,
546                                    XDefaultDepth(display,screen));
547   pix[PIX_DB_FIELD] = XCreatePixmap(display, window,
548                                     FXSIZE,FYSIZE,
549                                     XDefaultDepth(display,screen));
550
551   clip_gc_values.graphics_exposures = False;
552   clip_gc_valuemask = GCGraphicsExposures;
553   copy_clipmask_gc =
554     XCreateGC(display,clipmask[PIX_BACK],clip_gc_valuemask,&clip_gc_values);
555
556   clip_gc_values.graphics_exposures = False;
557   clip_gc_valuemask = GCGraphicsExposures;
558   tile_clip_gc =
559     XCreateGC(display,window,clip_gc_valuemask,&clip_gc_values);
560
561   /* initialize pixmap array to Pixmap 'None' */
562   for(i=0; i<NUM_TILES; i++)
563     tile_clipmask[i] = None;
564
565   /* create only those clipping Pixmaps we really need */
566   for(i=0; tile_needs_clipping[i].start>=0; i++)
567   {
568     for(j=0; j<tile_needs_clipping[i].count; j++)
569     {
570       int tile = tile_needs_clipping[i].start + j;
571       int graphic = tile;
572       int src_x, src_y;
573       Pixmap src_pixmap;
574
575       if (graphic >= GFX_START_ROCKSSCREEN &&
576           graphic <= GFX_END_ROCKSSCREEN)
577       {
578         src_pixmap = clipmask[PIX_BACK];
579         graphic -= GFX_START_ROCKSSCREEN;
580         src_x = SX + (graphic % GFX_PER_LINE) * TILEX;
581         src_y = SY + (graphic / GFX_PER_LINE) * TILEY;
582       }
583       else if (graphic >= GFX_START_ROCKSHEROES &&
584                graphic <= GFX_END_ROCKSHEROES)
585       {
586         src_pixmap = clipmask[PIX_HEROES];
587         graphic -= GFX_START_ROCKSHEROES;
588         src_x = (graphic % HEROES_PER_LINE) * TILEX;
589         src_y = (graphic / HEROES_PER_LINE) * TILEY;
590       }
591       else if (graphic >= GFX_START_ROCKSFONT &&
592                graphic <= GFX_END_ROCKSFONT)
593       {
594         src_pixmap = clipmask[PIX_BIGFONT];
595         graphic -= GFX_START_ROCKSFONT;
596         src_x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
597         src_y = (graphic / FONT_CHARS_PER_LINE) * TILEY +
598           FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY;
599       }
600       else
601         break;
602
603       tile_clipmask[tile] = XCreatePixmap(display, window, TILEX,TILEY, 1);
604
605       XCopyArea(display,src_pixmap,tile_clipmask[tile],copy_clipmask_gc,
606                 src_x,src_y, TILEX,TILEY, 0,0);
607     }
608   }
609
610   if (!pix[PIX_DB_BACK] || !pix[PIX_DB_DOOR])
611     Error(ERR_EXIT, "cannot create additional pixmaps");
612
613   for(i=0; i<NUM_PIXMAPS; i++)
614   {
615     if (clipmask[i])
616     {
617       clip_gc_values.graphics_exposures = False;
618       clip_gc_values.clip_mask = clipmask[i];
619       clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
620       clip_gc[i] = XCreateGC(display,window,clip_gc_valuemask,&clip_gc_values);
621     }
622   }
623
624   drawto = backbuffer = pix[PIX_DB_BACK];
625   fieldbuffer = pix[PIX_DB_FIELD];
626   SetDrawtoField(DRAW_BACKBUFFER);
627
628   XCopyArea(display,pix[PIX_BACK],backbuffer,gc,
629             0,0, WIN_XSIZE,WIN_YSIZE, 0,0);
630   XFillRectangle(display,pix[PIX_DB_BACK],gc,
631                  REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE);
632   XFillRectangle(display,pix[PIX_DB_DOOR],gc,
633                  0,0, 3*DXSIZE,DYSIZE+VYSIZE);
634
635   for(i=0; i<MAX_BUF_XSIZE; i++)
636     for(j=0; j<MAX_BUF_YSIZE; j++)
637       redraw[i][j] = 0;
638   redraw_tiles = 0;
639   redraw_mask = REDRAW_ALL;
640 }
641
642 void LoadGfx(int pos, struct PictureFileInfo *pic)
643 {
644   char basefilename[256];
645   char filename[256];
646
647 #ifdef USE_XPM_LIBRARY
648   int xpm_err, xbm_err;
649   unsigned int width,height;
650   int hot_x,hot_y;
651   Pixmap shapemask;
652   char *picture_ext = ".xpm";
653   char *picturemask_ext = "Mask.xbm";
654 #else
655   int pcx_err;
656
657 #if 1
658   char *picture_ext = ".pcx";
659 #else
660   char *picture_ext = ".gif";
661 #endif
662
663 #endif
664
665
666   print_debug("now load pic:");
667
668
669   /* Grafik laden */
670   if (pic->picture_filename)
671   {
672     sprintf(basefilename, "%s%s", pic->picture_filename, picture_ext);
673     DrawInitText(basefilename, 150, FC_YELLOW);
674     sprintf(filename, "%s/%s/%s",
675             options.base_directory, GRAPHICS_DIRECTORY, basefilename);
676
677 #ifdef MSDOS
678     rest(100);
679 #endif MSDOS
680
681 #if DEBUG_TIMING
682     debug_print_timestamp(1, NULL);     /* initialize timestamp function */
683 #endif
684
685 #ifdef USE_XPM_LIBRARY
686
687     xpm_att[pos].valuemask = XpmCloseness;
688     xpm_att[pos].closeness = 20000;
689     xpm_err = XpmReadFileToPixmap(display,window,filename,
690                                   &pix[pos],&shapemask,&xpm_att[pos]);
691     switch(xpm_err)
692     {
693       case XpmOpenFailed:
694         Error(ERR_EXIT, "cannot open XPM file '%s'", filename);
695       case XpmFileInvalid:
696         Error(ERR_EXIT, "invalid XPM file '%s'", filename);
697       case XpmNoMemory:
698         Error(ERR_EXIT, "not enough memory for XPM file '%s'", filename);
699       case XpmColorFailed:
700         Error(ERR_EXIT, "cannot get colors for XPM file '%s'", filename);
701       default:
702         break;
703     }
704
705 #if DEBUG_TIMING
706     printf("LOADING XPM FILE %s:", filename);
707     debug_print_timestamp(1, "");
708 #endif
709
710 #else /* !USE_XPM_LIBRARY */
711
712
713
714     print_debug(filename);
715
716
717
718     pcx_err = Read_PCX_to_Pixmap(display, window, gc, filename,
719                                  &pix[pos], &clipmask[pos]);
720
721
722     print_debug("ok-1");
723
724
725     switch(pcx_err)
726     {
727       case PCX_Success:
728         print_debug("Success");
729         break;
730       case PCX_OpenFailed:
731         print_debug("OpenFailed");
732         Error(ERR_EXIT, "cannot open PCX file '%s'", filename);
733       case PCX_ReadFailed:
734         print_debug("ReadFailed");
735         Error(ERR_EXIT, "cannot read PCX file '%s'", filename);
736       case PCX_FileInvalid:
737         print_debug("FileInvalid");
738         Error(ERR_EXIT, "invalid PCX file '%s'", filename);
739       case PCX_NoMemory:
740         print_debug("NoMemory");
741         Error(ERR_EXIT, "not enough memory for PCX file '%s'", filename);
742       case PCX_ColorFailed:
743         print_debug("ColorFailed");
744         Error(ERR_EXIT, "cannot get colors for PCX file '%s'", filename);
745       default:
746         print_debug("default");
747         break;
748     }
749
750     print_debug("ok-2");
751
752 #if DEBUG_TIMING
753     printf("SUMMARY LOADING PCX FILE %s:", filename);
754     debug_print_timestamp(1, "");
755 #endif
756
757 #endif /* !USE_XPM_LIBRARY */
758
759
760     print_debug("-> 1");
761
762
763
764     if (!pix[pos])
765       Error(ERR_EXIT, "cannot get graphics for '%s'", pic->picture_filename);
766
767
768     print_debug("-> 2");
769   }
770
771   /* zugehörige Maske laden (wenn vorhanden) */
772   if (pic->picture_with_mask)
773   {
774 #ifdef USE_XPM_LIBRARY
775
776     sprintf(basefilename, "%s%s", pic->picture_filename, picturemask_ext);
777     DrawInitText(basefilename, 150, FC_YELLOW);
778     sprintf(filename, "%s/%s/%s",
779             options.base_directory, GRAPHICS_DIRECTORY, basefilename);
780
781 #if DEBUG_TIMING
782     debug_print_timestamp(1, NULL);     /* initialize timestamp function */
783 #endif
784
785     xbm_err = XReadBitmapFile(display,window,filename,
786                               &width,&height,&clipmask[pos],&hot_x,&hot_y);
787     switch(xbm_err)
788     {
789       case BitmapSuccess:
790         break;
791       case BitmapOpenFailed:
792         Error(ERR_EXIT, "cannot open XBM file '%s'", filename);
793       case BitmapFileInvalid:
794         Error(ERR_EXIT, "invalid XBM file '%s'", filename);
795       case BitmapNoMemory:
796         Error(ERR_EXIT, "not enough memory for XBM file '%s'", filename);
797         break;
798       default:
799         break;
800     }
801
802 #if DEBUG_TIMING
803     printf("LOADING XBM FILE %s:", filename);
804     debug_print_timestamp(1, "");
805 #endif
806
807 #endif /* USE_XPM_LIBRARY */
808
809
810     if (!clipmask[pos])
811       print_debug("Oops -- no clipmask");
812
813     if (!clipmask[pos])
814       Error(ERR_EXIT, "cannot get clipmask for '%s'", pic->picture_filename);
815   }
816
817
818   print_debug("LoadGfx done");
819 }
820
821 void InitElementProperties()
822 {
823   int i,j;
824
825   static int ep_amoebalive[] =
826   {
827     EL_AMOEBE_NASS,
828     EL_AMOEBE_NORM,
829     EL_AMOEBE_VOLL,
830     EL_AMOEBE_BD
831   };
832   static int ep_amoebalive_num = sizeof(ep_amoebalive)/sizeof(int);
833
834   static int ep_amoeboid[] =
835   {
836     EL_AMOEBE_TOT,
837     EL_AMOEBE_NASS,
838     EL_AMOEBE_NORM,
839     EL_AMOEBE_VOLL,
840     EL_AMOEBE_BD
841   };
842   static int ep_amoeboid_num = sizeof(ep_amoeboid)/sizeof(int);
843
844   static int ep_schluessel[] =
845   {
846     EL_SCHLUESSEL1,
847     EL_SCHLUESSEL2,
848     EL_SCHLUESSEL3,
849     EL_SCHLUESSEL4
850   };
851   static int ep_schluessel_num = sizeof(ep_schluessel)/sizeof(int);
852
853   static int ep_pforte[] =
854   {
855     EL_PFORTE1,
856     EL_PFORTE2,
857     EL_PFORTE3,
858     EL_PFORTE4,
859     EL_PFORTE1X,
860     EL_PFORTE2X,
861     EL_PFORTE3X,
862     EL_PFORTE4X
863   };
864   static int ep_pforte_num = sizeof(ep_pforte)/sizeof(int);
865
866   static int ep_solid[] =
867   {
868     EL_BETON,
869     EL_MAUERWERK,
870     EL_MAUER_LEBT,
871     EL_MAUER_X,
872     EL_MAUER_Y,
873     EL_MAUER_XY,
874     EL_FELSBODEN,
875     EL_AUSGANG_ZU,
876     EL_AUSGANG_ACT,
877     EL_AUSGANG_AUF,
878     EL_AMOEBE_TOT,
879     EL_AMOEBE_NASS,
880     EL_AMOEBE_NORM,
881     EL_AMOEBE_VOLL,
882     EL_AMOEBE_BD,
883     EL_MORAST_VOLL,
884     EL_MORAST_LEER,
885     EL_SIEB_VOLL,
886     EL_SIEB_LEER,
887     EL_SIEB_TOT,
888     EL_SIEB2_VOLL,
889     EL_SIEB2_LEER,
890     EL_SIEB2_TOT,
891     EL_LIFE,
892     EL_LIFE_ASYNC,
893     EL_BADEWANNE1,
894     EL_BADEWANNE2,
895     EL_BADEWANNE3,
896     EL_BADEWANNE4,
897     EL_BADEWANNE5
898   };
899   static int ep_solid_num = sizeof(ep_solid)/sizeof(int);
900
901   static int ep_massiv[] =
902   {
903     EL_BETON,
904     EL_SALZSAEURE,
905     EL_BADEWANNE1,
906     EL_BADEWANNE2,
907     EL_BADEWANNE3,
908     EL_BADEWANNE4,
909     EL_BADEWANNE5,
910     EL_PFORTE1,
911     EL_PFORTE2,
912     EL_PFORTE3,
913     EL_PFORTE4,
914     EL_PFORTE1X,
915     EL_PFORTE2X,
916     EL_PFORTE3X,
917     EL_PFORTE4X
918   };
919   static int ep_massiv_num = sizeof(ep_massiv)/sizeof(int);
920
921   static int ep_slippery[] =
922   {
923     EL_FELSBODEN,
924     EL_FELSBROCKEN,
925     EL_EDELSTEIN,
926     EL_EDELSTEIN_BD,
927     EL_EDELSTEIN_GELB,
928     EL_EDELSTEIN_ROT,
929     EL_EDELSTEIN_LILA,
930     EL_DIAMANT,
931     EL_BOMBE,
932     EL_KOKOSNUSS,
933     EL_ABLENK_EIN,
934     EL_ABLENK_AUS,
935     EL_ZEIT_VOLL,
936     EL_ZEIT_LEER,
937     EL_BIRNE_EIN,
938     EL_BIRNE_AUS,
939     EL_BADEWANNE1,
940     EL_BADEWANNE2,
941     EL_SONDE
942   };
943   static int ep_slippery_num = sizeof(ep_slippery)/sizeof(int);
944
945   static int ep_enemy[] =
946   {
947     EL_KAEFER,
948     EL_FLIEGER,
949     EL_BUTTERFLY,
950     EL_FIREFLY,
951     EL_MAMPFER,
952     EL_MAMPFER2,
953     EL_ROBOT,
954     EL_PACMAN
955   };
956   static int ep_enemy_num = sizeof(ep_enemy)/sizeof(int);
957
958   static int ep_mauer[] =
959   {
960     EL_BETON,
961     EL_PFORTE1,
962     EL_PFORTE2,
963     EL_PFORTE3,
964     EL_PFORTE4,
965     EL_PFORTE1X,
966     EL_PFORTE2X,
967     EL_PFORTE3X,
968     EL_PFORTE4X,
969     EL_AUSGANG_ZU,
970     EL_AUSGANG_ACT,
971     EL_AUSGANG_AUF,
972     EL_MAUERWERK,
973     EL_FELSBODEN,
974     EL_MAUER_LEBT,
975     EL_MAUER_X,
976     EL_MAUER_Y,
977     EL_MAUER_XY,
978     EL_MAUERND
979   };
980   static int ep_mauer_num = sizeof(ep_mauer)/sizeof(int);
981
982   static int ep_can_fall[] =
983   {
984     EL_FELSBROCKEN,
985     EL_EDELSTEIN,
986     EL_EDELSTEIN_BD,
987     EL_EDELSTEIN_GELB,
988     EL_EDELSTEIN_ROT,
989     EL_EDELSTEIN_LILA,
990     EL_DIAMANT,
991     EL_BOMBE,
992     EL_KOKOSNUSS,
993     EL_TROPFEN,
994     EL_MORAST_VOLL,
995     EL_SIEB_VOLL,
996     EL_SIEB2_VOLL,
997     EL_ZEIT_VOLL,
998     EL_ZEIT_LEER
999   };
1000   static int ep_can_fall_num = sizeof(ep_can_fall)/sizeof(int);
1001
1002   static int ep_can_smash[] =
1003   {
1004     EL_FELSBROCKEN,
1005     EL_EDELSTEIN,
1006     EL_EDELSTEIN_BD,
1007     EL_EDELSTEIN_GELB,
1008     EL_EDELSTEIN_ROT,
1009     EL_EDELSTEIN_LILA,
1010     EL_DIAMANT,
1011     EL_SCHLUESSEL1,
1012     EL_SCHLUESSEL2,
1013     EL_SCHLUESSEL3,
1014     EL_SCHLUESSEL4,
1015     EL_BOMBE,
1016     EL_KOKOSNUSS,
1017     EL_TROPFEN,
1018     EL_ZEIT_VOLL,
1019     EL_ZEIT_LEER
1020   };
1021   static int ep_can_smash_num = sizeof(ep_can_smash)/sizeof(int);
1022
1023   static int ep_can_change[] =
1024   {
1025     EL_FELSBROCKEN,
1026     EL_EDELSTEIN,
1027     EL_EDELSTEIN_BD,
1028     EL_EDELSTEIN_GELB,
1029     EL_EDELSTEIN_ROT,
1030     EL_EDELSTEIN_LILA,
1031     EL_DIAMANT
1032   };
1033   static int ep_can_change_num = sizeof(ep_can_change)/sizeof(int);
1034
1035   static int ep_can_move[] =
1036   {
1037     EL_KAEFER,
1038     EL_FLIEGER,
1039     EL_BUTTERFLY,
1040     EL_FIREFLY,
1041     EL_MAMPFER,
1042     EL_MAMPFER2,
1043     EL_ROBOT,
1044     EL_PACMAN,
1045     EL_MAULWURF,
1046     EL_PINGUIN,
1047     EL_SCHWEIN,
1048     EL_DRACHE,
1049     EL_SONDE
1050   };
1051   static int ep_can_move_num = sizeof(ep_can_move)/sizeof(int);
1052
1053   static int ep_could_move[] =
1054   {
1055     EL_KAEFER_R,
1056     EL_KAEFER_O,
1057     EL_KAEFER_L,
1058     EL_KAEFER_U,
1059     EL_FLIEGER_R,
1060     EL_FLIEGER_O,
1061     EL_FLIEGER_L,
1062     EL_FLIEGER_U,
1063     EL_BUTTERFLY_R,
1064     EL_BUTTERFLY_O,
1065     EL_BUTTERFLY_L,
1066     EL_BUTTERFLY_U,
1067     EL_FIREFLY_R,
1068     EL_FIREFLY_O,
1069     EL_FIREFLY_L,
1070     EL_FIREFLY_U,
1071     EL_PACMAN_R,
1072     EL_PACMAN_O,
1073     EL_PACMAN_L,
1074     EL_PACMAN_U
1075   };
1076   static int ep_could_move_num = sizeof(ep_could_move)/sizeof(int);
1077
1078   static int ep_dont_touch[] =
1079   {
1080     EL_KAEFER,
1081     EL_FLIEGER,
1082     EL_BUTTERFLY,
1083     EL_FIREFLY
1084   };
1085   static int ep_dont_touch_num = sizeof(ep_dont_touch)/sizeof(int);
1086
1087   static int ep_dont_go_to[] =
1088   {
1089     EL_KAEFER,
1090     EL_FLIEGER,
1091     EL_BUTTERFLY,
1092     EL_FIREFLY,
1093     EL_MAMPFER,
1094     EL_MAMPFER2,
1095     EL_ROBOT,
1096     EL_PACMAN,
1097     EL_TROPFEN,
1098     EL_SALZSAEURE
1099   };
1100   static int ep_dont_go_to_num = sizeof(ep_dont_go_to)/sizeof(int);
1101
1102   static int ep_mampf2[] =
1103   {
1104     EL_ERDREICH,
1105     EL_KAEFER,
1106     EL_FLIEGER,
1107     EL_BUTTERFLY,
1108     EL_FIREFLY,
1109     EL_MAMPFER,
1110     EL_ROBOT,
1111     EL_PACMAN,
1112     EL_TROPFEN,
1113     EL_AMOEBE_TOT,
1114     EL_AMOEBE_NASS,
1115     EL_AMOEBE_NORM,
1116     EL_AMOEBE_VOLL,
1117     EL_AMOEBE_BD,
1118     EL_EDELSTEIN,
1119     EL_EDELSTEIN_BD,
1120     EL_EDELSTEIN_GELB,
1121     EL_EDELSTEIN_ROT,
1122     EL_EDELSTEIN_LILA,
1123     EL_DIAMANT
1124   };
1125   static int ep_mampf2_num = sizeof(ep_mampf2)/sizeof(int);
1126
1127   static int ep_bd_element[] =
1128   {
1129     EL_LEERRAUM,
1130     EL_ERDREICH,
1131     EL_FELSBODEN,
1132     EL_FELSBROCKEN,
1133     EL_EDELSTEIN_BD,
1134     EL_SIEB2_LEER,
1135     EL_AUSGANG_ZU,
1136     EL_AUSGANG_AUF,
1137     EL_BETON,
1138     EL_SPIELFIGUR,
1139     EL_FIREFLY,
1140     EL_FIREFLY_1,
1141     EL_FIREFLY_2,
1142     EL_FIREFLY_3,
1143     EL_FIREFLY_4,
1144     EL_BUTTERFLY,
1145     EL_BUTTERFLY_1,
1146     EL_BUTTERFLY_2,
1147     EL_BUTTERFLY_3,
1148     EL_BUTTERFLY_4,
1149     EL_AMOEBE_BD,
1150     EL_CHAR_FRAGE
1151   };
1152   static int ep_bd_element_num = sizeof(ep_bd_element)/sizeof(int);
1153
1154   static int ep_sb_element[] =
1155   {
1156     EL_LEERRAUM,
1157     EL_BETON,
1158     EL_SOKOBAN_OBJEKT,
1159     EL_SOKOBAN_FELD_LEER,
1160     EL_SOKOBAN_FELD_VOLL,
1161     EL_SPIELFIGUR
1162   };
1163   static int ep_sb_element_num = sizeof(ep_sb_element)/sizeof(int);
1164
1165   static int ep_gem[] =
1166   {
1167     EL_EDELSTEIN,
1168     EL_EDELSTEIN_BD,
1169     EL_EDELSTEIN_GELB,
1170     EL_EDELSTEIN_ROT,
1171     EL_EDELSTEIN_LILA,
1172     EL_DIAMANT
1173   };
1174   static int ep_gem_num = sizeof(ep_gem)/sizeof(int);
1175
1176   static int ep_inactive[] =
1177   {
1178     EL_LEERRAUM,
1179     EL_ERDREICH,
1180     EL_MAUERWERK,
1181     EL_FELSBODEN,
1182     EL_SCHLUESSEL,
1183     EL_BETON,
1184     EL_AMOEBE_TOT,
1185     EL_MORAST_LEER,
1186     EL_BADEWANNE,
1187     EL_ABLENK_AUS,
1188     EL_SCHLUESSEL1,
1189     EL_SCHLUESSEL2,
1190     EL_SCHLUESSEL3,
1191     EL_SCHLUESSEL4,
1192     EL_PFORTE1,
1193     EL_PFORTE2,
1194     EL_PFORTE3,
1195     EL_PFORTE4,
1196     EL_PFORTE1X,
1197     EL_PFORTE2X,
1198     EL_PFORTE3X,
1199     EL_PFORTE4X,
1200     EL_DYNAMIT_AUS,
1201     EL_UNSICHTBAR,
1202     EL_BIRNE_AUS,
1203     EL_BIRNE_EIN,
1204     EL_ERZ_EDEL,
1205     EL_ERZ_DIAM,
1206     EL_ERZ_EDEL_BD,
1207     EL_ERZ_EDEL_GELB,
1208     EL_DYNABOMB_NR,
1209     EL_DYNABOMB_SZ,
1210     EL_DYNABOMB_XL,
1211     EL_SOKOBAN_OBJEKT,
1212     EL_SOKOBAN_FELD_LEER,
1213     EL_SOKOBAN_FELD_VOLL,
1214     EL_ERZ_EDEL_ROT,
1215     EL_ERZ_EDEL_LILA,
1216     EL_BADEWANNE1,
1217     EL_BADEWANNE2,
1218     EL_BADEWANNE3,
1219     EL_BADEWANNE4,
1220     EL_BADEWANNE5,
1221     EL_SIEB_TOT,
1222     EL_SIEB2_TOT,
1223     EL_AMOEBA2DIAM,
1224     EL_BLOCKED
1225   };
1226   static int ep_inactive_num = sizeof(ep_inactive)/sizeof(int);
1227
1228   static int ep_explosive[] =
1229   {
1230     EL_BOMBE,
1231     EL_DYNAMIT,
1232     EL_DYNAMIT_AUS,
1233     EL_DYNABOMB,
1234     EL_DYNABOMB_NR,
1235     EL_DYNABOMB_SZ,
1236     EL_DYNABOMB_XL,
1237     EL_KAEFER,
1238     EL_MAULWURF,
1239     EL_PINGUIN,
1240     EL_SCHWEIN,
1241     EL_DRACHE,
1242     EL_SONDE
1243   };
1244   static int ep_explosive_num = sizeof(ep_explosive)/sizeof(int);
1245
1246   static int ep_mampf3[] =
1247   {
1248     EL_EDELSTEIN,
1249     EL_EDELSTEIN_BD,
1250     EL_EDELSTEIN_GELB,
1251     EL_EDELSTEIN_ROT,
1252     EL_EDELSTEIN_LILA,
1253     EL_DIAMANT
1254   };
1255   static int ep_mampf3_num = sizeof(ep_mampf3)/sizeof(int);
1256
1257   static int ep_pushable[] =
1258   {
1259     EL_FELSBROCKEN,
1260     EL_BOMBE,
1261     EL_KOKOSNUSS,
1262     EL_ZEIT_LEER,
1263     EL_SOKOBAN_FELD_VOLL,
1264     EL_SOKOBAN_OBJEKT,
1265     EL_SONDE
1266   };
1267   static int ep_pushable_num = sizeof(ep_pushable)/sizeof(int);
1268
1269   static int ep_player[] =
1270   {
1271     EL_SPIELFIGUR,
1272     EL_SPIELER1,
1273     EL_SPIELER2,
1274     EL_SPIELER3,
1275     EL_SPIELER4
1276   };
1277   static int ep_player_num = sizeof(ep_player)/sizeof(int);
1278
1279   static long ep_bit[] =
1280   {
1281     EP_BIT_AMOEBALIVE,
1282     EP_BIT_AMOEBOID,
1283     EP_BIT_SCHLUESSEL,
1284     EP_BIT_PFORTE,
1285     EP_BIT_SOLID,
1286     EP_BIT_MASSIV,
1287     EP_BIT_SLIPPERY,
1288     EP_BIT_ENEMY,
1289     EP_BIT_MAUER,
1290     EP_BIT_CAN_FALL,
1291     EP_BIT_CAN_SMASH,
1292     EP_BIT_CAN_CHANGE,
1293     EP_BIT_CAN_MOVE,
1294     EP_BIT_COULD_MOVE,
1295     EP_BIT_DONT_TOUCH,
1296     EP_BIT_DONT_GO_TO,
1297     EP_BIT_MAMPF2,
1298     EP_BIT_BD_ELEMENT,
1299     EP_BIT_SB_ELEMENT,
1300     EP_BIT_GEM,
1301     EP_BIT_INACTIVE,
1302     EP_BIT_EXPLOSIVE,
1303     EP_BIT_MAMPF3,
1304     EP_BIT_PUSHABLE,
1305     EP_BIT_PLAYER
1306   };
1307   static int *ep_array[] =
1308   {
1309     ep_amoebalive,
1310     ep_amoeboid,
1311     ep_schluessel,
1312     ep_pforte,
1313     ep_solid,
1314     ep_massiv,
1315     ep_slippery,
1316     ep_enemy,
1317     ep_mauer,
1318     ep_can_fall,
1319     ep_can_smash,
1320     ep_can_change,
1321     ep_can_move,
1322     ep_could_move,
1323     ep_dont_touch,
1324     ep_dont_go_to,
1325     ep_mampf2,
1326     ep_bd_element,
1327     ep_sb_element,
1328     ep_gem,
1329     ep_inactive,
1330     ep_explosive,
1331     ep_mampf3,
1332     ep_pushable,
1333     ep_player
1334   };
1335   static int *ep_num[] =
1336   {
1337     &ep_amoebalive_num,
1338     &ep_amoeboid_num,
1339     &ep_schluessel_num,
1340     &ep_pforte_num,
1341     &ep_solid_num,
1342     &ep_massiv_num,
1343     &ep_slippery_num,
1344     &ep_enemy_num,
1345     &ep_mauer_num,
1346     &ep_can_fall_num,
1347     &ep_can_smash_num,
1348     &ep_can_change_num,
1349     &ep_can_move_num,
1350     &ep_could_move_num,
1351     &ep_dont_touch_num,
1352     &ep_dont_go_to_num,
1353     &ep_mampf2_num,
1354     &ep_bd_element_num,
1355     &ep_sb_element_num,
1356     &ep_gem_num,
1357     &ep_inactive_num,
1358     &ep_explosive_num,
1359     &ep_mampf3_num,
1360     &ep_pushable_num,
1361     &ep_player_num
1362   };
1363   static int num_properties = sizeof(ep_num)/sizeof(int *);
1364
1365   for(i=0; i<MAX_ELEMENTS; i++)
1366     Elementeigenschaften[i] = 0;
1367
1368   for(i=0; i<num_properties; i++)
1369     for(j=0; j<*(ep_num[i]); j++)
1370       Elementeigenschaften[(ep_array[i])[j]] |= ep_bit[i];
1371   for(i=EL_CHAR_START; i<EL_CHAR_END; i++)
1372     Elementeigenschaften[i] |= (EP_BIT_CHAR | EP_BIT_INACTIVE);
1373 }
1374
1375 void CloseAllAndExit(int exit_value)
1376 {
1377   int i;
1378
1379   if (sound_process_id)
1380   {
1381     StopSounds();
1382     kill(sound_process_id, SIGTERM);
1383     FreeSounds(NUM_SOUNDS);
1384   }
1385
1386   for(i=0; i<NUM_PIXMAPS; i++)
1387   {
1388     if (pix[i])
1389     {
1390 #ifdef USE_XPM_LIBRARY
1391       if (i < NUM_PICTURES)     /* XPM pictures */
1392       {
1393         XFreeColors(display,DefaultColormap(display,screen),
1394                     xpm_att[i].pixels,xpm_att[i].npixels,0);
1395         XpmFreeAttributes(&xpm_att[i]);
1396       }
1397 #endif
1398       XFreePixmap(display,pix[i]);
1399     }
1400     if (clipmask[i])
1401       XFreePixmap(display,clipmask[i]);
1402     if (clip_gc[i])
1403       XFreeGC(display, clip_gc[i]);
1404   }
1405
1406   if (gc)
1407     XFreeGC(display, gc);
1408
1409   if (display)
1410   {
1411     XAutoRepeatOn(display);
1412     XCloseDisplay(display);
1413   }
1414
1415   exit(exit_value);
1416 }