rnd-19990130-2
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  tools.c                                                 *
12 ***********************************************************/
13
14 #include <stdarg.h>
15
16 #ifdef __FreeBSD__
17 #include <machine/joystick.h>
18 #endif
19
20 #include "tools.h"
21 #include "game.h"
22 #include "events.h"
23 #include "sound.h"
24 #include "misc.h"
25 #include "buttons.h"
26 #include "joystick.h"
27 #include "cartoons.h"
28 #include "network.h"
29
30 #ifdef MSDOS
31 extern boolean wait_for_vsync;
32 #endif
33
34 /* tool button identifiers */
35 #define TOOL_CTRL_ID_YES        0
36 #define TOOL_CTRL_ID_NO         1
37 #define TOOL_CTRL_ID_CONFIRM    2
38 #define TOOL_CTRL_ID_PLAYER_1   3
39 #define TOOL_CTRL_ID_PLAYER_2   4
40 #define TOOL_CTRL_ID_PLAYER_3   5
41 #define TOOL_CTRL_ID_PLAYER_4   6
42
43 #define NUM_TOOL_BUTTONS        7
44
45 /* forward declaration for internal use */
46 static void UnmapToolButtons();
47 static void HandleToolButtons(struct GadgetInfo *);
48
49 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
50 static int request_gadget_id = -1;
51
52 void SetDrawtoField(int mode)
53 {
54   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
55   {
56     FX = TILEX;
57     FY = TILEY;
58     BX1 = -1;
59     BY1 = -1;
60     BX2 = SCR_FIELDX;
61     BY2 = SCR_FIELDY;
62     redraw_x1 = 1;
63     redraw_y1 = 1;
64
65     drawto_field = fieldbuffer;
66   }
67   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
68   {
69     FX = SX;
70     FY = SY;
71     BX1 = 0;
72     BY1 = 0;
73     BX2 = SCR_FIELDX - 1;
74     BY2 = SCR_FIELDY - 1;
75     redraw_x1 = 0;
76     redraw_y1 = 0;
77
78     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
79   }
80 }
81
82 void BackToFront()
83 {
84   int x,y;
85   Drawable buffer = (drawto_field == window ? backbuffer : drawto_field);
86
87   if (setup.direct_draw && game_status == PLAYING)
88     redraw_mask &= ~REDRAW_MAIN;
89
90   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
91     redraw_mask |= REDRAW_FIELD;
92
93   if (redraw_mask & REDRAW_FIELD)
94     redraw_mask &= ~REDRAW_TILES;
95
96   /*
97   if (redraw_mask & REDRAW_FIELD ||
98       (ScreenGfxPos && setup.soft_scrolling && game_status == PLAYING))
99     redraw_mask &= ~REDRAW_TILES;
100   */
101
102   if (!redraw_mask)
103     return;
104
105   /* synchronize X11 graphics at this point; if we would synchronize the
106      display immediately after the buffer switching (after the XFlush),
107      this could mean that we have to wait for the graphics to complete,
108      although we could go on doing calculations for the next frame */
109
110   XSync(display, FALSE);
111
112   /*
113 #ifdef MSDOS
114   wait_for_vsync = TRUE;
115 #endif
116   */
117
118   if (redraw_mask & REDRAW_ALL)
119   {
120     XCopyArea(display, backbuffer, window, gc,
121               0, 0, WIN_XSIZE, WIN_YSIZE,
122               0, 0);
123     redraw_mask = 0;
124   }
125
126   if (redraw_mask & REDRAW_FIELD)
127   {
128     if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
129     {
130       XCopyArea(display, backbuffer, window, gc,
131                 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
132                 REAL_SX, REAL_SY);
133     }
134     else
135     {
136       int fx = FX, fy = FY;
137
138       if (setup.soft_scrolling)
139       {
140         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
141         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
142       }
143
144       if (setup.soft_scrolling ||
145           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
146           ABS(ScreenMovPos) == ScrollStepSize ||
147           redraw_tiles > REDRAWTILES_THRESHOLD)
148       {
149         XCopyArea(display, buffer, window, gc, fx, fy, SXSIZE, SYSIZE, SX, SY);
150
151 #ifdef DEBUG
152 #if 0
153         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
154                ScreenGfxPos,
155                (setup.soft_scrolling ?
156                 "setup.soft_scrolling" :
157                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
158                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
159                 ABS(ScreenGfxPos) == ScrollStepSize ?
160                 "ABS(ScreenGfxPos) == ScrollStepSize" :
161                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
162 #endif
163 #endif
164       }
165     }
166     redraw_mask &= ~REDRAW_MAIN;
167   }
168
169   if (redraw_mask & REDRAW_DOORS)
170   {
171     if (redraw_mask & REDRAW_DOOR_1)
172       XCopyArea(display, backbuffer, window, gc,
173                 DX, DY, DXSIZE, DYSIZE,
174                 DX, DY);
175     if (redraw_mask & REDRAW_DOOR_2)
176     {
177       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
178         XCopyArea(display,backbuffer,window,gc,
179                   VX,VY, VXSIZE,VYSIZE,
180                   VX,VY);
181       else
182       {
183         if (redraw_mask & REDRAW_VIDEO_1)
184           XCopyArea(display,backbuffer,window,gc,
185                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
186                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
187                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
188         if (redraw_mask & REDRAW_VIDEO_2)
189           XCopyArea(display,backbuffer,window,gc,
190                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
191                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
192                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
193         if (redraw_mask & REDRAW_VIDEO_3)
194           XCopyArea(display,backbuffer,window,gc,
195                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
196                     VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
197                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
198       }
199     }
200     if (redraw_mask & REDRAW_DOOR_3)
201       XCopyArea(display, backbuffer, window, gc,
202                 EX, EY, EXSIZE, EYSIZE,
203                 EX, EY);
204     redraw_mask &= ~REDRAW_DOORS;
205   }
206
207   if (redraw_mask & REDRAW_MICROLEVEL)
208   {
209     XCopyArea(display,backbuffer,window,gc,
210               MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
211               MICROLEV_XPOS, MICROLEV_YPOS);
212     XCopyArea(display,backbuffer,window,gc,
213               SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
214               SX, MICROLABEL_YPOS);
215     redraw_mask &= ~REDRAW_MICROLEVEL;
216   }
217
218   if (redraw_mask & REDRAW_TILES)
219   {
220     for(x=0; x<SCR_FIELDX; x++)
221       for(y=0; y<SCR_FIELDY; y++)
222         if (redraw[redraw_x1 + x][redraw_y1 + y])
223           XCopyArea(display, buffer, window, gc,
224                     FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
225                     SX + x * TILEX, SY + y * TILEY);
226   }
227
228   XFlush(display);
229
230   for(x=0; x<MAX_BUF_XSIZE; x++)
231     for(y=0; y<MAX_BUF_YSIZE; y++)
232       redraw[x][y] = 0;
233   redraw_tiles = 0;
234   redraw_mask = 0;
235 }
236
237 void FadeToFront()
238 {
239 /*
240   long fading_delay = 300;
241
242   if (setup.fading && (redraw_mask & REDRAW_FIELD))
243   {
244 */
245
246 /*
247     int x,y;
248
249     XFillRectangle(display,window,gc,
250                    REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
251     XFlush(display);
252
253     for(i=0;i<2*FULL_SYSIZE;i++)
254     {
255       for(y=0;y<FULL_SYSIZE;y++)
256       {
257         XCopyArea(display,backbuffer,window,gc,
258                   REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
259       }
260       XFlush(display);
261       Delay(10);
262     }
263 */
264
265 /*
266     for(i=1;i<FULL_SYSIZE;i+=2)
267       XCopyArea(display,backbuffer,window,gc,
268                 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
269     XFlush(display);
270     Delay(fading_delay);
271 */
272
273 /*
274     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
275     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
276               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
277     XFlush(display);
278     Delay(fading_delay);
279
280     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
281     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
282               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
283     XFlush(display);
284     Delay(fading_delay);
285
286     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
287     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
288               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
289     XFlush(display);
290     Delay(fading_delay);
291
292     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,0);
293     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
294               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
295     XFlush(display);
296     Delay(fading_delay);
297
298     redraw_mask &= ~REDRAW_MAIN;
299   }
300 */
301
302   BackToFront();
303 }
304
305 void ClearWindow()
306 {
307   XFillRectangle(display, backbuffer, gc,
308                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
309
310   if (setup.soft_scrolling && game_status == PLAYING)
311   {
312     XFillRectangle(display, fieldbuffer, gc, 0, 0, FXSIZE, FYSIZE);
313     SetDrawtoField(DRAW_BUFFERED);
314   }
315   else
316     SetDrawtoField(DRAW_BACKBUFFER);
317
318   if (setup.direct_draw && game_status == PLAYING)
319   {
320     XFillRectangle(display, window, gc,
321                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
322     SetDrawtoField(DRAW_DIRECT);
323   }
324
325   redraw_mask |= REDRAW_FIELD;
326 }
327
328 void DrawTextFCentered(int y, int font_type, char *format, ...)
329 {
330   char buffer[FULL_SXSIZE / FONT3_XSIZE + 10];
331   int font_xsize;
332   va_list ap;
333
334   font_xsize = (font_type < FC_SPECIAL1 ? FONT2_XSIZE :
335                 font_type < FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
336
337   va_start(ap, format);
338   vsprintf(buffer, format, ap);
339   va_end(ap);
340
341   DrawText(SX + (SXSIZE - strlen(buffer) * font_xsize) / 2, SY + y,
342            buffer, FS_SMALL, font_type);
343 }
344
345 void DrawTextF(int x, int y, int font_type, char *format, ...)
346 {
347   char buffer[FULL_SXSIZE / FONT3_XSIZE + 10];
348   va_list ap;
349
350   va_start(ap, format);
351   vsprintf(buffer, format, ap);
352   va_end(ap);
353
354   DrawText(SX + x, SY + y, buffer, FS_SMALL, font_type);
355 }
356
357 void DrawText(int x, int y, char *text, int font_size, int font_type)
358 {
359   DrawTextExt(drawto, gc, x, y, text, font_size, font_type);
360
361   if (x < DX)
362     redraw_mask |= REDRAW_FIELD;
363   else if (y < VY)
364     redraw_mask |= REDRAW_DOOR_1;
365 }
366
367 void DrawTextExt(Drawable d, GC gc, int x, int y,
368                  char *text, int font_size, int font_type)
369 {
370   int font_width, font_height, font_start;
371   int font_pixmap;
372   boolean print_inverse = FALSE;
373
374   if (font_size != FS_SMALL && font_size != FS_BIG)
375     font_size = FS_SMALL;
376   if (font_type < FC_RED || font_type > FC_SPECIAL2)
377     font_type = FC_RED;
378
379   font_width = (font_size == FS_BIG ? FONT1_XSIZE :
380                 font_type < FC_SPECIAL1 ? FONT2_XSIZE :
381                 font_type < FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
382   font_height = (font_size == FS_BIG ? FONT1_XSIZE :
383                  font_type < FC_SPECIAL2 ? FONT2_XSIZE : FONT4_XSIZE);
384   font_pixmap = (font_size == FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
385   font_start = (font_type * (font_size == FS_BIG ? FONT1_YSIZE : FONT2_YSIZE) *
386                 FONT_LINES_PER_FONT);
387
388   while (*text)
389   {
390     char c = *text++;
391
392     if (c == '~' && font_size == FS_SMALL && font_type <= FC_YELLOW)
393     {
394       print_inverse = TRUE;
395       continue;
396     }
397
398     if (c >= 'a' && c <= 'z')
399       c = 'A' + (c - 'a');
400     else if (c == 'ä' || c == 'Ä')
401       c = 91;
402     else if (c == 'ö' || c == 'Ö')
403       c = 92;
404     else if (c == 'ü' || c == 'Ãœ')
405       c = 93;
406
407     if (c >= 32 && c <= 95)
408     {
409       int src_x = ((c - 32) % FONT_CHARS_PER_LINE) * font_width;
410       int src_y = ((c - 32) / FONT_CHARS_PER_LINE) * font_height + font_start;
411       int dest_x = x, dest_y = y;
412
413       if (print_inverse)
414       {
415         XCopyArea(display, pix[font_pixmap], d, gc,
416                   FONT_CHARS_PER_LINE * font_width,
417                   3 * font_height + font_start,
418                   font_width, font_height, x, y);
419
420         XSetClipOrigin(display, clip_gc[font_pixmap],
421                        dest_x - src_x, dest_y - src_y);
422         XCopyArea(display, pix[font_pixmap], d, clip_gc[font_pixmap],
423                   0, 0, font_width, font_height, dest_x, dest_y);
424       }
425       else
426         XCopyArea(display, pix[font_pixmap], d, gc,
427                   src_x, src_y, font_width, font_height, dest_x, dest_y);
428     }
429
430     x += font_width;
431   }
432 }
433
434 void DrawAllPlayers()
435 {
436   int i;
437
438   for(i=0; i<MAX_PLAYERS; i++)
439     if (stored_player[i].active)
440       DrawPlayer(&stored_player[i]);
441 }
442
443 void DrawPlayerField(int x, int y)
444 {
445   if (!IS_PLAYER(x,y))
446     return;
447
448   DrawPlayer(PLAYERINFO(x,y));
449 }
450
451 void DrawPlayer(struct PlayerInfo *player)
452 {
453   int jx = player->jx, jy = player->jy;
454   int last_jx = player->last_jx, last_jy = player->last_jy;
455   int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
456   int sx = SCREENX(jx), sy = SCREENY(jy);
457   int sxx = 0, syy = 0;
458   int element = Feld[jx][jy];
459   int graphic, phase;
460
461   if (!player->active || player->gone ||
462       !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
463     return;
464
465 #if DEBUG
466   if (!IN_LEV_FIELD(jx,jy))
467   {
468     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
469     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
470     printf("DrawPlayerField(): This should never happen!\n");
471     return;
472   }
473 #endif
474
475   if (element == EL_EXPLODING)
476     return;
477
478   /* draw things in the field the player is leaving, if needed */
479
480   if (last_jx != jx || last_jy != jy)
481   {
482     if (Store[last_jx][last_jy])
483     {
484       DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
485       DrawLevelFieldThruMask(last_jx, last_jy);
486     }
487     else if (Feld[last_jx][last_jy] == EL_DYNAMIT)
488       DrawDynamite(last_jx, last_jy);
489     else
490       DrawLevelField(last_jx, last_jy);
491
492     if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
493     {
494       if (player->GfxPos)
495       {
496         if (Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
497           DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FELD_LEER);
498         else
499           DrawLevelElement(next_jx, next_jy, EL_LEERRAUM);
500       }
501       else
502         DrawLevelField(next_jx, next_jy);
503     }
504   }
505
506   if (!IN_SCR_FIELD(sx, sy))
507     return;
508
509   if (setup.direct_draw)
510     SetDrawtoField(DRAW_BUFFERED);
511
512   /* draw things behind the player, if needed */
513
514   if (Store[jx][jy])
515     DrawLevelElement(jx, jy, Store[jx][jy]);
516   else if (element != EL_DYNAMIT && element != EL_DYNABOMB)
517     DrawLevelField(jx, jy);
518
519   /* draw player himself */
520
521   if (game_emulation == EMU_SUPAPLEX)
522   {
523 #if 0
524     if (player->MovDir == MV_LEFT)
525       graphic =
526         (player->Pushing ? GFX_MURPHY_PUSH_LEFT : GFX_MURPHY_LEFT);
527     else if (player->MovDir == MV_RIGHT)
528       graphic =
529         (player->Pushing ? GFX_MURPHY_PUSH_RIGHT : GFX_MURPHY_RIGHT);
530     else if (player->MovDir == MV_UP)
531       graphic = GFX_MURPHY_UP;
532     else if (player->MovDir == MV_DOWN)
533       graphic = GFX_MURPHY_DOWN;
534     else        /* MV_NO_MOVING */
535       graphic = GFX_SP_MURPHY;
536
537
538     /*
539     if (player->snapped)
540       graphic = GFX_SPIELER1_PUSH_LEFT;
541     else
542       graphic = GFX_SPIELER1_PUSH_RIGHT;
543     */
544 #endif
545
546     static last_dir = MV_LEFT;
547
548     if (player->Pushing)
549     {
550       if (player->MovDir == MV_LEFT)
551         graphic = GFX_MURPHY_PUSH_LEFT;
552       else if (player->MovDir == MV_RIGHT)
553         graphic = GFX_MURPHY_PUSH_RIGHT;
554       else if (last_dir == MV_LEFT)
555         graphic = GFX_MURPHY_ANY_LEFT;
556       else if (last_dir == MV_RIGHT)
557         graphic = GFX_MURPHY_ANY_RIGHT;
558       else
559         graphic = GFX_SP_MURPHY;
560     }
561     else if (player->snapped)
562     {
563       if (player->MovDir == MV_LEFT)
564         graphic = GFX_MURPHY_SNAP_LEFT;
565       else if (player->MovDir == MV_RIGHT)
566         graphic = GFX_MURPHY_SNAP_RIGHT;
567       else if (player->MovDir == MV_UP)
568         graphic = GFX_MURPHY_SNAP_UP;
569       else if (player->MovDir == MV_DOWN)
570         graphic = GFX_MURPHY_SNAP_DOWN;
571       else
572         graphic = GFX_SP_MURPHY;
573     }
574     else
575     {
576       if (player->MovDir == MV_LEFT)
577         graphic = GFX_MURPHY_ANY_LEFT;
578       else if (player->MovDir == MV_RIGHT)
579         graphic = GFX_MURPHY_ANY_RIGHT;
580       else if (last_dir == MV_LEFT)
581         graphic = GFX_MURPHY_ANY_LEFT;
582       else if (last_dir == MV_RIGHT)
583         graphic = GFX_MURPHY_ANY_RIGHT;
584       else
585         graphic = GFX_SP_MURPHY;
586     }
587
588     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
589       last_dir = player->MovDir;
590
591     if (!player->Pushing && !player->snapped && player->MovDir != MV_NO_MOVING)
592       graphic -= player->Frame % 2;
593   }
594   else
595   {
596     if (player->MovDir == MV_LEFT)
597       graphic =
598         (player->Pushing ? GFX_SPIELER1_PUSH_LEFT : GFX_SPIELER1_LEFT);
599     else if (player->MovDir == MV_RIGHT)
600       graphic =
601         (player->Pushing ? GFX_SPIELER1_PUSH_RIGHT : GFX_SPIELER1_RIGHT);
602     else if (player->MovDir == MV_UP)
603       graphic = GFX_SPIELER1_UP;
604     else        /* MV_DOWN || MV_NO_MOVING */
605       graphic = GFX_SPIELER1_DOWN;
606
607     graphic += player->index_nr * 3 * HEROES_PER_LINE;
608     graphic += player->Frame;
609   }
610
611   if (player->GfxPos)
612   {
613     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
614       sxx = player->GfxPos;
615     else
616       syy = player->GfxPos;
617   }
618
619   if (!setup.soft_scrolling && ScreenMovPos)
620     sxx = syy = 0;
621
622   DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, NO_CUTTING);
623
624   if (player->Pushing && player->GfxPos)
625   {
626     int px = SCREENX(next_jx), py = SCREENY(next_jy);
627
628     if (Feld[jx][jy] == EL_SOKOBAN_FELD_LEER ||
629         Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
630       DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT,
631                                  NO_CUTTING);
632     else
633     {
634       int element = Feld[next_jx][next_jy];
635       int graphic = el2gfx(element);
636
637       if (element == EL_FELSBROCKEN && sxx)
638       {
639         int phase = (player->GfxPos / (TILEX/4));
640
641         if (player->MovDir == MV_LEFT)
642           graphic += phase;
643         else
644           graphic += (phase+4)%4;
645       }
646
647       DrawGraphicShifted(px, py, sxx, syy, graphic, NO_CUTTING, NO_MASKING);
648     }
649   }
650
651   /* draw things in front of player (EL_DYNAMIT || EL_DYNABOMB) */
652
653   if (element == EL_DYNAMIT || element == EL_DYNABOMB)
654   {
655     graphic = el2gfx(element);
656
657     if (element == EL_DYNAMIT)
658     {
659       if ((phase = (96 - MovDelay[jx][jy]) / 12) > 6)
660         phase = 6;
661     }
662     else
663     {
664       if ((phase = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
665         phase = 7 - phase;
666     }
667
668     if (game_emulation == EMU_SUPAPLEX)
669       DrawGraphic(sx, sy, GFX_SP_DISK_RED);
670     else
671       DrawGraphicThruMask(sx, sy, graphic + phase);
672   }
673
674   if ((last_jx != jx || last_jy != jy) &&
675       Feld[last_jx][last_jy] == EL_EXPLODING)
676   {
677     int phase = Frame[last_jx][last_jy];
678     int delay = 2;
679
680     if (phase > 2)
681       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy),
682                           GFX_EXPLOSION + ((phase - 1) / delay - 1));
683   }
684
685   if (setup.direct_draw)
686   {
687     int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
688     int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
689     int x_size = TILEX * (1 + ABS(jx - last_jx));
690     int y_size = TILEY * (1 + ABS(jy - last_jy));
691
692     XCopyArea(display, drawto_field, window, gc,
693               dest_x, dest_y, x_size, y_size, dest_x, dest_y);
694     SetDrawtoField(DRAW_DIRECT);
695   }
696
697   MarkTileDirty(sx,sy);
698 }
699
700 static int getGraphicAnimationPhase(int frames, int delay, int mode)
701 {
702   int phase;
703
704   if (mode == ANIM_OSCILLATE)
705   {
706     int max_anim_frames = 2 * frames - 2;
707     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
708     phase = (phase < frames ? phase : max_anim_frames - phase);
709   }
710   else
711     phase = (FrameCounter % (delay * frames)) / delay;
712
713   if (mode == ANIM_REVERSE)
714     phase = -phase;
715
716   return(phase);
717 }
718
719 void DrawGraphicAnimationExt(int x, int y, int graphic,
720                              int frames, int delay, int mode, int mask_mode)
721 {
722   int phase = getGraphicAnimationPhase(frames, delay, mode);
723
724   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
725   {
726     if (mask_mode == USE_MASKING)
727       DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic + phase);
728     else
729       DrawGraphic(SCREENX(x), SCREENY(y), graphic + phase);
730   }
731 }
732
733 void DrawGraphicAnimation(int x, int y, int graphic,
734                           int frames, int delay, int mode)
735 {
736   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
737 }
738
739 void DrawGraphicAnimationThruMask(int x, int y, int graphic,
740                                   int frames, int delay, int mode)
741 {
742   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, USE_MASKING);
743 }
744
745 void getGraphicSource(int graphic, int *pixmap_nr, int *x, int *y)
746 {
747   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
748   {
749     graphic -= GFX_START_ROCKSSCREEN;
750     *pixmap_nr = PIX_BACK;
751     *x = SX + (graphic % GFX_PER_LINE) * TILEX;
752     *y = SY + (graphic / GFX_PER_LINE) * TILEY;
753   }
754   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
755   {
756     graphic -= GFX_START_ROCKSMORE;
757     *pixmap_nr = PIX_MORE;
758     *x = (graphic % MORE_PER_LINE) * TILEX;
759     *y = (graphic / MORE_PER_LINE) * TILEY;
760   }
761   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
762   {
763     graphic -= GFX_START_ROCKSHEROES;
764     *pixmap_nr = PIX_HEROES;
765     *x = (graphic % HEROES_PER_LINE) * TILEX;
766     *y = (graphic / HEROES_PER_LINE) * TILEY;
767   }
768   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
769   {
770     graphic -= GFX_START_ROCKSFONT;
771     *pixmap_nr = PIX_BIGFONT;
772     *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
773     *y = ((graphic / FONT_CHARS_PER_LINE) * TILEY +
774           FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY);
775   }
776   else
777   {
778     *pixmap_nr = PIX_MORE;
779     *x = 0;
780     *y = 0;
781   }
782 }
783
784 void DrawGraphic(int x, int y, int graphic)
785 {
786 #if DEBUG
787   if (!IN_SCR_FIELD(x,y))
788   {
789     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
790     printf("DrawGraphic(): This should never happen!\n");
791     return;
792   }
793 #endif
794
795   DrawGraphicExt(drawto_field, gc, FX + x*TILEX, FY + y*TILEY, graphic);
796   MarkTileDirty(x,y);
797 }
798
799 void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
800 {
801
802 #if 1
803
804   int pixmap_nr;
805   int src_x, src_y;
806
807   getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
808   XCopyArea(display, pix[pixmap_nr], d, gc,
809             src_x, src_y, TILEX, TILEY, x, y);
810
811 #else
812
813   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
814   {
815     graphic -= GFX_START_ROCKSSCREEN;
816     XCopyArea(display, pix[PIX_BACK], d, gc,
817               SX + (graphic % GFX_PER_LINE) * TILEX,
818               SY + (graphic / GFX_PER_LINE) * TILEY,
819               TILEX, TILEY, x, y);
820   }
821   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
822   {
823     graphic -= GFX_START_ROCKSMORE;
824     XCopyArea(display, pix[PIX_MORE], d, gc,
825               (graphic % MORE_PER_LINE) * TILEX,
826               (graphic / MORE_PER_LINE) * TILEY,
827               TILEX, TILEY, x, y);
828   }
829   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
830   {
831     graphic -= GFX_START_ROCKSHEROES;
832     XCopyArea(display, pix[PIX_HEROES], d, gc,
833               (graphic % HEROES_PER_LINE) * TILEX,
834               (graphic / HEROES_PER_LINE) * TILEY,
835               TILEX, TILEY, x, y);
836   }
837   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
838   {
839     graphic -= GFX_START_ROCKSFONT;
840     XCopyArea(display, pix[PIX_BIGFONT], d, gc,
841               (graphic % FONT_CHARS_PER_LINE) * TILEX,
842               (graphic / FONT_CHARS_PER_LINE) * TILEY +
843               FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY,
844               TILEX, TILEY, x, y);
845   }
846   else
847     XFillRectangle(display, d, gc, x, y, TILEX, TILEY);
848
849 #endif
850
851 }
852
853 void DrawGraphicThruMask(int x, int y, int graphic)
854 {
855 #if DEBUG
856   if (!IN_SCR_FIELD(x,y))
857   {
858     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
859     printf("DrawGraphicThruMask(): This should never happen!\n");
860     return;
861   }
862 #endif
863
864   DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
865   MarkTileDirty(x,y);
866 }
867
868 void DrawGraphicThruMaskExt(Drawable d, int dest_x, int dest_y, int graphic)
869 {
870
871 #if 1
872
873   int tile = graphic;
874   int pixmap_nr;
875   int src_x, src_y;
876   Pixmap src_pixmap;
877   GC drawing_gc;
878
879   getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
880   src_pixmap = pix[pixmap_nr];
881   drawing_gc = clip_gc[pixmap_nr];
882
883 #else
884
885   int src_x, src_y;
886   int tile = graphic;
887   Pixmap src_pixmap;
888   GC drawing_gc;
889
890   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
891   {
892     src_pixmap = pix[PIX_BACK];
893     drawing_gc = clip_gc[PIX_BACK];
894     graphic -= GFX_START_ROCKSSCREEN;
895     src_x  = SX + (graphic % GFX_PER_LINE) * TILEX;
896     src_y  = SY + (graphic / GFX_PER_LINE) * TILEY;
897   }
898   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
899   {
900     src_pixmap = pix[PIX_MORE];
901     drawing_gc = clip_gc[PIX_MORE];
902     graphic -= GFX_START_ROCKSMORE;
903     src_x  = (graphic % MORE_PER_LINE) * TILEX;
904     src_y  = (graphic / MORE_PER_LINE) * TILEY;
905   }
906   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
907   {
908     src_pixmap = pix[PIX_HEROES];
909     drawing_gc = clip_gc[PIX_HEROES];
910     graphic -= GFX_START_ROCKSHEROES;
911     src_x  = (graphic % HEROES_PER_LINE) * TILEX;
912     src_y  = (graphic / HEROES_PER_LINE) * TILEY;
913   }
914   else
915   {
916     DrawGraphicExt(d, gc, dest_x,dest_y, graphic);
917     return;
918   }
919
920 #endif
921
922
923   if (tile_clipmask[tile] != None)
924   {
925     XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
926     XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
927     XCopyArea(display, src_pixmap, d, tile_clip_gc,
928               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
929   }
930   else
931   {
932 #if DEBUG
933     printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
934 #endif
935
936     XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y);
937     XCopyArea(display, src_pixmap, d, drawing_gc,
938               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
939   }
940 }
941
942 void DrawMiniGraphic(int x, int y, int graphic)
943 {
944   DrawMiniGraphicExt(drawto,gc, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
945   MarkTileDirty(x/2, y/2);
946 }
947
948 void getMiniGraphicSource(int graphic, Pixmap *pixmap, int *x, int *y)
949 {
950   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
951   {
952     graphic -= GFX_START_ROCKSSCREEN;
953     *pixmap = pix[PIX_BACK];
954     *x = MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX;
955     *y = MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY;
956   }
957   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
958   {
959     graphic -= GFX_START_ROCKSMORE;
960     *pixmap = pix[PIX_MORE];
961     *x = MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX;
962     *y = MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY;
963   }
964   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
965   {
966     graphic -= GFX_START_ROCKSFONT;
967     *pixmap = pix[PIX_SMALLFONT];
968     *x = (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE;
969     *y = ((graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
970               FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT);
971   }
972   else
973   {
974     *pixmap = pix[PIX_MORE];
975     *x = MINI_MORE_STARTX;
976     *y = MINI_MORE_STARTY;
977   }
978 }
979
980 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
981 {
982
983 #if 1
984
985   Pixmap pixmap;
986   int src_x, src_y;
987
988   getMiniGraphicSource(graphic, &pixmap, &src_x, &src_y);
989   XCopyArea(display, pixmap, d, gc,
990             src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
991
992 #else
993
994   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
995   {
996     graphic -= GFX_START_ROCKSSCREEN;
997     XCopyArea(display, pix[PIX_BACK], d, gc,
998               MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX,
999               MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY,
1000               MINI_TILEX, MINI_TILEY, x, y);
1001   }
1002   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1003   {
1004     graphic -= GFX_START_ROCKSMORE;
1005     XCopyArea(display, pix[PIX_MORE], d, gc,
1006               MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX,
1007               MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY,
1008               MINI_TILEX, MINI_TILEY, x, y);
1009   }
1010   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
1011   {
1012     graphic -= GFX_START_ROCKSFONT;
1013     XCopyArea(display, pix[PIX_SMALLFONT], d, gc,
1014               (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE,
1015               (graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
1016               FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT,
1017               MINI_TILEX, MINI_TILEY, x, y);
1018   }
1019   else
1020     XFillRectangle(display, d, gc, x, y, MINI_TILEX, MINI_TILEY);
1021
1022 #endif
1023
1024 }
1025
1026 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
1027                         int cut_mode, int mask_mode)
1028 {
1029   int width = TILEX, height = TILEY;
1030   int cx = 0, cy = 0;
1031   int src_x, src_y, dest_x, dest_y;
1032   int tile = graphic;
1033   Pixmap src_pixmap;
1034   GC drawing_gc;
1035
1036   if (graphic < 0)
1037   {
1038     DrawGraphic(x, y, graphic);
1039     return;
1040   }
1041
1042   if (dx || dy)                 /* Verschiebung der Grafik? */
1043   {
1044     if (x < BX1)                /* Element kommt von links ins Bild */
1045     {
1046       x = BX1;
1047       width = dx;
1048       cx = TILEX - dx;
1049       dx = 0;
1050     }
1051     else if (x > BX2)           /* Element kommt von rechts ins Bild */
1052     {
1053       x = BX2;
1054       width = -dx;
1055       dx = TILEX + dx;
1056     }
1057     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
1058     {
1059       width += dx;
1060       cx = -dx;
1061       dx = 0;
1062     }
1063     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
1064       width -= dx;
1065     else if (dx)                /* allg. Bewegung in x-Richtung */
1066       MarkTileDirty(x + SIGN(dx), y);
1067
1068     if (y < BY1)                /* Element kommt von oben ins Bild */
1069     {
1070       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
1071         return;
1072
1073       y = BY1;
1074       height = dy;
1075       cy = TILEY - dy;
1076       dy = 0;
1077     }
1078     else if (y > BY2)           /* Element kommt von unten ins Bild */
1079     {
1080       y = BY2;
1081       height = -dy;
1082       dy = TILEY + dy;
1083     }
1084     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
1085     {
1086       height += dy;
1087       cy = -dy;
1088       dy = 0;
1089     }
1090     else if (dy > 0 && cut_mode == CUT_ABOVE)
1091     {
1092       if (y == BY2)             /* Element unterhalb des Bildes */
1093         return;
1094
1095       height = dy;
1096       cy = TILEY - dy;
1097       dy = TILEY;
1098       MarkTileDirty(x, y + 1);
1099     }                           /* Element verläßt unten das Bild */
1100     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1101       height -= dy;
1102     else if (dy)                /* allg. Bewegung in y-Richtung */
1103       MarkTileDirty(x, y + SIGN(dy));
1104   }
1105
1106   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
1107   {
1108     src_pixmap = pix[PIX_BACK];
1109     drawing_gc = clip_gc[PIX_BACK];
1110     graphic -= GFX_START_ROCKSSCREEN;
1111     src_x  = SX + (graphic % GFX_PER_LINE) * TILEX + cx;
1112     src_y  = SY + (graphic / GFX_PER_LINE) * TILEY + cy;
1113   }
1114   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1115   {
1116     src_pixmap = pix[PIX_MORE];
1117     drawing_gc = clip_gc[PIX_MORE];
1118     graphic -= GFX_START_ROCKSMORE;
1119     src_x  = (graphic % MORE_PER_LINE) * TILEX + cx;
1120     src_y  = (graphic / MORE_PER_LINE) * TILEY + cy;
1121   }
1122   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
1123   {
1124     src_pixmap = pix[PIX_HEROES];
1125     drawing_gc = clip_gc[PIX_HEROES];
1126     graphic -= GFX_START_ROCKSHEROES;
1127     src_x  = (graphic % HEROES_PER_LINE) * TILEX + cx;
1128     src_y  = (graphic / HEROES_PER_LINE) * TILEY + cy;
1129   }
1130   else  /* big font graphics currently not allowed (and not needed) */
1131     return;
1132
1133   dest_x = FX + x * TILEX + dx;
1134   dest_y = FY + y * TILEY + dy;
1135
1136 #if DEBUG
1137   if (!IN_SCR_FIELD(x,y))
1138   {
1139     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1140     printf("DrawGraphicShifted(): This should never happen!\n");
1141     return;
1142   }
1143 #endif
1144
1145   if (mask_mode == USE_MASKING)
1146   {
1147     if (tile_clipmask[tile] != None)
1148     {
1149       XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
1150       XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
1151       XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
1152                 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1153     }
1154     else
1155     {
1156 #if DEBUG
1157       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
1158 #endif
1159
1160       XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
1161       XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
1162                 src_x, src_y, width, height, dest_x, dest_y);
1163     }
1164   }
1165   else
1166     XCopyArea(display, src_pixmap, drawto_field, gc,
1167               src_x, src_y, width, height, dest_x, dest_y);
1168
1169   MarkTileDirty(x,y);
1170 }
1171
1172 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1173                                 int cut_mode)
1174 {
1175   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
1176 }
1177
1178 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1179                           int cut_mode, int mask_mode)
1180 {
1181   int ux = LEVELX(x), uy = LEVELY(y);
1182   int graphic = el2gfx(element);
1183   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1184   int phase4 = phase8 / 2;
1185   int phase2  = phase8 / 4;
1186   int dir = MovDir[ux][uy];
1187
1188   if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
1189   {
1190     graphic += 4 * !phase2;
1191
1192     if (dir == MV_UP)
1193       graphic += 1;
1194     else if (dir == MV_LEFT)
1195       graphic += 2;
1196     else if (dir == MV_DOWN)
1197       graphic += 3;
1198   }
1199   else if (element == EL_SP_SNIKSNAK)
1200   {
1201     if (dir == MV_LEFT)
1202       graphic = GFX_SP_SNIKSNAK_LEFT;
1203     else if (dir == MV_RIGHT)
1204       graphic = GFX_SP_SNIKSNAK_RIGHT;
1205     else if (dir == MV_UP)
1206       graphic = GFX_SP_SNIKSNAK_UP;
1207     else
1208       graphic = GFX_SP_SNIKSNAK_DOWN;
1209
1210     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1211   }
1212   else if (element == EL_SP_ELECTRON)
1213   {
1214     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1215   }
1216   else if (element == EL_MAULWURF || element == EL_PINGUIN ||
1217            element == EL_SCHWEIN || element == EL_DRACHE)
1218   {
1219     if (dir == MV_LEFT)
1220       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT :
1221                  element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
1222                  element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1223     else if (dir == MV_RIGHT)
1224       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT :
1225                  element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
1226                  element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1227     else if (dir == MV_UP)
1228       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP :
1229                  element == EL_PINGUIN ? GFX_PINGUIN_UP :
1230                  element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1231     else
1232       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN :
1233                  element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
1234                  element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1235
1236     graphic += phase4;
1237   }
1238   else if (element == EL_SONDE)
1239   {
1240     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1241   }
1242   else if (element == EL_SALZSAEURE)
1243   {
1244     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
1245   }
1246   else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1247   {
1248     graphic += !phase2;
1249   }
1250   else if ((element == EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode)
1251   {
1252     if (element != EL_SP_INFOTRON)
1253       graphic += phase2 * (element == EL_FELSBROCKEN ? 2 : 1);
1254   }
1255   else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
1256            element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
1257   {
1258     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1259   }
1260   else if (IS_AMOEBOID(element))
1261   {
1262     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1263     graphic += (x + 2 * y + 4) % 4;
1264   }
1265   else if (element == EL_MAUER_LEBT)
1266   {
1267     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1268
1269     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1270       links_massiv = TRUE;
1271     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1272       rechts_massiv = TRUE;
1273
1274     if (links_massiv && rechts_massiv)
1275       graphic = GFX_MAUERWERK;
1276     else if (links_massiv)
1277       graphic = GFX_MAUER_R;
1278     else if (rechts_massiv)
1279       graphic = GFX_MAUER_L;
1280   }
1281
1282   if (dx || dy)
1283     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1284   else if (mask_mode == USE_MASKING)
1285     DrawGraphicThruMask(x, y, graphic);
1286   else
1287     DrawGraphic(x, y, graphic);
1288 }
1289
1290 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1291                          int cut_mode, int mask_mode)
1292 {
1293   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1294     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1295                          cut_mode, mask_mode);
1296 }
1297
1298 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1299                               int cut_mode)
1300 {
1301   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1302 }
1303
1304 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1305                              int cut_mode)
1306 {
1307   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1308 }
1309
1310 void DrawScreenElementThruMask(int x, int y, int element)
1311 {
1312   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1313 }
1314
1315 void DrawLevelElementThruMask(int x, int y, int element)
1316 {
1317   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1318 }
1319
1320 void DrawLevelFieldThruMask(int x, int y)
1321 {
1322   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1323 }
1324
1325 void ErdreichAnbroeckeln(int x, int y)
1326 {
1327   int i, width, height, cx,cy;
1328   int ux = LEVELX(x), uy = LEVELY(y);
1329   int element, graphic;
1330   int snip = 4;
1331   static int xy[4][2] =
1332   {
1333     { 0, -1 },
1334     { -1, 0 },
1335     { +1, 0 },
1336     { 0, +1 }
1337   };
1338
1339   if (!IN_LEV_FIELD(ux, uy))
1340     return;
1341
1342   element = Feld[ux][uy];
1343
1344   if (element == EL_ERDREICH)
1345   {
1346     if (!IN_SCR_FIELD(x, y))
1347       return;
1348
1349     graphic = GFX_ERDENRAND;
1350
1351     for(i=0; i<4; i++)
1352     {
1353       int uxx, uyy;
1354
1355       uxx = ux + xy[i][0];
1356       uyy = uy + xy[i][1];
1357       if (!IN_LEV_FIELD(uxx, uyy))
1358         element = EL_BETON;
1359       else
1360         element = Feld[uxx][uyy];
1361
1362       if (element == EL_ERDREICH)
1363         continue;
1364
1365       if (i == 1 || i == 2)
1366       {
1367         width = snip;
1368         height = TILEY;
1369         cx = (i == 2 ? TILEX - snip : 0);
1370         cy = 0;
1371       }
1372       else
1373       {
1374         width = TILEX;
1375         height = snip;
1376         cx = 0;
1377         cy = (i == 3 ? TILEY - snip : 0);
1378       }
1379
1380       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1381                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1382                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1383                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1384     }
1385
1386     MarkTileDirty(x, y);
1387   }
1388   else
1389   {
1390     graphic = GFX_ERDENRAND;
1391
1392     for(i=0; i<4; i++)
1393     {
1394       int xx, yy, uxx, uyy;
1395
1396       xx = x + xy[i][0];
1397       yy = y + xy[i][1];
1398       uxx = ux + xy[i][0];
1399       uyy = uy + xy[i][1];
1400
1401       if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
1402           !IN_SCR_FIELD(xx, yy))
1403         continue;
1404
1405       if (i == 1 || i == 2)
1406       {
1407         width = snip;
1408         height = TILEY;
1409         cx = (i == 1 ? TILEX - snip : 0);
1410         cy = 0;
1411       }
1412       else
1413       {
1414         width = TILEX;
1415         height = snip;
1416         cx = 0;
1417         cy = (i==0 ? TILEY-snip : 0);
1418       }
1419
1420       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1421                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1422                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1423                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1424
1425       MarkTileDirty(xx, yy);
1426     }
1427   }
1428 }
1429
1430 void DrawScreenElement(int x, int y, int element)
1431 {
1432   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1433   ErdreichAnbroeckeln(x, y);
1434 }
1435
1436 void DrawLevelElement(int x, int y, int element)
1437 {
1438   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1439     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1440 }
1441
1442 void DrawScreenField(int x, int y)
1443 {
1444   int ux = LEVELX(x), uy = LEVELY(y);
1445   int element;
1446
1447   if (!IN_LEV_FIELD(ux, uy))
1448   {
1449     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1450       element = EL_LEERRAUM;
1451     else
1452       element = BorderElement;
1453
1454     DrawScreenElement(x, y, element);
1455     return;
1456   }
1457
1458   element = Feld[ux][uy];
1459
1460   if (IS_MOVING(ux, uy))
1461   {
1462     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1463     boolean cut_mode = NO_CUTTING;
1464
1465     if (Store[ux][uy] == EL_MORAST_LEER ||
1466         Store[ux][uy] == EL_SIEB_LEER ||
1467         Store[ux][uy] == EL_SIEB2_LEER ||
1468         Store[ux][uy] == EL_AMOEBE_NASS)
1469       cut_mode = CUT_ABOVE;
1470     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1471              Store[ux][uy] == EL_SIEB_VOLL ||
1472              Store[ux][uy] == EL_SIEB2_VOLL)
1473       cut_mode = CUT_BELOW;
1474
1475     if (cut_mode == CUT_ABOVE)
1476       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1477     else
1478       DrawScreenElement(x, y, EL_LEERRAUM);
1479
1480     if (horiz_move)
1481       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1482     else
1483       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1484
1485     if (Store[ux][uy] == EL_SALZSAEURE)
1486       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1487   }
1488   else if (IS_BLOCKED(ux, uy))
1489   {
1490     int oldx, oldy;
1491     int sx, sy;
1492     int horiz_move;
1493     boolean cut_mode = NO_CUTTING;
1494
1495     Blocked2Moving(ux, uy, &oldx, &oldy);
1496     sx = SCREENX(oldx);
1497     sy = SCREENY(oldy);
1498     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1499                   MovDir[oldx][oldy] == MV_RIGHT);
1500
1501     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1502         Store[oldx][oldy] == EL_SIEB_LEER ||
1503         Store[oldx][oldy] == EL_SIEB2_LEER ||
1504         Store[oldx][oldy] == EL_AMOEBE_NASS)
1505       cut_mode = CUT_ABOVE;
1506
1507     DrawScreenElement(x, y, EL_LEERRAUM);
1508     element = Feld[oldx][oldy];
1509
1510     if (horiz_move)
1511       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1512     else
1513       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1514   }
1515   else if (IS_DRAWABLE(element))
1516     DrawScreenElement(x, y, element);
1517   else
1518     DrawScreenElement(x, y, EL_LEERRAUM);
1519 }
1520
1521 void DrawLevelField(int x, int y)
1522 {
1523   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1524     DrawScreenField(SCREENX(x), SCREENY(y));
1525   else if (IS_MOVING(x, y))
1526   {
1527     int newx,newy;
1528
1529     Moving2Blocked(x, y, &newx, &newy);
1530     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1531       DrawScreenField(SCREENX(newx), SCREENY(newy));
1532   }
1533   else if (IS_BLOCKED(x, y))
1534   {
1535     int oldx, oldy;
1536
1537     Blocked2Moving(x, y, &oldx, &oldy);
1538     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1539       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1540   }
1541 }
1542
1543 void DrawMiniElement(int x, int y, int element)
1544 {
1545   int graphic;
1546
1547   if (!element)
1548   {
1549     DrawMiniGraphic(x, y, -1);
1550     return;
1551   }
1552
1553   graphic = el2gfx(element);
1554   DrawMiniGraphic(x, y, graphic);
1555 }
1556
1557 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1558 {
1559   int x = sx + scroll_x, y = sy + scroll_y;
1560
1561   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1562     DrawMiniElement(sx, sy, EL_LEERRAUM);
1563   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1564     DrawMiniElement(sx, sy, Feld[x][y]);
1565   else
1566   {
1567     int steel_type, steel_position;
1568     int border[6][2] =
1569     {
1570       { GFX_VSTEEL_UPPER_LEFT,  GFX_ISTEEL_UPPER_LEFT  },
1571       { GFX_VSTEEL_UPPER_RIGHT, GFX_ISTEEL_UPPER_RIGHT },
1572       { GFX_VSTEEL_LOWER_LEFT,  GFX_ISTEEL_LOWER_LEFT  },
1573       { GFX_VSTEEL_LOWER_RIGHT, GFX_ISTEEL_LOWER_RIGHT },
1574       { GFX_VSTEEL_VERTICAL,    GFX_ISTEEL_VERTICAL    },
1575       { GFX_VSTEEL_HORIZONTAL,  GFX_ISTEEL_HORIZONTAL  }
1576     };
1577
1578     steel_type = (BorderElement == EL_BETON ? 0 : 1);
1579     steel_position = (x == -1 && y == -1                        ? 0 :
1580                       x == lev_fieldx && y == -1                ? 1 :
1581                       x == -1 && y == lev_fieldy                ? 2 :
1582                       x == lev_fieldx && y == lev_fieldy        ? 3 :
1583                       x == -1 || x == lev_fieldx                ? 4 :
1584                       y == -1 || y == lev_fieldy                ? 5 : -1);
1585
1586     if (steel_position != -1)
1587       DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1588
1589
1590 #if 0
1591     if (x == -1 && y == -1)
1592       DrawMiniGraphic(sx, sy, GFX_STEEL_UPPER_LEFT);
1593     else if (x == lev_fieldx && y == -1)
1594       DrawMiniGraphic(sx, sy, GFX_STEEL_UPPER_RIGHT);
1595     else if (x == -1 && y == lev_fieldy)
1596       DrawMiniGraphic(sx, sy, GFX_STEEL_LOWER_LEFT);
1597     else if (x == lev_fieldx && y == lev_fieldy)
1598       DrawMiniGraphic(sx, sy, GFX_STEEL_LOWER_RIGHT);
1599     else if (x == -1 || x == lev_fieldx)
1600       DrawMiniGraphic(sx, sy, GFX_STEEL_VERTICAL);
1601     else if (y == -1 || y == lev_fieldy)
1602       DrawMiniGraphic(sx, sy, GFX_STEEL_HORIZONTAL);
1603 #endif
1604
1605
1606   }
1607 }
1608
1609 void DrawMicroElement(int xpos, int ypos, int element)
1610 {
1611   int graphic;
1612
1613   if (element == EL_LEERRAUM)
1614     return;
1615
1616   graphic = el2gfx(element);
1617
1618   if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1619   {
1620     graphic -= GFX_START_ROCKSMORE;
1621     XCopyArea(display, pix[PIX_MORE], drawto, gc,
1622               MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
1623               MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
1624               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1625   }
1626   else
1627     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1628               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1629               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1630               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1631 }
1632
1633 void DrawLevel()
1634 {
1635   int x,y;
1636
1637   ClearWindow();
1638
1639   for(x=BX1; x<=BX2; x++)
1640     for(y=BY1; y<=BY2; y++)
1641       DrawScreenField(x, y);
1642
1643   if (setup.soft_scrolling)
1644     XCopyArea(display, fieldbuffer, backbuffer, gc,
1645               FX, FY, SXSIZE, SYSIZE, SX, SY);
1646
1647   redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
1648 }
1649
1650 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1651 {
1652   int x,y;
1653
1654   for(x=0; x<size_x; x++)
1655     for(y=0; y<size_y; y++)
1656       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1657
1658   redraw_mask |= REDRAW_FIELD;
1659 }
1660
1661 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1662 {
1663   int x, y;
1664
1665   /* determine border element for this level */
1666   SetBorderElement();
1667
1668   XFillRectangle(display, drawto, gc,
1669                  xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1670
1671   if (lev_fieldx < STD_LEV_FIELDX)
1672     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1673   if (lev_fieldy < STD_LEV_FIELDY)
1674     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1675
1676   xpos += MICRO_TILEX;
1677   ypos += MICRO_TILEY;
1678
1679   for(x=-1; x<=STD_LEV_FIELDX; x++)
1680   {
1681     for(y=-1; y<=STD_LEV_FIELDY; y++)
1682     {
1683       int lx = from_x + x, ly = from_y + y;
1684
1685       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1686         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1687                          Ur[lx][ly]);
1688       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1689         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1690                          BorderElement);
1691     }
1692   }
1693
1694   redraw_mask |= REDRAW_MICROLEVEL;
1695 }
1696
1697 static void DrawMicroLevelLabelExt(int mode)
1698 {
1699   char label_text[100];
1700
1701   XFillRectangle(display, drawto,gc,
1702                  SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1703
1704   strcpy(label_text, (mode == 1 ? level.name :
1705                       mode == 2 ? "created by" :
1706                       mode == 3 ? level.author : ""));
1707
1708   if (strlen(label_text) > 0)
1709   {
1710     int size, lxpos, lypos;
1711
1712     label_text[SXSIZE / FONT4_XSIZE] = '\0';
1713
1714     size = strlen(label_text);
1715     lxpos = SX + (SXSIZE - size * FONT4_XSIZE) / 2;
1716     lypos = MICROLABEL_YPOS;
1717
1718     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1719   }
1720
1721   redraw_mask |= REDRAW_MICROLEVEL;
1722 }
1723
1724 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1725 {
1726   static unsigned long scroll_delay = 0;
1727   static unsigned long label_delay = 0;
1728   static int from_x, from_y, scroll_direction;
1729   static int label_state, label_counter;
1730
1731   if (restart)
1732   {
1733     from_x = from_y = 0;
1734     scroll_direction = MV_RIGHT;
1735     label_state = 1;
1736     label_counter = 0;
1737
1738     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1739     DrawMicroLevelLabelExt(label_state);
1740
1741     /* initialize delay counters */
1742     DelayReached(&scroll_delay, 0);
1743     DelayReached(&label_delay, 0);
1744
1745     return;
1746   }
1747
1748   /* scroll micro level, if needed */
1749   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1750       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1751   {
1752     switch (scroll_direction)
1753     {
1754       case MV_LEFT:
1755         if (from_x > 0)
1756           from_x--;
1757         else
1758           scroll_direction = MV_UP;
1759         break;
1760
1761       case MV_RIGHT:
1762         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1763           from_x++;
1764         else
1765           scroll_direction = MV_DOWN;
1766         break;
1767
1768       case MV_UP:
1769         if (from_y > 0)
1770           from_y--;
1771         else
1772           scroll_direction = MV_RIGHT;
1773         break;
1774
1775       case MV_DOWN:
1776         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1777           from_y++;
1778         else
1779           scroll_direction = MV_LEFT;
1780         break;
1781
1782       default:
1783         break;
1784     }
1785
1786     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1787   }
1788
1789   /* redraw micro level label, if needed */
1790   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1791       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1792       strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
1793       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1794   {
1795     label_counter = (label_counter + 1) % 23;
1796     label_state = (label_counter >= 0 && label_counter <= 7 ? 1 :
1797                    label_counter >= 9 && label_counter <= 12 ? 2 :
1798                    label_counter >= 14 && label_counter <= 21 ? 3 : 0);
1799     DrawMicroLevelLabelExt(label_state);
1800   }
1801 }
1802
1803 int REQ_in_range(int x, int y)
1804 {
1805   if (y > DY+249 && y < DY+278)
1806   {
1807     if (x > DX+1 && x < DX+48)
1808       return 1;
1809     else if (x > DX+51 && x < DX+98) 
1810       return 2;
1811   }
1812   return 0;
1813 }
1814
1815 boolean Request(char *text, unsigned int req_state)
1816 {
1817   int mx, my, ty, result = -1;
1818   unsigned int old_door_state;
1819
1820 #ifndef MSDOS
1821   /* pause network game while waiting for request to answer */
1822   if (options.network &&
1823       game_status == PLAYING &&
1824       req_state & REQUEST_WAIT_FOR)
1825     SendToServer_PausePlaying();
1826 #endif
1827
1828   old_door_state = GetDoorState();
1829
1830   UnmapAllGadgets();
1831
1832   CloseDoor(DOOR_CLOSE_1);
1833
1834   /* save old door content */
1835   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1836             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1837             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1838
1839   /* clear door drawing field */
1840 #if 0
1841   XFillRectangle(display, pix[PIX_DB_DOOR], gc,
1842                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
1843 #else
1844   XFillRectangle(display, drawto, gc, DX, DY, DXSIZE, DYSIZE);
1845 #endif
1846
1847   /* write text for request */
1848   for(ty=0; ty<13; ty++)
1849   {
1850     int tx, tl, tc;
1851     char txt[256];
1852
1853     if (!*text)
1854       break;
1855
1856     for(tl=0,tx=0; tx<7; tl++,tx++)
1857     {
1858       tc = *(text + tx);
1859       if (!tc || tc == 32)
1860         break;
1861     }
1862     if (!tl)
1863     { 
1864       text++; 
1865       ty--; 
1866       continue; 
1867     }
1868     sprintf(txt, text); 
1869     txt[tl] = 0;
1870 #if 0
1871     DrawTextExt(pix[PIX_DB_DOOR], gc,
1872                 DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
1873                 txt, FS_SMALL, FC_YELLOW);
1874 #else
1875     DrawTextExt(drawto, gc,
1876                 DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
1877                 txt, FS_SMALL, FC_YELLOW);
1878 #endif
1879     text += tl + (tc == 32 ? 1 : 0);
1880   }
1881
1882 #if 0
1883   if (req_state & REQ_ASK)
1884   {
1885     DrawYesNoButton(BUTTON_OK, DB_INIT);
1886     DrawYesNoButton(BUTTON_NO, DB_INIT);
1887   }
1888   else if (req_state & REQ_CONFIRM)
1889   {
1890     DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
1891   }
1892   else if (req_state & REQ_PLAYER)
1893   {
1894     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1895     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1896     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1897     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1898   }
1899 #else
1900
1901   if (req_state & REQ_ASK)
1902   {
1903     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1904     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1905   }
1906   else if (req_state & REQ_CONFIRM)
1907   {
1908     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1909   }
1910   else if (req_state & REQ_PLAYER)
1911   {
1912     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1913     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1914     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1915     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1916   }
1917
1918   /* copy request gadgets to door backbuffer */
1919   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
1920             DX, DY, DXSIZE, DYSIZE,
1921             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1922
1923 #endif
1924
1925   OpenDoor(DOOR_OPEN_1);
1926   ClearEventQueue();
1927
1928   if (!(req_state & REQUEST_WAIT_FOR))
1929     return(FALSE);
1930
1931   if (game_status != MAINMENU)
1932     InitAnimation();
1933
1934   button_status = MB_RELEASED;
1935
1936   request_gadget_id = -1;
1937
1938   while(result < 0)
1939   {
1940     if (XPending(display))
1941     {
1942       XEvent event;
1943
1944       XNextEvent(display, &event);
1945
1946       switch(event.type)
1947       {
1948         case ButtonPress:
1949         case ButtonRelease:
1950         case MotionNotify:
1951         {
1952
1953 #if 0
1954           int choice;
1955 #endif
1956
1957           if (event.type == MotionNotify)
1958           {
1959             Window root, child;
1960             int root_x, root_y;
1961             int win_x, win_y;
1962             unsigned int mask;
1963
1964             if (!XQueryPointer(display, window, &root, &child,
1965                                &root_x, &root_y, &win_x, &win_y, &mask))
1966               continue;
1967
1968             if (!button_status)
1969               continue;
1970
1971             motion_status = TRUE;
1972             mx = ((XMotionEvent *) &event)->x;
1973             my = ((XMotionEvent *) &event)->y;
1974           }
1975           else
1976           {
1977             motion_status = FALSE;
1978             mx = ((XButtonEvent *) &event)->x;
1979             my = ((XButtonEvent *) &event)->y;
1980             if (event.type==ButtonPress)
1981               button_status = ((XButtonEvent *) &event)->button;
1982             else
1983               button_status = MB_RELEASED;
1984           }
1985
1986
1987
1988 #if 0
1989           if (req_state & REQ_ASK)
1990             choice = CheckYesNoButtons(mx,my,button_status);
1991           else if (req_state & REQ_CONFIRM)
1992             choice = CheckConfirmButton(mx,my,button_status);
1993           else
1994             choice = CheckPlayerButtons(mx,my,button_status);
1995
1996           switch(choice)
1997           {
1998             case BUTTON_OK:
1999               result = TRUE;
2000               break;
2001             case BUTTON_NO:
2002               result = FALSE;
2003               break;
2004             case BUTTON_CONFIRM:
2005               result = TRUE | FALSE;
2006               break;
2007
2008             case BUTTON_PLAYER_1:
2009               result = 1;
2010               break;
2011             case BUTTON_PLAYER_2:
2012               result = 2;
2013               break;
2014             case BUTTON_PLAYER_3:
2015               result = 3;
2016               break;
2017             case BUTTON_PLAYER_4:
2018               result = 4;
2019               break;
2020
2021             default:
2022               break;
2023           }
2024 #else
2025
2026           /* this sets 'request_gadget_id' */
2027           HandleGadgets(mx, my, button_status);
2028
2029           switch(request_gadget_id)
2030           {
2031             case TOOL_CTRL_ID_YES:
2032               result = TRUE;
2033               break;
2034             case TOOL_CTRL_ID_NO:
2035               result = FALSE;
2036               break;
2037             case TOOL_CTRL_ID_CONFIRM:
2038               result = TRUE | FALSE;
2039               break;
2040
2041             case TOOL_CTRL_ID_PLAYER_1:
2042               result = 1;
2043               break;
2044             case TOOL_CTRL_ID_PLAYER_2:
2045               result = 2;
2046               break;
2047             case TOOL_CTRL_ID_PLAYER_3:
2048               result = 3;
2049               break;
2050             case TOOL_CTRL_ID_PLAYER_4:
2051               result = 4;
2052               break;
2053
2054             default:
2055               break;
2056           }
2057 #endif
2058
2059           break;
2060         }
2061
2062         case KeyPress:
2063           switch(XLookupKeysym((XKeyEvent *)&event,
2064                                ((XKeyEvent *)&event)->state))
2065           {
2066             case XK_Return:
2067               result = 1;
2068               break;
2069
2070             case XK_Escape:
2071               result = 0;
2072               break;
2073
2074             default:
2075               break;
2076           }
2077           if (req_state & REQ_PLAYER)
2078             result = 0;
2079           break;
2080
2081         case KeyRelease:
2082           key_joystick_mapping = 0;
2083           break;
2084
2085         default:
2086           HandleOtherEvents(&event);
2087           break;
2088       }
2089     }
2090     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2091     {
2092       int joy = AnyJoystick();
2093
2094       if (joy & JOY_BUTTON_1)
2095         result = 1;
2096       else if (joy & JOY_BUTTON_2)
2097         result = 0;
2098     }
2099
2100     DoAnimation();
2101
2102     /* don't eat all CPU time */
2103     Delay(10);
2104   }
2105
2106   if (game_status != MAINMENU)
2107     StopAnimation();
2108
2109   UnmapToolButtons();
2110
2111   if (!(req_state & REQ_STAY_OPEN))
2112   {
2113     CloseDoor(DOOR_CLOSE_1);
2114
2115     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2116     {
2117       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
2118                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2119                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2120       OpenDoor(DOOR_OPEN_1);
2121     }
2122   }
2123
2124   RemapAllGadgets();
2125
2126 #ifndef MSDOS
2127   /* continue network game after request */
2128   if (options.network &&
2129       game_status == PLAYING &&
2130       req_state & REQUEST_WAIT_FOR)
2131     SendToServer_ContinuePlaying();
2132 #endif
2133
2134   return(result);
2135 }
2136
2137 unsigned int OpenDoor(unsigned int door_state)
2138 {
2139   unsigned int new_door_state;
2140
2141   if (door_state & DOOR_COPY_BACK)
2142   {
2143     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
2144               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2145               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2146     door_state &= ~DOOR_COPY_BACK;
2147   }
2148
2149   new_door_state = MoveDoor(door_state);
2150
2151   return(new_door_state);
2152 }
2153
2154 unsigned int CloseDoor(unsigned int door_state)
2155 {
2156   unsigned int new_door_state;
2157
2158   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
2159             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2160   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
2161             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2162
2163   new_door_state = MoveDoor(door_state);
2164
2165   return(new_door_state);
2166 }
2167
2168 unsigned int GetDoorState()
2169 {
2170   return(MoveDoor(DOOR_GET_STATE));
2171 }
2172
2173 unsigned int MoveDoor(unsigned int door_state)
2174 {
2175   static int door1 = DOOR_OPEN_1;
2176   static int door2 = DOOR_CLOSE_2;
2177   static unsigned long door_delay = 0;
2178   int x, start, stepsize = 2;
2179   unsigned long door_delay_value = stepsize * 5;
2180
2181   if (door_state == DOOR_GET_STATE)
2182     return(door1 | door2);
2183
2184   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2185     door_state &= ~DOOR_OPEN_1;
2186   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2187     door_state &= ~DOOR_CLOSE_1;
2188   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2189     door_state &= ~DOOR_OPEN_2;
2190   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2191     door_state &= ~DOOR_CLOSE_2;
2192
2193   if (setup.quick_doors)
2194   {
2195     stepsize = 20;
2196     door_delay_value = 0;
2197     StopSound(SND_OEFFNEN);
2198   }
2199
2200   if (door_state & DOOR_ACTION)
2201   {
2202     if (!(door_state & DOOR_NO_DELAY))
2203       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
2204
2205     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2206
2207     for(x=start; x<=DXSIZE; x+=stepsize)
2208     {
2209       WaitUntilDelayReached(&door_delay, door_delay_value);
2210
2211       if (door_state & DOOR_ACTION_1)
2212       {
2213         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2214         int j = (DXSIZE - i) / 3;
2215
2216         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2217                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2218                   DXSIZE,DYSIZE - i/2, DX, DY);
2219
2220         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2221
2222         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2223                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2224         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2225                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
2226         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2227                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
2228                   DY + 140 + j);
2229         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2230                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2231         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2232                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
2233         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2234                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
2235
2236         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2237                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2238                   DX, DY + 77 - j);
2239         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2240                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2241                   DX, DY + 203 - j);
2242         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2243                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2244         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2245                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2246                   DX + DXSIZE - i, DY + 77 + j);
2247         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2248                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2249                   DX + DXSIZE - i, DY + 203 + j);
2250
2251         redraw_mask |= REDRAW_DOOR_1;
2252       }
2253
2254       if (door_state & DOOR_ACTION_2)
2255       {
2256         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2257         int j = (VXSIZE - i) / 3;
2258
2259         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2260                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2261                   VXSIZE, VYSIZE - i/2, VX, VY);
2262
2263         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2264
2265         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2266                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2267         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2268                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
2269         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2270                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2271         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2272                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
2273
2274         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2275                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
2276                   VX, VY + VYSIZE / 2 - j);
2277         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2278                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2279         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2280                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
2281                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2282
2283         redraw_mask |= REDRAW_DOOR_2;
2284       }
2285
2286
2287
2288 #if 1
2289       BackToFront();
2290 #else
2291       XCopyArea(display, drawto, window, gc, DX, DY, DXSIZE, DYSIZE, DX, DY);
2292 #endif
2293
2294
2295
2296       if (game_status == MAINMENU)
2297         DoAnimation();
2298     }
2299   }
2300
2301   if (setup.quick_doors)
2302     StopSound(SND_OEFFNEN);
2303
2304   if (door_state & DOOR_ACTION_1)
2305     door1 = door_state & DOOR_ACTION_1;
2306   if (door_state & DOOR_ACTION_2)
2307     door2 = door_state & DOOR_ACTION_2;
2308
2309   return(door1 | door2);
2310 }
2311
2312 int ReadPixel(Drawable d, int x, int y)
2313 {
2314   XImage *pixel_image;
2315   unsigned long pixel_value;
2316
2317   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
2318   pixel_value = XGetPixel(pixel_image, 0, 0);
2319
2320   XDestroyImage(pixel_image);
2321
2322   return pixel_value;
2323 }
2324
2325 /* ---------- new tool button stuff ---------------------------------------- */
2326
2327 /* graphic position values for tool buttons */
2328 #define TOOL_BUTTON_YES_XPOS            2
2329 #define TOOL_BUTTON_YES_YPOS            250
2330 #define TOOL_BUTTON_YES_GFX_YPOS        0
2331 #define TOOL_BUTTON_YES_XSIZE           46
2332 #define TOOL_BUTTON_YES_YSIZE           28
2333 #define TOOL_BUTTON_NO_XPOS             52
2334 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2335 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2336 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2337 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2338 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2339 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2340 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2341 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2342 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2343 #define TOOL_BUTTON_PLAYER_XSIZE        30
2344 #define TOOL_BUTTON_PLAYER_YSIZE        30
2345 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2346 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2347 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2348 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2349 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2350                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2351 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2352                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2353 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2354                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2355 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2356                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2357 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2358                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2359 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2360                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2361 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2362                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2363 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2364                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2365
2366 static struct
2367 {
2368   int xpos, ypos;
2369   int x, y;
2370   int width, height;
2371   int gadget_id;
2372   char *infotext;
2373 } toolbutton_info[NUM_TOOL_BUTTONS] =
2374 {
2375   {
2376     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2377     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2378     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2379     TOOL_CTRL_ID_YES,
2380     "yes"
2381   },
2382   {
2383     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2384     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2385     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2386     TOOL_CTRL_ID_NO,
2387     "no"
2388   },
2389   {
2390     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2391     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2392     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2393     TOOL_CTRL_ID_CONFIRM,
2394     "confirm"
2395   },
2396   {
2397     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2398     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2399     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2400     TOOL_CTRL_ID_PLAYER_1,
2401     "player 1"
2402   },
2403   {
2404     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2405     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2406     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2407     TOOL_CTRL_ID_PLAYER_2,
2408     "player 2"
2409   },
2410   {
2411     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2412     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2413     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2414     TOOL_CTRL_ID_PLAYER_3,
2415     "player 3"
2416   },
2417   {
2418     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2419     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2420     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2421     TOOL_CTRL_ID_PLAYER_4,
2422     "player 4"
2423   }
2424 };
2425
2426 void CreateToolButtons()
2427 {
2428   int i;
2429
2430   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2431   {
2432     Pixmap gd_pixmap = pix[PIX_DOOR];
2433     Pixmap deco_pixmap = 0;
2434     int deco_x, deco_y, deco_xpos, deco_ypos;
2435     struct GadgetInfo *gi;
2436     unsigned long event_mask;
2437     int gd_xoffset, gd_yoffset;
2438     int gd_x1, gd_x2, gd_y;
2439     int id = i;
2440
2441     event_mask = GD_EVENT_RELEASED;
2442
2443     gd_xoffset = toolbutton_info[i].xpos;
2444     gd_yoffset = toolbutton_info[i].ypos;
2445     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2446     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2447     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2448
2449     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2450     {
2451       getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
2452                            &deco_pixmap, &deco_x, &deco_y);
2453       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2454       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2455     }
2456
2457     gi = CreateGadget(GDI_CUSTOM_ID, id,
2458                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2459                       GDI_X, DX + toolbutton_info[i].x,
2460                       GDI_Y, DY + toolbutton_info[i].y,
2461                       GDI_WIDTH, toolbutton_info[i].width,
2462                       GDI_HEIGHT, toolbutton_info[i].height,
2463                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2464                       GDI_STATE, GD_BUTTON_UNPRESSED,
2465                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
2466                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
2467                       GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
2468                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2469                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2470                       GDI_DECORATION_SHIFTING, 1, 1,
2471                       GDI_EVENT_MASK, event_mask,
2472                       GDI_CALLBACK_ACTION, HandleToolButtons,
2473                       GDI_END);
2474
2475     if (gi == NULL)
2476       Error(ERR_EXIT, "cannot create gadget");
2477
2478     tool_gadget[id] = gi;
2479   }
2480 }
2481
2482 static void UnmapToolButtons()
2483 {
2484   int i;
2485
2486   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2487     UnmapGadget(tool_gadget[i]);
2488 }
2489
2490 static void HandleToolButtons(struct GadgetInfo *gi)
2491 {
2492   request_gadget_id = gi->custom_id;
2493
2494
2495 #if 0
2496   int id = gi->custom_id;
2497
2498   if (game_status != PLAYING)
2499     return;
2500
2501   switch (id)
2502   {
2503     case GAME_CTRL_ID_STOP:
2504       if (AllPlayersGone)
2505       {
2506         CloseDoor(DOOR_CLOSE_1);
2507         game_status = MAINMENU;
2508         DrawMainMenu();
2509         break;
2510       }
2511
2512       if (Request("Do you really want to quit the game ?",
2513                   REQ_ASK | REQ_STAY_CLOSED))
2514       { 
2515 #ifndef MSDOS
2516         if (options.network)
2517           SendToServer_StopPlaying();
2518         else
2519 #endif
2520         {
2521           game_status = MAINMENU;
2522           DrawMainMenu();
2523         }
2524       }
2525       else
2526         OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2527       break;
2528
2529     case GAME_CTRL_ID_PAUSE:
2530       if (options.network)
2531       {
2532 #ifndef MSDOS
2533         if (tape.pausing)
2534           SendToServer_ContinuePlaying();
2535         else
2536           SendToServer_PausePlaying();
2537 #endif
2538       }
2539       else
2540         TapeTogglePause();
2541       break;
2542
2543     case GAME_CTRL_ID_PLAY:
2544       if (tape.pausing)
2545       {
2546 #ifndef MSDOS
2547         if (options.network)
2548           SendToServer_ContinuePlaying();
2549         else
2550 #endif
2551         {
2552           tape.pausing = FALSE;
2553           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
2554         }
2555       }
2556       break;
2557
2558     case SOUND_CTRL_ID_MUSIC:
2559       if (setup.sound_music)
2560       { 
2561         setup.sound_music = FALSE;
2562         FadeSound(background_loop[level_nr % num_bg_loops]);
2563       }
2564       else if (sound_loops_allowed)
2565       { 
2566         setup.sound = setup.sound_music = TRUE;
2567         PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
2568       }
2569       break;
2570
2571     case SOUND_CTRL_ID_LOOPS:
2572       if (setup.sound_loops)
2573         setup.sound_loops = FALSE;
2574       else if (sound_loops_allowed)
2575         setup.sound = setup.sound_loops = TRUE;
2576       break;
2577
2578     case SOUND_CTRL_ID_SIMPLE:
2579       if (setup.sound_simple)
2580         setup.sound_simple = FALSE;
2581       else if (sound_status==SOUND_AVAILABLE)
2582         setup.sound = setup.sound_simple = TRUE;
2583       break;
2584
2585     default:
2586       break;
2587   }
2588 #endif
2589
2590
2591
2592 }
2593
2594 int el2gfx(int element)
2595 {
2596   switch(element)
2597   {
2598     case EL_LEERRAUM:           return -1;
2599     case EL_ERDREICH:           return GFX_ERDREICH;
2600     case EL_MAUERWERK:          return GFX_MAUERWERK;
2601     case EL_FELSBODEN:          return GFX_FELSBODEN;
2602     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
2603     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
2604     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
2605     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
2606     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
2607     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
2608     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
2609     case EL_SPIELER1:           return GFX_SPIELER1;
2610     case EL_SPIELER2:           return GFX_SPIELER2;
2611     case EL_SPIELER3:           return GFX_SPIELER3;
2612     case EL_SPIELER4:           return GFX_SPIELER4;
2613     case EL_KAEFER:             return GFX_KAEFER;
2614     case EL_KAEFER_R:           return GFX_KAEFER_R;
2615     case EL_KAEFER_O:           return GFX_KAEFER_O;
2616     case EL_KAEFER_L:           return GFX_KAEFER_L;
2617     case EL_KAEFER_U:           return GFX_KAEFER_U;
2618     case EL_FLIEGER:            return GFX_FLIEGER;
2619     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
2620     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
2621     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
2622     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
2623     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
2624     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
2625     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
2626     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
2627     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
2628     case EL_FIREFLY:            return GFX_FIREFLY;
2629     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
2630     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
2631     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
2632     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
2633     case EL_MAMPFER:            return GFX_MAMPFER;
2634     case EL_ROBOT:              return GFX_ROBOT;
2635     case EL_BETON:              return GFX_BETON;
2636     case EL_DIAMANT:            return GFX_DIAMANT;
2637     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2638     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2639     case EL_TROPFEN:            return GFX_TROPFEN;
2640     case EL_BOMBE:              return GFX_BOMBE;
2641     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
2642     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
2643     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
2644     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
2645     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2646     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2647     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2648     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2649     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2650     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2651     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2652     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2653     case EL_LIFE:               return GFX_LIFE;
2654     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2655     case EL_DYNAMIT:            return GFX_DYNAMIT;
2656     case EL_BADEWANNE:          return GFX_BADEWANNE;
2657     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2658     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2659     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2660     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2661     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2662     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2663     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2664     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2665     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2666     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2667     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2668     case EL_PFORTE1:            return GFX_PFORTE1;
2669     case EL_PFORTE2:            return GFX_PFORTE2;
2670     case EL_PFORTE3:            return GFX_PFORTE3;
2671     case EL_PFORTE4:            return GFX_PFORTE4;
2672     case EL_PFORTE1X:           return GFX_PFORTE1X;
2673     case EL_PFORTE2X:           return GFX_PFORTE2X;
2674     case EL_PFORTE3X:           return GFX_PFORTE3X;
2675     case EL_PFORTE4X:           return GFX_PFORTE4X;
2676     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
2677     case EL_PACMAN:             return GFX_PACMAN;
2678     case EL_PACMAN_R:           return GFX_PACMAN_R;
2679     case EL_PACMAN_O:           return GFX_PACMAN_O;
2680     case EL_PACMAN_L:           return GFX_PACMAN_L;
2681     case EL_PACMAN_U:           return GFX_PACMAN_U;
2682     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2683     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2684     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2685     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2686     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2687     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2688     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2689     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2690     case EL_MAUER_X:            return GFX_MAUER_X;
2691     case EL_MAUER_Y:            return GFX_MAUER_Y;
2692     case EL_MAUER_XY:           return GFX_MAUER_XY;
2693     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2694     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2695     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2696     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2697     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2698     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2699     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2700     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2701     case EL_MAMPFER2:           return GFX_MAMPFER2;
2702     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
2703     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
2704     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
2705     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
2706     case EL_DYNABOMB:           return GFX_DYNABOMB;
2707     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2708     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2709     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2710     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2711     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2712     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2713     case EL_MAULWURF:           return GFX_MAULWURF;
2714     case EL_PINGUIN:            return GFX_PINGUIN;
2715     case EL_SCHWEIN:            return GFX_SCHWEIN;
2716     case EL_DRACHE:             return GFX_DRACHE;
2717     case EL_SONDE:              return GFX_SONDE;
2718     case EL_PFEIL_L:            return GFX_PFEIL_L;
2719     case EL_PFEIL_R:            return GFX_PFEIL_R;
2720     case EL_PFEIL_O:            return GFX_PFEIL_O;
2721     case EL_PFEIL_U:            return GFX_PFEIL_U;
2722     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2723     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2724     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2725     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2726     case EL_BLACK_ORB:          return GFX_BLACK_ORB;
2727
2728     default:
2729     {
2730       if (IS_CHAR(element))
2731         return GFX_CHAR_START + (element - EL_CHAR_START);
2732       else if (element >= EL_SP_START && element <= EL_SP_END)
2733       {
2734         int nr_element = element - EL_SP_START;
2735         int gfx_per_line = 8;
2736         int nr_graphic =
2737           (nr_element / gfx_per_line) * MORE_PER_LINE +
2738           (nr_element % gfx_per_line);
2739
2740         return GFX_START_ROCKSMORE + nr_graphic;
2741       }
2742       else
2743         return -1;
2744     }
2745   }
2746 }