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