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