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