rnd-19990123-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     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, Feld[x][y]);
1348   else if (x == -1 && y == -1)
1349     DrawMiniGraphic(sx, sy, GFX_STEEL_UPPER_LEFT);
1350   else if (x == lev_fieldx && y == -1)
1351     DrawMiniGraphic(sx, sy, GFX_STEEL_UPPER_RIGHT);
1352   else if (x == -1 && y == lev_fieldy)
1353     DrawMiniGraphic(sx, sy, GFX_STEEL_LOWER_LEFT);
1354   else if (x == lev_fieldx && y == lev_fieldy)
1355     DrawMiniGraphic(sx, sy, GFX_STEEL_LOWER_RIGHT);
1356   else if (x == -1 || x == lev_fieldx)
1357     DrawMiniGraphic(sx, sy, GFX_STEEL_VERTICAL);
1358   else if (y == -1 || y == lev_fieldy)
1359     DrawMiniGraphic(sx, sy, GFX_STEEL_HORIZONTAL);
1360 }
1361
1362 void DrawMicroElement(int xpos, int ypos, int element)
1363 {
1364   int graphic;
1365
1366   if (element == EL_LEERRAUM)
1367     return;
1368
1369   graphic = el2gfx(element);
1370
1371   if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1372   {
1373     graphic -= GFX_START_ROCKSMORE;
1374     XCopyArea(display, pix[PIX_MORE], drawto, gc,
1375               MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
1376               MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
1377               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1378   }
1379   else
1380     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1381               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1382               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1383               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1384 }
1385
1386 void DrawLevel()
1387 {
1388   int x,y;
1389
1390   ClearWindow();
1391
1392   for(x=BX1; x<=BX2; x++)
1393     for(y=BY1; y<=BY2; y++)
1394       DrawScreenField(x, y);
1395
1396   if (setup.soft_scrolling)
1397     XCopyArea(display, fieldbuffer, backbuffer, gc,
1398               FX, FY, SXSIZE, SYSIZE, SX, SY);
1399
1400   redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
1401 }
1402
1403 void DrawMiniLevel(int scroll_x, int scroll_y)
1404 {
1405   int x,y;
1406
1407   for(x=0; x<ED_FIELDX; x++)
1408     for(y=0; y<ED_FIELDY; y++)
1409       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1410
1411   redraw_mask |= REDRAW_FIELD;
1412 }
1413
1414 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1415 {
1416   int x, y;
1417
1418   /* determine border element for this level */
1419   SetBorderElement();
1420
1421   XFillRectangle(display, drawto, gc,
1422                  xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1423
1424   if (lev_fieldx < STD_LEV_FIELDX)
1425     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1426   if (lev_fieldy < STD_LEV_FIELDY)
1427     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1428
1429   xpos += MICRO_TILEX;
1430   ypos += MICRO_TILEY;
1431
1432   for(x=-1; x<=STD_LEV_FIELDX; x++)
1433   {
1434     for(y=-1; y<=STD_LEV_FIELDY; y++)
1435     {
1436       int lx = from_x + x, ly = from_y + y;
1437
1438       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1439         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1440                          Ur[lx][ly]);
1441       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1442         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1443                          BorderElement);
1444     }
1445   }
1446
1447   redraw_mask |= REDRAW_MICROLEVEL;
1448 }
1449
1450 static void DrawMicroLevelLabelExt(int mode)
1451 {
1452   char label_text[100];
1453
1454   XFillRectangle(display, drawto,gc,
1455                  SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1456
1457   strcpy(label_text, (mode == 1 ? level.name :
1458                       mode == 2 ? "created by" :
1459                       mode == 3 ? level.author : ""));
1460
1461   if (strlen(label_text) > 0)
1462   {
1463     int size, lxpos, lypos;
1464
1465     label_text[SXSIZE / FONT4_XSIZE] = '\0';
1466
1467     size = strlen(label_text);
1468     lxpos = SX + (SXSIZE - size * FONT4_XSIZE) / 2;
1469     lypos = MICROLABEL_YPOS;
1470
1471     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1472   }
1473
1474   redraw_mask |= REDRAW_MICROLEVEL;
1475 }
1476
1477 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1478 {
1479   static unsigned long scroll_delay = 0;
1480   static unsigned long label_delay = 0;
1481   static int from_x, from_y, scroll_direction;
1482   static int label_state, label_counter;
1483
1484   if (restart)
1485   {
1486     from_x = from_y = 0;
1487     scroll_direction = MV_RIGHT;
1488     label_state = 1;
1489     label_counter = 0;
1490
1491     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1492     DrawMicroLevelLabelExt(label_state);
1493
1494     /* initialize delay counters */
1495     DelayReached(&scroll_delay, 0);
1496     DelayReached(&label_delay, 0);
1497
1498     return;
1499   }
1500
1501   /* scroll micro level, if needed */
1502   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1503       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1504   {
1505     switch (scroll_direction)
1506     {
1507       case MV_LEFT:
1508         if (from_x > 0)
1509           from_x--;
1510         else
1511           scroll_direction = MV_UP;
1512         break;
1513
1514       case MV_RIGHT:
1515         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1516           from_x++;
1517         else
1518           scroll_direction = MV_DOWN;
1519         break;
1520
1521       case MV_UP:
1522         if (from_y > 0)
1523           from_y--;
1524         else
1525           scroll_direction = MV_RIGHT;
1526         break;
1527
1528       case MV_DOWN:
1529         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1530           from_y++;
1531         else
1532           scroll_direction = MV_LEFT;
1533         break;
1534
1535       default:
1536         break;
1537     }
1538
1539     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1540   }
1541
1542   /* redraw micro level label, if needed */
1543   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1544       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1545       strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
1546       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1547   {
1548     label_counter = (label_counter + 1) % 23;
1549     label_state = (label_counter >= 0 && label_counter <= 7 ? 1 :
1550                    label_counter >= 9 && label_counter <= 12 ? 2 :
1551                    label_counter >= 14 && label_counter <= 21 ? 3 : 0);
1552     DrawMicroLevelLabelExt(label_state);
1553   }
1554 }
1555
1556 int REQ_in_range(int x, int y)
1557 {
1558   if (y > DY+249 && y < DY+278)
1559   {
1560     if (x > DX+1 && x < DX+48)
1561       return 1;
1562     else if (x > DX+51 && x < DX+98) 
1563       return 2;
1564   }
1565   return 0;
1566 }
1567
1568 boolean Request(char *text, unsigned int req_state)
1569 {
1570   int mx, my, ty, result = -1;
1571   unsigned int old_door_state;
1572
1573 #ifndef MSDOS
1574   /* pause network game while waiting for request to answer */
1575   if (options.network &&
1576       game_status == PLAYING &&
1577       req_state & REQUEST_WAIT_FOR)
1578     SendToServer_PausePlaying();
1579 #endif
1580
1581   old_door_state = GetDoorState();
1582
1583   CloseDoor(DOOR_CLOSE_1);
1584
1585   /* Alten Türinhalt sichern */
1586   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1587             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1588             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1589
1590   /* Fragetext schreiben */
1591   XFillRectangle(display, pix[PIX_DB_DOOR], gc,
1592                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
1593
1594   for(ty=0; ty<13; ty++)
1595   {
1596     int tx, tl, tc;
1597     char txt[256];
1598
1599     if (!*text)
1600       break;
1601
1602     for(tl=0,tx=0; tx<7; tl++,tx++)
1603     {
1604       tc = *(text + tx);
1605       if (!tc || tc == 32)
1606         break;
1607     }
1608     if (!tl)
1609     { 
1610       text++; 
1611       ty--; 
1612       continue; 
1613     }
1614     sprintf(txt, text); 
1615     txt[tl] = 0;
1616     DrawTextExt(pix[PIX_DB_DOOR], gc,
1617                 DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
1618                 txt, FS_SMALL, FC_YELLOW);
1619     text += tl + (tc == 32 ? 1 : 0);
1620   }
1621
1622   if (req_state & REQ_ASK)
1623   {
1624     DrawYesNoButton(BUTTON_OK, DB_INIT);
1625     DrawYesNoButton(BUTTON_NO, DB_INIT);
1626   }
1627   else if (req_state & REQ_CONFIRM)
1628   {
1629     DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
1630   }
1631   else if (req_state & REQ_PLAYER)
1632   {
1633     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1634     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1635     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1636     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1637   }
1638
1639   OpenDoor(DOOR_OPEN_1);
1640   ClearEventQueue();
1641
1642   if (!(req_state & REQUEST_WAIT_FOR))
1643     return(FALSE);
1644
1645   if (game_status != MAINMENU)
1646     InitAnimation();
1647
1648   button_status = MB_RELEASED;
1649
1650   while(result < 0)
1651   {
1652     if (XPending(display))
1653     {
1654       XEvent event;
1655
1656       XNextEvent(display, &event);
1657
1658       switch(event.type)
1659       {
1660         case ButtonPress:
1661         case ButtonRelease:
1662         case MotionNotify:
1663         {
1664           int choice;
1665
1666           if (event.type == MotionNotify)
1667           {
1668             motion_status = TRUE;
1669             mx = ((XMotionEvent *) &event)->x;
1670             my = ((XMotionEvent *) &event)->y;
1671           }
1672           else
1673           {
1674             motion_status = FALSE;
1675             mx = ((XButtonEvent *) &event)->x;
1676             my = ((XButtonEvent *) &event)->y;
1677             if (event.type==ButtonPress)
1678               button_status = ((XButtonEvent *) &event)->button;
1679             else
1680               button_status = MB_RELEASED;
1681           }
1682
1683           if (req_state & REQ_ASK)
1684             choice = CheckYesNoButtons(mx,my,button_status);
1685           else if (req_state & REQ_CONFIRM)
1686             choice = CheckConfirmButton(mx,my,button_status);
1687           else
1688             choice = CheckPlayerButtons(mx,my,button_status);
1689
1690           switch(choice)
1691           {
1692             case BUTTON_OK:
1693               result = TRUE;
1694               break;
1695             case BUTTON_NO:
1696               result = FALSE;
1697               break;
1698             case BUTTON_CONFIRM:
1699               result = TRUE | FALSE;
1700               break;
1701
1702             case BUTTON_PLAYER_1:
1703               result = 1;
1704               break;
1705             case BUTTON_PLAYER_2:
1706               result = 2;
1707               break;
1708             case BUTTON_PLAYER_3:
1709               result = 3;
1710               break;
1711             case BUTTON_PLAYER_4:
1712               result = 4;
1713               break;
1714
1715             default:
1716               break;
1717           }
1718           break;
1719         }
1720
1721         case KeyPress:
1722           switch(XLookupKeysym((XKeyEvent *)&event,
1723                                ((XKeyEvent *)&event)->state))
1724           {
1725             case XK_Return:
1726               result = 1;
1727               break;
1728
1729             case XK_Escape:
1730               result = 0;
1731               break;
1732
1733             default:
1734               break;
1735           }
1736           if (req_state & REQ_PLAYER)
1737             result = 0;
1738           break;
1739
1740         case KeyRelease:
1741           key_joystick_mapping = 0;
1742           break;
1743
1744         default:
1745           HandleOtherEvents(&event);
1746           break;
1747       }
1748     }
1749     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1750     {
1751       int joy = AnyJoystick();
1752
1753       if (joy & JOY_BUTTON_1)
1754         result = 1;
1755       else if (joy & JOY_BUTTON_2)
1756         result = 0;
1757     }
1758
1759     DoAnimation();
1760
1761     /* don't eat all CPU time */
1762     Delay(10);
1763   }
1764
1765   if (game_status != MAINMENU)
1766     StopAnimation();
1767
1768   if (!(req_state & REQ_STAY_OPEN))
1769   {
1770     CloseDoor(DOOR_CLOSE_1);
1771
1772     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1773     {
1774       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1775                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1776                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1777       OpenDoor(DOOR_OPEN_1);
1778     }
1779   }
1780
1781 #ifndef MSDOS
1782   /* continue network game after request */
1783   if (options.network &&
1784       game_status == PLAYING &&
1785       req_state & REQUEST_WAIT_FOR)
1786     SendToServer_ContinuePlaying();
1787 #endif
1788
1789   return(result);
1790 }
1791
1792 unsigned int OpenDoor(unsigned int door_state)
1793 {
1794   unsigned int new_door_state;
1795
1796   if (door_state & DOOR_COPY_BACK)
1797   {
1798     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1799               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1800               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1801     door_state &= ~DOOR_COPY_BACK;
1802   }
1803
1804   new_door_state = MoveDoor(door_state);
1805
1806   return(new_door_state);
1807 }
1808
1809 unsigned int CloseDoor(unsigned int door_state)
1810 {
1811   unsigned int new_door_state;
1812
1813   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1814             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1815   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1816             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1817
1818   new_door_state = MoveDoor(door_state);
1819
1820   return(new_door_state);
1821 }
1822
1823 unsigned int GetDoorState()
1824 {
1825   return(MoveDoor(DOOR_GET_STATE));
1826 }
1827
1828 unsigned int MoveDoor(unsigned int door_state)
1829 {
1830   static int door1 = DOOR_OPEN_1;
1831   static int door2 = DOOR_CLOSE_2;
1832   static unsigned long door_delay = 0;
1833   int x, start, stepsize = 2;
1834   unsigned long door_delay_value = stepsize * 5;
1835
1836   if (door_state == DOOR_GET_STATE)
1837     return(door1 | door2);
1838
1839   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1840     door_state &= ~DOOR_OPEN_1;
1841   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1842     door_state &= ~DOOR_CLOSE_1;
1843   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1844     door_state &= ~DOOR_OPEN_2;
1845   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1846     door_state &= ~DOOR_CLOSE_2;
1847
1848   if (setup.quick_doors)
1849   {
1850     stepsize = 20;
1851     door_delay_value = 0;
1852     StopSound(SND_OEFFNEN);
1853   }
1854
1855   if (door_state & DOOR_ACTION)
1856   {
1857     if (!(door_state & DOOR_NO_DELAY))
1858       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1859
1860     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1861
1862     for(x=start; x<=DXSIZE; x+=stepsize)
1863     {
1864       WaitUntilDelayReached(&door_delay, door_delay_value);
1865
1866       if (door_state & DOOR_ACTION_1)
1867       {
1868         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1869         int j = (DXSIZE - i) / 3;
1870
1871         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1872                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
1873                   DXSIZE,DYSIZE - i/2, DX, DY);
1874
1875         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
1876
1877         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1878                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1879         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1880                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
1881         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1882                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
1883                   DY + 140 + j);
1884         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1885                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
1886         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1887                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
1888         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1889                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
1890
1891         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1892                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
1893                   DX, DY + 77 - j);
1894         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1895                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
1896                   DX, DY + 203 - j);
1897         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1898                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1899         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1900                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
1901                   DX + DXSIZE - i, DY + 77 + j);
1902         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1903                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
1904                   DX + DXSIZE - i, DY + 203 + j);
1905
1906         redraw_mask |= REDRAW_DOOR_1;
1907       }
1908
1909       if (door_state & DOOR_ACTION_2)
1910       {
1911         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
1912         int j = (VXSIZE - i) / 3;
1913
1914         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1915                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
1916                   VXSIZE, VYSIZE - i/2, VX, VY);
1917
1918         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
1919
1920         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1921                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1922         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1923                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
1924         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1925                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
1926         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1927                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
1928
1929         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1930                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
1931                   VX, VY + VYSIZE / 2 - j);
1932         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1933                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1934         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1935                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
1936                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
1937
1938         redraw_mask |= REDRAW_DOOR_2;
1939       }
1940
1941       BackToFront();
1942
1943       if (game_status == MAINMENU)
1944         DoAnimation();
1945     }
1946   }
1947
1948   if (setup.quick_doors)
1949     StopSound(SND_OEFFNEN);
1950
1951   if (door_state & DOOR_ACTION_1)
1952     door1 = door_state & DOOR_ACTION_1;
1953   if (door_state & DOOR_ACTION_2)
1954     door2 = door_state & DOOR_ACTION_2;
1955
1956   return(door1 | door2);
1957 }
1958
1959 int ReadPixel(Drawable d, int x, int y)
1960 {
1961   XImage *pixel_image;
1962   unsigned long pixel_value;
1963
1964   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
1965   pixel_value = XGetPixel(pixel_image, 0, 0);
1966
1967   XDestroyImage(pixel_image);
1968
1969   return pixel_value;
1970 }
1971
1972 int el2gfx(int element)
1973 {
1974   switch(element)
1975   {
1976     case EL_LEERRAUM:           return -1;
1977     case EL_ERDREICH:           return GFX_ERDREICH;
1978     case EL_MAUERWERK:          return GFX_MAUERWERK;
1979     case EL_FELSBODEN:          return GFX_FELSBODEN;
1980     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
1981     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
1982     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
1983     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
1984     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
1985     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
1986     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
1987     case EL_SPIELER1:           return GFX_SPIELER1;
1988     case EL_SPIELER2:           return GFX_SPIELER2;
1989     case EL_SPIELER3:           return GFX_SPIELER3;
1990     case EL_SPIELER4:           return GFX_SPIELER4;
1991     case EL_KAEFER:             return GFX_KAEFER;
1992     case EL_KAEFER_R:           return GFX_KAEFER_R;
1993     case EL_KAEFER_O:           return GFX_KAEFER_O;
1994     case EL_KAEFER_L:           return GFX_KAEFER_L;
1995     case EL_KAEFER_U:           return GFX_KAEFER_U;
1996     case EL_FLIEGER:            return GFX_FLIEGER;
1997     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
1998     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
1999     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
2000     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
2001     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
2002     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
2003     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
2004     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
2005     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
2006     case EL_FIREFLY:            return GFX_FIREFLY;
2007     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
2008     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
2009     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
2010     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
2011     case EL_MAMPFER:            return GFX_MAMPFER;
2012     case EL_ROBOT:              return GFX_ROBOT;
2013     case EL_BETON:              return GFX_BETON;
2014     case EL_DIAMANT:            return GFX_DIAMANT;
2015     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2016     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2017     case EL_TROPFEN:            return GFX_TROPFEN;
2018     case EL_BOMBE:              return GFX_BOMBE;
2019     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
2020     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
2021     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
2022     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
2023     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2024     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2025     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2026     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2027     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2028     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2029     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2030     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2031     case EL_LIFE:               return GFX_LIFE;
2032     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2033     case EL_DYNAMIT:            return GFX_DYNAMIT;
2034     case EL_BADEWANNE:          return GFX_BADEWANNE;
2035     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2036     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2037     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2038     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2039     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2040     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2041     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2042     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2043     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2044     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2045     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2046     case EL_PFORTE1:            return GFX_PFORTE1;
2047     case EL_PFORTE2:            return GFX_PFORTE2;
2048     case EL_PFORTE3:            return GFX_PFORTE3;
2049     case EL_PFORTE4:            return GFX_PFORTE4;
2050     case EL_PFORTE1X:           return GFX_PFORTE1X;
2051     case EL_PFORTE2X:           return GFX_PFORTE2X;
2052     case EL_PFORTE3X:           return GFX_PFORTE3X;
2053     case EL_PFORTE4X:           return GFX_PFORTE4X;
2054     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
2055     case EL_PACMAN:             return GFX_PACMAN;
2056     case EL_PACMAN_R:           return GFX_PACMAN_R;
2057     case EL_PACMAN_O:           return GFX_PACMAN_O;
2058     case EL_PACMAN_L:           return GFX_PACMAN_L;
2059     case EL_PACMAN_U:           return GFX_PACMAN_U;
2060     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2061     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2062     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2063     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2064     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2065     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2066     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2067     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2068     case EL_MAUER_X:            return GFX_MAUER_X;
2069     case EL_MAUER_Y:            return GFX_MAUER_Y;
2070     case EL_MAUER_XY:           return GFX_MAUER_XY;
2071     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2072     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2073     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2074     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2075     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2076     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2077     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2078     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2079     case EL_MAMPFER2:           return GFX_MAMPFER2;
2080     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
2081     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
2082     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
2083     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
2084     case EL_DYNABOMB:           return GFX_DYNABOMB;
2085     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2086     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2087     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2088     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2089     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2090     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2091     case EL_MAULWURF:           return GFX_MAULWURF;
2092     case EL_PINGUIN:            return GFX_PINGUIN;
2093     case EL_SCHWEIN:            return GFX_SCHWEIN;
2094     case EL_DRACHE:             return GFX_DRACHE;
2095     case EL_SONDE:              return GFX_SONDE;
2096     case EL_PFEIL_L:            return GFX_PFEIL_L;
2097     case EL_PFEIL_R:            return GFX_PFEIL_R;
2098     case EL_PFEIL_O:            return GFX_PFEIL_O;
2099     case EL_PFEIL_U:            return GFX_PFEIL_U;
2100     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2101     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2102     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2103     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2104
2105     default:
2106     {
2107       if (IS_CHAR(element))
2108         return GFX_CHAR_START + (element - EL_CHAR_START);
2109       else if (element >= EL_SP_START && element <= EL_SP_END)
2110       {
2111         int nr_element = element - EL_SP_START;
2112         int gfx_per_line = 8;
2113         int nr_graphic =
2114           (nr_element / gfx_per_line) * MORE_PER_LINE +
2115           (nr_element % gfx_per_line);
2116
2117         return GFX_START_ROCKSMORE + nr_graphic;
2118       }
2119       else
2120         return -1;
2121     }
2122   }
2123 }