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