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