rnd-19990124-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 getMiniGraphicSource(int graphic, Pixmap *pixmap, int *x, int *y)
779 {
780   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
781   {
782     graphic -= GFX_START_ROCKSSCREEN;
783     *pixmap = pix[PIX_BACK];
784     *x = MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX;
785     *y = MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY;
786   }
787   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
788   {
789     graphic -= GFX_START_ROCKSMORE;
790     *pixmap = pix[PIX_MORE];
791     *x = MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX;
792     *y = MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY;
793   }
794   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
795   {
796     graphic -= GFX_START_ROCKSFONT;
797     *pixmap = pix[PIX_SMALLFONT];
798     *x = (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE;
799     *y = ((graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
800           FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT);
801   }
802   else
803   {
804     *pixmap = pix[PIX_MORE];
805     *x = MINI_MORE_STARTX;
806     *y = MINI_MORE_STARTY;
807   }
808 }
809
810 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
811 {
812   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
813   {
814     graphic -= GFX_START_ROCKSSCREEN;
815     XCopyArea(display, pix[PIX_BACK], d, gc,
816               MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX,
817               MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY,
818               MINI_TILEX, MINI_TILEY, x, y);
819   }
820   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
821   {
822     graphic -= GFX_START_ROCKSMORE;
823     XCopyArea(display, pix[PIX_MORE], d, gc,
824               MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX,
825               MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY,
826               MINI_TILEX, MINI_TILEY, x, y);
827   }
828   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
829   {
830     graphic -= GFX_START_ROCKSFONT;
831     XCopyArea(display, pix[PIX_SMALLFONT], d, gc,
832               (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE,
833               (graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
834               FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT,
835               MINI_TILEX, MINI_TILEY, x, y);
836   }
837   else
838     XFillRectangle(display, d, gc, x, y, MINI_TILEX, MINI_TILEY);
839 }
840
841 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
842                         int cut_mode, int mask_mode)
843 {
844   int width = TILEX, height = TILEY;
845   int cx = 0, cy = 0;
846   int src_x, src_y, dest_x, dest_y;
847   int tile = graphic;
848   Pixmap src_pixmap;
849   GC drawing_gc;
850
851   if (graphic < 0)
852   {
853     DrawGraphic(x, y, graphic);
854     return;
855   }
856
857   if (dx || dy)                 /* Verschiebung der Grafik? */
858   {
859     if (x < BX1)                /* Element kommt von links ins Bild */
860     {
861       x = BX1;
862       width = dx;
863       cx = TILEX - dx;
864       dx = 0;
865     }
866     else if (x > BX2)           /* Element kommt von rechts ins Bild */
867     {
868       x = BX2;
869       width = -dx;
870       dx = TILEX + dx;
871     }
872     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
873     {
874       width += dx;
875       cx = -dx;
876       dx = 0;
877     }
878     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
879       width -= dx;
880     else if (dx)                /* allg. Bewegung in x-Richtung */
881       MarkTileDirty(x + SIGN(dx), y);
882
883     if (y < BY1)                /* Element kommt von oben ins Bild */
884     {
885       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
886         return;
887
888       y = BY1;
889       height = dy;
890       cy = TILEY - dy;
891       dy = 0;
892     }
893     else if (y > BY2)           /* Element kommt von unten ins Bild */
894     {
895       y = BY2;
896       height = -dy;
897       dy = TILEY + dy;
898     }
899     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
900     {
901       height += dy;
902       cy = -dy;
903       dy = 0;
904     }
905     else if (dy > 0 && cut_mode == CUT_ABOVE)
906     {
907       if (y == BY2)             /* Element unterhalb des Bildes */
908         return;
909
910       height = dy;
911       cy = TILEY - dy;
912       dy = TILEY;
913       MarkTileDirty(x, y + 1);
914     }                           /* Element verläßt unten das Bild */
915     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
916       height -= dy;
917     else if (dy)                /* allg. Bewegung in y-Richtung */
918       MarkTileDirty(x, y + SIGN(dy));
919   }
920
921   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
922   {
923     src_pixmap = pix[PIX_BACK];
924     drawing_gc = clip_gc[PIX_BACK];
925     graphic -= GFX_START_ROCKSSCREEN;
926     src_x  = SX + (graphic % GFX_PER_LINE) * TILEX + cx;
927     src_y  = SY + (graphic / GFX_PER_LINE) * TILEY + cy;
928   }
929   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
930   {
931     src_pixmap = pix[PIX_MORE];
932     drawing_gc = clip_gc[PIX_MORE];
933     graphic -= GFX_START_ROCKSMORE;
934     src_x  = (graphic % MORE_PER_LINE) * TILEX + cx;
935     src_y  = (graphic / MORE_PER_LINE) * TILEY + cy;
936   }
937   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
938   {
939     src_pixmap = pix[PIX_HEROES];
940     drawing_gc = clip_gc[PIX_HEROES];
941     graphic -= GFX_START_ROCKSHEROES;
942     src_x  = (graphic % HEROES_PER_LINE) * TILEX + cx;
943     src_y  = (graphic / HEROES_PER_LINE) * TILEY + cy;
944   }
945   else  /* big font graphics currently not allowed (and not needed) */
946     return;
947
948   dest_x = FX + x * TILEX + dx;
949   dest_y = FY + y * TILEY + dy;
950
951 #if DEBUG
952   if (!IN_SCR_FIELD(x,y))
953   {
954     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
955     printf("DrawGraphicShifted(): This should never happen!\n");
956     return;
957   }
958 #endif
959
960   if (mask_mode == USE_MASKING)
961   {
962     if (tile_clipmask[tile] != None)
963     {
964       XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
965       XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
966       XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
967                 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
968     }
969     else
970     {
971 #if DEBUG
972       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
973 #endif
974
975       XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
976       XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
977                 src_x, src_y, width, height, dest_x, dest_y);
978     }
979   }
980   else
981     XCopyArea(display, src_pixmap, drawto_field, gc,
982               src_x, src_y, width, height, dest_x, dest_y);
983
984   MarkTileDirty(x,y);
985 }
986
987 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
988                                 int cut_mode)
989 {
990   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
991 }
992
993 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
994                           int cut_mode, int mask_mode)
995 {
996   int ux = LEVELX(x), uy = LEVELY(y);
997   int graphic = el2gfx(element);
998   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
999   int phase4 = phase8 / 2;
1000   int phase2  = phase8 / 4;
1001   int dir = MovDir[ux][uy];
1002
1003   if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
1004   {
1005     graphic += 4 * !phase2;
1006
1007     if (dir == MV_UP)
1008       graphic += 1;
1009     else if (dir == MV_LEFT)
1010       graphic += 2;
1011     else if (dir == MV_DOWN)
1012       graphic += 3;
1013   }
1014   else if (element == EL_SP_SNIKSNAK)
1015   {
1016     if (dir == MV_LEFT)
1017       graphic = GFX_SP_SNIKSNAK_LEFT;
1018     else if (dir == MV_RIGHT)
1019       graphic = GFX_SP_SNIKSNAK_RIGHT;
1020     else if (dir == MV_UP)
1021       graphic = GFX_SP_SNIKSNAK_UP;
1022     else
1023       graphic = GFX_SP_SNIKSNAK_DOWN;
1024
1025     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1026   }
1027   else if (element == EL_SP_ELECTRON)
1028   {
1029     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1030   }
1031   else if (element == EL_MAULWURF || element == EL_PINGUIN ||
1032            element == EL_SCHWEIN || element == EL_DRACHE)
1033   {
1034     if (dir == MV_LEFT)
1035       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT :
1036                  element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
1037                  element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1038     else if (dir == MV_RIGHT)
1039       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT :
1040                  element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
1041                  element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1042     else if (dir == MV_UP)
1043       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP :
1044                  element == EL_PINGUIN ? GFX_PINGUIN_UP :
1045                  element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1046     else
1047       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN :
1048                  element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
1049                  element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1050
1051     graphic += phase4;
1052   }
1053   else if (element == EL_SONDE)
1054   {
1055     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1056   }
1057   else if (element == EL_SALZSAEURE)
1058   {
1059     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
1060   }
1061   else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1062   {
1063     graphic += !phase2;
1064   }
1065   else if ((element == EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode)
1066   {
1067     if (element != EL_SP_INFOTRON)
1068       graphic += phase2 * (element == EL_FELSBROCKEN ? 2 : 1);
1069   }
1070   else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
1071            element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
1072   {
1073     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1074   }
1075   else if (IS_AMOEBOID(element))
1076   {
1077     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1078     graphic += (x + 2 * y + 4) % 4;
1079   }
1080   else if (element == EL_MAUER_LEBT)
1081   {
1082     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1083
1084     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1085       links_massiv = TRUE;
1086     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1087       rechts_massiv = TRUE;
1088
1089     if (links_massiv && rechts_massiv)
1090       graphic = GFX_MAUERWERK;
1091     else if (links_massiv)
1092       graphic = GFX_MAUER_R;
1093     else if (rechts_massiv)
1094       graphic = GFX_MAUER_L;
1095   }
1096
1097   if (dx || dy)
1098     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1099   else if (mask_mode == USE_MASKING)
1100     DrawGraphicThruMask(x, y, graphic);
1101   else
1102     DrawGraphic(x, y, graphic);
1103 }
1104
1105 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1106                          int cut_mode, int mask_mode)
1107 {
1108   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1109     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1110                          cut_mode, mask_mode);
1111 }
1112
1113 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1114                               int cut_mode)
1115 {
1116   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1117 }
1118
1119 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1120                              int cut_mode)
1121 {
1122   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1123 }
1124
1125 void DrawScreenElementThruMask(int x, int y, int element)
1126 {
1127   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1128 }
1129
1130 void DrawLevelElementThruMask(int x, int y, int element)
1131 {
1132   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1133 }
1134
1135 void DrawLevelFieldThruMask(int x, int y)
1136 {
1137   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1138 }
1139
1140 void ErdreichAnbroeckeln(int x, int y)
1141 {
1142   int i, width, height, cx,cy;
1143   int ux = LEVELX(x), uy = LEVELY(y);
1144   int element, graphic;
1145   int snip = 4;
1146   static int xy[4][2] =
1147   {
1148     { 0, -1 },
1149     { -1, 0 },
1150     { +1, 0 },
1151     { 0, +1 }
1152   };
1153
1154   if (!IN_LEV_FIELD(ux, uy))
1155     return;
1156
1157   element = Feld[ux][uy];
1158
1159   if (element == EL_ERDREICH)
1160   {
1161     if (!IN_SCR_FIELD(x, y))
1162       return;
1163
1164     graphic = GFX_ERDENRAND;
1165
1166     for(i=0; i<4; i++)
1167     {
1168       int uxx, uyy;
1169
1170       uxx = ux + xy[i][0];
1171       uyy = uy + xy[i][1];
1172       if (!IN_LEV_FIELD(uxx, uyy))
1173         element = EL_BETON;
1174       else
1175         element = Feld[uxx][uyy];
1176
1177       if (element == EL_ERDREICH)
1178         continue;
1179
1180       if (i == 1 || i == 2)
1181       {
1182         width = snip;
1183         height = TILEY;
1184         cx = (i == 2 ? TILEX - snip : 0);
1185         cy = 0;
1186       }
1187       else
1188       {
1189         width = TILEX;
1190         height = snip;
1191         cx = 0;
1192         cy = (i == 3 ? TILEY - snip : 0);
1193       }
1194
1195       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1196                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1197                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1198                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1199     }
1200
1201     MarkTileDirty(x, y);
1202   }
1203   else
1204   {
1205     graphic = GFX_ERDENRAND;
1206
1207     for(i=0; i<4; i++)
1208     {
1209       int xx, yy, uxx, uyy;
1210
1211       xx = x + xy[i][0];
1212       yy = y + xy[i][1];
1213       uxx = ux + xy[i][0];
1214       uyy = uy + xy[i][1];
1215
1216       if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
1217           !IN_SCR_FIELD(xx, yy))
1218         continue;
1219
1220       if (i == 1 || i == 2)
1221       {
1222         width = snip;
1223         height = TILEY;
1224         cx = (i == 1 ? TILEX - snip : 0);
1225         cy = 0;
1226       }
1227       else
1228       {
1229         width = TILEX;
1230         height = snip;
1231         cx = 0;
1232         cy = (i==0 ? TILEY-snip : 0);
1233       }
1234
1235       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1236                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1237                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1238                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1239
1240       MarkTileDirty(xx, yy);
1241     }
1242   }
1243 }
1244
1245 void DrawScreenElement(int x, int y, int element)
1246 {
1247   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1248   ErdreichAnbroeckeln(x, y);
1249 }
1250
1251 void DrawLevelElement(int x, int y, int element)
1252 {
1253   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1254     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1255 }
1256
1257 void DrawScreenField(int x, int y)
1258 {
1259   int ux = LEVELX(x), uy = LEVELY(y);
1260   int element;
1261
1262   if (!IN_LEV_FIELD(ux, uy))
1263   {
1264     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1265       element = EL_LEERRAUM;
1266     else
1267       element = BorderElement;
1268
1269     DrawScreenElement(x, y, element);
1270     return;
1271   }
1272
1273   element = Feld[ux][uy];
1274
1275   if (IS_MOVING(ux, uy))
1276   {
1277     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1278     boolean cut_mode = NO_CUTTING;
1279
1280     if (Store[ux][uy] == EL_MORAST_LEER ||
1281         Store[ux][uy] == EL_SIEB_LEER ||
1282         Store[ux][uy] == EL_SIEB2_LEER ||
1283         Store[ux][uy] == EL_AMOEBE_NASS)
1284       cut_mode = CUT_ABOVE;
1285     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1286              Store[ux][uy] == EL_SIEB_VOLL ||
1287              Store[ux][uy] == EL_SIEB2_VOLL)
1288       cut_mode = CUT_BELOW;
1289
1290     if (cut_mode == CUT_ABOVE)
1291       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1292     else
1293       DrawScreenElement(x, y, EL_LEERRAUM);
1294
1295     if (horiz_move)
1296       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1297     else
1298       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1299
1300     if (Store[ux][uy] == EL_SALZSAEURE)
1301       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1302   }
1303   else if (IS_BLOCKED(ux, uy))
1304   {
1305     int oldx, oldy;
1306     int sx, sy;
1307     int horiz_move;
1308     boolean cut_mode = NO_CUTTING;
1309
1310     Blocked2Moving(ux, uy, &oldx, &oldy);
1311     sx = SCREENX(oldx);
1312     sy = SCREENY(oldy);
1313     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1314                   MovDir[oldx][oldy] == MV_RIGHT);
1315
1316     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1317         Store[oldx][oldy] == EL_SIEB_LEER ||
1318         Store[oldx][oldy] == EL_SIEB2_LEER ||
1319         Store[oldx][oldy] == EL_AMOEBE_NASS)
1320       cut_mode = CUT_ABOVE;
1321
1322     DrawScreenElement(x, y, EL_LEERRAUM);
1323     element = Feld[oldx][oldy];
1324
1325     if (horiz_move)
1326       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1327     else
1328       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1329   }
1330   else if (IS_DRAWABLE(element))
1331     DrawScreenElement(x, y, element);
1332   else
1333     DrawScreenElement(x, y, EL_LEERRAUM);
1334 }
1335
1336 void DrawLevelField(int x, int y)
1337 {
1338   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1339     DrawScreenField(SCREENX(x), SCREENY(y));
1340   else if (IS_MOVING(x, y))
1341   {
1342     int newx,newy;
1343
1344     Moving2Blocked(x, y, &newx, &newy);
1345     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1346       DrawScreenField(SCREENX(newx), SCREENY(newy));
1347   }
1348   else if (IS_BLOCKED(x, y))
1349   {
1350     int oldx, oldy;
1351
1352     Blocked2Moving(x, y, &oldx, &oldy);
1353     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1354       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1355   }
1356 }
1357
1358 void DrawMiniElement(int x, int y, int element)
1359 {
1360   int graphic;
1361
1362   if (!element)
1363   {
1364     DrawMiniGraphic(x, y, -1);
1365     return;
1366   }
1367
1368   graphic = el2gfx(element);
1369   DrawMiniGraphic(x, y, graphic);
1370 }
1371
1372 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1373 {
1374   int x = sx + scroll_x, y = sy + scroll_y;
1375
1376   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1377     DrawMiniElement(sx, sy, EL_LEERRAUM);
1378   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1379     DrawMiniElement(sx, sy, Feld[x][y]);
1380   else if (x == -1 && y == -1)
1381     DrawMiniGraphic(sx, sy, GFX_STEEL_UPPER_LEFT);
1382   else if (x == lev_fieldx && y == -1)
1383     DrawMiniGraphic(sx, sy, GFX_STEEL_UPPER_RIGHT);
1384   else if (x == -1 && y == lev_fieldy)
1385     DrawMiniGraphic(sx, sy, GFX_STEEL_LOWER_LEFT);
1386   else if (x == lev_fieldx && y == lev_fieldy)
1387     DrawMiniGraphic(sx, sy, GFX_STEEL_LOWER_RIGHT);
1388   else if (x == -1 || x == lev_fieldx)
1389     DrawMiniGraphic(sx, sy, GFX_STEEL_VERTICAL);
1390   else if (y == -1 || y == lev_fieldy)
1391     DrawMiniGraphic(sx, sy, GFX_STEEL_HORIZONTAL);
1392 }
1393
1394 void DrawMicroElement(int xpos, int ypos, int element)
1395 {
1396   int graphic;
1397
1398   if (element == EL_LEERRAUM)
1399     return;
1400
1401   graphic = el2gfx(element);
1402
1403   if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1404   {
1405     graphic -= GFX_START_ROCKSMORE;
1406     XCopyArea(display, pix[PIX_MORE], drawto, gc,
1407               MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
1408               MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
1409               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1410   }
1411   else
1412     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1413               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1414               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1415               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1416 }
1417
1418 void DrawLevel()
1419 {
1420   int x,y;
1421
1422   ClearWindow();
1423
1424   for(x=BX1; x<=BX2; x++)
1425     for(y=BY1; y<=BY2; y++)
1426       DrawScreenField(x, y);
1427
1428   if (setup.soft_scrolling)
1429     XCopyArea(display, fieldbuffer, backbuffer, gc,
1430               FX, FY, SXSIZE, SYSIZE, SX, SY);
1431
1432   redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
1433 }
1434
1435 void DrawMiniLevel(int scroll_x, int scroll_y)
1436 {
1437   int x,y;
1438
1439   for(x=0; x<ED_FIELDX; x++)
1440     for(y=0; y<ED_FIELDY; y++)
1441       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1442
1443   redraw_mask |= REDRAW_FIELD;
1444 }
1445
1446 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1447 {
1448   int x, y;
1449
1450   /* determine border element for this level */
1451   SetBorderElement();
1452
1453   XFillRectangle(display, drawto, gc,
1454                  xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1455
1456   if (lev_fieldx < STD_LEV_FIELDX)
1457     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1458   if (lev_fieldy < STD_LEV_FIELDY)
1459     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1460
1461   xpos += MICRO_TILEX;
1462   ypos += MICRO_TILEY;
1463
1464   for(x=-1; x<=STD_LEV_FIELDX; x++)
1465   {
1466     for(y=-1; y<=STD_LEV_FIELDY; y++)
1467     {
1468       int lx = from_x + x, ly = from_y + y;
1469
1470       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1471         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1472                          Ur[lx][ly]);
1473       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1474         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1475                          BorderElement);
1476     }
1477   }
1478
1479   redraw_mask |= REDRAW_MICROLEVEL;
1480 }
1481
1482 static void DrawMicroLevelLabelExt(int mode)
1483 {
1484   char label_text[100];
1485
1486   XFillRectangle(display, drawto,gc,
1487                  SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1488
1489   strcpy(label_text, (mode == 1 ? level.name :
1490                       mode == 2 ? "created by" :
1491                       mode == 3 ? level.author : ""));
1492
1493   if (strlen(label_text) > 0)
1494   {
1495     int size, lxpos, lypos;
1496
1497     label_text[SXSIZE / FONT4_XSIZE] = '\0';
1498
1499     size = strlen(label_text);
1500     lxpos = SX + (SXSIZE - size * FONT4_XSIZE) / 2;
1501     lypos = MICROLABEL_YPOS;
1502
1503     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1504   }
1505
1506   redraw_mask |= REDRAW_MICROLEVEL;
1507 }
1508
1509 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1510 {
1511   static unsigned long scroll_delay = 0;
1512   static unsigned long label_delay = 0;
1513   static int from_x, from_y, scroll_direction;
1514   static int label_state, label_counter;
1515
1516   if (restart)
1517   {
1518     from_x = from_y = 0;
1519     scroll_direction = MV_RIGHT;
1520     label_state = 1;
1521     label_counter = 0;
1522
1523     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1524     DrawMicroLevelLabelExt(label_state);
1525
1526     /* initialize delay counters */
1527     DelayReached(&scroll_delay, 0);
1528     DelayReached(&label_delay, 0);
1529
1530     return;
1531   }
1532
1533   /* scroll micro level, if needed */
1534   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1535       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1536   {
1537     switch (scroll_direction)
1538     {
1539       case MV_LEFT:
1540         if (from_x > 0)
1541           from_x--;
1542         else
1543           scroll_direction = MV_UP;
1544         break;
1545
1546       case MV_RIGHT:
1547         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1548           from_x++;
1549         else
1550           scroll_direction = MV_DOWN;
1551         break;
1552
1553       case MV_UP:
1554         if (from_y > 0)
1555           from_y--;
1556         else
1557           scroll_direction = MV_RIGHT;
1558         break;
1559
1560       case MV_DOWN:
1561         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1562           from_y++;
1563         else
1564           scroll_direction = MV_LEFT;
1565         break;
1566
1567       default:
1568         break;
1569     }
1570
1571     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1572   }
1573
1574   /* redraw micro level label, if needed */
1575   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1576       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1577       strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
1578       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1579   {
1580     label_counter = (label_counter + 1) % 23;
1581     label_state = (label_counter >= 0 && label_counter <= 7 ? 1 :
1582                    label_counter >= 9 && label_counter <= 12 ? 2 :
1583                    label_counter >= 14 && label_counter <= 21 ? 3 : 0);
1584     DrawMicroLevelLabelExt(label_state);
1585   }
1586 }
1587
1588 int REQ_in_range(int x, int y)
1589 {
1590   if (y > DY+249 && y < DY+278)
1591   {
1592     if (x > DX+1 && x < DX+48)
1593       return 1;
1594     else if (x > DX+51 && x < DX+98) 
1595       return 2;
1596   }
1597   return 0;
1598 }
1599
1600 boolean Request(char *text, unsigned int req_state)
1601 {
1602   int mx, my, ty, result = -1;
1603   unsigned int old_door_state;
1604
1605 #ifndef MSDOS
1606   /* pause network game while waiting for request to answer */
1607   if (options.network &&
1608       game_status == PLAYING &&
1609       req_state & REQUEST_WAIT_FOR)
1610     SendToServer_PausePlaying();
1611 #endif
1612
1613   old_door_state = GetDoorState();
1614
1615   CloseDoor(DOOR_CLOSE_1);
1616
1617   /* Alten Türinhalt sichern */
1618   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1619             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1620             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1621
1622   /* Fragetext schreiben */
1623   XFillRectangle(display, pix[PIX_DB_DOOR], gc,
1624                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
1625
1626   for(ty=0; ty<13; ty++)
1627   {
1628     int tx, tl, tc;
1629     char txt[256];
1630
1631     if (!*text)
1632       break;
1633
1634     for(tl=0,tx=0; tx<7; tl++,tx++)
1635     {
1636       tc = *(text + tx);
1637       if (!tc || tc == 32)
1638         break;
1639     }
1640     if (!tl)
1641     { 
1642       text++; 
1643       ty--; 
1644       continue; 
1645     }
1646     sprintf(txt, text); 
1647     txt[tl] = 0;
1648     DrawTextExt(pix[PIX_DB_DOOR], gc,
1649                 DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
1650                 txt, FS_SMALL, FC_YELLOW);
1651     text += tl + (tc == 32 ? 1 : 0);
1652   }
1653
1654   if (req_state & REQ_ASK)
1655   {
1656     DrawYesNoButton(BUTTON_OK, DB_INIT);
1657     DrawYesNoButton(BUTTON_NO, DB_INIT);
1658   }
1659   else if (req_state & REQ_CONFIRM)
1660   {
1661     DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
1662   }
1663   else if (req_state & REQ_PLAYER)
1664   {
1665     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1666     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1667     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1668     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1669   }
1670
1671   OpenDoor(DOOR_OPEN_1);
1672   ClearEventQueue();
1673
1674   if (!(req_state & REQUEST_WAIT_FOR))
1675     return(FALSE);
1676
1677   if (game_status != MAINMENU)
1678     InitAnimation();
1679
1680   button_status = MB_RELEASED;
1681
1682   while(result < 0)
1683   {
1684     if (XPending(display))
1685     {
1686       XEvent event;
1687
1688       XNextEvent(display, &event);
1689
1690       switch(event.type)
1691       {
1692         case ButtonPress:
1693         case ButtonRelease:
1694         case MotionNotify:
1695         {
1696           int choice;
1697
1698           if (event.type == MotionNotify)
1699           {
1700             motion_status = TRUE;
1701             mx = ((XMotionEvent *) &event)->x;
1702             my = ((XMotionEvent *) &event)->y;
1703           }
1704           else
1705           {
1706             motion_status = FALSE;
1707             mx = ((XButtonEvent *) &event)->x;
1708             my = ((XButtonEvent *) &event)->y;
1709             if (event.type==ButtonPress)
1710               button_status = ((XButtonEvent *) &event)->button;
1711             else
1712               button_status = MB_RELEASED;
1713           }
1714
1715           if (req_state & REQ_ASK)
1716             choice = CheckYesNoButtons(mx,my,button_status);
1717           else if (req_state & REQ_CONFIRM)
1718             choice = CheckConfirmButton(mx,my,button_status);
1719           else
1720             choice = CheckPlayerButtons(mx,my,button_status);
1721
1722           switch(choice)
1723           {
1724             case BUTTON_OK:
1725               result = TRUE;
1726               break;
1727             case BUTTON_NO:
1728               result = FALSE;
1729               break;
1730             case BUTTON_CONFIRM:
1731               result = TRUE | FALSE;
1732               break;
1733
1734             case BUTTON_PLAYER_1:
1735               result = 1;
1736               break;
1737             case BUTTON_PLAYER_2:
1738               result = 2;
1739               break;
1740             case BUTTON_PLAYER_3:
1741               result = 3;
1742               break;
1743             case BUTTON_PLAYER_4:
1744               result = 4;
1745               break;
1746
1747             default:
1748               break;
1749           }
1750           break;
1751         }
1752
1753         case KeyPress:
1754           switch(XLookupKeysym((XKeyEvent *)&event,
1755                                ((XKeyEvent *)&event)->state))
1756           {
1757             case XK_Return:
1758               result = 1;
1759               break;
1760
1761             case XK_Escape:
1762               result = 0;
1763               break;
1764
1765             default:
1766               break;
1767           }
1768           if (req_state & REQ_PLAYER)
1769             result = 0;
1770           break;
1771
1772         case KeyRelease:
1773           key_joystick_mapping = 0;
1774           break;
1775
1776         default:
1777           HandleOtherEvents(&event);
1778           break;
1779       }
1780     }
1781     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1782     {
1783       int joy = AnyJoystick();
1784
1785       if (joy & JOY_BUTTON_1)
1786         result = 1;
1787       else if (joy & JOY_BUTTON_2)
1788         result = 0;
1789     }
1790
1791     DoAnimation();
1792
1793     /* don't eat all CPU time */
1794     Delay(10);
1795   }
1796
1797   if (game_status != MAINMENU)
1798     StopAnimation();
1799
1800   if (!(req_state & REQ_STAY_OPEN))
1801   {
1802     CloseDoor(DOOR_CLOSE_1);
1803
1804     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1805     {
1806       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1807                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1808                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1809       OpenDoor(DOOR_OPEN_1);
1810     }
1811   }
1812
1813 #ifndef MSDOS
1814   /* continue network game after request */
1815   if (options.network &&
1816       game_status == PLAYING &&
1817       req_state & REQUEST_WAIT_FOR)
1818     SendToServer_ContinuePlaying();
1819 #endif
1820
1821   return(result);
1822 }
1823
1824 unsigned int OpenDoor(unsigned int door_state)
1825 {
1826   unsigned int new_door_state;
1827
1828   if (door_state & DOOR_COPY_BACK)
1829   {
1830     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1831               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1832               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1833     door_state &= ~DOOR_COPY_BACK;
1834   }
1835
1836   new_door_state = MoveDoor(door_state);
1837
1838   return(new_door_state);
1839 }
1840
1841 unsigned int CloseDoor(unsigned int door_state)
1842 {
1843   unsigned int new_door_state;
1844
1845   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1846             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1847   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1848             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1849
1850   new_door_state = MoveDoor(door_state);
1851
1852   return(new_door_state);
1853 }
1854
1855 unsigned int GetDoorState()
1856 {
1857   return(MoveDoor(DOOR_GET_STATE));
1858 }
1859
1860 unsigned int MoveDoor(unsigned int door_state)
1861 {
1862   static int door1 = DOOR_OPEN_1;
1863   static int door2 = DOOR_CLOSE_2;
1864   static unsigned long door_delay = 0;
1865   int x, start, stepsize = 2;
1866   unsigned long door_delay_value = stepsize * 5;
1867
1868   if (door_state == DOOR_GET_STATE)
1869     return(door1 | door2);
1870
1871   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1872     door_state &= ~DOOR_OPEN_1;
1873   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1874     door_state &= ~DOOR_CLOSE_1;
1875   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1876     door_state &= ~DOOR_OPEN_2;
1877   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1878     door_state &= ~DOOR_CLOSE_2;
1879
1880   if (setup.quick_doors)
1881   {
1882     stepsize = 20;
1883     door_delay_value = 0;
1884     StopSound(SND_OEFFNEN);
1885   }
1886
1887   if (door_state & DOOR_ACTION)
1888   {
1889     if (!(door_state & DOOR_NO_DELAY))
1890       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1891
1892     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1893
1894     for(x=start; x<=DXSIZE; x+=stepsize)
1895     {
1896       WaitUntilDelayReached(&door_delay, door_delay_value);
1897
1898       if (door_state & DOOR_ACTION_1)
1899       {
1900         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1901         int j = (DXSIZE - i) / 3;
1902
1903         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1904                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
1905                   DXSIZE,DYSIZE - i/2, DX, DY);
1906
1907         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
1908
1909         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1910                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1911         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1912                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
1913         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1914                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
1915                   DY + 140 + j);
1916         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1917                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
1918         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1919                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
1920         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1921                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
1922
1923         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1924                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
1925                   DX, DY + 77 - j);
1926         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1927                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
1928                   DX, DY + 203 - j);
1929         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1930                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1931         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1932                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
1933                   DX + DXSIZE - i, DY + 77 + j);
1934         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1935                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
1936                   DX + DXSIZE - i, DY + 203 + j);
1937
1938         redraw_mask |= REDRAW_DOOR_1;
1939       }
1940
1941       if (door_state & DOOR_ACTION_2)
1942       {
1943         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
1944         int j = (VXSIZE - i) / 3;
1945
1946         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1947                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
1948                   VXSIZE, VYSIZE - i/2, VX, VY);
1949
1950         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
1951
1952         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1953                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1954         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1955                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
1956         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1957                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
1958         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1959                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
1960
1961         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1962                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
1963                   VX, VY + VYSIZE / 2 - j);
1964         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1965                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1966         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1967                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
1968                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
1969
1970         redraw_mask |= REDRAW_DOOR_2;
1971       }
1972
1973       BackToFront();
1974
1975       if (game_status == MAINMENU)
1976         DoAnimation();
1977     }
1978   }
1979
1980   if (setup.quick_doors)
1981     StopSound(SND_OEFFNEN);
1982
1983   if (door_state & DOOR_ACTION_1)
1984     door1 = door_state & DOOR_ACTION_1;
1985   if (door_state & DOOR_ACTION_2)
1986     door2 = door_state & DOOR_ACTION_2;
1987
1988   return(door1 | door2);
1989 }
1990
1991 int ReadPixel(Drawable d, int x, int y)
1992 {
1993   XImage *pixel_image;
1994   unsigned long pixel_value;
1995
1996   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
1997   pixel_value = XGetPixel(pixel_image, 0, 0);
1998
1999   XDestroyImage(pixel_image);
2000
2001   return pixel_value;
2002 }
2003
2004 int el2gfx(int element)
2005 {
2006   switch(element)
2007   {
2008     case EL_LEERRAUM:           return -1;
2009     case EL_ERDREICH:           return GFX_ERDREICH;
2010     case EL_MAUERWERK:          return GFX_MAUERWERK;
2011     case EL_FELSBODEN:          return GFX_FELSBODEN;
2012     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
2013     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
2014     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
2015     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
2016     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
2017     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
2018     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
2019     case EL_SPIELER1:           return GFX_SPIELER1;
2020     case EL_SPIELER2:           return GFX_SPIELER2;
2021     case EL_SPIELER3:           return GFX_SPIELER3;
2022     case EL_SPIELER4:           return GFX_SPIELER4;
2023     case EL_KAEFER:             return GFX_KAEFER;
2024     case EL_KAEFER_R:           return GFX_KAEFER_R;
2025     case EL_KAEFER_O:           return GFX_KAEFER_O;
2026     case EL_KAEFER_L:           return GFX_KAEFER_L;
2027     case EL_KAEFER_U:           return GFX_KAEFER_U;
2028     case EL_FLIEGER:            return GFX_FLIEGER;
2029     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
2030     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
2031     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
2032     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
2033     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
2034     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
2035     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
2036     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
2037     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
2038     case EL_FIREFLY:            return GFX_FIREFLY;
2039     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
2040     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
2041     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
2042     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
2043     case EL_MAMPFER:            return GFX_MAMPFER;
2044     case EL_ROBOT:              return GFX_ROBOT;
2045     case EL_BETON:              return GFX_BETON;
2046     case EL_DIAMANT:            return GFX_DIAMANT;
2047     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2048     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2049     case EL_TROPFEN:            return GFX_TROPFEN;
2050     case EL_BOMBE:              return GFX_BOMBE;
2051     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
2052     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
2053     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
2054     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
2055     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2056     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2057     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2058     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2059     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2060     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2061     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2062     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2063     case EL_LIFE:               return GFX_LIFE;
2064     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2065     case EL_DYNAMIT:            return GFX_DYNAMIT;
2066     case EL_BADEWANNE:          return GFX_BADEWANNE;
2067     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2068     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2069     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2070     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2071     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2072     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2073     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2074     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2075     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2076     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2077     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2078     case EL_PFORTE1:            return GFX_PFORTE1;
2079     case EL_PFORTE2:            return GFX_PFORTE2;
2080     case EL_PFORTE3:            return GFX_PFORTE3;
2081     case EL_PFORTE4:            return GFX_PFORTE4;
2082     case EL_PFORTE1X:           return GFX_PFORTE1X;
2083     case EL_PFORTE2X:           return GFX_PFORTE2X;
2084     case EL_PFORTE3X:           return GFX_PFORTE3X;
2085     case EL_PFORTE4X:           return GFX_PFORTE4X;
2086     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
2087     case EL_PACMAN:             return GFX_PACMAN;
2088     case EL_PACMAN_R:           return GFX_PACMAN_R;
2089     case EL_PACMAN_O:           return GFX_PACMAN_O;
2090     case EL_PACMAN_L:           return GFX_PACMAN_L;
2091     case EL_PACMAN_U:           return GFX_PACMAN_U;
2092     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2093     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2094     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2095     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2096     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2097     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2098     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2099     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2100     case EL_MAUER_X:            return GFX_MAUER_X;
2101     case EL_MAUER_Y:            return GFX_MAUER_Y;
2102     case EL_MAUER_XY:           return GFX_MAUER_XY;
2103     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2104     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2105     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2106     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2107     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2108     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2109     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2110     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2111     case EL_MAMPFER2:           return GFX_MAMPFER2;
2112     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
2113     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
2114     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
2115     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
2116     case EL_DYNABOMB:           return GFX_DYNABOMB;
2117     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2118     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2119     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2120     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2121     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2122     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2123     case EL_MAULWURF:           return GFX_MAULWURF;
2124     case EL_PINGUIN:            return GFX_PINGUIN;
2125     case EL_SCHWEIN:            return GFX_SCHWEIN;
2126     case EL_DRACHE:             return GFX_DRACHE;
2127     case EL_SONDE:              return GFX_SONDE;
2128     case EL_PFEIL_L:            return GFX_PFEIL_L;
2129     case EL_PFEIL_R:            return GFX_PFEIL_R;
2130     case EL_PFEIL_O:            return GFX_PFEIL_O;
2131     case EL_PFEIL_U:            return GFX_PFEIL_U;
2132     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2133     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2134     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2135     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2136
2137     default:
2138     {
2139       if (IS_CHAR(element))
2140         return GFX_CHAR_START + (element - EL_CHAR_START);
2141       else if (element >= EL_SP_START && element <= EL_SP_END)
2142       {
2143         int nr_element = element - EL_SP_START;
2144         int gfx_per_line = 8;
2145         int nr_graphic =
2146           (nr_element / gfx_per_line) * MORE_PER_LINE +
2147           (nr_element % gfx_per_line);
2148
2149         return GFX_START_ROCKSMORE + nr_graphic;
2150       }
2151       else
2152         return -1;
2153     }
2154   }
2155 }