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