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