rocks_n_diamonds-0.9
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  ©1995 Artsoft Development                               *
5 *        Holger Schemel                                    *
6 *        33659 Bielefeld-Senne                             *
7 *        Telefon: (0521) 493245                            *
8 *        eMail: aeglos@valinor.owl.de                      *
9 *               aeglos@uni-paderborn.de                    *
10 *               q99492@pbhrzx.uni-paderborn.de             *
11 *----------------------------------------------------------*
12 *  tools.c                                                 *
13 *                                                          *
14 *  Letzte Aenderung: 15.06.1995                            *
15 ***********************************************************/
16
17 #include "tools.h"
18 #include "game.h"
19 #include "events.h"
20 #include "sound.h"
21 #include "screens.h"
22 #include "misc.h"
23
24 void BackToFront()
25 {
26   int x,y;
27
28   if (direct_draw_on && game_status==PLAYING)
29     redraw_mask &= ~REDRAW_MAIN;
30
31   if (!redraw_mask)
32     return;
33
34   if (redraw_mask & REDRAW_ALL ||
35       (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS))
36   {
37     XCopyArea(display,backbuffer,window,gc,
38               0,0, WIN_XSIZE,WIN_YSIZE,
39               0,0);
40     redraw_mask = 0;
41   }
42   else if (redraw_mask & REDRAW_FIELD)
43   {
44     XCopyArea(display,backbuffer,window,gc,
45               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
46               REAL_SX,REAL_SY);
47     redraw_mask &= ~REDRAW_MAIN;
48   }
49   else if (redraw_mask & REDRAW_DOORS)
50   {
51     if (redraw_mask & REDRAW_DOOR_1)
52       XCopyArea(display,backbuffer,window,gc,
53                 DX,DY, DXSIZE,DYSIZE, DX,DY);
54     if (redraw_mask & REDRAW_DOOR_2)
55     {
56       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
57         XCopyArea(display,backbuffer,window,gc,
58                   VX,VY, VXSIZE,VYSIZE, VX,VY);
59       else
60       {
61         if (redraw_mask & REDRAW_VIDEO_1)
62           XCopyArea(display,backbuffer,window,gc,
63                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
64                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
65                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
66         if (redraw_mask & REDRAW_VIDEO_2)
67           XCopyArea(display,backbuffer,window,gc,
68                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
69                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
70                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
71         if (redraw_mask & REDRAW_VIDEO_3)
72           XCopyArea(display,backbuffer,window,gc,
73                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
74                     VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
75                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
76       }
77     }
78     redraw_mask &= ~REDRAW_DOORS;
79   }
80
81   if (redraw_mask & REDRAW_MICROLEV)
82   {
83     XCopyArea(display,backbuffer,window,gc,
84               MICROLEV_XPOS,MICROLEV_YPOS, MICROLEV_XSIZE,MICROLEV_YSIZE,
85               MICROLEV_XPOS,MICROLEV_YPOS);
86     XCopyArea(display,backbuffer,window,gc,
87               SX,MICROLABEL_YPOS, SXSIZE,FONT4_YSIZE,
88               SX,MICROLABEL_YPOS);
89     redraw_mask &= ~REDRAW_MICROLEV;
90   }
91
92   if (redraw_mask & REDRAW_TILES)
93   {
94     if (redraw_tiles>REDRAWTILES_TH)
95       XCopyArea(display,backbuffer,window,gc,SX,SY,SXSIZE,SYSIZE,SX,SY);
96     else
97       for(x=0;x<SCR_FIELDX;x++)
98         for(y=0;y<SCR_FIELDY;y++)
99           if (redraw[x][y])
100             XCopyArea(display,backbuffer,window,gc,
101                       SX+x*TILEX,SY+y*TILEY,TILEX,TILEY,SX+x*TILEX,SY+y*TILEY);
102   }
103
104   XFlush(display);
105
106   for(x=0;x<SCR_FIELDX;x++)
107     for(y=0;y<SCR_FIELDY;y++)
108       redraw[x][y]=0;
109   redraw_tiles=0;
110   redraw_mask=0;
111 }
112
113 void FadeToFront()
114 {
115   long fading_delay = 300000;
116
117   if (fading_on && (redraw_mask & REDRAW_FIELD))
118   {
119     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
120     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
121               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
122     XFlush(display);
123     Delay(fading_delay);
124
125     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
126     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
127               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
128     XFlush(display);
129     Delay(fading_delay);
130
131     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
132     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
133               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
134     XFlush(display);
135     Delay(fading_delay);
136
137     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,0);
138     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
139               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
140     XFlush(display);
141     Delay(fading_delay);
142
143     redraw_mask &= ~REDRAW_MAIN;
144   }
145
146   BackToFront();
147 }
148
149 void ClearWindow()
150 {
151   drawto_field = backbuffer;
152   XFillRectangle(display,drawto_field,gc,
153                  REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
154   redraw_mask|=REDRAW_FIELD;
155
156   if (game_status==PLAYING && direct_draw_on)
157   {
158     drawto_field = window;
159     XFillRectangle(display,drawto_field,gc,
160                    REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
161   }
162 }
163
164 void DrawText(int x, int y, char *text, int font, int col)
165 {
166   DrawTextExt(drawto, gc, x, y, text, font, col);
167   if (x<DX)
168     redraw_mask|=REDRAW_FIELD;
169   else if (y<VY)
170     redraw_mask|=REDRAW_DOOR_1;
171 }
172
173 void DrawTextExt(Drawable d, GC gc, int x, int y,
174                  char *text, int font, int font_color)
175 {
176   int font_width, font_height, font_start;
177   int font_pixmap;
178
179   if (font!=FS_SMALL && font!=FS_BIG)
180     font = FS_SMALL;
181   if (font_color<FC_RED || font_color>FC_SPECIAL2)
182     font_color = FC_RED;
183
184   font_width =
185     (font==FS_BIG ? FONT1_XSIZE :
186      font_color<FC_SPECIAL1 ? FONT2_XSIZE :
187      font_color<FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
188   font_height =
189     (font==FS_BIG ? FONT1_XSIZE :
190      font_color<FC_SPECIAL2 ? FONT2_XSIZE: FONT4_XSIZE);
191   font_pixmap = (font==FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
192   font_start =
193     font_color*(font==FS_BIG ? FONT1_YSIZE : FONT2_YSIZE)*FONT_LINES_PER_FONT;
194
195   while(*text)
196   {
197     char c = *text++;
198
199     if (c>='a' && c<='z')
200       c = 'A' + (c - 'a');
201     else if (c=='ä' || c=='Ä')
202       c = 91;
203     else if (c=='ö' || c=='Ö')
204       c = 92;
205     else if (c=='ü' || c=='Ü')
206       c = 93;
207
208     if (c>=32 && c<=95)
209       XCopyArea(display,pix[font_pixmap],d,gc,
210                 ((c-32) % FONT_CHARS_PER_LINE)*font_width,
211                 ((c-32) / FONT_CHARS_PER_LINE)*font_height + font_start,
212                 font_width,font_height, x,y);
213
214     x += font_width;
215   }
216 }
217
218 void DrawGraphic(int x, int y, int graphic)
219 {
220   DrawGraphicExt(drawto_field, gc, x, y, graphic);
221   redraw_tiles++;
222   redraw[x][y] = TRUE;
223   redraw_mask |= REDRAW_TILES;
224 }
225
226 void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
227 {
228   DrawGraphicExtHiRes(d, gc, SX+x*TILEX, SY+y*TILEY, graphic);
229 }
230
231 void DrawGraphicExtHiRes(Drawable d, GC gc, int x, int y, int graphic)
232 {
233   if (graphic<0)
234     XFillRectangle(display,d,gc, x,y, TILEX,TILEY);
235   else if (graphic<256)
236     XCopyArea(display,pix[PIX_BACK],d,gc,
237               SX+(graphic % GFX_PER_LINE)*TILEX,
238               SY+(graphic / GFX_PER_LINE)*TILEY,
239               TILEX,TILEY, x,y);
240   else
241   {
242     graphic -= 256;
243     XCopyArea(display,pix[PIX_BIGFONT],d,gc,
244               (graphic % FONT_CHARS_PER_LINE)*TILEX,
245               (graphic / FONT_CHARS_PER_LINE)*TILEY +
246               FC_SPECIAL1*TILEY*FONT_LINES_PER_FONT,
247               TILEX,TILEY, x,y);
248   }
249 }
250
251 void DrawGraphicThruMask(int x, int y, int graphic)
252 {
253   int src_x,src_y, dest_x,dest_y;
254
255   if (graphic<0 || graphic>255)
256   {
257     DrawGraphic(x,y,graphic);
258     return;
259   }
260
261   src_x  = SX+(graphic % GFX_PER_LINE)*TILEX;
262   src_y  = SY+(graphic / GFX_PER_LINE)*TILEY;
263   dest_x = SX+x*TILEX;
264   dest_y = SY+y*TILEY;
265
266   XSetClipOrigin(display,clip_gc[PIX_BACK],dest_x-src_x,dest_y-src_y);
267   XCopyArea(display,pix[PIX_BACK],drawto_field,clip_gc[PIX_BACK], src_x,src_y,
268             TILEX,TILEY, dest_x,dest_y);
269
270   redraw_tiles++;
271   redraw[x][y]=TRUE;
272   redraw_mask|=REDRAW_TILES;
273 }
274
275 void DrawElementThruMask(int x, int y, int element)
276 {
277   DrawGraphicThruMask(x,y,el2gfx(element));
278 }
279
280 void DrawMiniGraphic(int x, int y, int graphic)
281 {
282   DrawMiniGraphicExt(drawto, gc, x, y, graphic);
283   redraw_tiles++;
284   redraw[x/2][y/2]=TRUE;
285   redraw_mask|=REDRAW_TILES;
286 }
287
288 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
289 {
290   DrawMiniGraphicExtHiRes(d,gc, SX+x*MINI_TILEX,SY+y*MINI_TILEY, graphic);
291 }
292
293 void DrawMiniGraphicExtHiRes(Drawable d, GC gc, int x, int y, int graphic)
294 {
295   if (graphic<0)
296     XFillRectangle(display,d,gc, x,y, MINI_TILEX,MINI_TILEY);
297   else if (graphic<256)
298     XCopyArea(display,pix[PIX_BACK],d,gc,
299               MINI_GFX_STARTX+(graphic % MINI_GFX_PER_LINE)*MINI_TILEX,
300               MINI_GFX_STARTY+(graphic / MINI_GFX_PER_LINE)*MINI_TILEY,
301               MINI_TILEX,MINI_TILEY, x,y);
302   else
303   {
304     graphic -= 256;
305     XCopyArea(display,pix[PIX_SMALLFONT],d,gc,
306               (graphic % FONT_CHARS_PER_LINE)*FONT4_XSIZE,
307               (graphic / FONT_CHARS_PER_LINE)*FONT4_YSIZE +
308               FC_SPECIAL2*FONT2_YSIZE*FONT_LINES_PER_FONT,
309               MINI_TILEX,MINI_TILEY, x,y);
310   }
311 }
312
313 int el2gfx(int element)
314 {
315   switch(element)
316   {
317     case EL_LEERRAUM:           return(-1);
318     case EL_ERDREICH:           return(GFX_ERDREICH);
319     case EL_MAUERWERK:          return(GFX_MAUERWERK);
320     case EL_FELSBODEN:          return(GFX_FELSBODEN);
321     case EL_FELSBROCKEN:        return(GFX_FELSBROCKEN);
322     case EL_SCHLUESSEL:         return(GFX_SCHLUESSEL);
323     case EL_EDELSTEIN:          return(GFX_EDELSTEIN);
324     case EL_AUSGANG_ZU:         return(GFX_AUSGANG_ZU);
325     case EL_AUSGANG_ACT:        return(GFX_AUSGANG_ACT);
326     case EL_AUSGANG_AUF:        return(GFX_AUSGANG_AUF);
327     case EL_SPIELFIGUR:         return(GFX_SPIELFIGUR);
328     case EL_SPIELER1:           return(GFX_SPIELER1);
329     case EL_SPIELER2:           return(GFX_SPIELER2);
330     case EL_SPIELER3:           return(GFX_SPIELER3);
331     case EL_SPIELER4:           return(GFX_SPIELER4);
332     case EL_KAEFER:             return(GFX_KAEFER);
333     case EL_KAEFER_R:           return(GFX_KAEFER_R);
334     case EL_KAEFER_O:           return(GFX_KAEFER_O);
335     case EL_KAEFER_L:           return(GFX_KAEFER_L);
336     case EL_KAEFER_U:           return(GFX_KAEFER_U);
337     case EL_FLIEGER:            return(GFX_FLIEGER);
338     case EL_FLIEGER_R:          return(GFX_FLIEGER_R);
339     case EL_FLIEGER_O:          return(GFX_FLIEGER_O);
340     case EL_FLIEGER_L:          return(GFX_FLIEGER_L);
341     case EL_FLIEGER_U:          return(GFX_FLIEGER_U);
342     case EL_MAMPFER:            return(GFX_MAMPFER);
343     case EL_ZOMBIE:             return(GFX_ZOMBIE);
344     case EL_BETON:              return(GFX_BETON);
345     case EL_DIAMANT:            return(GFX_DIAMANT);
346     case EL_MORAST_LEER:        return(GFX_MORAST_LEER);
347     case EL_MORAST_VOLL:        return(GFX_MORAST_VOLL);
348     case EL_TROPFEN:            return(GFX_TROPFEN);
349     case EL_BOMBE:              return(GFX_BOMBE);
350     case EL_SIEB_LEER:          return(GFX_SIEB_LEER);
351     case EL_SIEB_VOLL:          return(GFX_SIEB_VOLL);
352     case EL_SIEB_TOT:           return(GFX_SIEB_TOT);
353     case EL_SALZSAEURE:         return(GFX_SALZSAEURE);
354     case EL_AMOEBE1:            return(GFX_AMOEBE1);
355     case EL_AMOEBE2:            return(GFX_AMOEBE2);
356     case EL_AMOEBE3:            return(GFX_AMOEBE3);
357     case EL_KOKOSNUSS:          return(GFX_KOKOSNUSS);
358     case EL_LIFE:               return(GFX_LIFE);
359     case EL_LIFE_ASYNC:         return(GFX_LIFE_ASYNC);
360     case EL_DYNAMIT:            return(GFX_DYNAMIT);
361     case EL_BADEWANNE:          return(GFX_BADEWANNE);
362     case EL_BADEWANNE1:         return(GFX_BADEWANNE1);
363     case EL_BADEWANNE2:         return(GFX_BADEWANNE2);
364     case EL_BADEWANNE3:         return(GFX_BADEWANNE3);
365     case EL_BADEWANNE4:         return(GFX_BADEWANNE4);
366     case EL_BADEWANNE5:         return(GFX_BADEWANNE5);
367     case EL_ABLENK_AUS:         return(GFX_ABLENK_AUS);
368     case EL_ABLENK_EIN:         return(GFX_ABLENK_EIN);
369     case EL_SCHLUESSEL1:        return(GFX_SCHLUESSEL1);
370     case EL_SCHLUESSEL2:        return(GFX_SCHLUESSEL2);
371     case EL_SCHLUESSEL3:        return(GFX_SCHLUESSEL3);
372     case EL_SCHLUESSEL4:        return(GFX_SCHLUESSEL4);
373     case EL_PFORTE1:            return(GFX_PFORTE1);
374     case EL_PFORTE2:            return(GFX_PFORTE2);
375     case EL_PFORTE3:            return(GFX_PFORTE3);
376     case EL_PFORTE4:            return(GFX_PFORTE4);
377     case EL_PFORTE1X:           return(GFX_PFORTE1X);
378     case EL_PFORTE2X:           return(GFX_PFORTE2X);
379     case EL_PFORTE3X:           return(GFX_PFORTE3X);
380     case EL_PFORTE4X:           return(GFX_PFORTE4X);
381     case EL_DYNAMIT_AUS:        return(GFX_DYNAMIT_AUS);
382     case EL_PACMAN:             return(GFX_PACMAN);
383     case EL_PACMAN_R:           return(GFX_PACMAN_R);
384     case EL_PACMAN_O:           return(GFX_PACMAN_O);
385     case EL_PACMAN_L:           return(GFX_PACMAN_L);
386     case EL_PACMAN_U:           return(GFX_PACMAN_U);
387     case EL_UNSICHTBAR:         return(GFX_UNSICHTBAR);
388     case EL_ERZ_1:              return(GFX_ERZ_1);
389     case EL_ERZ_2:              return(GFX_ERZ_2);
390     case EL_BIRNE_AUS:          return(GFX_BIRNE_AUS);
391     case EL_BIRNE_EIN:          return(GFX_BIRNE_EIN);
392     default:
393     {
394       if (IS_CHAR(element))
395         return(GFX_CHAR_START + (element-EL_CHAR_START));
396       else
397         return(-1);
398     }
399   }
400 }
401
402 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int cut_mode)
403 {
404   int width = TILEX, height = TILEY;
405   int cx = 0, cy = 0;
406
407   if (graphic<0)
408   {
409     DrawGraphic(x,y,graphic);
410     return;
411   }
412
413   if (dx || dy)                 /* Verschiebung der Grafik? */
414   {
415     if (x<0)                    /* Element kommt von links ins Bild */
416     {
417       x=0;
418       width=dx;
419       cx=TILEX-dx;
420       dx=0;
421     }
422     else if (x==SCR_FIELDX)     /* Element kommt von rechts ins Bild */
423     {
424       x=SCR_FIELDX-1;
425       width=-dx;
426       dx=TILEX+dx;
427     }
428     else if (x==0 && dx<0)      /* Element verläßt links das Bild */
429     {
430       width+=dx;
431       cx=-dx;
432       dx=0;
433     }
434     else if (x==SCR_FIELDX-1 && dx>0)   /* El. verläßt rechts das Bild */
435       width-=dx;
436     else if (dx)                /* allg. Bewegung in x-Richtung */
437       redraw[x+SIGN(dx)][y]=TRUE;
438
439     if (y<0)                    /* Element kommt von oben ins Bild */
440     {
441       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
442         return;
443
444       y=0;
445       height=dy;
446       cy=TILEY-dy;
447       dy=0;
448     }
449     else if (y==SCR_FIELDY)     /* Element kommt von unten ins Bild */
450     {
451       y=SCR_FIELDY-1;
452       height=-dy;
453       dy=TILEY+dy;
454     }
455     else if (y==0 && dy<0)      /* Element verläßt oben das Bild */
456     {
457       height+=dy;
458       cy=-dy;
459       dy=0;
460     }
461     else if (dy>0 && cut_mode==CUT_ABOVE)
462     {
463       if (y==SCR_FIELDY-1)      /* Element unterhalb des Bildes */
464         return;
465
466       height=dy;
467       cy=TILEY-dy;
468       dy=TILEY;
469       redraw[x][y+1]=TRUE;
470     }                           /* Element verläßt unten das Bild */
471     else if (dy>0 && (y==SCR_FIELDY-1 || cut_mode==CUT_BELOW))
472       height-=dy;
473     else if (dy)                /* allg. Bewegung in y-Richtung */
474       redraw[x][y+SIGN(dy)]=TRUE;
475   }
476
477   XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
478             SX+(graphic % GFX_PER_LINE)*TILEX+cx,
479             SY+(graphic / GFX_PER_LINE)*TILEY+cy,
480             width,height, SX+x*TILEX+dx,SY+y*TILEY+dy);
481
482   redraw_tiles++;
483   redraw[x][y]=TRUE;
484   redraw_mask|=REDRAW_TILES;
485 }
486
487 void DrawElementShifted(int x, int y, int dx, int dy, int element,int cut_mode)
488 {
489   int ux = UNSCROLLX(x), uy = UNSCROLLY(y);
490   int graphic = el2gfx(element);
491   int phase = ABS(MovPos[ux][uy])/(TILEX/2);
492   int dir = MovDir[ux][uy];
493   int horiz_move = (dir==MV_LEFT || dir==MV_RIGHT);
494
495   if (element==EL_PACMAN ||
496       element==EL_KAEFER ||
497       element==EL_FLIEGER)
498   {
499     if (element==EL_PACMAN)
500       graphic = GFX_PACMAN + 4*!phase;
501     else
502       graphic += 4*!phase;
503
504     if (dir==MV_UP)
505       graphic += 1;
506     else if (dir==MV_LEFT)
507       graphic += 2;
508     else if (dir==MV_DOWN)
509       graphic += 3;
510   }
511   else if ((element==EL_FELSBROCKEN ||
512             element==EL_EDELSTEIN ||
513             element==EL_DIAMANT) && horiz_move && phase)
514   {
515     if (element==EL_FELSBROCKEN)
516       graphic += 2;
517     else
518       graphic += 1;
519   }
520   else if ((element==EL_SIEB_LEER ||
521             element==EL_SIEB_VOLL) && SiebAktiv)
522   {
523     graphic += 3-(SiebAktiv%8)/2;
524   }
525   else if (IS_AMOEBOID(element))
526   {
527     graphic = (element==EL_AMOEBE1 ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
528     graphic += (x+2*y) % 4;
529   }
530
531   if (dx || dy)
532     DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode);
533   else
534     DrawGraphic(x,y, graphic);
535 }
536
537 void ErdreichAnbroeckeln(int x, int y)
538 {
539   int i, width, height, cx,cy;
540   int ux = UNSCROLLX(x), uy = UNSCROLLY(y);
541   int element, graphic;
542   int snip = 4;
543   static int xy[4][2] =
544   {
545     0,-1,
546     -1,0,
547     +1,0,
548     0,+1
549   };
550
551   if (!IN_LEV_FIELD(ux,uy))
552     return;
553
554   element = Feld[ux][uy];
555
556   if (element==EL_ERDREICH)
557   {
558     if (!IN_SCR_FIELD(x,y))
559       return;
560
561     graphic = GFX_ERDENRAND;
562
563     for(i=0;i<4;i++)
564     {
565       int uxx,uyy;
566
567       uxx = ux+xy[i][0];
568       uyy = uy+xy[i][1];
569       if (!IN_LEV_FIELD(uxx,uyy))
570         element = EL_BETON;
571       else
572         element = Feld[uxx][uyy];
573
574 /*
575       if (element==EL_ERDREICH || IS_SOLID(element))
576         continue;
577 */
578       if (element==EL_ERDREICH)
579         continue;
580
581       if (i==1 || i==2)
582       {
583         width = snip;
584         height = TILEY;
585         cx = (i==2 ? TILEX-snip : 0);
586         cy = 0;
587       }
588       else
589       {
590         width = TILEX;
591         height = snip;
592         cx = 0;
593         cy = (i==3 ? TILEY-snip : 0);
594       }
595
596       XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
597                 SX+(graphic % GFX_PER_LINE)*TILEX+cx,
598                 SY+(graphic / GFX_PER_LINE)*TILEY+cy,
599                 width,height, SX+x*TILEX+cx,SY+y*TILEY+cy);
600     }
601
602     redraw_tiles++;
603     redraw[x][y]=TRUE;
604   }
605   else
606   {
607     graphic = GFX_ERDENRAND;
608
609     for(i=0;i<4;i++)
610     {
611       int xx,yy,uxx,uyy;
612
613       xx = x+xy[i][0];
614       yy = y+xy[i][1];
615       uxx = ux+xy[i][0];
616       uyy = uy+xy[i][1];
617 /*
618       if (!IN_LEV_FIELD(uxx,uyy) || Feld[uxx][uyy]!=EL_ERDREICH ||
619           !IN_SCR_FIELD(xx,yy) || IS_SOLID(element))
620         continue;
621 */
622
623       if (!IN_LEV_FIELD(uxx,uyy) || Feld[uxx][uyy]!=EL_ERDREICH ||
624           !IN_SCR_FIELD(xx,yy))
625         continue;
626
627       if (i==1 || i==2)
628       {
629         width = snip;
630         height = TILEY;
631         cx = (i==1 ? TILEX-snip : 0);
632         cy = 0;
633       }
634       else
635       {
636         width = TILEX;
637         height = snip;
638         cx = 0;
639         cy = (i==0 ? TILEY-snip : 0);
640       }
641
642       XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
643                 SX+(graphic % GFX_PER_LINE)*TILEX+cx,
644                 SY+(graphic / GFX_PER_LINE)*TILEY+cy,
645                 width,height, SX+xx*TILEX+cx,SY+yy*TILEY+cy);
646
647       redraw_tiles++;
648       redraw[xx][yy]=TRUE;
649     }
650   }
651 }
652
653 void DrawScreenElement(int x, int y, int element)
654 {
655   DrawElementShifted(x,y,0,0,element,CUT_NO_CUTTING);
656   ErdreichAnbroeckeln(x,y);
657 }
658
659 void DrawLevelElement(int x, int y, int element)
660 {
661   if (IN_LEV_FIELD(x,y) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
662     DrawScreenElement(SCROLLX(x),SCROLLY(y),element);
663 }
664
665 void DrawScreenField(int x, int y)
666 {
667   int ux = UNSCROLLX(x), uy = UNSCROLLY(y);
668   int element;
669
670   if (!IN_LEV_FIELD(ux,uy))
671   {
672     DrawScreenElement(x,y,EL_BETON);
673     return;
674   }
675
676   element = Feld[ux][uy];
677
678   if (IS_MOVING(ux,uy))
679   {
680     int horiz_move = (MovDir[ux][uy]==MV_LEFT || MovDir[ux][uy]==MV_RIGHT);
681     BOOL cut_mode = CUT_NO_CUTTING;
682
683     if (Store[ux][uy]==EL_MORAST_LEER ||
684         Store[ux][uy]==EL_SIEB_LEER ||
685         Store[ux][uy]==EL_AMOEBE2)
686       cut_mode = CUT_ABOVE;
687     else if (Store[ux][uy]==EL_MORAST_VOLL ||
688         Store[ux][uy]==EL_SIEB_VOLL ||
689         Store[ux][uy]==EL_SALZSAEURE)
690       cut_mode = CUT_BELOW;
691
692     if (cut_mode==CUT_ABOVE)
693       DrawElementShifted(x,y,0,0,Store[ux][uy],CUT_NO_CUTTING);
694     else
695       DrawScreenElement(x,y,EL_LEERRAUM);
696
697     if (horiz_move)
698       DrawElementShifted(x,y,MovPos[ux][uy],0,element,CUT_NO_CUTTING);
699     else
700       DrawElementShifted(x,y,0,MovPos[ux][uy],element,cut_mode);
701   }
702   else if (IS_BLOCKED(ux,uy))
703   {
704     int oldx,oldy;
705     int sx, sy;
706     int horiz_move;
707     BOOL cut_mode = CUT_NO_CUTTING;
708
709     Blocked2Moving(ux,uy,&oldx,&oldy);
710     sx = SCROLLX(oldx);
711     sy = SCROLLY(oldy);
712     horiz_move = (MovDir[oldx][oldy]==MV_LEFT || MovDir[oldx][oldy]==MV_RIGHT);
713
714     if (Store[oldx][oldy]==EL_MORAST_LEER ||
715         Store[oldx][oldy]==EL_SIEB_LEER ||
716         Store[oldx][oldy]==EL_AMOEBE2)
717       cut_mode = CUT_ABOVE;
718
719     DrawScreenElement(x,y,EL_LEERRAUM);
720     element = Feld[oldx][oldy];
721
722     if (horiz_move)
723       DrawElementShifted(sx,sy,MovPos[oldx][oldy],0,element,CUT_NO_CUTTING);
724     else
725       DrawElementShifted(sx,sy,0,MovPos[oldx][oldy],element,cut_mode);
726   }
727   else if (IS_DRAWABLE(element))
728     DrawScreenElement(x,y,element);
729   else
730     DrawScreenElement(x,y,EL_LEERRAUM);
731 }
732
733 void DrawLevelField(int x, int y)
734 {
735   if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
736     DrawScreenField(SCROLLX(x),SCROLLY(y));
737   else if (IS_MOVING(x,y))
738   {
739     int newx,newy;
740
741     Moving2Blocked(x,y,&newx,&newy);
742     if (IN_SCR_FIELD(SCROLLX(newx),SCROLLY(newy)))
743       DrawScreenField(SCROLLX(newx),SCROLLY(newy));
744   }
745   else if (IS_BLOCKED(x,y))
746   {
747     int oldx,oldy;
748
749     Blocked2Moving(x,y,&oldx,&oldy);
750     if (IN_SCR_FIELD(SCROLLX(oldx),SCROLLY(oldy)))
751       DrawScreenField(SCROLLX(oldx),SCROLLY(oldy));
752   }
753 }
754
755 void DrawMiniElement(int x, int y, int element)
756 {
757   int graphic;
758
759   if (!element)
760   {
761     DrawMiniGraphic(x,y,-1);
762     return;
763   }
764
765   graphic = el2gfx(element);
766   DrawMiniGraphic(x,y,graphic);
767
768   redraw_tiles++;
769   redraw[x/2][y/2]=TRUE;
770   redraw_mask|=REDRAW_TILES;
771 }
772
773 void DrawMiniElementOrWall(int x, int y, int scroll_x, int scroll_y)
774 {
775   if (x+scroll_x<-1 || x+scroll_x>lev_fieldx ||
776       y+scroll_y<-1 || y+scroll_y>lev_fieldy)
777     DrawMiniElement(x,y,EL_LEERRAUM);
778   else if (x+scroll_x==-1 || x+scroll_x==lev_fieldx ||
779            y+scroll_y==-1 || y+scroll_y==lev_fieldy)
780     DrawMiniElement(x,y,EL_BETON);
781   else
782     DrawMiniElement(x,y,Feld[x+scroll_x][y+scroll_y]);
783 }
784
785 void DrawMicroElement(int xpos, int ypos, int element)
786 {
787   int graphic;
788
789   if (element==EL_LEERRAUM)
790     return;
791
792   graphic = el2gfx(element);
793
794   XCopyArea(display,pix[PIX_BACK],drawto,gc,
795             MICRO_GFX_STARTX+(graphic % MICRO_GFX_PER_LINE)*MICRO_TILEX,
796             MICRO_GFX_STARTY+(graphic / MICRO_GFX_PER_LINE)*MICRO_TILEY,
797             MICRO_TILEX,MICRO_TILEY, xpos,ypos);
798 }
799
800 void DrawLevel()
801 {
802   int x,y;
803
804   ClearWindow();
805
806   for(x=0;x<SCR_FIELDX;x++)
807     for(y=0;y<SCR_FIELDY;y++)
808       DrawScreenField(x,y);
809
810   redraw_mask |= REDRAW_FIELD;
811 }
812
813 void DrawMiniLevel(int scroll_x, int scroll_y)
814 {
815   int x,y;
816
817   ClearWindow();
818
819   for(x=0;x<2*SCR_FIELDX;x++)
820     for(y=0;y<2*SCR_FIELDY;y++)
821       DrawMiniElementOrWall(x,y,scroll_x,scroll_y);
822
823   redraw_mask |= REDRAW_FIELD;
824 }
825
826 void DrawMicroLevel(int xpos, int ypos)
827 {
828   int x,y;
829
830   XFillRectangle(display,drawto,gc,
831                  xpos-MICRO_TILEX,ypos-MICRO_TILEY,
832                  MICRO_TILEX*(STD_LEV_FIELDX+2),
833                  MICRO_TILEY*(STD_LEV_FIELDY+2));
834
835   for(x=-1;x<=STD_LEV_FIELDX;x++)
836     for(y=-1;y<=STD_LEV_FIELDY;y++)
837       if (x>=0 && x<lev_fieldx && y>=0 && y<lev_fieldy)
838         DrawMicroElement(xpos+MICRO_TILEX*x,ypos+MICRO_TILEY*y,
839                          Feld[x][y]=Ur[x][y]);
840       else if (x>=-1 && x<lev_fieldx+1 && y>=-1 && y<lev_fieldy+1)
841         DrawMicroElement(xpos+MICRO_TILEX*x,ypos+MICRO_TILEY*y,
842                          EL_BETON);
843
844   XFillRectangle(display,drawto,gc, SX,MICROLABEL_YPOS, SXSIZE,FONT4_YSIZE);
845
846   if (level.name)
847   {
848     int len = strlen(level.name);
849     int lxpos = SX+(SXSIZE-len*FONT4_XSIZE)/2;
850     int lypos = MICROLABEL_YPOS;
851
852     DrawText(lxpos,lypos,level.name,FS_SMALL,FC_SPECIAL2);
853   }
854
855   redraw_mask |= REDRAW_MICROLEV;
856 }
857
858 int AYS_in_range(int x, int y)
859 {
860   if (y>DY+249 && y<DY+278)
861   {
862     if (x>DX+1 && x<DX+48)
863       return(1);
864     else if (x>DX+51 && x<DX+98) 
865       return(2);
866   }
867   return(0);
868 }
869
870 BOOL AreYouSure(char *text, unsigned int ays_state)
871 {
872   int mx,my, ty, result = -1;
873
874   CloseDoor(DOOR_CLOSE_1);
875
876   /* Alten Türinhalt sichern */
877   XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
878             DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
879             DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1);
880
881   /* Fragetext schreiben */
882   XFillRectangle(display,pix[PIX_DB_DOOR],gc,
883                  DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1,DXSIZE,DYSIZE);
884
885   for(ty=0;ty<13;ty++)
886   {
887     int tx,tl,tc;
888     char txt[256];
889
890     if (!(*text))
891       break;
892     for(tl=0,tx=0;tx<7;tl++,tx++)
893     {
894       tc=*(text+tx);
895       if (!tc || tc==32)
896         break;
897     }
898     if (!tl)
899     { 
900       text++; 
901       ty--; 
902       continue; 
903     }
904     sprintf(txt,text); 
905     txt[tl]=0;
906     DrawTextExt(pix[PIX_DB_DOOR],gc,
907                 DOOR_GFX_PAGEX1+51-(tl*14)/2,SY+ty*16,txt,FS_SMALL,FC_YELLOW);
908     text+=(tl+(tc==32));
909   }
910
911   if (ays_state & AYS_ASK)
912     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
913               DOOR_GFX_PAGEX4,OK_BUTTON_GFX_YPOS,
914               DXSIZE,OK_BUTTON_YSIZE,
915               DOOR_GFX_PAGEX1,OK_BUTTON_YPOS);
916   else if (ays_state & AYS_CONFIRM)
917     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
918               DOOR_GFX_PAGEX4,CONFIRM_BUTTON_GFX_YPOS,
919               DXSIZE,CONFIRM_BUTTON_YSIZE,
920               DOOR_GFX_PAGEX1,CONFIRM_BUTTON_YPOS);
921
922   OpenDoor(DOOR_OPEN_1);
923
924   if (!(ays_state & AYS_ASK) && !(ays_state & AYS_CONFIRM))
925     return(FALSE);
926
927   if (game_status!=MAINMENU)
928     InitAnimation();
929
930   button_status = MB_RELEASED;
931
932   while(result<0)
933   {
934     DoAnimation();
935     Delay(10000);
936
937     if (XPending(display))
938     {
939       XEvent event;
940
941       XNextEvent(display, &event);
942       switch(event.type)
943       {
944         case Expose:
945           HandleExposeEvent((XExposeEvent *) &event);
946           break;
947         case UnmapNotify:
948           SleepWhileUnmapped();
949           break;
950         case ButtonPress:
951         case ButtonRelease:
952         case MotionNotify:
953         {
954           int choice;
955
956           if (event.type==MotionNotify)
957           {
958             motion_status = TRUE;
959             mx = ((XMotionEvent *) &event)->x;
960             my = ((XMotionEvent *) &event)->y;
961           }
962           else
963           {
964             motion_status = FALSE;
965             mx = ((XButtonEvent *) &event)->x;
966             my = ((XButtonEvent *) &event)->y;
967             if (event.type==ButtonPress)
968               button_status = ((XButtonEvent *) &event)->button;
969             else
970               button_status = MB_RELEASED;
971           }
972
973           if (ays_state & AYS_ASK)
974             choice = CheckChooseButtons(mx,my,button_status);
975           else
976             choice = CheckConfirmButton(mx,my,button_status);
977
978           switch(choice)
979           {
980             case BUTTON_OK:
981               result = TRUE;
982               break;
983             case BUTTON_NO:
984               result = FALSE;
985               break;
986             case BUTTON_CONFIRM:
987               result = TRUE|FALSE;
988               break;
989             default:
990               break;
991           }
992           break;
993         }
994         case KeyPress:
995           key_status = KEY_PRESSED;
996           switch(XLookupKeysym((XKeyEvent *)&event,
997                                ((XKeyEvent *)&event)->state))
998           {
999             case XK_Return:
1000               result = 1;
1001               break;
1002             case XK_Escape:
1003               result = 0;
1004               break;
1005           }
1006           break;
1007         case FocusIn:
1008           HandleFocusEvent(FOCUS_IN);
1009           break;
1010         case FocusOut:
1011           HandleFocusEvent(FOCUS_OUT);
1012           break;
1013         default:
1014           break;
1015       }
1016     }
1017     else if (JoystickButton()==JOY_BUTTON_NEW_PRESSED)
1018     {
1019       int joy=Joystick();
1020
1021       if (joy & JOY_BUTTON_1)
1022         result = 1;
1023       else if (joy & JOY_BUTTON_2)
1024         result = 0;
1025     }
1026   }
1027
1028   if (game_status!=MAINMENU)
1029     StopAnimation();
1030
1031   if (!(ays_state & AYS_STAY_OPEN))
1032   {
1033     CloseDoor(DOOR_CLOSE_1);
1034
1035     if (!(ays_state & AYS_STAY_CLOSED) &&
1036         (game_status==PLAYING || game_status==LEVELED))
1037     {
1038       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1039                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1040                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1041       OpenDoor(DOOR_OPEN_1);
1042     }
1043   }
1044
1045   return(result);
1046 }
1047
1048 void OpenDoor(unsigned int door_state)
1049 {
1050   if (door_state & DOOR_COPY_BACK)
1051   {
1052     XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1053               DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE+VYSIZE,
1054               DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1055     door_state &= ~DOOR_COPY_BACK;
1056   }
1057
1058   MoveDoor(door_state);
1059   ClearEventQueue();
1060 }
1061
1062 void CloseDoor(unsigned int door_state)
1063 {
1064   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
1065             DX,DY, DXSIZE,DYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1066   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
1067             VX,VY, VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1068
1069   MoveDoor(door_state);
1070   ClearEventQueue();
1071 }
1072
1073 void MoveDoor(unsigned int door_state)
1074 {
1075   static int door1 = DOOR_CLOSE_1;
1076   static int door2 = DOOR_OPEN_2;
1077   int x, start, stepsize = 4;
1078
1079   if (door1==DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1080     door_state &= ~DOOR_OPEN_1;
1081   else if (door1==DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1082     door_state &= ~DOOR_CLOSE_1;
1083   if (door2==DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1084     door_state &= ~DOOR_OPEN_2;
1085   else if (door2==DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1086     door_state &= ~DOOR_CLOSE_2;
1087
1088   if (door_state & DOOR_ACTION)
1089   {
1090     if (door_state & DOOR_OPEN_1)
1091     {
1092       XCopyArea(display,pix[PIX_DOOR],pix[PIX_DOOR],gc,
1093                 104,136, 8,8, 146,136);
1094       if (!(door_state & DOOR_NO_DELAY))
1095       {
1096         int i;
1097
1098         XCopyArea(display,pix[PIX_DOOR],window,gc,
1099                   104,136, 8,8, DX+46,DY+136);
1100         XFlush(display);
1101         for(i=0;i<30;i++)
1102         {
1103           if (game_status==MAINMENU)
1104             DoAnimation();
1105           Delay(10000);
1106         }
1107       }
1108     }
1109     else if (door_state & DOOR_CLOSE_1)
1110       XCopyArea(display,pix[PIX_DOOR],pix[PIX_DOOR],gc,
1111                 88,136, 8,8, 146,136);
1112
1113     if (!(door_state & DOOR_NO_DELAY))
1114       PlaySoundStereo(SND_OEFFNEN,PSND_MAX_RIGHT);
1115
1116     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1117
1118     for(x=start;x<=DXSIZE;x+=stepsize)
1119     {
1120       if (door_state & DOOR_ACTION_1)
1121       {
1122         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1123
1124         XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
1125                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1+i/2,
1126                   DXSIZE,DYSIZE-i/2, DX,DY);
1127
1128         XFillRectangle(display,drawto,gc,DX,DY+DYSIZE-i/2,DXSIZE,i/2);
1129
1130         XSetClipOrigin(display,clip_gc[PIX_DOOR],DX-DXSIZE+i,DY);
1131         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1132                   DXSIZE-i,0, i,30, DX,DY);
1133         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1134                   DXSIZE-i,DYSIZE-30, i,30, DX,DY+DYSIZE-30);
1135         XSetClipOrigin(display,clip_gc[PIX_DOOR],DX-i,DY);
1136         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1137                   DXSIZE,0, i,30, DX+DXSIZE-i,DY);
1138         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1139                   DXSIZE,DYSIZE-30, i,30, DX+DXSIZE-i,DY+DYSIZE-30);
1140         if (i>14)
1141         {
1142           XSetClipOrigin(display,clip_gc[PIX_DOOR],DX-i,DY);
1143           XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1144                     DXSIZE+14,30,i-14,DYSIZE-60,DX+DXSIZE+14-i,DY+30);
1145           XSetClipOrigin(display,clip_gc[PIX_DOOR],DX-DXSIZE+i,DY);
1146           XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1147                     DXSIZE-i,30,i-14,DYSIZE-60,DX,DY+30);
1148         }
1149         redraw_mask |= REDRAW_DOOR_1;
1150       }
1151
1152       if (door_state & DOOR_ACTION_2)
1153       {
1154         int i = (door_state & DOOR_OPEN_2 ? VXSIZE-x : x);
1155
1156         XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
1157                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2+i/2,
1158                   VXSIZE,VYSIZE-i/2, VX,VY);
1159
1160         XFillRectangle(display,drawto,gc,VX,VY+VYSIZE-i/2,VXSIZE,i/2);
1161
1162         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1163                        VX-VXSIZE+i,VY-DOOR_GFX_PAGEY2);
1164         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1165                   VXSIZE-i,DOOR_GFX_PAGEY2, i,VYSIZE, VX,VY);
1166         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1167                        VX-i,VY-DOOR_GFX_PAGEY2);
1168         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1169                   VXSIZE,DOOR_GFX_PAGEY2, i,VYSIZE, VX+VXSIZE-i,VY);
1170
1171         redraw_mask |= REDRAW_DOOR_2;
1172       }
1173
1174       BackToFront();
1175       Delay(stepsize*5000);
1176
1177       if (game_status==MAINMENU)
1178         DoAnimation();
1179     }
1180   }
1181
1182   if (door_state & DOOR_ACTION_1)
1183     door1 = door_state & DOOR_ACTION_1;
1184   if (door_state & DOOR_ACTION_2)
1185     door2 = door_state & DOOR_ACTION_2;
1186 }
1187
1188 long mainCounter(int mode)
1189 {
1190   static struct timeval base_time = { 0, 0 };
1191   struct timeval current_time;
1192   long counter_ms;
1193
1194   gettimeofday(&current_time,NULL);
1195   if (mode==0 || current_time.tv_sec<base_time.tv_sec)
1196     base_time = current_time;
1197
1198   counter_ms = (current_time.tv_sec - base_time.tv_sec)*1000
1199              + (current_time.tv_usec - base_time.tv_usec)/1000;
1200
1201   if (mode==1)
1202     return(counter_ms/10);      /* return 1/100 secs since last init */
1203   else
1204     return(counter_ms);         /* return 1/1000 secs since last init */
1205 }
1206
1207 void InitCounter() /* set counter back to zero */
1208 {
1209   mainCounter(0);
1210 }
1211
1212 long Counter()  /* returns 1/100 secs since last call of InitCounter() */
1213 {
1214   return(mainCounter(1));
1215 }
1216
1217 long Counter2() /* returns 1/1000 secs since last call of InitCounter() */
1218 {
1219   return(mainCounter(2));
1220 }
1221
1222 void WaitCounter(long value)    /* wait for counter to reach value */
1223 {
1224   long wait;
1225
1226   while((wait=value-Counter())>0)
1227     microsleep(wait*10000);
1228 }
1229
1230 void WaitCounter2(long value)   /* wait for counter to reach value */
1231 {
1232   long wait;
1233
1234   while((wait=value-Counter2())>0)
1235     microsleep(wait*1000);
1236 }
1237
1238 void Delay(long value)
1239 {
1240   microsleep(value);
1241 }
1242
1243 BOOL DelayReached(long *counter_var, int delay)
1244 {
1245   long actual_counter = Counter();
1246
1247   if (actual_counter>*counter_var+delay || actual_counter<*counter_var)
1248   {
1249     *counter_var = actual_counter;
1250     return(TRUE);
1251   }
1252   else
1253     return(FALSE);
1254 }
1255
1256 int ReadPixel(Drawable d, int x, int y)
1257 {
1258   static XImage *pixelimage;
1259
1260   pixelimage = XGetImage(display, d, x,y, 1,1, AllPlanes, ZPixmap);
1261   return(XGetPixel(pixelimage,0,0));
1262 }
1263
1264 static struct JoystickInfo joystick[2] =
1265 {
1266   JOYSTICK_XLEFT, JOYSTICK_XRIGHT, JOYSTICK_XMIDDLE,
1267   JOYSTICK_YUPPER, JOYSTICK_YLOWER, JOYSTICK_YMIDDLE,
1268
1269   JOYSTICK_XLEFT, JOYSTICK_XRIGHT, JOYSTICK_XMIDDLE,
1270   JOYSTICK_YUPPER, JOYSTICK_YLOWER, JOYSTICK_YMIDDLE
1271 };
1272
1273 void LoadJoystickData()
1274 {
1275   int i;
1276   char cookie[256];
1277   FILE *file;
1278
1279   if (joystick_status==JOYSTICK_OFF)
1280     return;
1281
1282   if (!(file=fopen(JOYDAT_FILE,"r")))
1283     return;
1284
1285   fscanf(file,"%s",cookie);
1286   if (strcmp(cookie,JOYSTICK_COOKIE))   /* ungültiges Format? */
1287   {
1288     fprintf(stderr,"%s: wrong format of joystick file!\n",progname);
1289     fclose(file);
1290     return;
1291   }
1292
1293   for(i=0;i<2;i++)
1294   {
1295     fscanf(file,"%s",cookie);
1296     fscanf(file, "%d %d %d \n",
1297            &joystick[i].xleft, &joystick[i].xmiddle, &joystick[i].xright);
1298     fscanf(file, "%d %d %d \n",
1299            &joystick[i].yupper, &joystick[i].ymiddle, &joystick[i].ylower);
1300   }
1301   fclose(file);
1302
1303   CheckJoystickData();
1304 }
1305
1306 void SaveJoystickData()
1307 {
1308   int i;
1309   FILE *file;
1310
1311   if (joystick_status==JOYSTICK_OFF)
1312     return;
1313
1314   CheckJoystickData();
1315
1316   if (!(file=fopen(JOYDAT_FILE,"w")))
1317   {
1318     fprintf(stderr,"%s: cannot save joystick calibration data!\n",progname);
1319     return;
1320   }
1321
1322   fprintf(file,"%s\n",JOYSTICK_COOKIE); /* Formatkennung */
1323   for(i=0;i<2;i++)
1324   {
1325     fprintf(file,"JOYSTICK_%d_DATA\n",i);
1326     fprintf(file, "%d %d %d \n",
1327             joystick[i].xleft, joystick[i].xmiddle, joystick[i].xright);
1328     fprintf(file, "%d %d %d \n",
1329             joystick[i].yupper, joystick[i].ymiddle, joystick[i].ylower);
1330   }
1331   fclose(file);
1332
1333   chmod(JOYDAT_FILE, JOYDAT_PERMS);
1334 }
1335
1336 void CheckJoystickData()
1337 {
1338   int i;
1339   int distance = 100;
1340
1341   for(i=0;i<2;i++)
1342   {
1343     if (joystick[i].xmiddle <= distance)
1344       joystick[i].xmiddle = distance;
1345     if (joystick[i].ymiddle <= distance)
1346       joystick[i].ymiddle = distance;
1347
1348     if (joystick[i].xleft >= joystick[i].xmiddle)
1349       joystick[i].xleft = joystick[i].xmiddle-distance;
1350     if (joystick[i].xright <= joystick[i].xmiddle)
1351       joystick[i].xright = joystick[i].xmiddle+distance;
1352
1353     if (joystick[i].yupper >= joystick[i].ymiddle)
1354       joystick[i].yupper = joystick[i].ymiddle-distance;
1355     if (joystick[i].ylower <= joystick[i].ymiddle)
1356       joystick[i].ylower = joystick[i].ymiddle+distance;
1357   }
1358 }
1359
1360 int JoystickPosition(int middle, int margin, int actual)
1361 {
1362   long range, pos;
1363   int percentage;
1364
1365   if (margin<middle && actual>middle)
1366     return(0);
1367   if (margin>middle && actual<middle)
1368     return(0);
1369
1370   range=ABS(margin-middle);
1371   pos=ABS(actual-middle);
1372   percentage=(int)(pos*100/range);
1373   if (percentage>100)
1374     percentage=100;
1375
1376   return(percentage);
1377 }
1378
1379 int Joystick()
1380 {
1381   struct joystick_control
1382   {
1383     int buttons;
1384     int x;
1385     int y;
1386   } joy_ctrl;
1387
1388   int js_x,js_y, js_b1,js_b2;
1389   int left, right, up, down;
1390   int result=0;
1391
1392   if (joystick_status==JOYSTICK_OFF)
1393     return(0);
1394
1395   if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
1396   {
1397     fprintf(stderr,"%s: cannot read joystick settings - no joystick support\n",progname);
1398     joystick_status = JOYSTICK_OFF;
1399     return(0);
1400   }
1401
1402   js_x  = joy_ctrl.x;
1403   js_y  = joy_ctrl.y;
1404   js_b1 = joy_ctrl.buttons & 1;
1405   js_b2 = joy_ctrl.buttons & 2;
1406
1407   left = JoystickPosition(joystick[joystick_nr].xmiddle,
1408                           joystick[joystick_nr].xleft,  js_x);
1409   right = JoystickPosition(joystick[joystick_nr].xmiddle,
1410                            joystick[joystick_nr].xright, js_x);
1411   up =    JoystickPosition(joystick[joystick_nr].ymiddle,
1412                            joystick[joystick_nr].yupper, js_y);
1413   down =  JoystickPosition(joystick[joystick_nr].ymiddle,
1414                            joystick[joystick_nr].ylower, js_y);
1415
1416   if (left>JOYSTICK_PERCENT)
1417     result |= JOY_LEFT;
1418   else if (right>JOYSTICK_PERCENT)
1419     result |= JOY_RIGHT;
1420   if (up>JOYSTICK_PERCENT)
1421     result |= JOY_UP;
1422   else if (down>JOYSTICK_PERCENT)
1423     result |= JOY_DOWN;
1424   if (js_b1)
1425     result |= JOY_BUTTON_1;
1426   if (js_b2)
1427     result |= JOY_BUTTON_2;
1428
1429   return(result);
1430 }
1431
1432 int JoystickButton()
1433 {
1434   static int last_joy_button=0;
1435   int joy_button=(Joystick() & JOY_BUTTON);
1436   int result;
1437
1438   if (joy_button)
1439   {
1440     if (last_joy_button)
1441       result=JOY_BUTTON_PRESSED;
1442     else
1443       result=JOY_BUTTON_NEW_PRESSED;
1444   }
1445   else
1446   {
1447     if (last_joy_button)
1448       result=JOY_BUTTON_NEW_RELEASED;
1449     else
1450       result=JOY_BUTTON_NOT_PRESSED;
1451   }
1452
1453   last_joy_button = joy_button;
1454   return(result);
1455 }
1456
1457 void CalibrateJoystick()
1458 {
1459   struct joystick_control
1460   {
1461     int buttons;
1462     int x;
1463     int y;
1464   } joy_ctrl;
1465
1466   int new_joystick_xleft, new_joystick_xright, new_joystick_xmiddle;
1467   int new_joystick_yupper, new_joystick_ylower, new_joystick_ymiddle;
1468
1469   if (joystick_status==JOYSTICK_OFF)
1470     goto error_out;
1471
1472   ClearWindow();
1473   DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW);
1474   DrawText(SX+16, SY+8*32, " THE UPPER LEFT ",FS_BIG,FC_YELLOW);
1475   DrawText(SX+16, SY+9*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW);
1476   BackToFront();
1477
1478   joy_ctrl.buttons = 0;
1479   while(Joystick() & JOY_BUTTON);
1480   while(!joy_ctrl.buttons)
1481   {
1482     if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
1483     {
1484       joystick_status=JOYSTICK_OFF;
1485       goto error_out;
1486     }
1487     Delay(10000);
1488   }
1489
1490   new_joystick_xleft = joy_ctrl.x;
1491   new_joystick_yupper = joy_ctrl.y;
1492
1493   ClearWindow();
1494   DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW);
1495   DrawText(SX+32, SY+8*32, "THE LOWER RIGHT",FS_BIG,FC_YELLOW);
1496   DrawText(SX+16, SY+9*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW);
1497   BackToFront();
1498
1499   joy_ctrl.buttons = 0;
1500   while(Joystick() & JOY_BUTTON);
1501   while(!joy_ctrl.buttons)
1502   {
1503     if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
1504     {
1505       joystick_status=JOYSTICK_OFF;
1506       goto error_out;
1507     }
1508     Delay(10000);
1509   }
1510
1511   new_joystick_xright = joy_ctrl.x;
1512   new_joystick_ylower = joy_ctrl.y;
1513
1514   ClearWindow();
1515   DrawText(SX+32, SY+16+7*32, "CENTER JOYSTICK",FS_BIG,FC_YELLOW);
1516   DrawText(SX+16, SY+16+8*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW);
1517   BackToFront();
1518
1519   joy_ctrl.buttons = 0;
1520   while(Joystick() & JOY_BUTTON);
1521   while(!joy_ctrl.buttons)
1522   {
1523     if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
1524     {
1525       joystick_status=JOYSTICK_OFF;
1526       goto error_out;
1527     }
1528     Delay(10000);
1529   }
1530
1531   new_joystick_xmiddle = joy_ctrl.x;
1532   new_joystick_ymiddle = joy_ctrl.y;
1533
1534   joystick[joystick_nr].xleft = new_joystick_xleft;
1535   joystick[joystick_nr].yupper = new_joystick_yupper;
1536   joystick[joystick_nr].xright = new_joystick_xright;
1537   joystick[joystick_nr].ylower = new_joystick_ylower;
1538   joystick[joystick_nr].xmiddle = new_joystick_xmiddle;
1539   joystick[joystick_nr].ymiddle = new_joystick_ymiddle;
1540
1541   CheckJoystickData();
1542
1543   DrawSetupScreen();
1544   while(Joystick() & JOY_BUTTON);
1545   return;
1546
1547   error_out:
1548
1549   ClearWindow();
1550   DrawText(SX+16, SY+16, "NO JOYSTICK",FS_BIG,FC_YELLOW);
1551   DrawText(SX+16, SY+48, " AVAILABLE ",FS_BIG,FC_YELLOW);
1552   Delay(3000000);
1553   DrawSetupScreen();
1554 }