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