rnd-19990122-2
[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 void SetDrawtoField(int mode)
35 {
36   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
37   {
38     FX = TILEX;
39     FY = TILEY;
40     BX1 = -1;
41     BY1 = -1;
42     BX2 = SCR_FIELDX;
43     BY2 = SCR_FIELDY;
44     redraw_x1 = 1;
45     redraw_y1 = 1;
46
47     drawto_field = fieldbuffer;
48   }
49   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
50   {
51     FX = SX;
52     FY = SY;
53     BX1 = 0;
54     BY1 = 0;
55     BX2 = SCR_FIELDX - 1;
56     BY2 = SCR_FIELDY - 1;
57     redraw_x1 = 0;
58     redraw_y1 = 0;
59
60     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
61   }
62 }
63
64 void BackToFront()
65 {
66   int x,y;
67   Drawable buffer = (drawto_field == window ? backbuffer : drawto_field);
68
69   if (setup.direct_draw && game_status == PLAYING)
70     redraw_mask &= ~REDRAW_MAIN;
71
72   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
73     redraw_mask |= REDRAW_FIELD;
74
75   if (redraw_mask & REDRAW_FIELD)
76     redraw_mask &= ~REDRAW_TILES;
77
78   /*
79   if (redraw_mask & REDRAW_FIELD ||
80       (ScreenGfxPos && setup.soft_scrolling && game_status == PLAYING))
81     redraw_mask &= ~REDRAW_TILES;
82   */
83
84   if (!redraw_mask)
85     return;
86
87   /* synchronize X11 graphics at this point; if we would synchronize the
88      display immediately after the buffer switching (after the XFlush),
89      this could mean that we have to wait for the graphics to complete,
90      although we could go on doing calculations for the next frame */
91
92   XSync(display, FALSE);
93
94   /*
95 #ifdef MSDOS
96   wait_for_vsync = TRUE;
97 #endif
98   */
99
100   if (redraw_mask & REDRAW_ALL)
101   {
102     XCopyArea(display,backbuffer,window,gc,
103               0,0, WIN_XSIZE,WIN_YSIZE,
104               0,0);
105     redraw_mask = 0;
106   }
107
108   if (redraw_mask & REDRAW_FIELD)
109   {
110     if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
111       XCopyArea(display,backbuffer,window,gc,
112                 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
113                 REAL_SX,REAL_SY);
114     else
115     {
116       int fx = FX, fy = FY;
117
118       if (setup.soft_scrolling)
119       {
120         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
121         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
122       }
123
124       if (setup.soft_scrolling ||
125           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
126           ABS(ScreenMovPos) == ScrollStepSize ||
127           redraw_tiles > REDRAWTILES_THRESHOLD)
128       {
129         XCopyArea(display, buffer, window, gc, fx, fy, SXSIZE, SYSIZE, SX, SY);
130
131 #ifdef DEBUG
132 #if 0
133         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
134                ScreenGfxPos,
135                (setup.soft_scrolling ?
136                 "setup.soft_scrolling" :
137                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
138                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
139                 ABS(ScreenGfxPos) == ScrollStepSize ?
140                 "ABS(ScreenGfxPos) == ScrollStepSize" :
141                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
142 #endif
143 #endif
144       }
145     }
146     redraw_mask &= ~REDRAW_MAIN;
147   }
148
149   if (redraw_mask & REDRAW_DOORS)
150   {
151     if (redraw_mask & REDRAW_DOOR_1)
152       XCopyArea(display,backbuffer,window,gc,
153                 DX,DY, DXSIZE,DYSIZE,
154                 DX,DY);
155     if (redraw_mask & REDRAW_DOOR_2)
156     {
157       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
158         XCopyArea(display,backbuffer,window,gc,
159                   VX,VY, VXSIZE,VYSIZE,
160                   VX,VY);
161       else
162       {
163         if (redraw_mask & REDRAW_VIDEO_1)
164           XCopyArea(display,backbuffer,window,gc,
165                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
166                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
167                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
168         if (redraw_mask & REDRAW_VIDEO_2)
169           XCopyArea(display,backbuffer,window,gc,
170                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
171                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
172                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
173         if (redraw_mask & REDRAW_VIDEO_3)
174           XCopyArea(display,backbuffer,window,gc,
175                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
176                     VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
177                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
178       }
179     }
180     if (redraw_mask & REDRAW_DOOR_3)
181       XCopyArea(display, backbuffer, window, gc,
182                 EX, EY, EXSIZE, EYSIZE,
183                 EX, EY);
184     redraw_mask &= ~REDRAW_DOORS;
185   }
186
187   if (redraw_mask & REDRAW_MICROLEVEL)
188   {
189     XCopyArea(display,backbuffer,window,gc,
190               MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
191               MICROLEV_XPOS, MICROLEV_YPOS);
192     redraw_mask &= ~REDRAW_MICROLEVEL;
193   }
194
195   if (redraw_mask & REDRAW_MICROLEVEL_LABEL)
196   {
197     XCopyArea(display,backbuffer,window,gc,
198               SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
199               SX, MICROLABEL_YPOS);
200     redraw_mask &= ~REDRAW_MICROLEVEL_LABEL;
201   }
202
203   if (redraw_mask & REDRAW_TILES)
204   {
205     for(x=0; x<SCR_FIELDX; x++)
206       for(y=0; y<SCR_FIELDY; y++)
207         if (redraw[redraw_x1 + x][redraw_y1 + y])
208           XCopyArea(display,buffer,window,gc,
209                     FX+x*TILEX,FX+y*TILEY, TILEX,TILEY,
210                     SX+x*TILEX,SY+y*TILEY);
211   }
212
213   XFlush(display);
214
215   for(x=0; x<MAX_BUF_XSIZE; x++)
216     for(y=0; y<MAX_BUF_YSIZE; y++)
217       redraw[x][y] = 0;
218   redraw_tiles = 0;
219   redraw_mask = 0;
220 }
221
222 void FadeToFront()
223 {
224 /*
225   long fading_delay = 300;
226
227   if (setup.fading && (redraw_mask & REDRAW_FIELD))
228   {
229 */
230
231 /*
232     int x,y;
233
234     XFillRectangle(display,window,gc,
235                    REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
236     XFlush(display);
237
238     for(i=0;i<2*FULL_SYSIZE;i++)
239     {
240       for(y=0;y<FULL_SYSIZE;y++)
241       {
242         XCopyArea(display,backbuffer,window,gc,
243                   REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
244       }
245       XFlush(display);
246       Delay(10);
247     }
248 */
249
250 /*
251     for(i=1;i<FULL_SYSIZE;i+=2)
252       XCopyArea(display,backbuffer,window,gc,
253                 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
254     XFlush(display);
255     Delay(fading_delay);
256 */
257
258 /*
259     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
260     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
261               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
262     XFlush(display);
263     Delay(fading_delay);
264
265     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
266     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
267               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
268     XFlush(display);
269     Delay(fading_delay);
270
271     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
272     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
273               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
274     XFlush(display);
275     Delay(fading_delay);
276
277     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,0);
278     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
279               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
280     XFlush(display);
281     Delay(fading_delay);
282
283     redraw_mask &= ~REDRAW_MAIN;
284   }
285 */
286
287   BackToFront();
288 }
289
290 void ClearWindow()
291 {
292   XFillRectangle(display, backbuffer, gc,
293                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
294
295   if (setup.soft_scrolling && game_status == PLAYING)
296   {
297     XFillRectangle(display, fieldbuffer, gc, 0, 0, FXSIZE, FYSIZE);
298     SetDrawtoField(DRAW_BUFFERED);
299   }
300   else
301     SetDrawtoField(DRAW_BACKBUFFER);
302
303   if (setup.direct_draw && game_status == PLAYING)
304   {
305     XFillRectangle(display, window, gc,
306                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
307     SetDrawtoField(DRAW_DIRECT);
308   }
309
310   redraw_mask |= REDRAW_FIELD;
311 }
312
313 void DrawTextFCentered(int y, int font_type, char *format, ...)
314 {
315   char buffer[FULL_SXSIZE / FONT3_XSIZE + 10];
316   int font_xsize;
317   va_list ap;
318
319   font_xsize = (font_type < FC_SPECIAL1 ? FONT2_XSIZE :
320                 font_type < FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
321
322   va_start(ap, format);
323   vsprintf(buffer, format, ap);
324   va_end(ap);
325
326   DrawText(SX + (SXSIZE - strlen(buffer) * font_xsize) / 2, SY + y,
327            buffer, FS_SMALL, font_type);
328 }
329
330 void DrawTextF(int x, int y, int font_type, char *format, ...)
331 {
332   char buffer[FULL_SXSIZE / FONT3_XSIZE + 10];
333   va_list ap;
334
335   va_start(ap, format);
336   vsprintf(buffer, format, ap);
337   va_end(ap);
338
339   DrawText(SX + x, SY + y, buffer, FS_SMALL, font_type);
340 }
341
342 void DrawText(int x, int y, char *text, int font_size, int font_type)
343 {
344   DrawTextExt(drawto, gc, x, y, text, font_size, font_type);
345
346   if (x < DX)
347     redraw_mask |= REDRAW_FIELD;
348   else if (y < VY)
349     redraw_mask |= REDRAW_DOOR_1;
350 }
351
352 void DrawTextExt(Drawable d, GC gc, int x, int y,
353                  char *text, int font_size, int font_type)
354 {
355   int font_width, font_height, font_start;
356   int font_pixmap;
357   boolean print_inverse = FALSE;
358
359   if (font_size != FS_SMALL && font_size != FS_BIG)
360     font_size = FS_SMALL;
361   if (font_type < FC_RED || font_type > FC_SPECIAL2)
362     font_type = FC_RED;
363
364   font_width = (font_size == FS_BIG ? FONT1_XSIZE :
365                 font_type < FC_SPECIAL1 ? FONT2_XSIZE :
366                 font_type < FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
367   font_height = (font_size == FS_BIG ? FONT1_XSIZE :
368                  font_type < FC_SPECIAL2 ? FONT2_XSIZE : FONT4_XSIZE);
369   font_pixmap = (font_size == FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
370   font_start = (font_type * (font_size == FS_BIG ? FONT1_YSIZE : FONT2_YSIZE) *
371                 FONT_LINES_PER_FONT);
372
373   while (*text)
374   {
375     char c = *text++;
376
377     if (c == '~' && font_size == FS_SMALL && font_type <= FC_YELLOW)
378     {
379       print_inverse = TRUE;
380       continue;
381     }
382
383     if (c >= 'a' && c <= 'z')
384       c = 'A' + (c - 'a');
385     else if (c == 'ä' || c == 'Ä')
386       c = 91;
387     else if (c == 'ö' || c == 'Ö')
388       c = 92;
389     else if (c == 'ü' || c == 'Ãœ')
390       c = 93;
391
392     if (c >= 32 && c <= 95)
393     {
394       int src_x = ((c - 32) % FONT_CHARS_PER_LINE) * font_width;
395       int src_y = ((c - 32) / FONT_CHARS_PER_LINE) * font_height + font_start;
396       int dest_x = x, dest_y = y;
397
398       if (print_inverse)
399       {
400         XCopyArea(display, pix[font_pixmap], d, gc,
401                   FONT_CHARS_PER_LINE * font_width,
402                   3 * font_height + font_start,
403                   font_width, font_height, x, y);
404
405         XSetClipOrigin(display, clip_gc[font_pixmap],
406                        dest_x - src_x, dest_y - src_y);
407         XCopyArea(display, pix[font_pixmap], drawto, clip_gc[font_pixmap],
408                   0, 0, font_width, font_height, dest_x, dest_y);
409       }
410       else
411         XCopyArea(display, pix[font_pixmap], d, gc,
412                   src_x, src_y, font_width, font_height, dest_x, dest_y);
413     }
414
415     x += font_width;
416   }
417 }
418
419 void DrawAllPlayers()
420 {
421   int i;
422
423   for(i=0; i<MAX_PLAYERS; i++)
424     if (stored_player[i].active)
425       DrawPlayer(&stored_player[i]);
426 }
427
428 void DrawPlayerField(int x, int y)
429 {
430   if (!IS_PLAYER(x,y))
431     return;
432
433   DrawPlayer(PLAYERINFO(x,y));
434 }
435
436 void DrawPlayer(struct PlayerInfo *player)
437 {
438   int jx = player->jx, jy = player->jy;
439   int last_jx = player->last_jx, last_jy = player->last_jy;
440   int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
441   int sx = SCREENX(jx), sy = SCREENY(jy);
442   int sxx = 0, syy = 0;
443   int element = Feld[jx][jy];
444   int graphic, phase;
445
446   if (!player->active || player->gone ||
447       !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
448     return;
449
450 #if DEBUG
451   if (!IN_LEV_FIELD(jx,jy))
452   {
453     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
454     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
455     printf("DrawPlayerField(): This should never happen!\n");
456     return;
457   }
458 #endif
459
460   if (element == EL_EXPLODING)
461     return;
462
463   /* draw things in the field the player is leaving, if needed */
464
465   if (last_jx != jx || last_jy != jy)
466   {
467     if (Store[last_jx][last_jy])
468     {
469       DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
470       DrawLevelFieldThruMask(last_jx, last_jy);
471     }
472     else if (Feld[last_jx][last_jy] == EL_DYNAMIT)
473       DrawDynamite(last_jx, last_jy);
474     else
475       DrawLevelField(last_jx, last_jy);
476
477     if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
478     {
479       if (player->GfxPos)
480       {
481         if (Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
482           DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FELD_LEER);
483         else
484           DrawLevelElement(next_jx, next_jy, EL_LEERRAUM);
485       }
486       else
487         DrawLevelField(next_jx, next_jy);
488     }
489   }
490
491   if (!IN_SCR_FIELD(sx, sy))
492     return;
493
494   if (setup.direct_draw)
495     SetDrawtoField(DRAW_BUFFERED);
496
497   /* draw things behind the player, if needed */
498
499   if (Store[jx][jy])
500     DrawLevelElement(jx, jy, Store[jx][jy]);
501   else if (element != EL_DYNAMIT && element != EL_DYNABOMB)
502     DrawLevelField(jx, jy);
503
504   /* draw player himself */
505
506   if (player->MovDir == MV_LEFT)
507     graphic = (player->Pushing ? GFX_SPIELER1_PUSH_LEFT : GFX_SPIELER1_LEFT);
508   else if (player->MovDir == MV_RIGHT)
509     graphic = (player->Pushing ? GFX_SPIELER1_PUSH_RIGHT : GFX_SPIELER1_RIGHT);
510   else if (player->MovDir == MV_UP)
511     graphic = GFX_SPIELER1_UP;
512   else  /* MV_DOWN || MV_NO_MOVING */
513     graphic = GFX_SPIELER1_DOWN;
514
515   graphic += player->index_nr * 3*HEROES_PER_LINE;
516   graphic += player->Frame;
517
518   if (player->GfxPos)
519   {
520     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
521       sxx = player->GfxPos;
522     else
523       syy = player->GfxPos;
524   }
525
526   if (!setup.soft_scrolling && ScreenMovPos)
527     sxx = syy = 0;
528
529   DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, NO_CUTTING);
530
531   if (player->Pushing && player->GfxPos)
532   {
533     int px = SCREENX(next_jx), py = SCREENY(next_jy);
534
535     if (Feld[jx][jy] == EL_SOKOBAN_FELD_LEER ||
536         Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
537       DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT,
538                                  NO_CUTTING);
539     else
540     {
541       int element = Feld[next_jx][next_jy];
542       int graphic = el2gfx(element);
543
544       if (element == EL_FELSBROCKEN && sxx)
545       {
546         int phase = (player->GfxPos / (TILEX/4));
547
548         if (player->MovDir == MV_LEFT)
549           graphic += phase;
550         else
551           graphic += (phase+4)%4;
552       }
553
554       DrawGraphicShifted(px, py, sxx, syy, graphic, NO_CUTTING, NO_MASKING);
555     }
556   }
557
558   /* draw things in front of player (EL_DYNAMIT || EL_DYNABOMB) */
559
560   if (element == EL_DYNAMIT || element == EL_DYNABOMB)
561   {
562     graphic = el2gfx(element);
563
564     if (element == EL_DYNAMIT)
565     {
566       if ((phase = (96 - MovDelay[jx][jy]) / 12) > 6)
567         phase = 6;
568     }
569     else
570     {
571       if ((phase = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
572         phase = 7 - phase;
573     }
574
575     if (game_emulation == EMU_SUPAPLEX)
576       DrawGraphic(sx, sy, GFX_SP_DISK_RED);
577     else
578       DrawGraphicThruMask(sx, sy, graphic + phase);
579   }
580
581   if ((last_jx != jx || last_jy != jy) &&
582       Feld[last_jx][last_jy] == EL_EXPLODING)
583   {
584     int phase = Frame[last_jx][last_jy];
585     int delay = 2;
586
587     if (phase > 2)
588       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy),
589                           GFX_EXPLOSION + ((phase - 1) / delay - 1));
590   }
591
592   if (setup.direct_draw)
593   {
594     int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
595     int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
596     int x_size = TILEX * (1 + ABS(jx - last_jx));
597     int y_size = TILEY * (1 + ABS(jy - last_jy));
598
599     XCopyArea(display, drawto_field, window, gc,
600               dest_x, dest_y, x_size, y_size, dest_x, dest_y);
601     SetDrawtoField(DRAW_DIRECT);
602   }
603
604   MarkTileDirty(sx,sy);
605 }
606
607 static int getGraphicAnimationPhase(int frames, int delay, int mode)
608 {
609   int phase;
610
611   if (mode == ANIM_OSCILLATE)
612   {
613     int max_anim_frames = 2 * frames - 2;
614     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
615     phase = (phase < frames ? phase : max_anim_frames - phase);
616   }
617   else
618     phase = (FrameCounter % (delay * frames)) / delay;
619
620   if (mode == ANIM_REVERSE)
621     phase = -phase;
622
623   return(phase);
624 }
625
626 void DrawGraphicAnimationExt(int x, int y, int graphic,
627                              int frames, int delay, int mode, int mask_mode)
628 {
629   int phase = getGraphicAnimationPhase(frames, delay, mode);
630
631   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
632   {
633     if (mask_mode == USE_MASKING)
634       DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic + phase);
635     else
636       DrawGraphic(SCREENX(x), SCREENY(y), graphic + phase);
637   }
638 }
639
640 void DrawGraphicAnimation(int x, int y, int graphic,
641                           int frames, int delay, int mode)
642 {
643   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
644 }
645
646 void DrawGraphicAnimationThruMask(int x, int y, int graphic,
647                                   int frames, int delay, int mode)
648 {
649   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, USE_MASKING);
650 }
651
652 void DrawGraphic(int x, int y, int graphic)
653 {
654 #if DEBUG
655   if (!IN_SCR_FIELD(x,y))
656   {
657     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
658     printf("DrawGraphic(): This should never happen!\n");
659     return;
660   }
661 #endif
662
663   DrawGraphicExt(drawto_field, gc, FX + x*TILEX, FY + y*TILEY, graphic);
664   MarkTileDirty(x,y);
665 }
666
667 void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
668 {
669   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
670   {
671     graphic -= GFX_START_ROCKSSCREEN;
672     XCopyArea(display, pix[PIX_BACK], d, gc,
673               SX + (graphic % GFX_PER_LINE) * TILEX,
674               SY + (graphic / GFX_PER_LINE) * TILEY,
675               TILEX, TILEY, x, y);
676   }
677   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
678   {
679     graphic -= GFX_START_ROCKSMORE;
680     XCopyArea(display, pix[PIX_MORE], d, gc,
681               (graphic % MORE_PER_LINE) * TILEX,
682               (graphic / MORE_PER_LINE) * TILEY,
683               TILEX, TILEY, x, y);
684   }
685   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
686   {
687     graphic -= GFX_START_ROCKSHEROES;
688     XCopyArea(display, pix[PIX_HEROES], d, gc,
689               (graphic % HEROES_PER_LINE) * TILEX,
690               (graphic / HEROES_PER_LINE) * TILEY,
691               TILEX, TILEY, x, y);
692   }
693   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
694   {
695     graphic -= GFX_START_ROCKSFONT;
696     XCopyArea(display, pix[PIX_BIGFONT], d, gc,
697               (graphic % FONT_CHARS_PER_LINE) * TILEX,
698               (graphic / FONT_CHARS_PER_LINE) * TILEY +
699               FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY,
700               TILEX, TILEY, x, y);
701   }
702   else
703     XFillRectangle(display, d, gc, x, y, TILEX, TILEY);
704 }
705
706 void DrawGraphicThruMask(int x, int y, int graphic)
707 {
708 #if DEBUG
709   if (!IN_SCR_FIELD(x,y))
710   {
711     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
712     printf("DrawGraphicThruMask(): This should never happen!\n");
713     return;
714   }
715 #endif
716
717   DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
718   MarkTileDirty(x,y);
719 }
720
721 void DrawGraphicThruMaskExt(Drawable d, int dest_x, int dest_y, int graphic)
722 {
723   int src_x, src_y;
724   int tile = graphic;
725   Pixmap src_pixmap;
726   GC drawing_gc;
727
728   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
729   {
730     src_pixmap = pix[PIX_BACK];
731     drawing_gc = clip_gc[PIX_BACK];
732     graphic -= GFX_START_ROCKSSCREEN;
733     src_x  = SX + (graphic % GFX_PER_LINE) * TILEX;
734     src_y  = SY + (graphic / GFX_PER_LINE) * TILEY;
735   }
736   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
737   {
738     src_pixmap = pix[PIX_MORE];
739     drawing_gc = clip_gc[PIX_MORE];
740     graphic -= GFX_START_ROCKSMORE;
741     src_x  = (graphic % MORE_PER_LINE) * TILEX;
742     src_y  = (graphic / MORE_PER_LINE) * TILEY;
743   }
744   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
745   {
746     src_pixmap = pix[PIX_HEROES];
747     drawing_gc = clip_gc[PIX_HEROES];
748     graphic -= GFX_START_ROCKSHEROES;
749     src_x  = (graphic % HEROES_PER_LINE) * TILEX;
750     src_y  = (graphic / HEROES_PER_LINE) * TILEY;
751   }
752   else
753   {
754     DrawGraphicExt(d, gc, dest_x,dest_y, graphic);
755     return;
756   }
757
758   if (tile_clipmask[tile] != None)
759   {
760     XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
761     XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
762     XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
763               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
764   }
765   else
766   {
767 #if DEBUG
768     printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
769 #endif
770
771     XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y);
772     XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
773               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
774   }
775 }
776
777 void DrawMiniGraphic(int x, int y, int graphic)
778 {
779   DrawMiniGraphicExt(drawto,gc, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
780   MarkTileDirty(x/2, y/2);
781 }
782
783 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
784 {
785   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
786   {
787     graphic -= GFX_START_ROCKSSCREEN;
788     XCopyArea(display, pix[PIX_BACK], d, gc,
789               MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX,
790               MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY,
791               MINI_TILEX, MINI_TILEY, x, y);
792   }
793   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
794   {
795     graphic -= GFX_START_ROCKSMORE;
796     XCopyArea(display, pix[PIX_MORE], d, gc,
797               MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX,
798               MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY,
799               MINI_TILEX, MINI_TILEY, x, y);
800   }
801   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
802   {
803     graphic -= GFX_START_ROCKSFONT;
804     XCopyArea(display, pix[PIX_SMALLFONT], d, gc,
805               (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE,
806               (graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
807               FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT,
808               MINI_TILEX, MINI_TILEY, x, y);
809   }
810   else
811     XFillRectangle(display, d, gc, x, y, MINI_TILEX, MINI_TILEY);
812 }
813
814 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
815                         int cut_mode, int mask_mode)
816 {
817   int width = TILEX, height = TILEY;
818   int cx = 0, cy = 0;
819   int src_x, src_y, dest_x, dest_y;
820   int tile = graphic;
821   Pixmap src_pixmap;
822   GC drawing_gc;
823
824   if (graphic < 0)
825   {
826     DrawGraphic(x, y, graphic);
827     return;
828   }
829
830   if (dx || dy)                 /* Verschiebung der Grafik? */
831   {
832     if (x < BX1)                /* Element kommt von links ins Bild */
833     {
834       x = BX1;
835       width = dx;
836       cx = TILEX - dx;
837       dx = 0;
838     }
839     else if (x > BX2)           /* Element kommt von rechts ins Bild */
840     {
841       x = BX2;
842       width = -dx;
843       dx = TILEX + dx;
844     }
845     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
846     {
847       width += dx;
848       cx = -dx;
849       dx = 0;
850     }
851     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
852       width -= dx;
853     else if (dx)                /* allg. Bewegung in x-Richtung */
854       MarkTileDirty(x + SIGN(dx), y);
855
856     if (y < BY1)                /* Element kommt von oben ins Bild */
857     {
858       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
859         return;
860
861       y = BY1;
862       height = dy;
863       cy = TILEY - dy;
864       dy = 0;
865     }
866     else if (y > BY2)           /* Element kommt von unten ins Bild */
867     {
868       y = BY2;
869       height = -dy;
870       dy = TILEY + dy;
871     }
872     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
873     {
874       height += dy;
875       cy = -dy;
876       dy = 0;
877     }
878     else if (dy > 0 && cut_mode == CUT_ABOVE)
879     {
880       if (y == BY2)             /* Element unterhalb des Bildes */
881         return;
882
883       height = dy;
884       cy = TILEY - dy;
885       dy = TILEY;
886       MarkTileDirty(x, y + 1);
887     }                           /* Element verläßt unten das Bild */
888     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
889       height -= dy;
890     else if (dy)                /* allg. Bewegung in y-Richtung */
891       MarkTileDirty(x, y + SIGN(dy));
892   }
893
894   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
895   {
896     src_pixmap = pix[PIX_BACK];
897     drawing_gc = clip_gc[PIX_BACK];
898     graphic -= GFX_START_ROCKSSCREEN;
899     src_x  = SX + (graphic % GFX_PER_LINE) * TILEX + cx;
900     src_y  = SY + (graphic / GFX_PER_LINE) * TILEY + cy;
901   }
902   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
903   {
904     src_pixmap = pix[PIX_MORE];
905     drawing_gc = clip_gc[PIX_MORE];
906     graphic -= GFX_START_ROCKSMORE;
907     src_x  = (graphic % MORE_PER_LINE) * TILEX + cx;
908     src_y  = (graphic / MORE_PER_LINE) * TILEY + cy;
909   }
910   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
911   {
912     src_pixmap = pix[PIX_HEROES];
913     drawing_gc = clip_gc[PIX_HEROES];
914     graphic -= GFX_START_ROCKSHEROES;
915     src_x  = (graphic % HEROES_PER_LINE) * TILEX + cx;
916     src_y  = (graphic / HEROES_PER_LINE) * TILEY + cy;
917   }
918   else  /* big font graphics currently not allowed (and not needed) */
919     return;
920
921   dest_x = FX + x * TILEX + dx;
922   dest_y = FY + y * TILEY + dy;
923
924 #if DEBUG
925   if (!IN_SCR_FIELD(x,y))
926   {
927     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
928     printf("DrawGraphicShifted(): This should never happen!\n");
929     return;
930   }
931 #endif
932
933   if (mask_mode == USE_MASKING)
934   {
935     if (tile_clipmask[tile] != None)
936     {
937       XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
938       XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
939       XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
940                 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
941     }
942     else
943     {
944 #if DEBUG
945       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
946 #endif
947
948       XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
949       XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
950                 src_x, src_y, width, height, dest_x, dest_y);
951     }
952   }
953   else
954     XCopyArea(display, src_pixmap, drawto_field, gc,
955               src_x, src_y, width, height, dest_x, dest_y);
956
957   MarkTileDirty(x,y);
958 }
959
960 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
961                                 int cut_mode)
962 {
963   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
964 }
965
966 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
967                           int cut_mode, int mask_mode)
968 {
969   int ux = LEVELX(x), uy = LEVELY(y);
970   int graphic = el2gfx(element);
971   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
972   int phase4 = phase8 / 2;
973   int phase2  = phase8 / 4;
974   int dir = MovDir[ux][uy];
975
976   if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
977   {
978     graphic += 4 * !phase2;
979
980     if (dir == MV_UP)
981       graphic += 1;
982     else if (dir == MV_LEFT)
983       graphic += 2;
984     else if (dir == MV_DOWN)
985       graphic += 3;
986   }
987   else if (element == EL_SP_SNIKSNAK)
988   {
989     if (dir == MV_LEFT)
990       graphic = GFX_SP_SNIKSNAK_LEFT;
991     else if (dir == MV_RIGHT)
992       graphic = GFX_SP_SNIKSNAK_RIGHT;
993     else if (dir == MV_UP)
994       graphic = GFX_SP_SNIKSNAK_UP;
995     else
996       graphic = GFX_SP_SNIKSNAK_DOWN;
997
998     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
999   }
1000   else if (element == EL_SP_ELECTRON)
1001   {
1002     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1003   }
1004   else if (element == EL_MAULWURF || element == EL_PINGUIN ||
1005            element == EL_SCHWEIN || element == EL_DRACHE)
1006   {
1007     if (dir == MV_LEFT)
1008       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT :
1009                  element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
1010                  element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1011     else if (dir == MV_RIGHT)
1012       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT :
1013                  element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
1014                  element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1015     else if (dir == MV_UP)
1016       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP :
1017                  element == EL_PINGUIN ? GFX_PINGUIN_UP :
1018                  element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1019     else
1020       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN :
1021                  element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
1022                  element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1023
1024     graphic += phase4;
1025   }
1026   else if (element == EL_SONDE)
1027   {
1028     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1029   }
1030   else if (element == EL_SALZSAEURE)
1031   {
1032     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
1033   }
1034   else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1035   {
1036     graphic += !phase2;
1037   }
1038   else if ((element == EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode)
1039   {
1040     if (element != EL_SP_INFOTRON)
1041       graphic += phase2 * (element == EL_FELSBROCKEN ? 2 : 1);
1042   }
1043   else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
1044            element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
1045   {
1046     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1047   }
1048   else if (IS_AMOEBOID(element))
1049   {
1050     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1051     graphic += (x + 2 * y + 4) % 4;
1052   }
1053   else if (element == EL_MAUER_LEBT)
1054   {
1055     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1056
1057     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1058       links_massiv = TRUE;
1059     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1060       rechts_massiv = TRUE;
1061
1062     if (links_massiv && rechts_massiv)
1063       graphic = GFX_MAUERWERK;
1064     else if (links_massiv)
1065       graphic = GFX_MAUER_R;
1066     else if (rechts_massiv)
1067       graphic = GFX_MAUER_L;
1068   }
1069
1070   if (dx || dy)
1071     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1072   else if (mask_mode == USE_MASKING)
1073     DrawGraphicThruMask(x, y, graphic);
1074   else
1075     DrawGraphic(x, y, graphic);
1076 }
1077
1078 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1079                          int cut_mode, int mask_mode)
1080 {
1081   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1082     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1083                          cut_mode, mask_mode);
1084 }
1085
1086 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1087                               int cut_mode)
1088 {
1089   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1090 }
1091
1092 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1093                              int cut_mode)
1094 {
1095   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1096 }
1097
1098 void DrawScreenElementThruMask(int x, int y, int element)
1099 {
1100   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1101 }
1102
1103 void DrawLevelElementThruMask(int x, int y, int element)
1104 {
1105   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1106 }
1107
1108 void DrawLevelFieldThruMask(int x, int y)
1109 {
1110   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1111 }
1112
1113 void ErdreichAnbroeckeln(int x, int y)
1114 {
1115   int i, width, height, cx,cy;
1116   int ux = LEVELX(x), uy = LEVELY(y);
1117   int element, graphic;
1118   int snip = 4;
1119   static int xy[4][2] =
1120   {
1121     { 0, -1 },
1122     { -1, 0 },
1123     { +1, 0 },
1124     { 0, +1 }
1125   };
1126
1127   if (!IN_LEV_FIELD(ux, uy))
1128     return;
1129
1130   element = Feld[ux][uy];
1131
1132   if (element == EL_ERDREICH)
1133   {
1134     if (!IN_SCR_FIELD(x, y))
1135       return;
1136
1137     graphic = GFX_ERDENRAND;
1138
1139     for(i=0; i<4; i++)
1140     {
1141       int uxx, uyy;
1142
1143       uxx = ux + xy[i][0];
1144       uyy = uy + xy[i][1];
1145       if (!IN_LEV_FIELD(uxx, uyy))
1146         element = EL_BETON;
1147       else
1148         element = Feld[uxx][uyy];
1149
1150       if (element == EL_ERDREICH)
1151         continue;
1152
1153       if (i == 1 || i == 2)
1154       {
1155         width = snip;
1156         height = TILEY;
1157         cx = (i == 2 ? TILEX - snip : 0);
1158         cy = 0;
1159       }
1160       else
1161       {
1162         width = TILEX;
1163         height = snip;
1164         cx = 0;
1165         cy = (i == 3 ? TILEY - snip : 0);
1166       }
1167
1168       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1169                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1170                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1171                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1172     }
1173
1174     MarkTileDirty(x, y);
1175   }
1176   else
1177   {
1178     graphic = GFX_ERDENRAND;
1179
1180     for(i=0; i<4; i++)
1181     {
1182       int xx, yy, uxx, uyy;
1183
1184       xx = x + xy[i][0];
1185       yy = y + xy[i][1];
1186       uxx = ux + xy[i][0];
1187       uyy = uy + xy[i][1];
1188
1189       if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
1190           !IN_SCR_FIELD(xx, yy))
1191         continue;
1192
1193       if (i == 1 || i == 2)
1194       {
1195         width = snip;
1196         height = TILEY;
1197         cx = (i == 1 ? TILEX - snip : 0);
1198         cy = 0;
1199       }
1200       else
1201       {
1202         width = TILEX;
1203         height = snip;
1204         cx = 0;
1205         cy = (i==0 ? TILEY-snip : 0);
1206       }
1207
1208       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1209                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1210                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1211                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1212
1213       MarkTileDirty(xx, yy);
1214     }
1215   }
1216 }
1217
1218 void DrawScreenElement(int x, int y, int element)
1219 {
1220   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1221   ErdreichAnbroeckeln(x, y);
1222 }
1223
1224 void DrawLevelElement(int x, int y, int element)
1225 {
1226   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1227     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1228 }
1229
1230 void DrawScreenField(int x, int y)
1231 {
1232   int ux = LEVELX(x), uy = LEVELY(y);
1233   int element;
1234
1235   if (!IN_LEV_FIELD(ux, uy))
1236   {
1237     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1238       element = EL_LEERRAUM;
1239     else
1240       element = BorderElement;
1241
1242     DrawScreenElement(x, y, element);
1243     return;
1244   }
1245
1246   element = Feld[ux][uy];
1247
1248   if (IS_MOVING(ux, uy))
1249   {
1250     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1251     boolean cut_mode = NO_CUTTING;
1252
1253     if (Store[ux][uy] == EL_MORAST_LEER ||
1254         Store[ux][uy] == EL_SIEB_LEER ||
1255         Store[ux][uy] == EL_SIEB2_LEER ||
1256         Store[ux][uy] == EL_AMOEBE_NASS)
1257       cut_mode = CUT_ABOVE;
1258     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1259              Store[ux][uy] == EL_SIEB_VOLL ||
1260              Store[ux][uy] == EL_SIEB2_VOLL)
1261       cut_mode = CUT_BELOW;
1262
1263     if (cut_mode == CUT_ABOVE)
1264       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1265     else
1266       DrawScreenElement(x, y, EL_LEERRAUM);
1267
1268     if (horiz_move)
1269       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1270     else
1271       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1272
1273     if (Store[ux][uy] == EL_SALZSAEURE)
1274       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1275   }
1276   else if (IS_BLOCKED(ux, uy))
1277   {
1278     int oldx, oldy;
1279     int sx, sy;
1280     int horiz_move;
1281     boolean cut_mode = NO_CUTTING;
1282
1283     Blocked2Moving(ux, uy, &oldx, &oldy);
1284     sx = SCREENX(oldx);
1285     sy = SCREENY(oldy);
1286     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1287                   MovDir[oldx][oldy] == MV_RIGHT);
1288
1289     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1290         Store[oldx][oldy] == EL_SIEB_LEER ||
1291         Store[oldx][oldy] == EL_SIEB2_LEER ||
1292         Store[oldx][oldy] == EL_AMOEBE_NASS)
1293       cut_mode = CUT_ABOVE;
1294
1295     DrawScreenElement(x, y, EL_LEERRAUM);
1296     element = Feld[oldx][oldy];
1297
1298     if (horiz_move)
1299       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1300     else
1301       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1302   }
1303   else if (IS_DRAWABLE(element))
1304     DrawScreenElement(x, y, element);
1305   else
1306     DrawScreenElement(x, y, EL_LEERRAUM);
1307 }
1308
1309 void DrawLevelField(int x, int y)
1310 {
1311   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1312     DrawScreenField(SCREENX(x), SCREENY(y));
1313   else if (IS_MOVING(x, y))
1314   {
1315     int newx,newy;
1316
1317     Moving2Blocked(x, y, &newx, &newy);
1318     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1319       DrawScreenField(SCREENX(newx), SCREENY(newy));
1320   }
1321   else if (IS_BLOCKED(x, y))
1322   {
1323     int oldx, oldy;
1324
1325     Blocked2Moving(x, y, &oldx, &oldy);
1326     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1327       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1328   }
1329 }
1330
1331 void DrawMiniElement(int x, int y, int element)
1332 {
1333   int graphic;
1334
1335   if (!element)
1336   {
1337     DrawMiniGraphic(x, y, -1);
1338     return;
1339   }
1340
1341   graphic = el2gfx(element);
1342   DrawMiniGraphic(x, y, graphic);
1343 }
1344
1345 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1346 {
1347   int x = sx + scroll_x, y = sy + scroll_y;
1348
1349   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1350     DrawMiniElement(sx, sy, EL_LEERRAUM);
1351   else if (x == -1 || x == lev_fieldx || y == -1 || y == lev_fieldy)
1352     DrawMiniElement(sx, sy, EL_BETON);
1353   else
1354     DrawMiniElement(sx, sy, Feld[x][y]);
1355 }
1356
1357 void DrawMicroElement(int xpos, int ypos, int element)
1358 {
1359   int graphic;
1360
1361   if (element == EL_LEERRAUM)
1362     return;
1363
1364   graphic = el2gfx(element);
1365
1366   if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1367   {
1368     graphic -= GFX_START_ROCKSMORE;
1369     XCopyArea(display, pix[PIX_MORE], drawto, gc,
1370               MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
1371               MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
1372               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1373   }
1374   else
1375     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1376               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1377               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1378               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1379 }
1380
1381 void DrawLevel()
1382 {
1383   int x,y;
1384
1385   ClearWindow();
1386
1387   for(x=BX1; x<=BX2; x++)
1388     for(y=BY1; y<=BY2; y++)
1389       DrawScreenField(x, y);
1390
1391   if (setup.soft_scrolling)
1392     XCopyArea(display, fieldbuffer, backbuffer, gc,
1393               FX, FY, SXSIZE, SYSIZE, SX, SY);
1394
1395   redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
1396 }
1397
1398 void DrawMiniLevel(int scroll_x, int scroll_y)
1399 {
1400   int x,y;
1401
1402   for(x=0; x<ED_FIELDX; x++)
1403     for(y=0; y<ED_FIELDY; y++)
1404       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1405
1406   redraw_mask |= REDRAW_FIELD;
1407 }
1408
1409 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1410 {
1411   int x, y;
1412
1413   /* determine border element for this level */
1414   SetBorderElement();
1415
1416   XFillRectangle(display, drawto, gc,
1417                  xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1418
1419   if (lev_fieldx < STD_LEV_FIELDX)
1420     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1421   if (lev_fieldy < STD_LEV_FIELDY)
1422     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1423
1424   xpos += MICRO_TILEX;
1425   ypos += MICRO_TILEY;
1426
1427   for(x=-1; x<=STD_LEV_FIELDX; x++)
1428   {
1429     for(y=-1; y<=STD_LEV_FIELDY; y++)
1430     {
1431       int lx = from_x + x, ly = from_y + y;
1432
1433       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1434         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1435                          Ur[lx][ly]);
1436       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1437         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1438                          BorderElement);
1439     }
1440   }
1441
1442   redraw_mask |= REDRAW_MICROLEVEL;
1443 }
1444
1445 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1446 {
1447   static unsigned long scroll_delay = 0;
1448   static int from_x, from_y, scroll_direction;
1449
1450   if (restart)
1451   {
1452     from_x = from_y = 0;
1453     scroll_direction = MV_RIGHT;
1454
1455     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1456
1457     XFillRectangle(display, drawto,gc,
1458                    SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1459
1460     if (level.name && restart)
1461     {
1462       int len = strlen(level.name);
1463       int lxpos = SX + (SXSIZE - len * FONT4_XSIZE) / 2;
1464       int lypos = MICROLABEL_YPOS;
1465
1466       DrawText(lxpos, lypos, level.name, FS_SMALL, FC_SPECIAL2);
1467     }
1468
1469     /* initialize delay counter */
1470     DelayReached(&scroll_delay, 0);
1471
1472     redraw_mask |= REDRAW_MICROLEVEL_LABEL;
1473   }
1474   else
1475   {
1476     if ((lev_fieldx <= STD_LEV_FIELDX && lev_fieldy <= STD_LEV_FIELDY) ||
1477         !DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1478       return;
1479
1480     switch (scroll_direction)
1481     {
1482       case MV_LEFT:
1483         if (from_x > 0)
1484           from_x--;
1485         else
1486           scroll_direction = MV_UP;
1487         break;
1488
1489       case MV_RIGHT:
1490         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1491           from_x++;
1492         else
1493           scroll_direction = MV_DOWN;
1494         break;
1495
1496       case MV_UP:
1497         if (from_y > 0)
1498           from_y--;
1499         else
1500           scroll_direction = MV_RIGHT;
1501         break;
1502
1503       case MV_DOWN:
1504         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1505           from_y++;
1506         else
1507           scroll_direction = MV_LEFT;
1508         break;
1509
1510       default:
1511         break;
1512     }
1513
1514     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1515   }
1516 }
1517
1518 int REQ_in_range(int x, int y)
1519 {
1520   if (y > DY+249 && y < DY+278)
1521   {
1522     if (x > DX+1 && x < DX+48)
1523       return 1;
1524     else if (x > DX+51 && x < DX+98) 
1525       return 2;
1526   }
1527   return 0;
1528 }
1529
1530 boolean Request(char *text, unsigned int req_state)
1531 {
1532   int mx, my, ty, result = -1;
1533   unsigned int old_door_state;
1534
1535 #ifndef MSDOS
1536   /* pause network game while waiting for request to answer */
1537   if (options.network &&
1538       game_status == PLAYING &&
1539       req_state & REQUEST_WAIT_FOR)
1540     SendToServer_PausePlaying();
1541 #endif
1542
1543   old_door_state = GetDoorState();
1544
1545   CloseDoor(DOOR_CLOSE_1);
1546
1547   /* Alten Türinhalt sichern */
1548   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1549             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1550             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1551
1552   /* Fragetext schreiben */
1553   XFillRectangle(display, pix[PIX_DB_DOOR], gc,
1554                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
1555
1556   for(ty=0; ty<13; ty++)
1557   {
1558     int tx, tl, tc;
1559     char txt[256];
1560
1561     if (!*text)
1562       break;
1563
1564     for(tl=0,tx=0; tx<7; tl++,tx++)
1565     {
1566       tc = *(text + tx);
1567       if (!tc || tc == 32)
1568         break;
1569     }
1570     if (!tl)
1571     { 
1572       text++; 
1573       ty--; 
1574       continue; 
1575     }
1576     sprintf(txt, text); 
1577     txt[tl] = 0;
1578     DrawTextExt(pix[PIX_DB_DOOR], gc,
1579                 DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
1580                 txt, FS_SMALL, FC_YELLOW);
1581     text += tl + (tc == 32 ? 1 : 0);
1582   }
1583
1584   if (req_state & REQ_ASK)
1585   {
1586     DrawYesNoButton(BUTTON_OK, DB_INIT);
1587     DrawYesNoButton(BUTTON_NO, DB_INIT);
1588   }
1589   else if (req_state & REQ_CONFIRM)
1590   {
1591     DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
1592   }
1593   else if (req_state & REQ_PLAYER)
1594   {
1595     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1596     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1597     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1598     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1599   }
1600
1601   OpenDoor(DOOR_OPEN_1);
1602   ClearEventQueue();
1603
1604   if (!(req_state & REQUEST_WAIT_FOR))
1605     return(FALSE);
1606
1607   if (game_status != MAINMENU)
1608     InitAnimation();
1609
1610   button_status = MB_RELEASED;
1611
1612   while(result < 0)
1613   {
1614     if (XPending(display))
1615     {
1616       XEvent event;
1617
1618       XNextEvent(display, &event);
1619
1620       switch(event.type)
1621       {
1622         case ButtonPress:
1623         case ButtonRelease:
1624         case MotionNotify:
1625         {
1626           int choice;
1627
1628           if (event.type == MotionNotify)
1629           {
1630             motion_status = TRUE;
1631             mx = ((XMotionEvent *) &event)->x;
1632             my = ((XMotionEvent *) &event)->y;
1633           }
1634           else
1635           {
1636             motion_status = FALSE;
1637             mx = ((XButtonEvent *) &event)->x;
1638             my = ((XButtonEvent *) &event)->y;
1639             if (event.type==ButtonPress)
1640               button_status = ((XButtonEvent *) &event)->button;
1641             else
1642               button_status = MB_RELEASED;
1643           }
1644
1645           if (req_state & REQ_ASK)
1646             choice = CheckYesNoButtons(mx,my,button_status);
1647           else if (req_state & REQ_CONFIRM)
1648             choice = CheckConfirmButton(mx,my,button_status);
1649           else
1650             choice = CheckPlayerButtons(mx,my,button_status);
1651
1652           switch(choice)
1653           {
1654             case BUTTON_OK:
1655               result = TRUE;
1656               break;
1657             case BUTTON_NO:
1658               result = FALSE;
1659               break;
1660             case BUTTON_CONFIRM:
1661               result = TRUE | FALSE;
1662               break;
1663
1664             case BUTTON_PLAYER_1:
1665               result = 1;
1666               break;
1667             case BUTTON_PLAYER_2:
1668               result = 2;
1669               break;
1670             case BUTTON_PLAYER_3:
1671               result = 3;
1672               break;
1673             case BUTTON_PLAYER_4:
1674               result = 4;
1675               break;
1676
1677             default:
1678               break;
1679           }
1680           break;
1681         }
1682
1683         case KeyPress:
1684           switch(XLookupKeysym((XKeyEvent *)&event,
1685                                ((XKeyEvent *)&event)->state))
1686           {
1687             case XK_Return:
1688               result = 1;
1689               break;
1690
1691             case XK_Escape:
1692               result = 0;
1693               break;
1694
1695             default:
1696               break;
1697           }
1698           if (req_state & REQ_PLAYER)
1699             result = 0;
1700           break;
1701
1702         case KeyRelease:
1703           key_joystick_mapping = 0;
1704           break;
1705
1706         default:
1707           HandleOtherEvents(&event);
1708           break;
1709       }
1710     }
1711     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1712     {
1713       int joy = AnyJoystick();
1714
1715       if (joy & JOY_BUTTON_1)
1716         result = 1;
1717       else if (joy & JOY_BUTTON_2)
1718         result = 0;
1719     }
1720
1721     DoAnimation();
1722
1723     /* don't eat all CPU time */
1724     Delay(10);
1725   }
1726
1727   if (game_status != MAINMENU)
1728     StopAnimation();
1729
1730   if (!(req_state & REQ_STAY_OPEN))
1731   {
1732     CloseDoor(DOOR_CLOSE_1);
1733
1734     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1735     {
1736       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1737                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1738                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1739       OpenDoor(DOOR_OPEN_1);
1740     }
1741   }
1742
1743 #ifndef MSDOS
1744   /* continue network game after request */
1745   if (options.network &&
1746       game_status == PLAYING &&
1747       req_state & REQUEST_WAIT_FOR)
1748     SendToServer_ContinuePlaying();
1749 #endif
1750
1751   return(result);
1752 }
1753
1754 unsigned int OpenDoor(unsigned int door_state)
1755 {
1756   unsigned int new_door_state;
1757
1758   if (door_state & DOOR_COPY_BACK)
1759   {
1760     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1761               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1762               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1763     door_state &= ~DOOR_COPY_BACK;
1764   }
1765
1766   new_door_state = MoveDoor(door_state);
1767
1768   return(new_door_state);
1769 }
1770
1771 unsigned int CloseDoor(unsigned int door_state)
1772 {
1773   unsigned int new_door_state;
1774
1775   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1776             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1777   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1778             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1779
1780   new_door_state = MoveDoor(door_state);
1781
1782   return(new_door_state);
1783 }
1784
1785 unsigned int GetDoorState()
1786 {
1787   return(MoveDoor(DOOR_GET_STATE));
1788 }
1789
1790 unsigned int MoveDoor(unsigned int door_state)
1791 {
1792   static int door1 = DOOR_OPEN_1;
1793   static int door2 = DOOR_CLOSE_2;
1794   static unsigned long door_delay = 0;
1795   int x, start, stepsize = 2;
1796   unsigned long door_delay_value = stepsize * 5;
1797
1798   if (door_state == DOOR_GET_STATE)
1799     return(door1 | door2);
1800
1801   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1802     door_state &= ~DOOR_OPEN_1;
1803   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1804     door_state &= ~DOOR_CLOSE_1;
1805   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1806     door_state &= ~DOOR_OPEN_2;
1807   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1808     door_state &= ~DOOR_CLOSE_2;
1809
1810   if (setup.quick_doors)
1811   {
1812     stepsize = 20;
1813     door_delay_value = 0;
1814     StopSound(SND_OEFFNEN);
1815   }
1816
1817   if (door_state & DOOR_ACTION)
1818   {
1819     if (!(door_state & DOOR_NO_DELAY))
1820       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1821
1822     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1823
1824     for(x=start; x<=DXSIZE; x+=stepsize)
1825     {
1826       WaitUntilDelayReached(&door_delay, door_delay_value);
1827
1828       if (door_state & DOOR_ACTION_1)
1829       {
1830         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1831         int j = (DXSIZE - i) / 3;
1832
1833         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1834                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
1835                   DXSIZE,DYSIZE - i/2, DX, DY);
1836
1837         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
1838
1839         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1840                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1841         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1842                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
1843         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1844                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
1845                   DY + 140 + j);
1846         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1847                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
1848         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1849                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
1850         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1851                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
1852
1853         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1854                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
1855                   DX, DY + 77 - j);
1856         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1857                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
1858                   DX, DY + 203 - j);
1859         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1860                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1861         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1862                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
1863                   DX + DXSIZE - i, DY + 77 + j);
1864         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1865                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
1866                   DX + DXSIZE - i, DY + 203 + j);
1867
1868         redraw_mask |= REDRAW_DOOR_1;
1869       }
1870
1871       if (door_state & DOOR_ACTION_2)
1872       {
1873         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
1874         int j = (VXSIZE - i) / 3;
1875
1876         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1877                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
1878                   VXSIZE, VYSIZE - i/2, VX, VY);
1879
1880         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
1881
1882         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1883                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1884         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1885                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
1886         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1887                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
1888         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1889                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
1890
1891         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1892                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
1893                   VX, VY + VYSIZE / 2 - j);
1894         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1895                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1896         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1897                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
1898                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
1899
1900         redraw_mask |= REDRAW_DOOR_2;
1901       }
1902
1903       BackToFront();
1904
1905       if (game_status == MAINMENU)
1906         DoAnimation();
1907     }
1908   }
1909
1910   if (setup.quick_doors)
1911     StopSound(SND_OEFFNEN);
1912
1913   if (door_state & DOOR_ACTION_1)
1914     door1 = door_state & DOOR_ACTION_1;
1915   if (door_state & DOOR_ACTION_2)
1916     door2 = door_state & DOOR_ACTION_2;
1917
1918   return(door1 | door2);
1919 }
1920
1921 int ReadPixel(Drawable d, int x, int y)
1922 {
1923   XImage *pixel_image;
1924   unsigned long pixel_value;
1925
1926   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
1927   pixel_value = XGetPixel(pixel_image, 0, 0);
1928
1929   XDestroyImage(pixel_image);
1930
1931   return pixel_value;
1932 }
1933
1934 int el2gfx(int element)
1935 {
1936   switch(element)
1937   {
1938     case EL_LEERRAUM:           return -1;
1939     case EL_ERDREICH:           return GFX_ERDREICH;
1940     case EL_MAUERWERK:          return GFX_MAUERWERK;
1941     case EL_FELSBODEN:          return GFX_FELSBODEN;
1942     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
1943     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
1944     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
1945     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
1946     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
1947     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
1948     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
1949     case EL_SPIELER1:           return GFX_SPIELER1;
1950     case EL_SPIELER2:           return GFX_SPIELER2;
1951     case EL_SPIELER3:           return GFX_SPIELER3;
1952     case EL_SPIELER4:           return GFX_SPIELER4;
1953     case EL_KAEFER:             return GFX_KAEFER;
1954     case EL_KAEFER_R:           return GFX_KAEFER_R;
1955     case EL_KAEFER_O:           return GFX_KAEFER_O;
1956     case EL_KAEFER_L:           return GFX_KAEFER_L;
1957     case EL_KAEFER_U:           return GFX_KAEFER_U;
1958     case EL_FLIEGER:            return GFX_FLIEGER;
1959     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
1960     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
1961     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
1962     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
1963     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
1964     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
1965     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
1966     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
1967     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
1968     case EL_FIREFLY:            return GFX_FIREFLY;
1969     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
1970     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
1971     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
1972     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
1973     case EL_MAMPFER:            return GFX_MAMPFER;
1974     case EL_ROBOT:              return GFX_ROBOT;
1975     case EL_BETON:              return GFX_BETON;
1976     case EL_DIAMANT:            return GFX_DIAMANT;
1977     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
1978     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
1979     case EL_TROPFEN:            return GFX_TROPFEN;
1980     case EL_BOMBE:              return GFX_BOMBE;
1981     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
1982     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
1983     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
1984     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
1985     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
1986     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
1987     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
1988     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
1989     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
1990     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
1991     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
1992     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
1993     case EL_LIFE:               return GFX_LIFE;
1994     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
1995     case EL_DYNAMIT:            return GFX_DYNAMIT;
1996     case EL_BADEWANNE:          return GFX_BADEWANNE;
1997     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
1998     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
1999     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2000     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2001     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2002     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2003     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2004     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2005     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2006     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2007     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2008     case EL_PFORTE1:            return GFX_PFORTE1;
2009     case EL_PFORTE2:            return GFX_PFORTE2;
2010     case EL_PFORTE3:            return GFX_PFORTE3;
2011     case EL_PFORTE4:            return GFX_PFORTE4;
2012     case EL_PFORTE1X:           return GFX_PFORTE1X;
2013     case EL_PFORTE2X:           return GFX_PFORTE2X;
2014     case EL_PFORTE3X:           return GFX_PFORTE3X;
2015     case EL_PFORTE4X:           return GFX_PFORTE4X;
2016     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
2017     case EL_PACMAN:             return GFX_PACMAN;
2018     case EL_PACMAN_R:           return GFX_PACMAN_R;
2019     case EL_PACMAN_O:           return GFX_PACMAN_O;
2020     case EL_PACMAN_L:           return GFX_PACMAN_L;
2021     case EL_PACMAN_U:           return GFX_PACMAN_U;
2022     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2023     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2024     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2025     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2026     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2027     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2028     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2029     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2030     case EL_MAUER_X:            return GFX_MAUER_X;
2031     case EL_MAUER_Y:            return GFX_MAUER_Y;
2032     case EL_MAUER_XY:           return GFX_MAUER_XY;
2033     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2034     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2035     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2036     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2037     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2038     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2039     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2040     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2041     case EL_MAMPFER2:           return GFX_MAMPFER2;
2042     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
2043     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
2044     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
2045     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
2046     case EL_DYNABOMB:           return GFX_DYNABOMB;
2047     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2048     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2049     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2050     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2051     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2052     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2053     case EL_MAULWURF:           return GFX_MAULWURF;
2054     case EL_PINGUIN:            return GFX_PINGUIN;
2055     case EL_SCHWEIN:            return GFX_SCHWEIN;
2056     case EL_DRACHE:             return GFX_DRACHE;
2057     case EL_SONDE:              return GFX_SONDE;
2058     case EL_PFEIL_L:            return GFX_PFEIL_L;
2059     case EL_PFEIL_R:            return GFX_PFEIL_R;
2060     case EL_PFEIL_O:            return GFX_PFEIL_O;
2061     case EL_PFEIL_U:            return GFX_PFEIL_U;
2062     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2063     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2064     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2065     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2066
2067     default:
2068     {
2069       if (IS_CHAR(element))
2070         return GFX_CHAR_START + (element - EL_CHAR_START);
2071       else if (element >= EL_SP_START && element <= EL_SP_END)
2072       {
2073         int nr_element = element - EL_SP_START;
2074         int gfx_per_line = 8;
2075         int nr_graphic =
2076           (nr_element / gfx_per_line) * MORE_PER_LINE +
2077           (nr_element % gfx_per_line);
2078
2079         return GFX_START_ROCKSMORE + nr_graphic;
2080       }
2081       else
2082         return -1;
2083     }
2084   }
2085 }