rnd-19990925-2-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_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
805   {
806     graphic -= GFX_START_ROCKSFONT;
807     *pixmap_nr = PIX_BIGFONT;
808     *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
809     *y = ((graphic / FONT_CHARS_PER_LINE) * TILEY +
810           FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY);
811   }
812   else
813   {
814     *pixmap_nr = PIX_SP;
815     *x = 0;
816     *y = 0;
817   }
818 }
819
820 void DrawGraphic(int x, int y, int graphic)
821 {
822 #if DEBUG
823   if (!IN_SCR_FIELD(x,y))
824   {
825     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
826     printf("DrawGraphic(): This should never happen!\n");
827     return;
828   }
829 #endif
830
831   DrawGraphicExt(drawto_field, gc, FX + x*TILEX, FY + y*TILEY, graphic);
832   MarkTileDirty(x,y);
833 }
834
835 void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
836 {
837   int pixmap_nr;
838   int src_x, src_y;
839
840   getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
841   XCopyArea(display, pix[pixmap_nr], d, gc,
842             src_x, src_y, TILEX, TILEY, x, y);
843 }
844
845 void DrawGraphicThruMask(int x, int y, int graphic)
846 {
847 #if DEBUG
848   if (!IN_SCR_FIELD(x,y))
849   {
850     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
851     printf("DrawGraphicThruMask(): This should never happen!\n");
852     return;
853   }
854 #endif
855
856   DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
857   MarkTileDirty(x,y);
858 }
859
860 void DrawGraphicThruMaskExt(Drawable d, int dest_x, int dest_y, int graphic)
861 {
862   int tile = graphic;
863   int pixmap_nr;
864   int src_x, src_y;
865   Pixmap src_pixmap;
866   GC drawing_gc;
867
868   if (graphic == GFX_LEERRAUM)
869     return;
870
871   getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
872   src_pixmap = pix[pixmap_nr];
873   drawing_gc = clip_gc[pixmap_nr];
874
875   if (tile_clipmask[tile] != None)
876   {
877     XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
878     XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
879     XCopyArea(display, src_pixmap, d, tile_clip_gc,
880               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
881   }
882   else
883   {
884 #if DEBUG
885     printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
886 #endif
887
888     XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y);
889     XCopyArea(display, src_pixmap, d, drawing_gc,
890               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
891   }
892 }
893
894 void DrawMiniGraphic(int x, int y, int graphic)
895 {
896   DrawMiniGraphicExt(drawto,gc, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
897   MarkTileDirty(x/2, y/2);
898 }
899
900 void getMiniGraphicSource(int graphic, Pixmap *pixmap, int *x, int *y)
901 {
902   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
903   {
904     graphic -= GFX_START_ROCKSSCREEN;
905     *pixmap = pix[PIX_BACK];
906     *x = MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX;
907     *y = MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY;
908   }
909   else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
910   {
911     graphic -= GFX_START_ROCKSSP;
912     graphic -= ((graphic / SP_PER_LINE) * SP_PER_LINE) / 2;
913     *pixmap = pix[PIX_SP];
914     *x = MINI_SP_STARTX + (graphic % MINI_SP_PER_LINE) * MINI_TILEX;
915     *y = MINI_SP_STARTY + (graphic / MINI_SP_PER_LINE) * MINI_TILEY;
916   }
917   else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
918   {
919     graphic -= GFX_START_ROCKSDC;
920     *pixmap = pix[PIX_DC];
921     *x = MINI_DC_STARTX + (graphic % MINI_DC_PER_LINE) * MINI_TILEX;
922     *y = MINI_DC_STARTY + (graphic / MINI_DC_PER_LINE) * MINI_TILEY;
923   }
924   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
925   {
926     graphic -= GFX_START_ROCKSFONT;
927     *pixmap = pix[PIX_SMALLFONT];
928     *x = (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE;
929     *y = ((graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
930               FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT);
931   }
932   else
933   {
934     *pixmap = pix[PIX_SP];
935     *x = MINI_SP_STARTX;
936     *y = MINI_SP_STARTY;
937   }
938 }
939
940 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
941 {
942   Pixmap pixmap;
943   int src_x, src_y;
944
945   getMiniGraphicSource(graphic, &pixmap, &src_x, &src_y);
946   XCopyArea(display, pixmap, d, gc,
947             src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
948 }
949
950 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
951                         int cut_mode, int mask_mode)
952 {
953   int width = TILEX, height = TILEY;
954   int cx = 0, cy = 0;
955   int src_x, src_y, dest_x, dest_y;
956   int tile = graphic;
957   int pixmap_nr;
958   Pixmap src_pixmap;
959   GC drawing_gc;
960
961   if (graphic < 0)
962   {
963     DrawGraphic(x, y, graphic);
964     return;
965   }
966
967   if (dx || dy)                 /* Verschiebung der Grafik? */
968   {
969     if (x < BX1)                /* Element kommt von links ins Bild */
970     {
971       x = BX1;
972       width = dx;
973       cx = TILEX - dx;
974       dx = 0;
975     }
976     else if (x > BX2)           /* Element kommt von rechts ins Bild */
977     {
978       x = BX2;
979       width = -dx;
980       dx = TILEX + dx;
981     }
982     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
983     {
984       width += dx;
985       cx = -dx;
986       dx = 0;
987     }
988     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
989       width -= dx;
990     else if (dx)                /* allg. Bewegung in x-Richtung */
991       MarkTileDirty(x + SIGN(dx), y);
992
993     if (y < BY1)                /* Element kommt von oben ins Bild */
994     {
995       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
996         return;
997
998       y = BY1;
999       height = dy;
1000       cy = TILEY - dy;
1001       dy = 0;
1002     }
1003     else if (y > BY2)           /* Element kommt von unten ins Bild */
1004     {
1005       y = BY2;
1006       height = -dy;
1007       dy = TILEY + dy;
1008     }
1009     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
1010     {
1011       height += dy;
1012       cy = -dy;
1013       dy = 0;
1014     }
1015     else if (dy > 0 && cut_mode == CUT_ABOVE)
1016     {
1017       if (y == BY2)             /* Element unterhalb des Bildes */
1018         return;
1019
1020       height = dy;
1021       cy = TILEY - dy;
1022       dy = TILEY;
1023       MarkTileDirty(x, y + 1);
1024     }                           /* Element verläßt unten das Bild */
1025     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1026       height -= dy;
1027     else if (dy)                /* allg. Bewegung in y-Richtung */
1028       MarkTileDirty(x, y + SIGN(dy));
1029   }
1030
1031   getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
1032   src_pixmap = pix[pixmap_nr];
1033   drawing_gc = clip_gc[pixmap_nr];
1034
1035   src_x += cx;
1036   src_y += cy;
1037
1038   dest_x = FX + x * TILEX + dx;
1039   dest_y = FY + y * TILEY + dy;
1040
1041 #if DEBUG
1042   if (!IN_SCR_FIELD(x,y))
1043   {
1044     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1045     printf("DrawGraphicShifted(): This should never happen!\n");
1046     return;
1047   }
1048 #endif
1049
1050   if (mask_mode == USE_MASKING)
1051   {
1052     if (tile_clipmask[tile] != None)
1053     {
1054       XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
1055       XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
1056       XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
1057                 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1058     }
1059     else
1060     {
1061 #if DEBUG
1062       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
1063 #endif
1064
1065       XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
1066       XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
1067                 src_x, src_y, width, height, dest_x, dest_y);
1068     }
1069   }
1070   else
1071     XCopyArea(display, src_pixmap, drawto_field, gc,
1072               src_x, src_y, width, height, dest_x, dest_y);
1073
1074   MarkTileDirty(x,y);
1075 }
1076
1077 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1078                                 int cut_mode)
1079 {
1080   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
1081 }
1082
1083 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1084                           int cut_mode, int mask_mode)
1085 {
1086   int ux = LEVELX(x), uy = LEVELY(y);
1087   int graphic = el2gfx(element);
1088   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1089   int phase4 = phase8 / 2;
1090   int phase2  = phase8 / 4;
1091   int dir = MovDir[ux][uy];
1092
1093   if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
1094   {
1095     graphic += 4 * !phase2;
1096
1097     if (dir == MV_UP)
1098       graphic += 1;
1099     else if (dir == MV_LEFT)
1100       graphic += 2;
1101     else if (dir == MV_DOWN)
1102       graphic += 3;
1103   }
1104   else if (element == EL_SP_SNIKSNAK)
1105   {
1106     if (dir == MV_LEFT)
1107       graphic = GFX_SP_SNIKSNAK_LEFT;
1108     else if (dir == MV_RIGHT)
1109       graphic = GFX_SP_SNIKSNAK_RIGHT;
1110     else if (dir == MV_UP)
1111       graphic = GFX_SP_SNIKSNAK_UP;
1112     else
1113       graphic = GFX_SP_SNIKSNAK_DOWN;
1114
1115     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1116   }
1117   else if (element == EL_SP_ELECTRON)
1118   {
1119     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1120   }
1121   else if (element == EL_MOLE || element == EL_PINGUIN ||
1122            element == EL_SCHWEIN || element == EL_DRACHE)
1123   {
1124     if (dir == MV_LEFT)
1125       graphic = (element == EL_MOLE ? GFX_MOLE_LEFT :
1126                  element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
1127                  element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1128     else if (dir == MV_RIGHT)
1129       graphic = (element == EL_MOLE ? GFX_MOLE_RIGHT :
1130                  element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
1131                  element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1132     else if (dir == MV_UP)
1133       graphic = (element == EL_MOLE ? GFX_MOLE_UP :
1134                  element == EL_PINGUIN ? GFX_PINGUIN_UP :
1135                  element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1136     else
1137       graphic = (element == EL_MOLE ? GFX_MOLE_DOWN :
1138                  element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
1139                  element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1140
1141     graphic += phase4;
1142   }
1143   else if (element == EL_SONDE)
1144   {
1145     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1146   }
1147   else if (element == EL_SALZSAEURE)
1148   {
1149     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
1150   }
1151   else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1152   {
1153     graphic += !phase2;
1154   }
1155   else if (element == EL_BALLOON)
1156   {
1157     graphic += phase4;
1158   }
1159   else if ((element == EL_FELSBROCKEN || element == EL_SP_ZONK ||
1160             IS_GEM(element)) && !cut_mode)
1161   {
1162     if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1163     {
1164       if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
1165       {
1166         if (dir == MV_LEFT)
1167           graphic += (4 - phase4) % 4;
1168         else if (dir == MV_RIGHT)
1169           graphic += phase4;
1170         else
1171           graphic += phase2 * 2;
1172       }
1173       else if (element != EL_SP_INFOTRON)
1174         graphic += phase2;
1175     }
1176   }
1177   else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
1178            element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
1179   {
1180     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1181   }
1182   else if (IS_AMOEBOID(element))
1183   {
1184     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1185     graphic += (x + 2 * y + 4) % 4;
1186   }
1187   else if (element == EL_MAUER_LEBT)
1188   {
1189     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1190
1191     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1192       links_massiv = TRUE;
1193     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1194       rechts_massiv = TRUE;
1195
1196     if (links_massiv && rechts_massiv)
1197       graphic = GFX_MAUERWERK;
1198     else if (links_massiv)
1199       graphic = GFX_MAUER_R;
1200     else if (rechts_massiv)
1201       graphic = GFX_MAUER_L;
1202   }
1203   else if ((element == EL_INVISIBLE_STEEL ||
1204             element == EL_UNSICHTBAR ||
1205             element == EL_SAND_INVISIBLE) && game.light_time_left)
1206   {
1207     graphic = (element == EL_INVISIBLE_STEEL ? GFX_INVISIBLE_STEEL_ON :
1208                element == EL_UNSICHTBAR ? GFX_UNSICHTBAR_ON :
1209                GFX_SAND_INVISIBLE_ON);
1210   }
1211
1212   if (dx || dy)
1213     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1214   else if (mask_mode == USE_MASKING)
1215     DrawGraphicThruMask(x, y, graphic);
1216   else
1217     DrawGraphic(x, y, graphic);
1218 }
1219
1220 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1221                          int cut_mode, int mask_mode)
1222 {
1223   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1224     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1225                          cut_mode, mask_mode);
1226 }
1227
1228 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1229                               int cut_mode)
1230 {
1231   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1232 }
1233
1234 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1235                              int cut_mode)
1236 {
1237   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1238 }
1239
1240 void DrawScreenElementThruMask(int x, int y, int element)
1241 {
1242   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1243 }
1244
1245 void DrawLevelElementThruMask(int x, int y, int element)
1246 {
1247   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1248 }
1249
1250 void DrawLevelFieldThruMask(int x, int y)
1251 {
1252   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1253 }
1254
1255 void ErdreichAnbroeckeln(int x, int y)
1256 {
1257   int i, width, height, cx,cy;
1258   int ux = LEVELX(x), uy = LEVELY(y);
1259   int element, graphic;
1260   int snip = 4;
1261   static int xy[4][2] =
1262   {
1263     { 0, -1 },
1264     { -1, 0 },
1265     { +1, 0 },
1266     { 0, +1 }
1267   };
1268
1269   if (!IN_LEV_FIELD(ux, uy))
1270     return;
1271
1272   element = Feld[ux][uy];
1273
1274   if (element == EL_ERDREICH || element == EL_LANDMINE)
1275   {
1276     if (!IN_SCR_FIELD(x, y))
1277       return;
1278
1279     graphic = GFX_ERDENRAND;
1280
1281     for(i=0; i<4; i++)
1282     {
1283       int uxx, uyy;
1284
1285       uxx = ux + xy[i][0];
1286       uyy = uy + xy[i][1];
1287       if (!IN_LEV_FIELD(uxx, uyy))
1288         element = EL_BETON;
1289       else
1290         element = Feld[uxx][uyy];
1291
1292       if (element == EL_ERDREICH || element == EL_LANDMINE)
1293         continue;
1294
1295       if (i == 1 || i == 2)
1296       {
1297         width = snip;
1298         height = TILEY;
1299         cx = (i == 2 ? TILEX - snip : 0);
1300         cy = 0;
1301       }
1302       else
1303       {
1304         width = TILEX;
1305         height = snip;
1306         cx = 0;
1307         cy = (i == 3 ? TILEY - snip : 0);
1308       }
1309
1310       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1311                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1312                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1313                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1314     }
1315
1316     MarkTileDirty(x, y);
1317   }
1318   else
1319   {
1320     graphic = GFX_ERDENRAND;
1321
1322     for(i=0; i<4; i++)
1323     {
1324       int xx, yy, uxx, uyy;
1325
1326       xx = x + xy[i][0];
1327       yy = y + xy[i][1];
1328       uxx = ux + xy[i][0];
1329       uyy = uy + xy[i][1];
1330
1331       if (!IN_LEV_FIELD(uxx, uyy) ||
1332           (Feld[uxx][uyy] != EL_ERDREICH && Feld[uxx][uyy] != EL_LANDMINE) ||
1333           !IN_SCR_FIELD(xx, yy))
1334         continue;
1335
1336       if (i == 1 || i == 2)
1337       {
1338         width = snip;
1339         height = TILEY;
1340         cx = (i == 1 ? TILEX - snip : 0);
1341         cy = 0;
1342       }
1343       else
1344       {
1345         width = TILEX;
1346         height = snip;
1347         cx = 0;
1348         cy = (i==0 ? TILEY-snip : 0);
1349       }
1350
1351       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1352                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1353                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1354                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1355
1356       MarkTileDirty(xx, yy);
1357     }
1358   }
1359 }
1360
1361 void DrawScreenElement(int x, int y, int element)
1362 {
1363   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1364   ErdreichAnbroeckeln(x, y);
1365 }
1366
1367 void DrawLevelElement(int x, int y, int element)
1368 {
1369   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1370     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1371 }
1372
1373 void DrawScreenField(int x, int y)
1374 {
1375   int ux = LEVELX(x), uy = LEVELY(y);
1376   int element;
1377
1378   if (!IN_LEV_FIELD(ux, uy))
1379   {
1380     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1381       element = EL_LEERRAUM;
1382     else
1383       element = BorderElement;
1384
1385     DrawScreenElement(x, y, element);
1386     return;
1387   }
1388
1389   element = Feld[ux][uy];
1390
1391   if (IS_MOVING(ux, uy))
1392   {
1393     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1394     boolean cut_mode = NO_CUTTING;
1395
1396     if (Store[ux][uy] == EL_MORAST_LEER ||
1397         Store[ux][uy] == EL_SIEB_LEER ||
1398         Store[ux][uy] == EL_SIEB2_LEER ||
1399         Store[ux][uy] == EL_AMOEBE_NASS)
1400       cut_mode = CUT_ABOVE;
1401     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1402              Store[ux][uy] == EL_SIEB_VOLL ||
1403              Store[ux][uy] == EL_SIEB2_VOLL)
1404       cut_mode = CUT_BELOW;
1405
1406     if (cut_mode == CUT_ABOVE)
1407       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1408     else
1409       DrawScreenElement(x, y, EL_LEERRAUM);
1410
1411     if (horiz_move)
1412       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1413     else
1414       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1415
1416     if (Store[ux][uy] == EL_SALZSAEURE)
1417       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1418   }
1419   else if (IS_BLOCKED(ux, uy))
1420   {
1421     int oldx, oldy;
1422     int sx, sy;
1423     int horiz_move;
1424     boolean cut_mode = NO_CUTTING;
1425
1426     Blocked2Moving(ux, uy, &oldx, &oldy);
1427     sx = SCREENX(oldx);
1428     sy = SCREENY(oldy);
1429     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1430                   MovDir[oldx][oldy] == MV_RIGHT);
1431
1432     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1433         Store[oldx][oldy] == EL_SIEB_LEER ||
1434         Store[oldx][oldy] == EL_SIEB2_LEER ||
1435         Store[oldx][oldy] == EL_AMOEBE_NASS)
1436       cut_mode = CUT_ABOVE;
1437
1438     DrawScreenElement(x, y, EL_LEERRAUM);
1439     element = Feld[oldx][oldy];
1440
1441     if (horiz_move)
1442       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1443     else
1444       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1445   }
1446   else if (IS_DRAWABLE(element))
1447     DrawScreenElement(x, y, element);
1448   else
1449     DrawScreenElement(x, y, EL_LEERRAUM);
1450 }
1451
1452 void DrawLevelField(int x, int y)
1453 {
1454   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1455     DrawScreenField(SCREENX(x), SCREENY(y));
1456   else if (IS_MOVING(x, y))
1457   {
1458     int newx,newy;
1459
1460     Moving2Blocked(x, y, &newx, &newy);
1461     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1462       DrawScreenField(SCREENX(newx), SCREENY(newy));
1463   }
1464   else if (IS_BLOCKED(x, y))
1465   {
1466     int oldx, oldy;
1467
1468     Blocked2Moving(x, y, &oldx, &oldy);
1469     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1470       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1471   }
1472 }
1473
1474 void DrawMiniElement(int x, int y, int element)
1475 {
1476   int graphic;
1477
1478   if (!element)
1479   {
1480     DrawMiniGraphic(x, y, -1);
1481     return;
1482   }
1483
1484   graphic = el2gfx(element);
1485   DrawMiniGraphic(x, y, graphic);
1486 }
1487
1488 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1489 {
1490   int x = sx + scroll_x, y = sy + scroll_y;
1491
1492   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1493     DrawMiniElement(sx, sy, EL_LEERRAUM);
1494   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1495     DrawMiniElement(sx, sy, Feld[x][y]);
1496   else
1497   {
1498     int steel_type, steel_position;
1499     int border[6][2] =
1500     {
1501       { GFX_VSTEEL_UPPER_LEFT,  GFX_ISTEEL_UPPER_LEFT  },
1502       { GFX_VSTEEL_UPPER_RIGHT, GFX_ISTEEL_UPPER_RIGHT },
1503       { GFX_VSTEEL_LOWER_LEFT,  GFX_ISTEEL_LOWER_LEFT  },
1504       { GFX_VSTEEL_LOWER_RIGHT, GFX_ISTEEL_LOWER_RIGHT },
1505       { GFX_VSTEEL_VERTICAL,    GFX_ISTEEL_VERTICAL    },
1506       { GFX_VSTEEL_HORIZONTAL,  GFX_ISTEEL_HORIZONTAL  }
1507     };
1508
1509     steel_type = (BorderElement == EL_BETON ? 0 : 1);
1510     steel_position = (x == -1 && y == -1                        ? 0 :
1511                       x == lev_fieldx && y == -1                ? 1 :
1512                       x == -1 && y == lev_fieldy                ? 2 :
1513                       x == lev_fieldx && y == lev_fieldy        ? 3 :
1514                       x == -1 || x == lev_fieldx                ? 4 :
1515                       y == -1 || y == lev_fieldy                ? 5 : -1);
1516
1517     if (steel_position != -1)
1518       DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1519   }
1520 }
1521
1522 void DrawMicroElement(int xpos, int ypos, int element)
1523 {
1524   int graphic;
1525
1526   if (element == EL_LEERRAUM)
1527     return;
1528
1529   graphic = el2gfx(element);
1530
1531   if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
1532   {
1533     graphic -= GFX_START_ROCKSSP;
1534     graphic -= ((graphic / SP_PER_LINE) * SP_PER_LINE) / 2;
1535     XCopyArea(display, pix[PIX_SP], drawto, gc,
1536               MICRO_SP_STARTX + (graphic % MICRO_SP_PER_LINE) * MICRO_TILEX,
1537               MICRO_SP_STARTY + (graphic / MICRO_SP_PER_LINE) * MICRO_TILEY,
1538               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1539   }
1540   else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
1541   {
1542     graphic -= GFX_START_ROCKSDC;
1543     XCopyArea(display, pix[PIX_DC], drawto, gc,
1544               MICRO_DC_STARTX + (graphic % MICRO_DC_PER_LINE) * MICRO_TILEX,
1545               MICRO_DC_STARTY + (graphic / MICRO_DC_PER_LINE) * MICRO_TILEY,
1546               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1547   }
1548   else
1549     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1550               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1551               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1552               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1553 }
1554
1555 void DrawLevel()
1556 {
1557   int x,y;
1558
1559   ClearWindow();
1560
1561   for(x=BX1; x<=BX2; x++)
1562     for(y=BY1; y<=BY2; y++)
1563       DrawScreenField(x, y);
1564
1565   redraw_mask |= REDRAW_FIELD;
1566 }
1567
1568 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1569 {
1570   int x,y;
1571
1572   for(x=0; x<size_x; x++)
1573     for(y=0; y<size_y; y++)
1574       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1575
1576   redraw_mask |= REDRAW_FIELD;
1577 }
1578
1579 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1580 {
1581   int x, y;
1582
1583   XFillRectangle(display, drawto, gc,
1584                  xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1585
1586   if (lev_fieldx < STD_LEV_FIELDX)
1587     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1588   if (lev_fieldy < STD_LEV_FIELDY)
1589     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1590
1591   xpos += MICRO_TILEX;
1592   ypos += MICRO_TILEY;
1593
1594   for(x=-1; x<=STD_LEV_FIELDX; x++)
1595   {
1596     for(y=-1; y<=STD_LEV_FIELDY; y++)
1597     {
1598       int lx = from_x + x, ly = from_y + y;
1599
1600       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1601         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1602                          Ur[lx][ly]);
1603       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1604         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1605                          BorderElement);
1606     }
1607   }
1608
1609   redraw_mask |= REDRAW_MICROLEVEL;
1610 }
1611
1612 #define MICROLABEL_EMPTY                0
1613 #define MICROLABEL_LEVEL_NAME           1
1614 #define MICROLABEL_CREATED_BY           2
1615 #define MICROLABEL_LEVEL_AUTHOR         3
1616 #define MICROLABEL_IMPORTED_FROM        4
1617 #define MICROLABEL_LEVEL_IMPORT_INFO    5
1618
1619 #define MAX_MICROLABEL_SIZE             (SXSIZE / FONT4_XSIZE)
1620
1621 static void DrawMicroLevelLabelExt(int mode)
1622 {
1623   char label_text[MAX_MICROLABEL_SIZE + 1];
1624
1625   XFillRectangle(display, drawto,gc,
1626                  SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1627
1628   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1629                        mode == MICROLABEL_CREATED_BY ? "created by" :
1630                        mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1631                        mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1632                        mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1633                        leveldir[leveldir_nr].imported_from : ""),
1634           MAX_MICROLABEL_SIZE);
1635   label_text[MAX_MICROLABEL_SIZE] = '\0';
1636
1637   if (strlen(label_text) > 0)
1638   {
1639     int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1640     int lypos = MICROLABEL_YPOS;
1641
1642     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1643   }
1644
1645   redraw_mask |= REDRAW_MICROLEVEL;
1646 }
1647
1648 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1649 {
1650   static unsigned long scroll_delay = 0;
1651   static unsigned long label_delay = 0;
1652   static int from_x, from_y, scroll_direction;
1653   static int label_state, label_counter;
1654
1655   if (restart)
1656   {
1657     from_x = from_y = 0;
1658     scroll_direction = MV_RIGHT;
1659     label_state = 1;
1660     label_counter = 0;
1661
1662     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1663     DrawMicroLevelLabelExt(label_state);
1664
1665     /* initialize delay counters */
1666     DelayReached(&scroll_delay, 0);
1667     DelayReached(&label_delay, 0);
1668
1669     return;
1670   }
1671
1672   /* scroll micro level, if needed */
1673   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1674       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1675   {
1676     switch (scroll_direction)
1677     {
1678       case MV_LEFT:
1679         if (from_x > 0)
1680           from_x--;
1681         else
1682           scroll_direction = MV_UP;
1683         break;
1684
1685       case MV_RIGHT:
1686         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1687           from_x++;
1688         else
1689           scroll_direction = MV_DOWN;
1690         break;
1691
1692       case MV_UP:
1693         if (from_y > 0)
1694           from_y--;
1695         else
1696           scroll_direction = MV_RIGHT;
1697         break;
1698
1699       case MV_DOWN:
1700         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1701           from_y++;
1702         else
1703           scroll_direction = MV_LEFT;
1704         break;
1705
1706       default:
1707         break;
1708     }
1709
1710     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1711   }
1712
1713   /* redraw micro level label, if needed */
1714   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1715       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1716       strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
1717       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1718   {
1719     int max_label_counter = 23;
1720
1721     if (leveldir[leveldir_nr].imported_from != NULL)
1722       max_label_counter += 14;
1723
1724     label_counter = (label_counter + 1) % max_label_counter;
1725     label_state = (label_counter >= 0 && label_counter <= 7 ?
1726                    MICROLABEL_LEVEL_NAME :
1727                    label_counter >= 9 && label_counter <= 12 ?
1728                    MICROLABEL_CREATED_BY :
1729                    label_counter >= 14 && label_counter <= 21 ?
1730                    MICROLABEL_LEVEL_AUTHOR :
1731                    label_counter >= 23 && label_counter <= 26 ?
1732                    MICROLABEL_IMPORTED_FROM :
1733                    label_counter >= 28 && label_counter <= 35 ?
1734                    MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1735     DrawMicroLevelLabelExt(label_state);
1736   }
1737 }
1738
1739 int REQ_in_range(int x, int y)
1740 {
1741   if (y > DY+249 && y < DY+278)
1742   {
1743     if (x > DX+1 && x < DX+48)
1744       return 1;
1745     else if (x > DX+51 && x < DX+98) 
1746       return 2;
1747   }
1748   return 0;
1749 }
1750
1751 boolean Request(char *text, unsigned int req_state)
1752 {
1753   int mx, my, ty, result = -1;
1754   unsigned int old_door_state;
1755
1756 #ifndef MSDOS
1757   /* pause network game while waiting for request to answer */
1758   if (options.network &&
1759       game_status == PLAYING &&
1760       req_state & REQUEST_WAIT_FOR)
1761     SendToServer_PausePlaying();
1762 #endif
1763
1764   old_door_state = GetDoorState();
1765
1766   UnmapAllGadgets();
1767
1768   CloseDoor(DOOR_CLOSE_1);
1769
1770   /* save old door content */
1771   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1772             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1773             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1774
1775   /* clear door drawing field */
1776   XFillRectangle(display, drawto, gc, DX, DY, DXSIZE, DYSIZE);
1777
1778   /* write text for request */
1779   for(ty=0; ty<13; ty++)
1780   {
1781     int tx, tl, tc;
1782     char txt[256];
1783
1784     if (!*text)
1785       break;
1786
1787     for(tl=0,tx=0; tx<7; tl++,tx++)
1788     {
1789       tc = *(text + tx);
1790       if (!tc || tc == 32)
1791         break;
1792     }
1793     if (!tl)
1794     { 
1795       text++; 
1796       ty--; 
1797       continue; 
1798     }
1799     sprintf(txt, text); 
1800     txt[tl] = 0;
1801     DrawTextExt(drawto, gc,
1802                 DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
1803                 txt, FS_SMALL, FC_YELLOW);
1804     text += tl + (tc == 32 ? 1 : 0);
1805   }
1806
1807   if (req_state & REQ_ASK)
1808   {
1809     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1810     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1811   }
1812   else if (req_state & REQ_CONFIRM)
1813   {
1814     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1815   }
1816   else if (req_state & REQ_PLAYER)
1817   {
1818     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1819     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1820     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1821     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1822   }
1823
1824   /* copy request gadgets to door backbuffer */
1825   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
1826             DX, DY, DXSIZE, DYSIZE,
1827             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1828
1829   OpenDoor(DOOR_OPEN_1);
1830
1831 #if 0
1832   ClearEventQueue();
1833 #endif
1834
1835   if (!(req_state & REQUEST_WAIT_FOR))
1836     return(FALSE);
1837
1838   if (game_status != MAINMENU)
1839     InitAnimation();
1840
1841   button_status = MB_RELEASED;
1842
1843   request_gadget_id = -1;
1844
1845   while(result < 0)
1846   {
1847     if (XPending(display))
1848     {
1849       XEvent event;
1850
1851       XNextEvent(display, &event);
1852
1853       switch(event.type)
1854       {
1855         case ButtonPress:
1856         case ButtonRelease:
1857         case MotionNotify:
1858         {
1859           if (event.type == MotionNotify)
1860           {
1861             Window root, child;
1862             int root_x, root_y;
1863             int win_x, win_y;
1864             unsigned int mask;
1865
1866             if (!XQueryPointer(display, window, &root, &child,
1867                                &root_x, &root_y, &win_x, &win_y, &mask))
1868               continue;
1869
1870             if (!button_status)
1871               continue;
1872
1873             motion_status = TRUE;
1874             mx = ((XMotionEvent *) &event)->x;
1875             my = ((XMotionEvent *) &event)->y;
1876           }
1877           else
1878           {
1879             motion_status = FALSE;
1880             mx = ((XButtonEvent *) &event)->x;
1881             my = ((XButtonEvent *) &event)->y;
1882             if (event.type==ButtonPress)
1883               button_status = ((XButtonEvent *) &event)->button;
1884             else
1885               button_status = MB_RELEASED;
1886           }
1887
1888           /* this sets 'request_gadget_id' */
1889           HandleGadgets(mx, my, button_status);
1890
1891           switch(request_gadget_id)
1892           {
1893             case TOOL_CTRL_ID_YES:
1894               result = TRUE;
1895               break;
1896             case TOOL_CTRL_ID_NO:
1897               result = FALSE;
1898               break;
1899             case TOOL_CTRL_ID_CONFIRM:
1900               result = TRUE | FALSE;
1901               break;
1902
1903             case TOOL_CTRL_ID_PLAYER_1:
1904               result = 1;
1905               break;
1906             case TOOL_CTRL_ID_PLAYER_2:
1907               result = 2;
1908               break;
1909             case TOOL_CTRL_ID_PLAYER_3:
1910               result = 3;
1911               break;
1912             case TOOL_CTRL_ID_PLAYER_4:
1913               result = 4;
1914               break;
1915
1916             default:
1917               break;
1918           }
1919
1920           break;
1921         }
1922
1923         case KeyPress:
1924           switch(XLookupKeysym((XKeyEvent *)&event,
1925                                ((XKeyEvent *)&event)->state))
1926           {
1927             case XK_Return:
1928               result = 1;
1929               break;
1930
1931             case XK_Escape:
1932               result = 0;
1933               break;
1934
1935             default:
1936               break;
1937           }
1938           if (req_state & REQ_PLAYER)
1939             result = 0;
1940           break;
1941
1942         case KeyRelease:
1943           key_joystick_mapping = 0;
1944           break;
1945
1946         default:
1947           HandleOtherEvents(&event);
1948           break;
1949       }
1950     }
1951     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1952     {
1953       int joy = AnyJoystick();
1954
1955       if (joy & JOY_BUTTON_1)
1956         result = 1;
1957       else if (joy & JOY_BUTTON_2)
1958         result = 0;
1959     }
1960
1961     DoAnimation();
1962
1963     /* don't eat all CPU time */
1964     Delay(10);
1965   }
1966
1967   if (game_status != MAINMENU)
1968     StopAnimation();
1969
1970   UnmapToolButtons();
1971
1972   if (!(req_state & REQ_STAY_OPEN))
1973   {
1974     CloseDoor(DOOR_CLOSE_1);
1975
1976     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1977     {
1978       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1979                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1980                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1981       OpenDoor(DOOR_OPEN_1);
1982     }
1983   }
1984
1985   RemapAllGadgets();
1986
1987 #ifndef MSDOS
1988   /* continue network game after request */
1989   if (options.network &&
1990       game_status == PLAYING &&
1991       req_state & REQUEST_WAIT_FOR)
1992     SendToServer_ContinuePlaying();
1993 #endif
1994
1995   return(result);
1996 }
1997
1998 unsigned int OpenDoor(unsigned int door_state)
1999 {
2000   unsigned int new_door_state;
2001
2002   if (door_state & DOOR_COPY_BACK)
2003   {
2004     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
2005               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2006               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2007     door_state &= ~DOOR_COPY_BACK;
2008   }
2009
2010   new_door_state = MoveDoor(door_state);
2011
2012   return(new_door_state);
2013 }
2014
2015 unsigned int CloseDoor(unsigned int door_state)
2016 {
2017   unsigned int new_door_state;
2018
2019   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
2020             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2021   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
2022             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2023
2024   new_door_state = MoveDoor(door_state);
2025
2026   return(new_door_state);
2027 }
2028
2029 unsigned int GetDoorState()
2030 {
2031   return(MoveDoor(DOOR_GET_STATE));
2032 }
2033
2034 unsigned int MoveDoor(unsigned int door_state)
2035 {
2036   static int door1 = DOOR_OPEN_1;
2037   static int door2 = DOOR_CLOSE_2;
2038   static unsigned long door_delay = 0;
2039   int x, start, stepsize = 2;
2040   unsigned long door_delay_value = stepsize * 5;
2041
2042   if (door_state == DOOR_GET_STATE)
2043     return(door1 | door2);
2044
2045   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2046     door_state &= ~DOOR_OPEN_1;
2047   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2048     door_state &= ~DOOR_CLOSE_1;
2049   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2050     door_state &= ~DOOR_OPEN_2;
2051   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2052     door_state &= ~DOOR_CLOSE_2;
2053
2054   if (setup.quick_doors)
2055   {
2056     stepsize = 20;
2057     door_delay_value = 0;
2058     StopSound(SND_OEFFNEN);
2059   }
2060
2061   if (door_state & DOOR_ACTION)
2062   {
2063     if (!(door_state & DOOR_NO_DELAY))
2064       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
2065
2066     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2067
2068     for(x=start; x<=DXSIZE; x+=stepsize)
2069     {
2070       WaitUntilDelayReached(&door_delay, door_delay_value);
2071
2072       if (door_state & DOOR_ACTION_1)
2073       {
2074         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2075         int j = (DXSIZE - i) / 3;
2076
2077         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2078                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2079                   DXSIZE,DYSIZE - i/2, DX, DY);
2080
2081         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2082
2083         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2084                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2085         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2086                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
2087         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2088                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
2089                   DY + 140 + j);
2090         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2091                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2092         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2093                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
2094         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2095                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
2096
2097         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2098                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2099                   DX, DY + 77 - j);
2100         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2101                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2102                   DX, DY + 203 - j);
2103         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2104                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2105         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2106                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2107                   DX + DXSIZE - i, DY + 77 + j);
2108         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2109                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2110                   DX + DXSIZE - i, DY + 203 + j);
2111
2112         redraw_mask |= REDRAW_DOOR_1;
2113       }
2114
2115       if (door_state & DOOR_ACTION_2)
2116       {
2117         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2118         int j = (VXSIZE - i) / 3;
2119
2120         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2121                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2122                   VXSIZE, VYSIZE - i/2, VX, VY);
2123
2124         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2125
2126         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2127                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2128         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2129                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
2130         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2131                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2132         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2133                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
2134
2135         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2136                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
2137                   VX, VY + VYSIZE / 2 - j);
2138         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2139                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2140         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2141                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
2142                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2143
2144         redraw_mask |= REDRAW_DOOR_2;
2145       }
2146
2147       BackToFront();
2148
2149       if (game_status == MAINMENU)
2150         DoAnimation();
2151     }
2152   }
2153
2154   if (setup.quick_doors)
2155     StopSound(SND_OEFFNEN);
2156
2157   if (door_state & DOOR_ACTION_1)
2158     door1 = door_state & DOOR_ACTION_1;
2159   if (door_state & DOOR_ACTION_2)
2160     door2 = door_state & DOOR_ACTION_2;
2161
2162   return (door1 | door2);
2163 }
2164
2165 void DrawSpecialEditorDoor()
2166 {
2167   /* draw bigger toolbox window */
2168   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2169             DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2170
2171   redraw_mask |= REDRAW_ALL;
2172 }
2173
2174 void UndrawSpecialEditorDoor()
2175 {
2176   /* draw normal tape recorder window */
2177   XCopyArea(display, pix[PIX_BACK], drawto, gc,
2178             562, 344, 108, 56, EX - 4, EY - 12);
2179
2180   redraw_mask |= REDRAW_ALL;
2181 }
2182
2183 int ReadPixel(Drawable d, int x, int y)
2184 {
2185   XImage *pixel_image;
2186   unsigned long pixel_value;
2187
2188   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
2189   pixel_value = XGetPixel(pixel_image, 0, 0);
2190
2191   XDestroyImage(pixel_image);
2192
2193   return pixel_value;
2194 }
2195
2196 /* ---------- new tool button stuff ---------------------------------------- */
2197
2198 /* graphic position values for tool buttons */
2199 #define TOOL_BUTTON_YES_XPOS            2
2200 #define TOOL_BUTTON_YES_YPOS            250
2201 #define TOOL_BUTTON_YES_GFX_YPOS        0
2202 #define TOOL_BUTTON_YES_XSIZE           46
2203 #define TOOL_BUTTON_YES_YSIZE           28
2204 #define TOOL_BUTTON_NO_XPOS             52
2205 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2206 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2207 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2208 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2209 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2210 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2211 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2212 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2213 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2214 #define TOOL_BUTTON_PLAYER_XSIZE        30
2215 #define TOOL_BUTTON_PLAYER_YSIZE        30
2216 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2217 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2218 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2219 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2220 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2221                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2222 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2223                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2224 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2225                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2226 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2227                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2228 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2229                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2230 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2231                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2232 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2233                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2234 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2235                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2236
2237 static struct
2238 {
2239   int xpos, ypos;
2240   int x, y;
2241   int width, height;
2242   int gadget_id;
2243   char *infotext;
2244 } toolbutton_info[NUM_TOOL_BUTTONS] =
2245 {
2246   {
2247     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2248     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2249     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2250     TOOL_CTRL_ID_YES,
2251     "yes"
2252   },
2253   {
2254     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2255     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2256     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2257     TOOL_CTRL_ID_NO,
2258     "no"
2259   },
2260   {
2261     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2262     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2263     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2264     TOOL_CTRL_ID_CONFIRM,
2265     "confirm"
2266   },
2267   {
2268     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2269     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2270     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2271     TOOL_CTRL_ID_PLAYER_1,
2272     "player 1"
2273   },
2274   {
2275     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2276     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2277     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2278     TOOL_CTRL_ID_PLAYER_2,
2279     "player 2"
2280   },
2281   {
2282     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2283     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2284     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2285     TOOL_CTRL_ID_PLAYER_3,
2286     "player 3"
2287   },
2288   {
2289     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2290     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2291     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2292     TOOL_CTRL_ID_PLAYER_4,
2293     "player 4"
2294   }
2295 };
2296
2297 static void DoNotDisplayInfoText(void *ptr)
2298 {
2299   return;
2300 }
2301
2302 void CreateToolButtons()
2303 {
2304   int i;
2305
2306   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2307   {
2308     Pixmap gd_pixmap = pix[PIX_DOOR];
2309     Pixmap deco_pixmap = None;
2310     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2311     struct GadgetInfo *gi;
2312     unsigned long event_mask;
2313     int gd_xoffset, gd_yoffset;
2314     int gd_x1, gd_x2, gd_y;
2315     int id = i;
2316
2317     event_mask = GD_EVENT_RELEASED;
2318
2319     gd_xoffset = toolbutton_info[i].xpos;
2320     gd_yoffset = toolbutton_info[i].ypos;
2321     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2322     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2323     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2324
2325     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2326     {
2327       getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
2328                            &deco_pixmap, &deco_x, &deco_y);
2329       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2330       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2331     }
2332
2333     gi = CreateGadget(GDI_CUSTOM_ID, id,
2334                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2335                       GDI_X, DX + toolbutton_info[i].x,
2336                       GDI_Y, DY + toolbutton_info[i].y,
2337                       GDI_WIDTH, toolbutton_info[i].width,
2338                       GDI_HEIGHT, toolbutton_info[i].height,
2339                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2340                       GDI_STATE, GD_BUTTON_UNPRESSED,
2341                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
2342                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
2343                       GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
2344                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2345                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2346                       GDI_DECORATION_SHIFTING, 1, 1,
2347                       GDI_EVENT_MASK, event_mask,
2348                       GDI_CALLBACK_ACTION, HandleToolButtons,
2349                       GDI_CALLBACK_INFO, DoNotDisplayInfoText,
2350                       GDI_END);
2351
2352     if (gi == NULL)
2353       Error(ERR_EXIT, "cannot create gadget");
2354
2355     tool_gadget[id] = gi;
2356   }
2357 }
2358
2359 static void UnmapToolButtons()
2360 {
2361   int i;
2362
2363   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2364     UnmapGadget(tool_gadget[i]);
2365 }
2366
2367 static void HandleToolButtons(struct GadgetInfo *gi)
2368 {
2369   request_gadget_id = gi->custom_id;
2370 }
2371
2372 int el2gfx(int element)
2373 {
2374   switch(element)
2375   {
2376     case EL_LEERRAUM:           return -1;
2377     case EL_ERDREICH:           return GFX_ERDREICH;
2378     case EL_MAUERWERK:          return GFX_MAUERWERK;
2379     case EL_FELSBODEN:          return GFX_FELSBODEN;
2380     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
2381     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
2382     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
2383     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
2384     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
2385     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
2386     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
2387     case EL_SPIELER1:           return GFX_SPIELER1;
2388     case EL_SPIELER2:           return GFX_SPIELER2;
2389     case EL_SPIELER3:           return GFX_SPIELER3;
2390     case EL_SPIELER4:           return GFX_SPIELER4;
2391     case EL_KAEFER:             return GFX_KAEFER;
2392     case EL_KAEFER_RIGHT:       return GFX_KAEFER_RIGHT;
2393     case EL_KAEFER_UP:          return GFX_KAEFER_UP;
2394     case EL_KAEFER_LEFT:        return GFX_KAEFER_LEFT;
2395     case EL_KAEFER_DOWN:        return GFX_KAEFER_DOWN;
2396     case EL_FLIEGER:            return GFX_FLIEGER;
2397     case EL_FLIEGER_RIGHT:      return GFX_FLIEGER_RIGHT;
2398     case EL_FLIEGER_UP:         return GFX_FLIEGER_UP;
2399     case EL_FLIEGER_LEFT:       return GFX_FLIEGER_LEFT;
2400     case EL_FLIEGER_DOWN:       return GFX_FLIEGER_DOWN;
2401     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
2402     case EL_BUTTERFLY_RIGHT:    return GFX_BUTTERFLY_RIGHT;
2403     case EL_BUTTERFLY_UP:       return GFX_BUTTERFLY_UP;
2404     case EL_BUTTERFLY_LEFT:     return GFX_BUTTERFLY_LEFT;
2405     case EL_BUTTERFLY_DOWN:     return GFX_BUTTERFLY_DOWN;
2406     case EL_FIREFLY:            return GFX_FIREFLY;
2407     case EL_FIREFLY_RIGHT:      return GFX_FIREFLY_RIGHT;
2408     case EL_FIREFLY_UP:         return GFX_FIREFLY_UP;
2409     case EL_FIREFLY_LEFT:       return GFX_FIREFLY_LEFT;
2410     case EL_FIREFLY_DOWN:       return GFX_FIREFLY_DOWN;
2411     case EL_MAMPFER:            return GFX_MAMPFER;
2412     case EL_ROBOT:              return GFX_ROBOT;
2413     case EL_BETON:              return GFX_BETON;
2414     case EL_DIAMANT:            return GFX_DIAMANT;
2415     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2416     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2417     case EL_TROPFEN:            return GFX_TROPFEN;
2418     case EL_BOMBE:              return GFX_BOMBE;
2419     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
2420     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
2421     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
2422     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
2423     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2424     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2425     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2426     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2427     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2428     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2429     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2430     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2431     case EL_LIFE:               return GFX_LIFE;
2432     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2433     case EL_DYNAMITE_ACTIVE:    return GFX_DYNAMIT;
2434     case EL_BADEWANNE:          return GFX_BADEWANNE;
2435     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2436     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2437     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2438     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2439     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2440     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2441     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2442     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2443     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2444     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2445     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2446     case EL_PFORTE1:            return GFX_PFORTE1;
2447     case EL_PFORTE2:            return GFX_PFORTE2;
2448     case EL_PFORTE3:            return GFX_PFORTE3;
2449     case EL_PFORTE4:            return GFX_PFORTE4;
2450     case EL_PFORTE1X:           return GFX_PFORTE1X;
2451     case EL_PFORTE2X:           return GFX_PFORTE2X;
2452     case EL_PFORTE3X:           return GFX_PFORTE3X;
2453     case EL_PFORTE4X:           return GFX_PFORTE4X;
2454     case EL_DYNAMITE_INACTIVE:  return GFX_DYNAMIT_AUS;
2455     case EL_PACMAN:             return GFX_PACMAN;
2456     case EL_PACMAN_RIGHT:       return GFX_PACMAN_RIGHT;
2457     case EL_PACMAN_UP:          return GFX_PACMAN_UP;
2458     case EL_PACMAN_LEFT:        return GFX_PACMAN_LEFT;
2459     case EL_PACMAN_DOWN:        return GFX_PACMAN_DOWN;
2460     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2461     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2462     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2463     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2464     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2465     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2466     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2467     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2468     case EL_MAUER_X:            return GFX_MAUER_X;
2469     case EL_MAUER_Y:            return GFX_MAUER_Y;
2470     case EL_MAUER_XY:           return GFX_MAUER_XY;
2471     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2472     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2473     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2474     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2475     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2476     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2477     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2478     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2479     case EL_MAMPFER2:           return GFX_MAMPFER2;
2480     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
2481     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
2482     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
2483     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
2484     case EL_DYNABOMB_ACTIVE_1:  return GFX_DYNABOMB;
2485     case EL_DYNABOMB_ACTIVE_2:  return GFX_DYNABOMB;
2486     case EL_DYNABOMB_ACTIVE_3:  return GFX_DYNABOMB;
2487     case EL_DYNABOMB_ACTIVE_4:  return GFX_DYNABOMB;
2488     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2489     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2490     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2491     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2492     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2493     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2494     case EL_MOLE:               return GFX_MOLE;
2495     case EL_PINGUIN:            return GFX_PINGUIN;
2496     case EL_SCHWEIN:            return GFX_SCHWEIN;
2497     case EL_DRACHE:             return GFX_DRACHE;
2498     case EL_SONDE:              return GFX_SONDE;
2499     case EL_PFEIL_LEFT:         return GFX_PFEIL_LEFT;
2500     case EL_PFEIL_RIGHT:        return GFX_PFEIL_RIGHT;
2501     case EL_PFEIL_UP:           return GFX_PFEIL_UP;
2502     case EL_PFEIL_DOWN:         return GFX_PFEIL_DOWN;
2503     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2504     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2505     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2506     case EL_SP_ZONK:            return GFX_SP_ZONK;
2507       /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2508     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2509     case EL_BLACK_ORB:          return GFX_BLACK_ORB;
2510     case EL_EM_GATE_1:          return GFX_EM_GATE_1;
2511     case EL_EM_GATE_2:          return GFX_EM_GATE_2;
2512     case EL_EM_GATE_3:          return GFX_EM_GATE_3;
2513     case EL_EM_GATE_4:          return GFX_EM_GATE_4;
2514     case EL_EM_GATE_1X:         return GFX_EM_GATE_1X;
2515     case EL_EM_GATE_2X:         return GFX_EM_GATE_2X;
2516     case EL_EM_GATE_3X:         return GFX_EM_GATE_3X;
2517     case EL_EM_GATE_4X:         return GFX_EM_GATE_4X;
2518     case EL_EM_KEY_1_FILE:      return GFX_EM_KEY_1;
2519     case EL_EM_KEY_2_FILE:      return GFX_EM_KEY_2;
2520     case EL_EM_KEY_3_FILE:      return GFX_EM_KEY_3;
2521     case EL_EM_KEY_4_FILE:      return GFX_EM_KEY_4;
2522     case EL_EM_KEY_1:           return GFX_EM_KEY_1;
2523     case EL_EM_KEY_2:           return GFX_EM_KEY_2;
2524     case EL_EM_KEY_3:           return GFX_EM_KEY_3;
2525     case EL_EM_KEY_4:           return GFX_EM_KEY_4;
2526     case EL_PEARL:              return GFX_PEARL;
2527     case EL_CRYSTAL:            return GFX_CRYSTAL;
2528     case EL_WALL_PEARL:         return GFX_WALL_PEARL;
2529     case EL_WALL_CRYSTAL:       return GFX_WALL_CRYSTAL;
2530     case EL_DOOR_WHITE:         return GFX_DOOR_WHITE;
2531     case EL_DOOR_WHITE_GRAY:    return GFX_DOOR_WHITE_GRAY;
2532     case EL_KEY_WHITE:          return GFX_KEY_WHITE;
2533     case EL_SHIELD_PASSIVE:     return GFX_SHIELD_PASSIVE;
2534     case EL_SHIELD_ACTIVE:      return GFX_SHIELD_ACTIVE;
2535     case EL_EXTRA_TIME:         return GFX_EXTRA_TIME;
2536     case EL_SWITCHGATE_OPEN:    return GFX_SWITCHGATE_OPEN;
2537     case EL_SWITCHGATE_CLOSED:  return GFX_SWITCHGATE_CLOSED;
2538     case EL_SWITCHGATE_SWITCH_1:return GFX_SWITCHGATE_SWITCH_1;
2539     case EL_SWITCHGATE_SWITCH_2:return GFX_SWITCHGATE_SWITCH_2;
2540     case EL_BELT1_LEFT:         return GFX_BELT1_LEFT;
2541     case EL_BELT1_MIDDLE:       return GFX_BELT1_MIDDLE;
2542     case EL_BELT1_RIGHT:        return GFX_BELT1_RIGHT;
2543     case EL_BELT1_SWITCH_LEFT:  return GFX_BELT1_SWITCH_LEFT;
2544     case EL_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
2545     case EL_BELT1_SWITCH_RIGHT: return GFX_BELT1_SWITCH_RIGHT;
2546     case EL_BELT2_LEFT:         return GFX_BELT2_LEFT;
2547     case EL_BELT2_MIDDLE:       return GFX_BELT2_MIDDLE;
2548     case EL_BELT2_RIGHT:        return GFX_BELT2_RIGHT;
2549     case EL_BELT2_SWITCH_LEFT:  return GFX_BELT2_SWITCH_LEFT;
2550     case EL_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
2551     case EL_BELT2_SWITCH_RIGHT: return GFX_BELT2_SWITCH_RIGHT;
2552     case EL_BELT3_LEFT:         return GFX_BELT3_LEFT;
2553     case EL_BELT3_MIDDLE:       return GFX_BELT3_MIDDLE;
2554     case EL_BELT3_RIGHT:        return GFX_BELT3_RIGHT;
2555     case EL_BELT3_SWITCH_LEFT:  return GFX_BELT3_SWITCH_LEFT;
2556     case EL_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
2557     case EL_BELT3_SWITCH_RIGHT: return GFX_BELT3_SWITCH_RIGHT;
2558     case EL_BELT4_LEFT:         return GFX_BELT4_LEFT;
2559     case EL_BELT4_MIDDLE:       return GFX_BELT4_MIDDLE;
2560     case EL_BELT4_RIGHT:        return GFX_BELT4_RIGHT;
2561     case EL_BELT4_SWITCH_LEFT:  return GFX_BELT4_SWITCH_LEFT;
2562     case EL_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
2563     case EL_BELT4_SWITCH_RIGHT: return GFX_BELT4_SWITCH_RIGHT;
2564     case EL_LANDMINE:           return GFX_LANDMINE;
2565     case EL_ENVELOPE:           return GFX_ENVELOPE;
2566     case EL_LIGHT_SWITCH_OFF:   return GFX_LIGHT_SWITCH_OFF;
2567     case EL_LIGHT_SWITCH_ON:    return GFX_LIGHT_SWITCH_ON;
2568     case EL_SIGN_EXCLAMATION:   return GFX_SIGN_EXCLAMATION;
2569     case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2570     case EL_SIGN_STOP:          return GFX_SIGN_STOP;
2571     case EL_SIGN_WHEELCHAIR:    return GFX_SIGN_WHEELCHAIR;
2572     case EL_SIGN_PARKING:       return GFX_SIGN_PARKING;
2573     case EL_SIGN_ONEWAY:        return GFX_SIGN_ONEWAY;
2574     case EL_SIGN_HEART:         return GFX_SIGN_HEART;
2575     case EL_SIGN_TRIANGLE:      return GFX_SIGN_TRIANGLE;
2576     case EL_SIGN_ROUND:         return GFX_SIGN_ROUND;
2577     case EL_SIGN_EXIT:          return GFX_SIGN_EXIT;
2578     case EL_SIGN_YINYANG:       return GFX_SIGN_YINYANG;
2579     case EL_SIGN_OTHER:         return GFX_SIGN_OTHER;
2580     case EL_MOLE_LEFT:          return GFX_MOLE_LEFT;
2581     case EL_MOLE_RIGHT:         return GFX_MOLE_RIGHT;
2582     case EL_MOLE_UP:            return GFX_MOLE_UP;
2583     case EL_MOLE_DOWN:          return GFX_MOLE_DOWN;
2584     case EL_STEEL_SLANTED:      return GFX_STEEL_SLANTED;
2585     case EL_SAND_INVISIBLE:     return GFX_SAND_INVISIBLE;
2586     case EL_DX_UNKNOWN_15:      return GFX_DX_UNKNOWN_15;
2587     case EL_DX_UNKNOWN_42:      return GFX_DX_UNKNOWN_42;
2588     case EL_TIMEGATE_OPEN:      return GFX_TIMEGATE_OPEN;
2589     case EL_TIMEGATE_CLOSED:    return GFX_TIMEGATE_CLOSED;
2590     case EL_TIMEGATE_SWITCH_ON: return GFX_TIMEGATE_SWITCH;
2591     case EL_TIMEGATE_SWITCH_OFF:return GFX_TIMEGATE_SWITCH;
2592     case EL_BALLOON:            return GFX_BALLOON;
2593     case EL_BALLOON_SEND_LEFT:  return GFX_BALLOON_SEND_LEFT;
2594     case EL_BALLOON_SEND_RIGHT: return GFX_BALLOON_SEND_RIGHT;
2595     case EL_BALLOON_SEND_UP:    return GFX_BALLOON_SEND_UP;
2596     case EL_BALLOON_SEND_DOWN:  return GFX_BALLOON_SEND_DOWN;
2597     case EL_BALLOON_SEND_ANY:   return GFX_BALLOON_SEND_ANY;
2598     case EL_EMC_STEEL_WALL_1:   return GFX_EMC_STEEL_WALL_1;
2599     case EL_EMC_STEEL_WALL_2:   return GFX_EMC_STEEL_WALL_2;
2600     case EL_EMC_STEEL_WALL_3:   return GFX_EMC_STEEL_WALL_3;
2601     case EL_EMC_STEEL_WALL_4:   return GFX_EMC_STEEL_WALL_4;
2602     case EL_EMC_WALL_1:         return GFX_EMC_WALL_1;
2603     case EL_EMC_WALL_2:         return GFX_EMC_WALL_2;
2604     case EL_EMC_WALL_3:         return GFX_EMC_WALL_3;
2605     case EL_EMC_WALL_4:         return GFX_EMC_WALL_4;
2606     case EL_EMC_WALL_5:         return GFX_EMC_WALL_5;
2607     case EL_EMC_WALL_6:         return GFX_EMC_WALL_6;
2608     case EL_EMC_WALL_7:         return GFX_EMC_WALL_7;
2609     case EL_EMC_WALL_8:         return GFX_EMC_WALL_8;
2610
2611     default:
2612     {
2613       if (IS_CHAR(element))
2614         return GFX_CHAR_START + (element - EL_CHAR_START);
2615       else if (element >= EL_SP_START && element <= EL_SP_END)
2616       {
2617         int nr_element = element - EL_SP_START;
2618         int gfx_per_line = 8;
2619         int nr_graphic =
2620           (nr_element / gfx_per_line) * SP_PER_LINE +
2621           (nr_element % gfx_per_line);
2622
2623         return GFX_START_ROCKSSP + nr_graphic;
2624       }
2625       else
2626         return -1;
2627     }
2628   }
2629 }