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