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