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