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