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