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