rnd-19990122-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 (DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1534   {
1535     label_counter = (label_counter + 1) % 23;
1536     label_state = (label_counter >= 0 && label_counter <= 7 ? 1 :
1537                    label_counter >= 9 && label_counter <= 12 ? 2 :
1538                    label_counter >= 14 && label_counter <= 21 ? 3 : 0);
1539     DrawMicroLevelLabelExt(label_state);
1540   }
1541 }
1542
1543 int REQ_in_range(int x, int y)
1544 {
1545   if (y > DY+249 && y < DY+278)
1546   {
1547     if (x > DX+1 && x < DX+48)
1548       return 1;
1549     else if (x > DX+51 && x < DX+98) 
1550       return 2;
1551   }
1552   return 0;
1553 }
1554
1555 boolean Request(char *text, unsigned int req_state)
1556 {
1557   int mx, my, ty, result = -1;
1558   unsigned int old_door_state;
1559
1560 #ifndef MSDOS
1561   /* pause network game while waiting for request to answer */
1562   if (options.network &&
1563       game_status == PLAYING &&
1564       req_state & REQUEST_WAIT_FOR)
1565     SendToServer_PausePlaying();
1566 #endif
1567
1568   old_door_state = GetDoorState();
1569
1570   CloseDoor(DOOR_CLOSE_1);
1571
1572   /* Alten Türinhalt sichern */
1573   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1574             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1575             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1576
1577   /* Fragetext schreiben */
1578   XFillRectangle(display, pix[PIX_DB_DOOR], gc,
1579                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
1580
1581   for(ty=0; ty<13; ty++)
1582   {
1583     int tx, tl, tc;
1584     char txt[256];
1585
1586     if (!*text)
1587       break;
1588
1589     for(tl=0,tx=0; tx<7; tl++,tx++)
1590     {
1591       tc = *(text + tx);
1592       if (!tc || tc == 32)
1593         break;
1594     }
1595     if (!tl)
1596     { 
1597       text++; 
1598       ty--; 
1599       continue; 
1600     }
1601     sprintf(txt, text); 
1602     txt[tl] = 0;
1603     DrawTextExt(pix[PIX_DB_DOOR], gc,
1604                 DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
1605                 txt, FS_SMALL, FC_YELLOW);
1606     text += tl + (tc == 32 ? 1 : 0);
1607   }
1608
1609   if (req_state & REQ_ASK)
1610   {
1611     DrawYesNoButton(BUTTON_OK, DB_INIT);
1612     DrawYesNoButton(BUTTON_NO, DB_INIT);
1613   }
1614   else if (req_state & REQ_CONFIRM)
1615   {
1616     DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
1617   }
1618   else if (req_state & REQ_PLAYER)
1619   {
1620     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1621     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1622     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1623     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1624   }
1625
1626   OpenDoor(DOOR_OPEN_1);
1627   ClearEventQueue();
1628
1629   if (!(req_state & REQUEST_WAIT_FOR))
1630     return(FALSE);
1631
1632   if (game_status != MAINMENU)
1633     InitAnimation();
1634
1635   button_status = MB_RELEASED;
1636
1637   while(result < 0)
1638   {
1639     if (XPending(display))
1640     {
1641       XEvent event;
1642
1643       XNextEvent(display, &event);
1644
1645       switch(event.type)
1646       {
1647         case ButtonPress:
1648         case ButtonRelease:
1649         case MotionNotify:
1650         {
1651           int choice;
1652
1653           if (event.type == MotionNotify)
1654           {
1655             motion_status = TRUE;
1656             mx = ((XMotionEvent *) &event)->x;
1657             my = ((XMotionEvent *) &event)->y;
1658           }
1659           else
1660           {
1661             motion_status = FALSE;
1662             mx = ((XButtonEvent *) &event)->x;
1663             my = ((XButtonEvent *) &event)->y;
1664             if (event.type==ButtonPress)
1665               button_status = ((XButtonEvent *) &event)->button;
1666             else
1667               button_status = MB_RELEASED;
1668           }
1669
1670           if (req_state & REQ_ASK)
1671             choice = CheckYesNoButtons(mx,my,button_status);
1672           else if (req_state & REQ_CONFIRM)
1673             choice = CheckConfirmButton(mx,my,button_status);
1674           else
1675             choice = CheckPlayerButtons(mx,my,button_status);
1676
1677           switch(choice)
1678           {
1679             case BUTTON_OK:
1680               result = TRUE;
1681               break;
1682             case BUTTON_NO:
1683               result = FALSE;
1684               break;
1685             case BUTTON_CONFIRM:
1686               result = TRUE | FALSE;
1687               break;
1688
1689             case BUTTON_PLAYER_1:
1690               result = 1;
1691               break;
1692             case BUTTON_PLAYER_2:
1693               result = 2;
1694               break;
1695             case BUTTON_PLAYER_3:
1696               result = 3;
1697               break;
1698             case BUTTON_PLAYER_4:
1699               result = 4;
1700               break;
1701
1702             default:
1703               break;
1704           }
1705           break;
1706         }
1707
1708         case KeyPress:
1709           switch(XLookupKeysym((XKeyEvent *)&event,
1710                                ((XKeyEvent *)&event)->state))
1711           {
1712             case XK_Return:
1713               result = 1;
1714               break;
1715
1716             case XK_Escape:
1717               result = 0;
1718               break;
1719
1720             default:
1721               break;
1722           }
1723           if (req_state & REQ_PLAYER)
1724             result = 0;
1725           break;
1726
1727         case KeyRelease:
1728           key_joystick_mapping = 0;
1729           break;
1730
1731         default:
1732           HandleOtherEvents(&event);
1733           break;
1734       }
1735     }
1736     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1737     {
1738       int joy = AnyJoystick();
1739
1740       if (joy & JOY_BUTTON_1)
1741         result = 1;
1742       else if (joy & JOY_BUTTON_2)
1743         result = 0;
1744     }
1745
1746     DoAnimation();
1747
1748     /* don't eat all CPU time */
1749     Delay(10);
1750   }
1751
1752   if (game_status != MAINMENU)
1753     StopAnimation();
1754
1755   if (!(req_state & REQ_STAY_OPEN))
1756   {
1757     CloseDoor(DOOR_CLOSE_1);
1758
1759     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1760     {
1761       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1762                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1763                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1764       OpenDoor(DOOR_OPEN_1);
1765     }
1766   }
1767
1768 #ifndef MSDOS
1769   /* continue network game after request */
1770   if (options.network &&
1771       game_status == PLAYING &&
1772       req_state & REQUEST_WAIT_FOR)
1773     SendToServer_ContinuePlaying();
1774 #endif
1775
1776   return(result);
1777 }
1778
1779 unsigned int OpenDoor(unsigned int door_state)
1780 {
1781   unsigned int new_door_state;
1782
1783   if (door_state & DOOR_COPY_BACK)
1784   {
1785     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1786               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1787               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1788     door_state &= ~DOOR_COPY_BACK;
1789   }
1790
1791   new_door_state = MoveDoor(door_state);
1792
1793   return(new_door_state);
1794 }
1795
1796 unsigned int CloseDoor(unsigned int door_state)
1797 {
1798   unsigned int new_door_state;
1799
1800   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1801             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1802   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1803             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1804
1805   new_door_state = MoveDoor(door_state);
1806
1807   return(new_door_state);
1808 }
1809
1810 unsigned int GetDoorState()
1811 {
1812   return(MoveDoor(DOOR_GET_STATE));
1813 }
1814
1815 unsigned int MoveDoor(unsigned int door_state)
1816 {
1817   static int door1 = DOOR_OPEN_1;
1818   static int door2 = DOOR_CLOSE_2;
1819   static unsigned long door_delay = 0;
1820   int x, start, stepsize = 2;
1821   unsigned long door_delay_value = stepsize * 5;
1822
1823   if (door_state == DOOR_GET_STATE)
1824     return(door1 | door2);
1825
1826   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1827     door_state &= ~DOOR_OPEN_1;
1828   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1829     door_state &= ~DOOR_CLOSE_1;
1830   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1831     door_state &= ~DOOR_OPEN_2;
1832   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1833     door_state &= ~DOOR_CLOSE_2;
1834
1835   if (setup.quick_doors)
1836   {
1837     stepsize = 20;
1838     door_delay_value = 0;
1839     StopSound(SND_OEFFNEN);
1840   }
1841
1842   if (door_state & DOOR_ACTION)
1843   {
1844     if (!(door_state & DOOR_NO_DELAY))
1845       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1846
1847     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1848
1849     for(x=start; x<=DXSIZE; x+=stepsize)
1850     {
1851       WaitUntilDelayReached(&door_delay, door_delay_value);
1852
1853       if (door_state & DOOR_ACTION_1)
1854       {
1855         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1856         int j = (DXSIZE - i) / 3;
1857
1858         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1859                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
1860                   DXSIZE,DYSIZE - i/2, DX, DY);
1861
1862         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
1863
1864         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1865                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1866         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1867                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
1868         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1869                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
1870                   DY + 140 + j);
1871         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1872                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
1873         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1874                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
1875         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1876                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
1877
1878         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1879                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
1880                   DX, DY + 77 - j);
1881         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1882                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
1883                   DX, DY + 203 - j);
1884         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1885                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1886         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1887                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
1888                   DX + DXSIZE - i, DY + 77 + j);
1889         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1890                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
1891                   DX + DXSIZE - i, DY + 203 + j);
1892
1893         redraw_mask |= REDRAW_DOOR_1;
1894       }
1895
1896       if (door_state & DOOR_ACTION_2)
1897       {
1898         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
1899         int j = (VXSIZE - i) / 3;
1900
1901         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1902                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
1903                   VXSIZE, VYSIZE - i/2, VX, VY);
1904
1905         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
1906
1907         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1908                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1909         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1910                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
1911         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1912                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
1913         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1914                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
1915
1916         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1917                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
1918                   VX, VY + VYSIZE / 2 - j);
1919         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1920                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1921         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1922                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
1923                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
1924
1925         redraw_mask |= REDRAW_DOOR_2;
1926       }
1927
1928       BackToFront();
1929
1930       if (game_status == MAINMENU)
1931         DoAnimation();
1932     }
1933   }
1934
1935   if (setup.quick_doors)
1936     StopSound(SND_OEFFNEN);
1937
1938   if (door_state & DOOR_ACTION_1)
1939     door1 = door_state & DOOR_ACTION_1;
1940   if (door_state & DOOR_ACTION_2)
1941     door2 = door_state & DOOR_ACTION_2;
1942
1943   return(door1 | door2);
1944 }
1945
1946 int ReadPixel(Drawable d, int x, int y)
1947 {
1948   XImage *pixel_image;
1949   unsigned long pixel_value;
1950
1951   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
1952   pixel_value = XGetPixel(pixel_image, 0, 0);
1953
1954   XDestroyImage(pixel_image);
1955
1956   return pixel_value;
1957 }
1958
1959 int el2gfx(int element)
1960 {
1961   switch(element)
1962   {
1963     case EL_LEERRAUM:           return -1;
1964     case EL_ERDREICH:           return GFX_ERDREICH;
1965     case EL_MAUERWERK:          return GFX_MAUERWERK;
1966     case EL_FELSBODEN:          return GFX_FELSBODEN;
1967     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
1968     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
1969     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
1970     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
1971     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
1972     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
1973     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
1974     case EL_SPIELER1:           return GFX_SPIELER1;
1975     case EL_SPIELER2:           return GFX_SPIELER2;
1976     case EL_SPIELER3:           return GFX_SPIELER3;
1977     case EL_SPIELER4:           return GFX_SPIELER4;
1978     case EL_KAEFER:             return GFX_KAEFER;
1979     case EL_KAEFER_R:           return GFX_KAEFER_R;
1980     case EL_KAEFER_O:           return GFX_KAEFER_O;
1981     case EL_KAEFER_L:           return GFX_KAEFER_L;
1982     case EL_KAEFER_U:           return GFX_KAEFER_U;
1983     case EL_FLIEGER:            return GFX_FLIEGER;
1984     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
1985     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
1986     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
1987     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
1988     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
1989     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
1990     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
1991     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
1992     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
1993     case EL_FIREFLY:            return GFX_FIREFLY;
1994     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
1995     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
1996     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
1997     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
1998     case EL_MAMPFER:            return GFX_MAMPFER;
1999     case EL_ROBOT:              return GFX_ROBOT;
2000     case EL_BETON:              return GFX_BETON;
2001     case EL_DIAMANT:            return GFX_DIAMANT;
2002     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2003     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2004     case EL_TROPFEN:            return GFX_TROPFEN;
2005     case EL_BOMBE:              return GFX_BOMBE;
2006     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
2007     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
2008     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
2009     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
2010     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2011     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2012     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2013     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2014     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2015     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2016     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2017     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2018     case EL_LIFE:               return GFX_LIFE;
2019     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2020     case EL_DYNAMIT:            return GFX_DYNAMIT;
2021     case EL_BADEWANNE:          return GFX_BADEWANNE;
2022     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2023     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2024     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2025     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2026     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2027     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2028     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2029     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2030     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2031     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2032     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2033     case EL_PFORTE1:            return GFX_PFORTE1;
2034     case EL_PFORTE2:            return GFX_PFORTE2;
2035     case EL_PFORTE3:            return GFX_PFORTE3;
2036     case EL_PFORTE4:            return GFX_PFORTE4;
2037     case EL_PFORTE1X:           return GFX_PFORTE1X;
2038     case EL_PFORTE2X:           return GFX_PFORTE2X;
2039     case EL_PFORTE3X:           return GFX_PFORTE3X;
2040     case EL_PFORTE4X:           return GFX_PFORTE4X;
2041     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
2042     case EL_PACMAN:             return GFX_PACMAN;
2043     case EL_PACMAN_R:           return GFX_PACMAN_R;
2044     case EL_PACMAN_O:           return GFX_PACMAN_O;
2045     case EL_PACMAN_L:           return GFX_PACMAN_L;
2046     case EL_PACMAN_U:           return GFX_PACMAN_U;
2047     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2048     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2049     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2050     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2051     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2052     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2053     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2054     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2055     case EL_MAUER_X:            return GFX_MAUER_X;
2056     case EL_MAUER_Y:            return GFX_MAUER_Y;
2057     case EL_MAUER_XY:           return GFX_MAUER_XY;
2058     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2059     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2060     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2061     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2062     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2063     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2064     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2065     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2066     case EL_MAMPFER2:           return GFX_MAMPFER2;
2067     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
2068     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
2069     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
2070     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
2071     case EL_DYNABOMB:           return GFX_DYNABOMB;
2072     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2073     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2074     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2075     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2076     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2077     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2078     case EL_MAULWURF:           return GFX_MAULWURF;
2079     case EL_PINGUIN:            return GFX_PINGUIN;
2080     case EL_SCHWEIN:            return GFX_SCHWEIN;
2081     case EL_DRACHE:             return GFX_DRACHE;
2082     case EL_SONDE:              return GFX_SONDE;
2083     case EL_PFEIL_L:            return GFX_PFEIL_L;
2084     case EL_PFEIL_R:            return GFX_PFEIL_R;
2085     case EL_PFEIL_O:            return GFX_PFEIL_O;
2086     case EL_PFEIL_U:            return GFX_PFEIL_U;
2087     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2088     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2089     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2090     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2091
2092     default:
2093     {
2094       if (IS_CHAR(element))
2095         return GFX_CHAR_START + (element - EL_CHAR_START);
2096       else if (element >= EL_SP_START && element <= EL_SP_END)
2097       {
2098         int nr_element = element - EL_SP_START;
2099         int gfx_per_line = 8;
2100         int nr_graphic =
2101           (nr_element / gfx_per_line) * MORE_PER_LINE +
2102           (nr_element % gfx_per_line);
2103
2104         return GFX_START_ROCKSMORE + nr_graphic;
2105       }
2106       else
2107         return -1;
2108     }
2109   }
2110 }