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