rocksndiamonds-1.4.0
[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_MAGIC_WALL_EMPTY ||
1200            element == EL_MAGIC_WALL_BD_EMPTY ||
1201            element == EL_MAGIC_WALL_FULL ||
1202            element == EL_MAGIC_WALL_BD_FULL)
1203   {
1204     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1205   }
1206   else if (IS_AMOEBOID(element))
1207   {
1208     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1209     graphic += (x + 2 * y + 4) % 4;
1210   }
1211   else if (element == EL_MAUER_LEBT)
1212   {
1213     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1214
1215     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1216       links_massiv = TRUE;
1217     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1218       rechts_massiv = TRUE;
1219
1220     if (links_massiv && rechts_massiv)
1221       graphic = GFX_MAUERWERK;
1222     else if (links_massiv)
1223       graphic = GFX_MAUER_R;
1224     else if (rechts_massiv)
1225       graphic = GFX_MAUER_L;
1226   }
1227   else if ((element == EL_INVISIBLE_STEEL ||
1228             element == EL_UNSICHTBAR ||
1229             element == EL_SAND_INVISIBLE) && game.light_time_left)
1230   {
1231     graphic = (element == EL_INVISIBLE_STEEL ? GFX_INVISIBLE_STEEL_ON :
1232                element == EL_UNSICHTBAR ? GFX_UNSICHTBAR_ON :
1233                GFX_SAND_INVISIBLE_ON);
1234   }
1235
1236   if (dx || dy)
1237     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1238   else if (mask_mode == USE_MASKING)
1239     DrawGraphicThruMask(x, y, graphic);
1240   else
1241     DrawGraphic(x, y, graphic);
1242 }
1243
1244 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1245                          int cut_mode, int mask_mode)
1246 {
1247   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1248     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1249                          cut_mode, mask_mode);
1250 }
1251
1252 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1253                               int cut_mode)
1254 {
1255   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1256 }
1257
1258 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1259                              int cut_mode)
1260 {
1261   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1262 }
1263
1264 void DrawScreenElementThruMask(int x, int y, int element)
1265 {
1266   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1267 }
1268
1269 void DrawLevelElementThruMask(int x, int y, int element)
1270 {
1271   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1272 }
1273
1274 void DrawLevelFieldThruMask(int x, int y)
1275 {
1276   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1277 }
1278
1279 void ErdreichAnbroeckeln(int x, int y)
1280 {
1281   int i, width, height, cx,cy;
1282   int ux = LEVELX(x), uy = LEVELY(y);
1283   int element, graphic;
1284   int snip = 4;
1285   static int xy[4][2] =
1286   {
1287     { 0, -1 },
1288     { -1, 0 },
1289     { +1, 0 },
1290     { 0, +1 }
1291   };
1292
1293   if (!IN_LEV_FIELD(ux, uy))
1294     return;
1295
1296   element = Feld[ux][uy];
1297
1298   if (element == EL_ERDREICH ||
1299       element == EL_LANDMINE ||
1300       element == EL_TRAP_INACTIVE ||
1301       element == EL_TRAP_ACTIVE)
1302   {
1303     if (!IN_SCR_FIELD(x, y))
1304       return;
1305
1306     graphic = GFX_ERDENRAND;
1307
1308     for(i=0; i<4; i++)
1309     {
1310       int uxx, uyy;
1311
1312       uxx = ux + xy[i][0];
1313       uyy = uy + xy[i][1];
1314       if (!IN_LEV_FIELD(uxx, uyy))
1315         element = EL_BETON;
1316       else
1317         element = Feld[uxx][uyy];
1318
1319       if (element == EL_ERDREICH ||
1320           element == EL_LANDMINE ||
1321           element == EL_TRAP_INACTIVE ||
1322           element == EL_TRAP_ACTIVE)
1323         continue;
1324
1325       if (i == 1 || i == 2)
1326       {
1327         width = snip;
1328         height = TILEY;
1329         cx = (i == 2 ? TILEX - snip : 0);
1330         cy = 0;
1331       }
1332       else
1333       {
1334         width = TILEX;
1335         height = snip;
1336         cx = 0;
1337         cy = (i == 3 ? TILEY - snip : 0);
1338       }
1339
1340       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1341                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1342                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1343                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1344     }
1345
1346     MarkTileDirty(x, y);
1347   }
1348   else
1349   {
1350     graphic = GFX_ERDENRAND;
1351
1352     for(i=0; i<4; i++)
1353     {
1354       int xx, yy, uxx, uyy;
1355
1356       xx = x + xy[i][0];
1357       yy = y + xy[i][1];
1358       uxx = ux + xy[i][0];
1359       uyy = uy + xy[i][1];
1360
1361       if (!IN_LEV_FIELD(uxx, uyy) ||
1362           (Feld[uxx][uyy] != EL_ERDREICH &&
1363            Feld[uxx][uyy] != EL_LANDMINE &&
1364            Feld[uxx][uyy] != EL_TRAP_INACTIVE &&
1365            Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1366           !IN_SCR_FIELD(xx, yy))
1367         continue;
1368
1369       if (i == 1 || i == 2)
1370       {
1371         width = snip;
1372         height = TILEY;
1373         cx = (i == 1 ? TILEX - snip : 0);
1374         cy = 0;
1375       }
1376       else
1377       {
1378         width = TILEX;
1379         height = snip;
1380         cx = 0;
1381         cy = (i==0 ? TILEY-snip : 0);
1382       }
1383
1384       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1385                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1386                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1387                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1388
1389       MarkTileDirty(xx, yy);
1390     }
1391   }
1392 }
1393
1394 void DrawScreenElement(int x, int y, int element)
1395 {
1396   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1397   ErdreichAnbroeckeln(x, y);
1398 }
1399
1400 void DrawLevelElement(int x, int y, int element)
1401 {
1402   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1403     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1404 }
1405
1406 void DrawScreenField(int x, int y)
1407 {
1408   int ux = LEVELX(x), uy = LEVELY(y);
1409   int element;
1410
1411   if (!IN_LEV_FIELD(ux, uy))
1412   {
1413     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1414       element = EL_LEERRAUM;
1415     else
1416       element = BorderElement;
1417
1418     DrawScreenElement(x, y, element);
1419     return;
1420   }
1421
1422   element = Feld[ux][uy];
1423
1424   if (IS_MOVING(ux, uy))
1425   {
1426     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1427     boolean cut_mode = NO_CUTTING;
1428
1429     if (Store[ux][uy] == EL_MORAST_LEER ||
1430         Store[ux][uy] == EL_MAGIC_WALL_EMPTY ||
1431         Store[ux][uy] == EL_MAGIC_WALL_BD_EMPTY ||
1432         Store[ux][uy] == EL_AMOEBE_NASS)
1433       cut_mode = CUT_ABOVE;
1434     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1435              Store[ux][uy] == EL_MAGIC_WALL_FULL ||
1436              Store[ux][uy] == EL_MAGIC_WALL_BD_FULL)
1437       cut_mode = CUT_BELOW;
1438
1439     if (cut_mode == CUT_ABOVE)
1440       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1441     else
1442       DrawScreenElement(x, y, EL_LEERRAUM);
1443
1444     if (horiz_move)
1445       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1446     else
1447       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1448
1449     if (Store[ux][uy] == EL_SALZSAEURE)
1450       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1451   }
1452   else if (IS_BLOCKED(ux, uy))
1453   {
1454     int oldx, oldy;
1455     int sx, sy;
1456     int horiz_move;
1457     boolean cut_mode = NO_CUTTING;
1458
1459     Blocked2Moving(ux, uy, &oldx, &oldy);
1460     sx = SCREENX(oldx);
1461     sy = SCREENY(oldy);
1462     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1463                   MovDir[oldx][oldy] == MV_RIGHT);
1464
1465     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1466         Store[oldx][oldy] == EL_MAGIC_WALL_EMPTY ||
1467         Store[oldx][oldy] == EL_MAGIC_WALL_BD_EMPTY ||
1468         Store[oldx][oldy] == EL_AMOEBE_NASS)
1469       cut_mode = CUT_ABOVE;
1470
1471     DrawScreenElement(x, y, EL_LEERRAUM);
1472     element = Feld[oldx][oldy];
1473
1474     if (horiz_move)
1475       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1476     else
1477       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1478   }
1479   else if (IS_DRAWABLE(element))
1480     DrawScreenElement(x, y, element);
1481   else
1482     DrawScreenElement(x, y, EL_LEERRAUM);
1483 }
1484
1485 void DrawLevelField(int x, int y)
1486 {
1487   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1488     DrawScreenField(SCREENX(x), SCREENY(y));
1489   else if (IS_MOVING(x, y))
1490   {
1491     int newx,newy;
1492
1493     Moving2Blocked(x, y, &newx, &newy);
1494     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1495       DrawScreenField(SCREENX(newx), SCREENY(newy));
1496   }
1497   else if (IS_BLOCKED(x, y))
1498   {
1499     int oldx, oldy;
1500
1501     Blocked2Moving(x, y, &oldx, &oldy);
1502     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1503       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1504   }
1505 }
1506
1507 void DrawMiniElement(int x, int y, int element)
1508 {
1509   int graphic;
1510
1511   if (!element)
1512   {
1513     DrawMiniGraphic(x, y, -1);
1514     return;
1515   }
1516
1517   graphic = el2gfx(element);
1518   DrawMiniGraphic(x, y, graphic);
1519 }
1520
1521 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1522 {
1523   int x = sx + scroll_x, y = sy + scroll_y;
1524
1525   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1526     DrawMiniElement(sx, sy, EL_LEERRAUM);
1527   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1528     DrawMiniElement(sx, sy, Feld[x][y]);
1529   else
1530   {
1531     int steel_type, steel_position;
1532     int border[6][2] =
1533     {
1534       { GFX_VSTEEL_UPPER_LEFT,  GFX_ISTEEL_UPPER_LEFT  },
1535       { GFX_VSTEEL_UPPER_RIGHT, GFX_ISTEEL_UPPER_RIGHT },
1536       { GFX_VSTEEL_LOWER_LEFT,  GFX_ISTEEL_LOWER_LEFT  },
1537       { GFX_VSTEEL_LOWER_RIGHT, GFX_ISTEEL_LOWER_RIGHT },
1538       { GFX_VSTEEL_VERTICAL,    GFX_ISTEEL_VERTICAL    },
1539       { GFX_VSTEEL_HORIZONTAL,  GFX_ISTEEL_HORIZONTAL  }
1540     };
1541
1542     steel_type = (BorderElement == EL_BETON ? 0 : 1);
1543     steel_position = (x == -1 && y == -1                        ? 0 :
1544                       x == lev_fieldx && y == -1                ? 1 :
1545                       x == -1 && y == lev_fieldy                ? 2 :
1546                       x == lev_fieldx && y == lev_fieldy        ? 3 :
1547                       x == -1 || x == lev_fieldx                ? 4 :
1548                       y == -1 || y == lev_fieldy                ? 5 : -1);
1549
1550     if (steel_position != -1)
1551       DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1552   }
1553 }
1554
1555 void DrawMicroElement(int xpos, int ypos, int element)
1556 {
1557   int graphic;
1558
1559   if (element == EL_LEERRAUM)
1560     return;
1561
1562   graphic = el2gfx(element);
1563
1564   if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
1565   {
1566     graphic -= GFX_START_ROCKSSP;
1567     graphic -= ((graphic / SP_PER_LINE) * SP_PER_LINE) / 2;
1568     XCopyArea(display, pix[PIX_SP], drawto, gc,
1569               MICRO_SP_STARTX + (graphic % MICRO_SP_PER_LINE) * MICRO_TILEX,
1570               MICRO_SP_STARTY + (graphic / MICRO_SP_PER_LINE) * MICRO_TILEY,
1571               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1572   }
1573   else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
1574   {
1575     graphic -= GFX_START_ROCKSDC;
1576     XCopyArea(display, pix[PIX_DC], drawto, gc,
1577               MICRO_DC_STARTX + (graphic % MICRO_DC_PER_LINE) * MICRO_TILEX,
1578               MICRO_DC_STARTY + (graphic / MICRO_DC_PER_LINE) * MICRO_TILEY,
1579               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1580   }
1581   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1582   {
1583     graphic -= GFX_START_ROCKSMORE;
1584     XCopyArea(display, pix[PIX_MORE], drawto, gc,
1585               MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
1586               MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
1587               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1588   }
1589   else
1590     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1591               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1592               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1593               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1594 }
1595
1596 void DrawLevel()
1597 {
1598   int x,y;
1599
1600   ClearWindow();
1601
1602   for(x=BX1; x<=BX2; x++)
1603     for(y=BY1; y<=BY2; y++)
1604       DrawScreenField(x, y);
1605
1606   redraw_mask |= REDRAW_FIELD;
1607 }
1608
1609 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1610 {
1611   int x,y;
1612
1613   for(x=0; x<size_x; x++)
1614     for(y=0; y<size_y; y++)
1615       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1616
1617   redraw_mask |= REDRAW_FIELD;
1618 }
1619
1620 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1621 {
1622   int x, y;
1623
1624   XFillRectangle(display, drawto, gc,
1625                  xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1626
1627   if (lev_fieldx < STD_LEV_FIELDX)
1628     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1629   if (lev_fieldy < STD_LEV_FIELDY)
1630     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1631
1632   xpos += MICRO_TILEX;
1633   ypos += MICRO_TILEY;
1634
1635   for(x=-1; x<=STD_LEV_FIELDX; x++)
1636   {
1637     for(y=-1; y<=STD_LEV_FIELDY; y++)
1638     {
1639       int lx = from_x + x, ly = from_y + y;
1640
1641       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1642         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1643                          Ur[lx][ly]);
1644       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1645         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1646                          BorderElement);
1647     }
1648   }
1649
1650   redraw_mask |= REDRAW_MICROLEVEL;
1651 }
1652
1653 #define MICROLABEL_EMPTY                0
1654 #define MICROLABEL_LEVEL_NAME           1
1655 #define MICROLABEL_CREATED_BY           2
1656 #define MICROLABEL_LEVEL_AUTHOR         3
1657 #define MICROLABEL_IMPORTED_FROM        4
1658 #define MICROLABEL_LEVEL_IMPORT_INFO    5
1659
1660 #define MAX_MICROLABEL_SIZE             (SXSIZE / FONT4_XSIZE)
1661
1662 static void DrawMicroLevelLabelExt(int mode)
1663 {
1664   char label_text[MAX_MICROLABEL_SIZE + 1];
1665
1666   XFillRectangle(display, drawto,gc,
1667                  SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1668
1669   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1670                        mode == MICROLABEL_CREATED_BY ? "created by" :
1671                        mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1672                        mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1673                        mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1674                        leveldir_current->imported_from : ""),
1675           MAX_MICROLABEL_SIZE);
1676   label_text[MAX_MICROLABEL_SIZE] = '\0';
1677
1678   if (strlen(label_text) > 0)
1679   {
1680     int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1681     int lypos = MICROLABEL_YPOS;
1682
1683     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1684   }
1685
1686   redraw_mask |= REDRAW_MICROLEVEL;
1687 }
1688
1689 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1690 {
1691   static unsigned long scroll_delay = 0;
1692   static unsigned long label_delay = 0;
1693   static int from_x, from_y, scroll_direction;
1694   static int label_state, label_counter;
1695
1696   if (restart)
1697   {
1698     from_x = from_y = 0;
1699     scroll_direction = MV_RIGHT;
1700     label_state = 1;
1701     label_counter = 0;
1702
1703     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1704     DrawMicroLevelLabelExt(label_state);
1705
1706     /* initialize delay counters */
1707     DelayReached(&scroll_delay, 0);
1708     DelayReached(&label_delay, 0);
1709
1710     return;
1711   }
1712
1713   /* scroll micro level, if needed */
1714   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1715       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1716   {
1717     switch (scroll_direction)
1718     {
1719       case MV_LEFT:
1720         if (from_x > 0)
1721           from_x--;
1722         else
1723           scroll_direction = MV_UP;
1724         break;
1725
1726       case MV_RIGHT:
1727         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1728           from_x++;
1729         else
1730           scroll_direction = MV_DOWN;
1731         break;
1732
1733       case MV_UP:
1734         if (from_y > 0)
1735           from_y--;
1736         else
1737           scroll_direction = MV_RIGHT;
1738         break;
1739
1740       case MV_DOWN:
1741         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1742           from_y++;
1743         else
1744           scroll_direction = MV_LEFT;
1745         break;
1746
1747       default:
1748         break;
1749     }
1750
1751     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1752   }
1753
1754   /* redraw micro level label, if needed */
1755   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1756       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1757       strcmp(level.author, leveldir_current->name) != 0 &&
1758       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1759   {
1760     int max_label_counter = 23;
1761
1762     if (leveldir_current->imported_from != NULL)
1763       max_label_counter += 14;
1764
1765     label_counter = (label_counter + 1) % max_label_counter;
1766     label_state = (label_counter >= 0 && label_counter <= 7 ?
1767                    MICROLABEL_LEVEL_NAME :
1768                    label_counter >= 9 && label_counter <= 12 ?
1769                    MICROLABEL_CREATED_BY :
1770                    label_counter >= 14 && label_counter <= 21 ?
1771                    MICROLABEL_LEVEL_AUTHOR :
1772                    label_counter >= 23 && label_counter <= 26 ?
1773                    MICROLABEL_IMPORTED_FROM :
1774                    label_counter >= 28 && label_counter <= 35 ?
1775                    MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1776     DrawMicroLevelLabelExt(label_state);
1777   }
1778 }
1779
1780 int REQ_in_range(int x, int y)
1781 {
1782   if (y > DY+249 && y < DY+278)
1783   {
1784     if (x > DX+1 && x < DX+48)
1785       return 1;
1786     else if (x > DX+51 && x < DX+98) 
1787       return 2;
1788   }
1789   return 0;
1790 }
1791
1792 boolean Request(char *text, unsigned int req_state)
1793 {
1794   int mx, my, ty, result = -1;
1795   unsigned int old_door_state;
1796
1797 #ifndef MSDOS
1798   /* pause network game while waiting for request to answer */
1799   if (options.network &&
1800       game_status == PLAYING &&
1801       req_state & REQUEST_WAIT_FOR)
1802     SendToServer_PausePlaying();
1803 #endif
1804
1805   old_door_state = GetDoorState();
1806
1807   UnmapAllGadgets();
1808
1809   CloseDoor(DOOR_CLOSE_1);
1810
1811   /* save old door content */
1812   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1813             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1814             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1815
1816   /* clear door drawing field */
1817   XFillRectangle(display, drawto, gc, DX, DY, DXSIZE, DYSIZE);
1818
1819   /* write text for request */
1820   for(ty=0; ty<13; ty++)
1821   {
1822     int tx, tl, tc;
1823     char txt[256];
1824
1825     if (!*text)
1826       break;
1827
1828     for(tl=0,tx=0; tx<7; tl++,tx++)
1829     {
1830       tc = *(text + tx);
1831       if (!tc || tc == 32)
1832         break;
1833     }
1834     if (!tl)
1835     { 
1836       text++; 
1837       ty--; 
1838       continue; 
1839     }
1840     sprintf(txt, text); 
1841     txt[tl] = 0;
1842     DrawTextExt(drawto, gc,
1843                 DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
1844                 txt, FS_SMALL, FC_YELLOW);
1845     text += tl + (tc == 32 ? 1 : 0);
1846   }
1847
1848   if (req_state & REQ_ASK)
1849   {
1850     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1851     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1852   }
1853   else if (req_state & REQ_CONFIRM)
1854   {
1855     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1856   }
1857   else if (req_state & REQ_PLAYER)
1858   {
1859     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1860     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1861     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1862     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1863   }
1864
1865   /* copy request gadgets to door backbuffer */
1866   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
1867             DX, DY, DXSIZE, DYSIZE,
1868             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1869
1870   OpenDoor(DOOR_OPEN_1);
1871
1872 #if 0
1873   ClearEventQueue();
1874 #endif
1875
1876   if (!(req_state & REQUEST_WAIT_FOR))
1877     return(FALSE);
1878
1879   if (game_status != MAINMENU)
1880     InitAnimation();
1881
1882   button_status = MB_RELEASED;
1883
1884   request_gadget_id = -1;
1885
1886   while(result < 0)
1887   {
1888     if (XPending(display))
1889     {
1890       XEvent event;
1891
1892       XNextEvent(display, &event);
1893
1894       switch(event.type)
1895       {
1896         case ButtonPress:
1897         case ButtonRelease:
1898         case MotionNotify:
1899         {
1900           if (event.type == MotionNotify)
1901           {
1902             Window root, child;
1903             int root_x, root_y;
1904             int win_x, win_y;
1905             unsigned int mask;
1906
1907             if (!XQueryPointer(display, window, &root, &child,
1908                                &root_x, &root_y, &win_x, &win_y, &mask))
1909               continue;
1910
1911             if (!button_status)
1912               continue;
1913
1914             motion_status = TRUE;
1915             mx = ((XMotionEvent *) &event)->x;
1916             my = ((XMotionEvent *) &event)->y;
1917           }
1918           else
1919           {
1920             motion_status = FALSE;
1921             mx = ((XButtonEvent *) &event)->x;
1922             my = ((XButtonEvent *) &event)->y;
1923             if (event.type==ButtonPress)
1924               button_status = ((XButtonEvent *) &event)->button;
1925             else
1926               button_status = MB_RELEASED;
1927           }
1928
1929           /* this sets 'request_gadget_id' */
1930           HandleGadgets(mx, my, button_status);
1931
1932           switch(request_gadget_id)
1933           {
1934             case TOOL_CTRL_ID_YES:
1935               result = TRUE;
1936               break;
1937             case TOOL_CTRL_ID_NO:
1938               result = FALSE;
1939               break;
1940             case TOOL_CTRL_ID_CONFIRM:
1941               result = TRUE | FALSE;
1942               break;
1943
1944             case TOOL_CTRL_ID_PLAYER_1:
1945               result = 1;
1946               break;
1947             case TOOL_CTRL_ID_PLAYER_2:
1948               result = 2;
1949               break;
1950             case TOOL_CTRL_ID_PLAYER_3:
1951               result = 3;
1952               break;
1953             case TOOL_CTRL_ID_PLAYER_4:
1954               result = 4;
1955               break;
1956
1957             default:
1958               break;
1959           }
1960
1961           break;
1962         }
1963
1964         case KeyPress:
1965           switch(XLookupKeysym((XKeyEvent *)&event,
1966                                ((XKeyEvent *)&event)->state))
1967           {
1968             case XK_Return:
1969               result = 1;
1970               break;
1971
1972             case XK_Escape:
1973               result = 0;
1974               break;
1975
1976             default:
1977               break;
1978           }
1979           if (req_state & REQ_PLAYER)
1980             result = 0;
1981           break;
1982
1983         case KeyRelease:
1984           key_joystick_mapping = 0;
1985           break;
1986
1987         default:
1988           HandleOtherEvents(&event);
1989           break;
1990       }
1991     }
1992     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1993     {
1994       int joy = AnyJoystick();
1995
1996       if (joy & JOY_BUTTON_1)
1997         result = 1;
1998       else if (joy & JOY_BUTTON_2)
1999         result = 0;
2000     }
2001
2002     DoAnimation();
2003
2004     /* don't eat all CPU time */
2005     Delay(10);
2006   }
2007
2008   if (game_status != MAINMENU)
2009     StopAnimation();
2010
2011   UnmapToolButtons();
2012
2013   if (!(req_state & REQ_STAY_OPEN))
2014   {
2015     CloseDoor(DOOR_CLOSE_1);
2016
2017     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2018     {
2019       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
2020                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2021                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2022       OpenDoor(DOOR_OPEN_1);
2023     }
2024   }
2025
2026   RemapAllGadgets();
2027
2028 #ifndef MSDOS
2029   /* continue network game after request */
2030   if (options.network &&
2031       game_status == PLAYING &&
2032       req_state & REQUEST_WAIT_FOR)
2033     SendToServer_ContinuePlaying();
2034 #endif
2035
2036   return(result);
2037 }
2038
2039 unsigned int OpenDoor(unsigned int door_state)
2040 {
2041   unsigned int new_door_state;
2042
2043   if (door_state & DOOR_COPY_BACK)
2044   {
2045     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
2046               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2047               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2048     door_state &= ~DOOR_COPY_BACK;
2049   }
2050
2051   new_door_state = MoveDoor(door_state);
2052
2053   return(new_door_state);
2054 }
2055
2056 unsigned int CloseDoor(unsigned int door_state)
2057 {
2058   unsigned int new_door_state;
2059
2060   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
2061             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2062   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
2063             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2064
2065   new_door_state = MoveDoor(door_state);
2066
2067   return(new_door_state);
2068 }
2069
2070 unsigned int GetDoorState()
2071 {
2072   return(MoveDoor(DOOR_GET_STATE));
2073 }
2074
2075 unsigned int MoveDoor(unsigned int door_state)
2076 {
2077   static int door1 = DOOR_OPEN_1;
2078   static int door2 = DOOR_CLOSE_2;
2079   static unsigned long door_delay = 0;
2080   int x, start, stepsize = 2;
2081   unsigned long door_delay_value = stepsize * 5;
2082
2083   if (door_state == DOOR_GET_STATE)
2084     return(door1 | door2);
2085
2086   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2087     door_state &= ~DOOR_OPEN_1;
2088   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2089     door_state &= ~DOOR_CLOSE_1;
2090   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2091     door_state &= ~DOOR_OPEN_2;
2092   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2093     door_state &= ~DOOR_CLOSE_2;
2094
2095   if (setup.quick_doors)
2096   {
2097     stepsize = 20;
2098     door_delay_value = 0;
2099     StopSound(SND_OEFFNEN);
2100   }
2101
2102   if (door_state & DOOR_ACTION)
2103   {
2104     if (!(door_state & DOOR_NO_DELAY))
2105       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
2106
2107     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2108
2109     for(x=start; x<=DXSIZE; x+=stepsize)
2110     {
2111       WaitUntilDelayReached(&door_delay, door_delay_value);
2112
2113       if (door_state & DOOR_ACTION_1)
2114       {
2115         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2116         int j = (DXSIZE - i) / 3;
2117
2118         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2119                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2120                   DXSIZE,DYSIZE - i/2, DX, DY);
2121
2122         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2123
2124         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2125                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2126         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2127                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
2128         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2129                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
2130                   DY + 140 + j);
2131         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2132                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2133         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2134                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
2135         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2136                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
2137
2138         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2139                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2140                   DX, DY + 77 - j);
2141         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2142                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2143                   DX, DY + 203 - j);
2144         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2145                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2146         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2147                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2148                   DX + DXSIZE - i, DY + 77 + j);
2149         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2150                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2151                   DX + DXSIZE - i, DY + 203 + j);
2152
2153         redraw_mask |= REDRAW_DOOR_1;
2154       }
2155
2156       if (door_state & DOOR_ACTION_2)
2157       {
2158         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2159         int j = (VXSIZE - i) / 3;
2160
2161         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2162                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2163                   VXSIZE, VYSIZE - i/2, VX, VY);
2164
2165         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2166
2167         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2168                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2169         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2170                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
2171         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2172                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2173         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2174                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
2175
2176         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2177                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
2178                   VX, VY + VYSIZE / 2 - j);
2179         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2180                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2181         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2182                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
2183                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2184
2185         redraw_mask |= REDRAW_DOOR_2;
2186       }
2187
2188       BackToFront();
2189
2190       if (game_status == MAINMENU)
2191         DoAnimation();
2192     }
2193   }
2194
2195   if (setup.quick_doors)
2196     StopSound(SND_OEFFNEN);
2197
2198   if (door_state & DOOR_ACTION_1)
2199     door1 = door_state & DOOR_ACTION_1;
2200   if (door_state & DOOR_ACTION_2)
2201     door2 = door_state & DOOR_ACTION_2;
2202
2203   return (door1 | door2);
2204 }
2205
2206 void DrawSpecialEditorDoor()
2207 {
2208   /* draw bigger toolbox window */
2209   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2210             DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2211
2212   redraw_mask |= REDRAW_ALL;
2213 }
2214
2215 void UndrawSpecialEditorDoor()
2216 {
2217   /* draw normal tape recorder window */
2218   XCopyArea(display, pix[PIX_BACK], drawto, gc,
2219             562, 344, 108, 56, EX - 4, EY - 12);
2220
2221   redraw_mask |= REDRAW_ALL;
2222 }
2223
2224 int ReadPixel(Drawable d, int x, int y)
2225 {
2226   XImage *pixel_image;
2227   unsigned long pixel_value;
2228
2229   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
2230   pixel_value = XGetPixel(pixel_image, 0, 0);
2231
2232   XDestroyImage(pixel_image);
2233
2234   return pixel_value;
2235 }
2236
2237 /* ---------- new tool button stuff ---------------------------------------- */
2238
2239 /* graphic position values for tool buttons */
2240 #define TOOL_BUTTON_YES_XPOS            2
2241 #define TOOL_BUTTON_YES_YPOS            250
2242 #define TOOL_BUTTON_YES_GFX_YPOS        0
2243 #define TOOL_BUTTON_YES_XSIZE           46
2244 #define TOOL_BUTTON_YES_YSIZE           28
2245 #define TOOL_BUTTON_NO_XPOS             52
2246 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2247 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2248 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2249 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2250 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2251 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2252 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2253 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2254 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2255 #define TOOL_BUTTON_PLAYER_XSIZE        30
2256 #define TOOL_BUTTON_PLAYER_YSIZE        30
2257 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2258 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2259 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2260 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2261 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2262                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2263 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2264                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2265 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2266                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2267 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2268                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2269 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2270                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2271 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2272                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2273 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2274                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2275 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2276                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2277
2278 static struct
2279 {
2280   int xpos, ypos;
2281   int x, y;
2282   int width, height;
2283   int gadget_id;
2284   char *infotext;
2285 } toolbutton_info[NUM_TOOL_BUTTONS] =
2286 {
2287   {
2288     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2289     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2290     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2291     TOOL_CTRL_ID_YES,
2292     "yes"
2293   },
2294   {
2295     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2296     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2297     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2298     TOOL_CTRL_ID_NO,
2299     "no"
2300   },
2301   {
2302     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2303     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2304     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2305     TOOL_CTRL_ID_CONFIRM,
2306     "confirm"
2307   },
2308   {
2309     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2310     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2311     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2312     TOOL_CTRL_ID_PLAYER_1,
2313     "player 1"
2314   },
2315   {
2316     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2317     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2318     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2319     TOOL_CTRL_ID_PLAYER_2,
2320     "player 2"
2321   },
2322   {
2323     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2324     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2325     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2326     TOOL_CTRL_ID_PLAYER_3,
2327     "player 3"
2328   },
2329   {
2330     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2331     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2332     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2333     TOOL_CTRL_ID_PLAYER_4,
2334     "player 4"
2335   }
2336 };
2337
2338 static void DoNotDisplayInfoText(void *ptr)
2339 {
2340   return;
2341 }
2342
2343 void CreateToolButtons()
2344 {
2345   int i;
2346
2347   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2348   {
2349     Pixmap gd_pixmap = pix[PIX_DOOR];
2350     Pixmap deco_pixmap = None;
2351     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2352     struct GadgetInfo *gi;
2353     unsigned long event_mask;
2354     int gd_xoffset, gd_yoffset;
2355     int gd_x1, gd_x2, gd_y;
2356     int id = i;
2357
2358     event_mask = GD_EVENT_RELEASED;
2359
2360     gd_xoffset = toolbutton_info[i].xpos;
2361     gd_yoffset = toolbutton_info[i].ypos;
2362     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2363     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2364     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2365
2366     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2367     {
2368       getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
2369                            &deco_pixmap, &deco_x, &deco_y);
2370       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2371       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2372     }
2373
2374     gi = CreateGadget(GDI_CUSTOM_ID, id,
2375                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2376                       GDI_X, DX + toolbutton_info[i].x,
2377                       GDI_Y, DY + toolbutton_info[i].y,
2378                       GDI_WIDTH, toolbutton_info[i].width,
2379                       GDI_HEIGHT, toolbutton_info[i].height,
2380                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2381                       GDI_STATE, GD_BUTTON_UNPRESSED,
2382                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
2383                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
2384                       GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
2385                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2386                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2387                       GDI_DECORATION_SHIFTING, 1, 1,
2388                       GDI_EVENT_MASK, event_mask,
2389                       GDI_CALLBACK_ACTION, HandleToolButtons,
2390                       GDI_CALLBACK_INFO, DoNotDisplayInfoText,
2391                       GDI_END);
2392
2393     if (gi == NULL)
2394       Error(ERR_EXIT, "cannot create gadget");
2395
2396     tool_gadget[id] = gi;
2397   }
2398 }
2399
2400 static void UnmapToolButtons()
2401 {
2402   int i;
2403
2404   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2405     UnmapGadget(tool_gadget[i]);
2406 }
2407
2408 static void HandleToolButtons(struct GadgetInfo *gi)
2409 {
2410   request_gadget_id = gi->custom_id;
2411 }
2412
2413 int el2gfx(int element)
2414 {
2415   switch(element)
2416   {
2417     case EL_LEERRAUM:           return -1;
2418     case EL_ERDREICH:           return GFX_ERDREICH;
2419     case EL_MAUERWERK:          return GFX_MAUERWERK;
2420     case EL_FELSBODEN:          return GFX_FELSBODEN;
2421     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
2422     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
2423     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
2424     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
2425     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
2426     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
2427     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
2428     case EL_SPIELER1:           return GFX_SPIELER1;
2429     case EL_SPIELER2:           return GFX_SPIELER2;
2430     case EL_SPIELER3:           return GFX_SPIELER3;
2431     case EL_SPIELER4:           return GFX_SPIELER4;
2432     case EL_KAEFER:             return GFX_KAEFER;
2433     case EL_KAEFER_RIGHT:       return GFX_KAEFER_RIGHT;
2434     case EL_KAEFER_UP:          return GFX_KAEFER_UP;
2435     case EL_KAEFER_LEFT:        return GFX_KAEFER_LEFT;
2436     case EL_KAEFER_DOWN:        return GFX_KAEFER_DOWN;
2437     case EL_FLIEGER:            return GFX_FLIEGER;
2438     case EL_FLIEGER_RIGHT:      return GFX_FLIEGER_RIGHT;
2439     case EL_FLIEGER_UP:         return GFX_FLIEGER_UP;
2440     case EL_FLIEGER_LEFT:       return GFX_FLIEGER_LEFT;
2441     case EL_FLIEGER_DOWN:       return GFX_FLIEGER_DOWN;
2442     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
2443     case EL_BUTTERFLY_RIGHT:    return GFX_BUTTERFLY_RIGHT;
2444     case EL_BUTTERFLY_UP:       return GFX_BUTTERFLY_UP;
2445     case EL_BUTTERFLY_LEFT:     return GFX_BUTTERFLY_LEFT;
2446     case EL_BUTTERFLY_DOWN:     return GFX_BUTTERFLY_DOWN;
2447     case EL_FIREFLY:            return GFX_FIREFLY;
2448     case EL_FIREFLY_RIGHT:      return GFX_FIREFLY_RIGHT;
2449     case EL_FIREFLY_UP:         return GFX_FIREFLY_UP;
2450     case EL_FIREFLY_LEFT:       return GFX_FIREFLY_LEFT;
2451     case EL_FIREFLY_DOWN:       return GFX_FIREFLY_DOWN;
2452     case EL_MAMPFER:            return GFX_MAMPFER;
2453     case EL_ROBOT:              return GFX_ROBOT;
2454     case EL_BETON:              return GFX_BETON;
2455     case EL_DIAMANT:            return GFX_DIAMANT;
2456     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2457     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2458     case EL_TROPFEN:            return GFX_TROPFEN;
2459     case EL_BOMBE:              return GFX_BOMBE;
2460     case EL_MAGIC_WALL_OFF:     return GFX_MAGIC_WALL_OFF;
2461     case EL_MAGIC_WALL_EMPTY:   return GFX_MAGIC_WALL_EMPTY;
2462     case EL_MAGIC_WALL_FULL:    return GFX_MAGIC_WALL_FULL;
2463     case EL_MAGIC_WALL_DEAD:    return GFX_MAGIC_WALL_DEAD;
2464     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2465     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2466     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2467     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2468     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2469     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2470     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2471     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2472     case EL_LIFE:               return GFX_LIFE;
2473     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2474     case EL_DYNAMITE_ACTIVE:    return GFX_DYNAMIT;
2475     case EL_BADEWANNE:          return GFX_BADEWANNE;
2476     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2477     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2478     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2479     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2480     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2481     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2482     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2483     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2484     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2485     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2486     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2487     case EL_PFORTE1:            return GFX_PFORTE1;
2488     case EL_PFORTE2:            return GFX_PFORTE2;
2489     case EL_PFORTE3:            return GFX_PFORTE3;
2490     case EL_PFORTE4:            return GFX_PFORTE4;
2491     case EL_PFORTE1X:           return GFX_PFORTE1X;
2492     case EL_PFORTE2X:           return GFX_PFORTE2X;
2493     case EL_PFORTE3X:           return GFX_PFORTE3X;
2494     case EL_PFORTE4X:           return GFX_PFORTE4X;
2495     case EL_DYNAMITE_INACTIVE:  return GFX_DYNAMIT_AUS;
2496     case EL_PACMAN:             return GFX_PACMAN;
2497     case EL_PACMAN_RIGHT:       return GFX_PACMAN_RIGHT;
2498     case EL_PACMAN_UP:          return GFX_PACMAN_UP;
2499     case EL_PACMAN_LEFT:        return GFX_PACMAN_LEFT;
2500     case EL_PACMAN_DOWN:        return GFX_PACMAN_DOWN;
2501     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2502     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2503     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2504     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2505     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2506     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2507     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2508     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2509     case EL_MAUER_X:            return GFX_MAUER_X;
2510     case EL_MAUER_Y:            return GFX_MAUER_Y;
2511     case EL_MAUER_XY:           return GFX_MAUER_XY;
2512     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2513     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2514     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2515     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2516     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2517     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2518     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2519     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2520     case EL_MAMPFER2:           return GFX_MAMPFER2;
2521     case EL_MAGIC_WALL_BD_OFF:  return GFX_MAGIC_WALL_BD_OFF;
2522     case EL_MAGIC_WALL_BD_EMPTY:return GFX_MAGIC_WALL_BD_EMPTY;
2523     case EL_MAGIC_WALL_BD_FULL: return GFX_MAGIC_WALL_BD_FULL;
2524     case EL_MAGIC_WALL_BD_DEAD: return GFX_MAGIC_WALL_BD_DEAD;
2525     case EL_DYNABOMB_ACTIVE_1:  return GFX_DYNABOMB;
2526     case EL_DYNABOMB_ACTIVE_2:  return GFX_DYNABOMB;
2527     case EL_DYNABOMB_ACTIVE_3:  return GFX_DYNABOMB;
2528     case EL_DYNABOMB_ACTIVE_4:  return GFX_DYNABOMB;
2529     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2530     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2531     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2532     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2533     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2534     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2535     case EL_MOLE:               return GFX_MOLE;
2536     case EL_PINGUIN:            return GFX_PINGUIN;
2537     case EL_SCHWEIN:            return GFX_SCHWEIN;
2538     case EL_DRACHE:             return GFX_DRACHE;
2539     case EL_SONDE:              return GFX_SONDE;
2540     case EL_PFEIL_LEFT:         return GFX_PFEIL_LEFT;
2541     case EL_PFEIL_RIGHT:        return GFX_PFEIL_RIGHT;
2542     case EL_PFEIL_UP:           return GFX_PFEIL_UP;
2543     case EL_PFEIL_DOWN:         return GFX_PFEIL_DOWN;
2544     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2545     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2546     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2547     case EL_SP_ZONK:            return GFX_SP_ZONK;
2548       /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2549     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2550     case EL_BLACK_ORB:          return GFX_BLACK_ORB;
2551     case EL_EM_GATE_1:          return GFX_EM_GATE_1;
2552     case EL_EM_GATE_2:          return GFX_EM_GATE_2;
2553     case EL_EM_GATE_3:          return GFX_EM_GATE_3;
2554     case EL_EM_GATE_4:          return GFX_EM_GATE_4;
2555     case EL_EM_GATE_1X:         return GFX_EM_GATE_1X;
2556     case EL_EM_GATE_2X:         return GFX_EM_GATE_2X;
2557     case EL_EM_GATE_3X:         return GFX_EM_GATE_3X;
2558     case EL_EM_GATE_4X:         return GFX_EM_GATE_4X;
2559     case EL_EM_KEY_1_FILE:      return GFX_EM_KEY_1;
2560     case EL_EM_KEY_2_FILE:      return GFX_EM_KEY_2;
2561     case EL_EM_KEY_3_FILE:      return GFX_EM_KEY_3;
2562     case EL_EM_KEY_4_FILE:      return GFX_EM_KEY_4;
2563     case EL_EM_KEY_1:           return GFX_EM_KEY_1;
2564     case EL_EM_KEY_2:           return GFX_EM_KEY_2;
2565     case EL_EM_KEY_3:           return GFX_EM_KEY_3;
2566     case EL_EM_KEY_4:           return GFX_EM_KEY_4;
2567     case EL_PEARL:              return GFX_PEARL;
2568     case EL_CRYSTAL:            return GFX_CRYSTAL;
2569     case EL_WALL_PEARL:         return GFX_WALL_PEARL;
2570     case EL_WALL_CRYSTAL:       return GFX_WALL_CRYSTAL;
2571     case EL_DOOR_WHITE:         return GFX_DOOR_WHITE;
2572     case EL_DOOR_WHITE_GRAY:    return GFX_DOOR_WHITE_GRAY;
2573     case EL_KEY_WHITE:          return GFX_KEY_WHITE;
2574     case EL_SHIELD_PASSIVE:     return GFX_SHIELD_PASSIVE;
2575     case EL_SHIELD_ACTIVE:      return GFX_SHIELD_ACTIVE;
2576     case EL_EXTRA_TIME:         return GFX_EXTRA_TIME;
2577     case EL_SWITCHGATE_OPEN:    return GFX_SWITCHGATE_OPEN;
2578     case EL_SWITCHGATE_CLOSED:  return GFX_SWITCHGATE_CLOSED;
2579     case EL_SWITCHGATE_SWITCH_1:return GFX_SWITCHGATE_SWITCH_1;
2580     case EL_SWITCHGATE_SWITCH_2:return GFX_SWITCHGATE_SWITCH_2;
2581     case EL_BELT1_LEFT:         return GFX_BELT1_LEFT;
2582     case EL_BELT1_MIDDLE:       return GFX_BELT1_MIDDLE;
2583     case EL_BELT1_RIGHT:        return GFX_BELT1_RIGHT;
2584     case EL_BELT1_SWITCH_LEFT:  return GFX_BELT1_SWITCH_LEFT;
2585     case EL_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
2586     case EL_BELT1_SWITCH_RIGHT: return GFX_BELT1_SWITCH_RIGHT;
2587     case EL_BELT2_LEFT:         return GFX_BELT2_LEFT;
2588     case EL_BELT2_MIDDLE:       return GFX_BELT2_MIDDLE;
2589     case EL_BELT2_RIGHT:        return GFX_BELT2_RIGHT;
2590     case EL_BELT2_SWITCH_LEFT:  return GFX_BELT2_SWITCH_LEFT;
2591     case EL_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
2592     case EL_BELT2_SWITCH_RIGHT: return GFX_BELT2_SWITCH_RIGHT;
2593     case EL_BELT3_LEFT:         return GFX_BELT3_LEFT;
2594     case EL_BELT3_MIDDLE:       return GFX_BELT3_MIDDLE;
2595     case EL_BELT3_RIGHT:        return GFX_BELT3_RIGHT;
2596     case EL_BELT3_SWITCH_LEFT:  return GFX_BELT3_SWITCH_LEFT;
2597     case EL_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
2598     case EL_BELT3_SWITCH_RIGHT: return GFX_BELT3_SWITCH_RIGHT;
2599     case EL_BELT4_LEFT:         return GFX_BELT4_LEFT;
2600     case EL_BELT4_MIDDLE:       return GFX_BELT4_MIDDLE;
2601     case EL_BELT4_RIGHT:        return GFX_BELT4_RIGHT;
2602     case EL_BELT4_SWITCH_LEFT:  return GFX_BELT4_SWITCH_LEFT;
2603     case EL_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
2604     case EL_BELT4_SWITCH_RIGHT: return GFX_BELT4_SWITCH_RIGHT;
2605     case EL_LANDMINE:           return GFX_LANDMINE;
2606     case EL_ENVELOPE:           return GFX_ENVELOPE;
2607     case EL_LIGHT_SWITCH_OFF:   return GFX_LIGHT_SWITCH_OFF;
2608     case EL_LIGHT_SWITCH_ON:    return GFX_LIGHT_SWITCH_ON;
2609     case EL_SIGN_EXCLAMATION:   return GFX_SIGN_EXCLAMATION;
2610     case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2611     case EL_SIGN_STOP:          return GFX_SIGN_STOP;
2612     case EL_SIGN_WHEELCHAIR:    return GFX_SIGN_WHEELCHAIR;
2613     case EL_SIGN_PARKING:       return GFX_SIGN_PARKING;
2614     case EL_SIGN_ONEWAY:        return GFX_SIGN_ONEWAY;
2615     case EL_SIGN_HEART:         return GFX_SIGN_HEART;
2616     case EL_SIGN_TRIANGLE:      return GFX_SIGN_TRIANGLE;
2617     case EL_SIGN_ROUND:         return GFX_SIGN_ROUND;
2618     case EL_SIGN_EXIT:          return GFX_SIGN_EXIT;
2619     case EL_SIGN_YINYANG:       return GFX_SIGN_YINYANG;
2620     case EL_SIGN_OTHER:         return GFX_SIGN_OTHER;
2621     case EL_MOLE_LEFT:          return GFX_MOLE_LEFT;
2622     case EL_MOLE_RIGHT:         return GFX_MOLE_RIGHT;
2623     case EL_MOLE_UP:            return GFX_MOLE_UP;
2624     case EL_MOLE_DOWN:          return GFX_MOLE_DOWN;
2625     case EL_STEEL_SLANTED:      return GFX_STEEL_SLANTED;
2626     case EL_SAND_INVISIBLE:     return GFX_SAND_INVISIBLE;
2627     case EL_DX_UNKNOWN_15:      return GFX_DX_UNKNOWN_15;
2628     case EL_DX_UNKNOWN_42:      return GFX_DX_UNKNOWN_42;
2629     case EL_TIMEGATE_OPEN:      return GFX_TIMEGATE_OPEN;
2630     case EL_TIMEGATE_CLOSED:    return GFX_TIMEGATE_CLOSED;
2631     case EL_TIMEGATE_SWITCH_ON: return GFX_TIMEGATE_SWITCH;
2632     case EL_TIMEGATE_SWITCH_OFF:return GFX_TIMEGATE_SWITCH;
2633     case EL_BALLOON:            return GFX_BALLOON;
2634     case EL_BALLOON_SEND_LEFT:  return GFX_BALLOON_SEND_LEFT;
2635     case EL_BALLOON_SEND_RIGHT: return GFX_BALLOON_SEND_RIGHT;
2636     case EL_BALLOON_SEND_UP:    return GFX_BALLOON_SEND_UP;
2637     case EL_BALLOON_SEND_DOWN:  return GFX_BALLOON_SEND_DOWN;
2638     case EL_BALLOON_SEND_ANY:   return GFX_BALLOON_SEND_ANY;
2639     case EL_EMC_STEEL_WALL_1:   return GFX_EMC_STEEL_WALL_1;
2640     case EL_EMC_STEEL_WALL_2:   return GFX_EMC_STEEL_WALL_2;
2641     case EL_EMC_STEEL_WALL_3:   return GFX_EMC_STEEL_WALL_3;
2642     case EL_EMC_STEEL_WALL_4:   return GFX_EMC_STEEL_WALL_4;
2643     case EL_EMC_WALL_1:         return GFX_EMC_WALL_1;
2644     case EL_EMC_WALL_2:         return GFX_EMC_WALL_2;
2645     case EL_EMC_WALL_3:         return GFX_EMC_WALL_3;
2646     case EL_EMC_WALL_4:         return GFX_EMC_WALL_4;
2647     case EL_EMC_WALL_5:         return GFX_EMC_WALL_5;
2648     case EL_EMC_WALL_6:         return GFX_EMC_WALL_6;
2649     case EL_EMC_WALL_7:         return GFX_EMC_WALL_7;
2650     case EL_EMC_WALL_8:         return GFX_EMC_WALL_8;
2651     case EL_TUBE_CROSS:         return GFX_TUBE_CROSS;
2652     case EL_TUBE_VERTICAL:      return GFX_TUBE_VERTICAL;
2653     case EL_TUBE_HORIZONTAL:    return GFX_TUBE_HORIZONTAL;
2654     case EL_TUBE_VERT_LEFT:     return GFX_TUBE_VERT_LEFT;
2655     case EL_TUBE_VERT_RIGHT:    return GFX_TUBE_VERT_RIGHT;
2656     case EL_TUBE_HORIZ_UP:      return GFX_TUBE_HORIZ_UP;
2657     case EL_TUBE_HORIZ_DOWN:    return GFX_TUBE_HORIZ_DOWN;
2658     case EL_TUBE_LEFT_UP:       return GFX_TUBE_LEFT_UP;
2659     case EL_TUBE_LEFT_DOWN:     return GFX_TUBE_LEFT_DOWN;
2660     case EL_TUBE_RIGHT_UP:      return GFX_TUBE_RIGHT_UP;
2661     case EL_TUBE_RIGHT_DOWN:    return GFX_TUBE_RIGHT_DOWN;
2662     case EL_SPRING:             return GFX_SPRING;
2663     case EL_SPRING_MOVING:      return GFX_SPRING;
2664     case EL_TRAP_INACTIVE:      return GFX_TRAP_INACTIVE;
2665     case EL_TRAP_ACTIVE:        return GFX_TRAP_ACTIVE;
2666     case EL_BD_WALL:            return GFX_BD_WALL;
2667     case EL_BD_ROCK:            return GFX_BD_ROCK;
2668     case EL_DX_SUPABOMB:        return GFX_DX_SUPABOMB;
2669     case EL_SP_MURPHY_CLONE:    return GFX_SP_MURPHY_CLONE;
2670
2671     default:
2672     {
2673       if (IS_CHAR(element))
2674         return GFX_CHAR_START + (element - EL_CHAR_START);
2675       else if (element >= EL_SP_START && element <= EL_SP_END)
2676       {
2677         int nr_element = element - EL_SP_START;
2678         int gfx_per_line = 8;
2679         int nr_graphic =
2680           (nr_element / gfx_per_line) * SP_PER_LINE +
2681           (nr_element % gfx_per_line);
2682
2683         return GFX_START_ROCKSSP + nr_graphic;
2684       }
2685       else
2686         return -1;
2687     }
2688   }
2689 }