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