rnd-19980915
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  ©1995 Artsoft Development                               *
5 *        Holger Schemel                                    *
6 *        33659 Bielefeld-Senne                             *
7 *        Telefon: (0521) 493245                            *
8 *        eMail: aeglos@valinor.owl.de                      *
9 *               aeglos@uni-paderborn.de                    *
10 *               q99492@pbhrzx.uni-paderborn.de             *
11 *----------------------------------------------------------*
12 *  tools.c                                                 *
13 ***********************************************************/
14
15 #ifdef __FreeBSD__
16 #include <machine/joystick.h>
17 #endif
18
19 #include "tools.h"
20 #include "game.h"
21 #include "events.h"
22 #include "sound.h"
23 #include "misc.h"
24 #include "buttons.h"
25 #include "joystick.h"
26 #include "cartoons.h"
27
28 #include <math.h>
29
30 #ifdef MSDOS
31 extern BOOL wait_for_vsync;
32 #endif
33
34 void SetDrawtoField(int mode)
35 {
36   if (mode == DRAW_BUFFERED && soft_scrolling_on)
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 ? drawto_field : backbuffer);
68
69   if (direct_draw_on && 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 || ScreenMovPos)
76     redraw_mask &= ~REDRAW_TILES;
77
78   if (!redraw_mask)
79     return;
80
81   /* synchronize X11 graphics at this point; if we would synchronize the
82      display immediately after the buffer switching (after the XFlush),
83      this could mean that we have to wait for the graphics to complete,
84      although we could go on doing calculations for the next frame */
85
86   XSync(display,FALSE);
87
88 #ifdef MSDOS
89   wait_for_vsync = TRUE;
90 #endif
91
92   if (redraw_mask & REDRAW_ALL)
93   {
94     XCopyArea(display,backbuffer,window,gc,
95               0,0, WIN_XSIZE,WIN_YSIZE,
96               0,0);
97     redraw_mask = 0;
98   }
99
100   if (redraw_mask & REDRAW_FIELD)
101   {
102     if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
103       XCopyArea(display,backbuffer,window,gc,
104                 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
105                 REAL_SX,REAL_SY);
106     else
107     {
108       int fx = FX, fy = FY;
109
110       if (soft_scrolling_on)
111       {
112         fx += (PlayerMovDir & (MV_LEFT|MV_RIGHT) ? ScreenMovPos : 0);
113         fy += (PlayerMovDir & (MV_UP|MV_DOWN)    ? ScreenMovPos : 0);
114       }
115
116       XCopyArea(display,buffer,window,gc,
117                 fx,fy, SXSIZE,SYSIZE,
118                 SX,SY);
119     }
120     redraw_mask &= ~REDRAW_MAIN;
121   }
122
123   if (redraw_mask & REDRAW_DOORS)
124   {
125     if (redraw_mask & REDRAW_DOOR_1)
126       XCopyArea(display,backbuffer,window,gc,
127                 DX,DY, DXSIZE,DYSIZE,
128                 DX,DY);
129     if (redraw_mask & REDRAW_DOOR_2)
130     {
131       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
132         XCopyArea(display,backbuffer,window,gc,
133                   VX,VY, VXSIZE,VYSIZE,
134                   VX,VY);
135       else
136       {
137         if (redraw_mask & REDRAW_VIDEO_1)
138           XCopyArea(display,backbuffer,window,gc,
139                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
140                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
141                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
142         if (redraw_mask & REDRAW_VIDEO_2)
143           XCopyArea(display,backbuffer,window,gc,
144                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
145                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
146                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
147         if (redraw_mask & REDRAW_VIDEO_3)
148           XCopyArea(display,backbuffer,window,gc,
149                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
150                     VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
151                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
152       }
153     }
154     redraw_mask &= ~REDRAW_DOORS;
155   }
156
157   if (redraw_mask & REDRAW_MICROLEV)
158   {
159     XCopyArea(display,backbuffer,window,gc,
160               MICROLEV_XPOS,MICROLEV_YPOS, MICROLEV_XSIZE,MICROLEV_YSIZE,
161               MICROLEV_XPOS,MICROLEV_YPOS);
162     XCopyArea(display,backbuffer,window,gc,
163               SX,MICROLABEL_YPOS, SXSIZE,FONT4_YSIZE,
164               SX,MICROLABEL_YPOS);
165     redraw_mask &= ~REDRAW_MICROLEV;
166   }
167
168   if (redraw_mask & REDRAW_TILES)
169   {
170     for(x=0; x<SCR_FIELDX; x++)
171       for(y=0; y<SCR_FIELDY; y++)
172         if (redraw[redraw_x1 + x][redraw_y1 + y])
173           XCopyArea(display,buffer,window,gc,
174                     FX+x*TILEX,FX+y*TILEY, TILEX,TILEY,
175                     SX+x*TILEX,SY+y*TILEY);
176   }
177
178   XFlush(display);
179
180   for(x=0; x<MAX_BUF_XSIZE; x++)
181     for(y=0; y<MAX_BUF_YSIZE; y++)
182       redraw[x][y] = 0;
183   redraw_tiles = 0;
184   redraw_mask = 0;
185 }
186
187 void FadeToFront()
188 {
189 /*
190   long fading_delay = 300000;
191
192   if (fading_on && (redraw_mask & REDRAW_FIELD))
193   {
194 */
195
196 /*
197     int x,y;
198
199     XFillRectangle(display,window,gc,
200                    REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
201     XFlush(display);
202
203     for(i=0;i<2*FULL_SYSIZE;i++)
204     {
205       for(y=0;y<FULL_SYSIZE;y++)
206       {
207         XCopyArea(display,backbuffer,window,gc,
208                   REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
209       }
210       XFlush(display);
211       Delay(10000);
212     }
213 */
214
215 /*
216     for(i=1;i<FULL_SYSIZE;i+=2)
217       XCopyArea(display,backbuffer,window,gc,
218                 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
219     XFlush(display);
220     Delay(fading_delay);
221 */
222
223 /*
224     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
225     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
226               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
227     XFlush(display);
228     Delay(fading_delay);
229
230     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
231     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
232               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
233     XFlush(display);
234     Delay(fading_delay);
235
236     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
237     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
238               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
239     XFlush(display);
240     Delay(fading_delay);
241
242     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,0);
243     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
244               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
245     XFlush(display);
246     Delay(fading_delay);
247
248     redraw_mask &= ~REDRAW_MAIN;
249   }
250 */
251
252   BackToFront();
253 }
254
255 void ClearWindow()
256 {
257   XFillRectangle(display,backbuffer,gc,
258                  REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE);
259
260   if (soft_scrolling_on && game_status==PLAYING)
261   {
262     XFillRectangle(display,fieldbuffer,gc,
263                    0,0, FXSIZE,FYSIZE);
264     SetDrawtoField(DRAW_BUFFERED);
265   }
266   else
267     SetDrawtoField(DRAW_BACKBUFFER);
268
269   if (direct_draw_on && game_status==PLAYING)
270   {
271     XFillRectangle(display,window,gc,
272                    REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE);
273     SetDrawtoField(DRAW_DIRECT);
274   }
275
276   redraw_mask |= REDRAW_FIELD;
277 }
278
279 void DrawText(int x, int y, char *text, int font, int col)
280 {
281   DrawTextExt(drawto, gc, x, y, text, font, col);
282   if (x < DX)
283     redraw_mask |= REDRAW_FIELD;
284   else if (y < VY)
285     redraw_mask |= REDRAW_DOOR_1;
286 }
287
288 void DrawTextExt(Drawable d, GC gc, int x, int y,
289                  char *text, int font, int font_color)
290 {
291   int font_width, font_height, font_start;
292   int font_pixmap;
293
294   if (font!=FS_SMALL && font!=FS_BIG)
295     font = FS_SMALL;
296   if (font_color<FC_RED || font_color>FC_SPECIAL2)
297     font_color = FC_RED;
298
299   font_width =
300     (font==FS_BIG ? FONT1_XSIZE :
301      font_color<FC_SPECIAL1 ? FONT2_XSIZE :
302      font_color<FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
303   font_height =
304     (font==FS_BIG ? FONT1_XSIZE :
305      font_color<FC_SPECIAL2 ? FONT2_XSIZE: FONT4_XSIZE);
306   font_pixmap = (font==FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
307   font_start =
308     font_color*(font==FS_BIG ? FONT1_YSIZE : FONT2_YSIZE)*FONT_LINES_PER_FONT;
309
310   while(*text)
311   {
312     char c = *text++;
313
314     if (c>='a' && c<='z')
315       c = 'A' + (c - 'a');
316     else if (c=='ä' || c=='Ä')
317       c = 91;
318     else if (c=='ö' || c=='Ö')
319       c = 92;
320     else if (c=='ü' || c=='Ü')
321       c = 93;
322
323     if (c>=32 && c<=95)
324       XCopyArea(display,pix[font_pixmap],d,gc,
325                 ((c-32) % FONT_CHARS_PER_LINE)*font_width,
326                 ((c-32) / FONT_CHARS_PER_LINE)*font_height + font_start,
327                 font_width,font_height, x,y);
328
329     x += font_width;
330   }
331 }
332
333 void DrawPlayerField()
334 {
335   int x = JX, y = JY;
336   int sx = SCROLLX(x), sy = SCROLLY(y);
337
338   int sxx = 0, syy = 0;
339
340   int element = Feld[x][y];
341   int graphic, phase;
342
343   if (PlayerGone)
344     return;
345
346 #if DEBUG
347   if (!IN_LEV_FIELD(x,y) || !IN_SCR_FIELD(sx,sy))
348   {
349     printf("DrawPlayerField(): x = %d, y = %d\n",x,y);
350     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
351     printf("DrawPlayerField(): This should never happen!\n");
352     return;
353   }
354 #endif
355
356   if (element == EL_EXPLODING)
357     return;
358
359   if (direct_draw_on)
360     SetDrawtoField(DRAW_BUFFERED);
361
362   /* draw things in the field the player is leaving, if needed */
363
364   if (lastJX != JX || lastJY != JY)
365   {
366     if (Store[lastJX][lastJY])
367     {
368       DrawLevelElement(lastJX,lastJY, Store[lastJX][lastJY]);
369       DrawLevelElementThruMask(lastJX,lastJY, Feld[lastJX][lastJY]);
370     }
371     else if (Feld[lastJX][lastJY] == EL_DYNAMIT)
372       DrawDynamite(lastJX,lastJY);
373     else
374       DrawLevelField(lastJX,lastJY);
375
376     if (PlayerPushing)
377     {
378       int nextJX = JX + (JX - lastJX);
379       int nextJY = JY + (JY - lastJY);
380
381       if (PlayerGfxPos)
382       {
383         if (Feld[nextJX][nextJY] == EL_SOKOBAN_FELD_VOLL)
384           DrawLevelElement(nextJX,nextJY, EL_SOKOBAN_FELD_LEER);
385         else
386           DrawLevelElement(nextJX,nextJY, EL_LEERRAUM);
387       }
388       else
389         DrawLevelField(nextJX,nextJY);
390     }
391   }
392
393   /* draw things behind the player, if needed */
394
395   if (Store[x][y])
396     DrawLevelElement(x,y, Store[x][y]);
397   else if (element != EL_DYNAMIT && element != EL_DYNABOMB)
398     DrawLevelField(x,y);
399
400   /* draw player himself */
401
402   if (PlayerMovDir==MV_LEFT)
403     graphic = (PlayerPushing ? GFX_SPIELER_PUSH_LEFT : GFX_SPIELER_LEFT);
404   else if (PlayerMovDir==MV_RIGHT)
405     graphic = (PlayerPushing ? GFX_SPIELER_PUSH_RIGHT : GFX_SPIELER_RIGHT);
406   else if (PlayerMovDir==MV_UP)
407     graphic = GFX_SPIELER_UP;
408   else  /* MV_DOWN || MV_NO_MOVING */
409     graphic = GFX_SPIELER_DOWN;
410
411   graphic += PlayerFrame;
412
413   if (PlayerGfxPos)
414   {
415     if (PlayerMovDir == MV_LEFT || PlayerMovDir == MV_RIGHT)
416       sxx = PlayerGfxPos;
417     else
418       syy = PlayerGfxPos;
419   }
420
421   if (!soft_scrolling_on && ScreenMovPos)
422     sxx = syy = 0;
423
424   DrawGraphicShiftedThruMask(sx,sy, sxx,syy, graphic, NO_CUTTING);
425
426   if (PlayerPushing && PlayerGfxPos)
427   {
428     int nextJX = JX + (JX - lastJX);
429     int nextJY = JY + (JY - lastJY);
430     int px = SCROLLX(nextJX), py = SCROLLY(nextJY);
431
432     if (Feld[JX][JY] == EL_SOKOBAN_FELD_LEER ||
433         Feld[nextJX][nextJY] == EL_SOKOBAN_FELD_VOLL)
434       DrawGraphicShiftedThruMask(px,py,sxx,syy, GFX_SOKOBAN_OBJEKT,NO_CUTTING);
435     else
436     {
437       int element = Feld[nextJX][nextJY];
438       int graphic = el2gfx(element);
439
440       if (element == EL_FELSBROCKEN && sxx)
441       {
442         int phase = (PlayerGfxPos / (TILEX/4));
443
444         if (PlayerMovDir == MV_LEFT)
445           graphic += phase;
446         else
447           graphic += (phase+4)%4;
448       }
449
450       DrawGraphicShifted(px,py, sxx,syy, graphic, NO_CUTTING, NO_MASKING);
451     }
452   }
453
454   /* draw things in front of player (EL_DYNAMIT || EL_DYNABOMB) */
455
456   if (element == EL_DYNAMIT || element == EL_DYNABOMB)
457   {
458     graphic = el2gfx(element);
459
460     if (element == EL_DYNAMIT)
461     {
462       if ((phase = (96-MovDelay[x][y])/12) > 6)
463         phase = 6;
464     }
465     else
466     {
467       if ((phase = ((96-MovDelay[x][y])/6) % 8) > 3)
468         phase = 7-phase;
469     }
470
471     DrawGraphicThruMask(sx,sy, graphic + phase);
472   }
473
474   if (direct_draw_on)
475   {
476     int dest_x = SX+SCROLLX(x)*TILEX;
477     int dest_y = SY+SCROLLY(y)*TILEY;
478     int x_size = TILEX;
479     int y_size = TILEY;
480
481     if (!ScreenMovPos)
482     {
483       dest_x = SX + SCROLLX(MIN(JX,lastJX))*TILEX;
484       dest_y = SY + SCROLLY(MIN(JY,lastJY))*TILEY;
485       x_size = TILEX * (1 + ABS(JX - lastJX));
486       y_size = TILEY * (1 + ABS(JY - lastJY));
487     }
488
489     XCopyArea(display,drawto_field,window,gc,
490               dest_x,dest_y, x_size,y_size, dest_x,dest_y);
491     SetDrawtoField(DRAW_DIRECT);
492   }
493
494   MarkTileDirty(sx,sy);
495 }
496
497 static int getGraphicAnimationPhase(int frames, int delay, int mode)
498 {
499   int phase;
500
501   if (mode == ANIM_OSCILLATE)
502   {
503     int max_anim_frames = frames*2 - 2;
504     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
505     phase = (phase < frames ? phase : max_anim_frames - phase);
506   }
507   else
508     phase = (FrameCounter % (delay * frames)) / delay;
509
510   if (mode == ANIM_REVERSE)
511     phase = -phase;
512
513   return(phase);
514 }
515
516 void DrawGraphicAnimation(int x, int y, int graphic,
517                           int frames, int delay, int mode)
518 {
519   int phase = getGraphicAnimationPhase(frames, delay, mode);
520
521   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
522     DrawGraphic(SCROLLX(x),SCROLLY(y), graphic + phase);
523 }
524
525 void DrawGraphic(int x, int y, int graphic)
526 {
527
528 #if DEBUG
529   if (!IN_SCR_FIELD(x,y))
530   {
531     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
532     printf("DrawGraphic(): This should never happen!\n");
533     return;
534   }
535 #endif
536
537   DrawGraphicExt(drawto_field, gc, x, y, graphic);
538   MarkTileDirty(x,y);
539 }
540
541 void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
542 {
543   DrawGraphicExtHiRes(d, gc, FX+x*TILEX, FY+y*TILEY, graphic);
544 }
545
546 void DrawGraphicExtHiRes(Drawable d, GC gc, int x, int y, int graphic)
547 {
548   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
549   {
550     graphic -= GFX_START_ROCKSSCREEN;
551     XCopyArea(display,pix[PIX_BACK],d,gc,
552               SX+(graphic % GFX_PER_LINE)*TILEX,
553               SY+(graphic / GFX_PER_LINE)*TILEY,
554               TILEX,TILEY, x,y);
555   }
556   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
557   {
558     graphic -= GFX_START_ROCKSHEROES;
559     XCopyArea(display,pix[PIX_HEROES],d,gc,
560               (graphic % HEROES_PER_LINE)*TILEX,
561               (graphic / HEROES_PER_LINE)*TILEY,
562               TILEX,TILEY, x,y);
563   }
564   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
565   {
566     graphic -= GFX_START_ROCKSFONT;
567     XCopyArea(display,pix[PIX_BIGFONT],d,gc,
568               (graphic % FONT_CHARS_PER_LINE)*TILEX,
569               (graphic / FONT_CHARS_PER_LINE)*TILEY +
570               FC_SPECIAL1*TILEY*FONT_LINES_PER_FONT,
571               TILEX,TILEY, x,y);
572   }
573   else
574     XFillRectangle(display,d,gc, x,y, TILEX,TILEY);
575 }
576
577 void DrawGraphicThruMask(int x, int y, int graphic)
578 {
579   int src_x,src_y, dest_x,dest_y;
580
581 #if DEBUG
582   if (!IN_SCR_FIELD(x,y))
583   {
584     printf("DrawGraphicThruMask(): x = %d, y = %d\n",x,y);
585     printf("DrawGraphicThruMask(): This should never happen!\n");
586     return;
587   }
588 #endif
589
590   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
591   {
592     graphic -= GFX_START_ROCKSSCREEN;
593     src_x  = SX+(graphic % GFX_PER_LINE)*TILEX;
594     src_y  = SY+(graphic / GFX_PER_LINE)*TILEY;
595     dest_x = FX+x*TILEX;
596     dest_y = FY+y*TILEY;
597
598     XSetClipOrigin(display,clip_gc[PIX_BACK],dest_x-src_x,dest_y-src_y);
599     XCopyArea(display,pix[PIX_BACK],drawto_field,clip_gc[PIX_BACK],
600               src_x,src_y, TILEX,TILEY, dest_x,dest_y);
601   }
602   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
603   {
604     graphic -= GFX_START_ROCKSHEROES;
605     src_x  = (graphic % HEROES_PER_LINE)*TILEX;
606     src_y  = (graphic / HEROES_PER_LINE)*TILEY;
607     dest_x = FX+x*TILEX;
608     dest_y = FY+y*TILEY;
609
610     XSetClipOrigin(display,clip_gc[PIX_HEROES],dest_x-src_x,dest_y-src_y);
611     XCopyArea(display,pix[PIX_HEROES],drawto_field,clip_gc[PIX_HEROES],
612               src_x,src_y, TILEX,TILEY, dest_x,dest_y);
613   }
614   else
615   {
616     DrawGraphic(x,y,graphic);
617     return;
618   }
619
620   MarkTileDirty(x,y);
621 }
622
623 void DrawScreenElementThruMask(int x, int y, int element)
624 {
625   DrawGraphicThruMask(x,y,el2gfx(element));
626 }
627
628 void DrawLevelElementThruMask(int x, int y, int element)
629 {
630   if (IN_LEV_FIELD(x,y) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
631     DrawScreenElementThruMask(SCROLLX(x),SCROLLY(y),element);
632 }
633
634 void DrawMiniGraphic(int x, int y, int graphic)
635 {
636   DrawMiniGraphicExt(drawto, gc, x, y, graphic);
637   MarkTileDirty(x/2, y/2);
638 }
639
640 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
641 {
642   DrawMiniGraphicExtHiRes(d,gc, SX+x*MINI_TILEX,SY+y*MINI_TILEY, graphic);
643 }
644
645 void DrawMiniGraphicExtHiRes(Drawable d, GC gc, int x, int y, int graphic)
646 {
647   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
648   {
649     graphic -= GFX_START_ROCKSSCREEN;
650     XCopyArea(display,pix[PIX_BACK],d,gc,
651               MINI_GFX_STARTX+(graphic % MINI_GFX_PER_LINE)*MINI_TILEX,
652               MINI_GFX_STARTY+(graphic / MINI_GFX_PER_LINE)*MINI_TILEY,
653               MINI_TILEX,MINI_TILEY, x,y);
654   }
655   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
656   {
657     graphic -= GFX_START_ROCKSFONT;
658     XCopyArea(display,pix[PIX_SMALLFONT],d,gc,
659               (graphic % FONT_CHARS_PER_LINE)*FONT4_XSIZE,
660               (graphic / FONT_CHARS_PER_LINE)*FONT4_YSIZE +
661               FC_SPECIAL2*FONT2_YSIZE*FONT_LINES_PER_FONT,
662               MINI_TILEX,MINI_TILEY, x,y);
663   }
664   else
665     XFillRectangle(display,d,gc, x,y, MINI_TILEX,MINI_TILEY);
666 }
667
668 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
669                         int cut_mode, int mask_mode)
670 {
671   int width = TILEX, height = TILEY;
672   int cx = 0, cy = 0;
673   int src_x,src_y, dest_x,dest_y;
674
675   if (graphic < 0)
676   {
677     DrawGraphic(x,y,graphic);
678     return;
679   }
680
681   if (dx || dy)                 /* Verschiebung der Grafik? */
682   {
683     if (x < BX1)                /* Element kommt von links ins Bild */
684     {
685       x = BX1;
686       width = dx;
687       cx = TILEX - dx;
688       dx = 0;
689     }
690     else if (x > BX2)           /* Element kommt von rechts ins Bild */
691     {
692       x = BX2;
693       width = -dx;
694       dx = TILEX + dx;
695     }
696     else if (x==BX1 && dx<0)    /* Element verläßt links das Bild */
697     {
698       width += dx;
699       cx = -dx;
700       dx = 0;
701     }
702     else if (x==BX2 && dx>0)    /* Element verläßt rechts das Bild */
703       width -= dx;
704     else if (dx)                /* allg. Bewegung in x-Richtung */
705       MarkTileDirty(x + SIGN(dx), y);
706
707     if (y < BY1)                /* Element kommt von oben ins Bild */
708     {
709       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
710         return;
711
712       y = BY1;
713       height = dy;
714       cy = TILEY - dy;
715       dy = 0;
716     }
717     else if (y > BY2)           /* Element kommt von unten ins Bild */
718     {
719       y = BY2;
720       height = -dy;
721       dy = TILEY + dy;
722     }
723     else if (y==BY1 && dy<0)    /* Element verläßt oben das Bild */
724     {
725       height += dy;
726       cy = -dy;
727       dy = 0;
728     }
729     else if (dy > 0 && cut_mode==CUT_ABOVE)
730     {
731       if (y == BY2)             /* Element unterhalb des Bildes */
732         return;
733
734       height = dy;
735       cy = TILEY-dy;
736       dy = TILEY;
737       MarkTileDirty(x, y + 1);
738     }                           /* Element verläßt unten das Bild */
739     else if (dy > 0 && (y == BY2 || cut_mode==CUT_BELOW))
740       height -= dy;
741     else if (dy)                /* allg. Bewegung in y-Richtung */
742       MarkTileDirty(x, y + SIGN(dy));
743   }
744
745   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
746   {
747     graphic -= GFX_START_ROCKSSCREEN;
748     src_x  = SX+(graphic % GFX_PER_LINE)*TILEX+cx;
749     src_y  = SY+(graphic / GFX_PER_LINE)*TILEY+cy;
750     dest_x = FX+x*TILEX+dx;
751     dest_y = FY+y*TILEY+dy;
752
753     if (mask_mode == USE_MASKING)
754     {
755       XSetClipOrigin(display,clip_gc[PIX_BACK],dest_x-src_x,dest_y-src_y);
756       XCopyArea(display,pix[PIX_BACK],drawto_field,clip_gc[PIX_BACK],
757                 src_x,src_y, width,height, dest_x,dest_y);
758     }
759     else
760       XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
761                 src_x,src_y, width,height, dest_x,dest_y);
762   }
763   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
764   {
765     graphic -= GFX_START_ROCKSHEROES;
766     src_x  = (graphic % HEROES_PER_LINE)*TILEX+cx;
767     src_y  = (graphic / HEROES_PER_LINE)*TILEY+cy;
768     dest_x = FX+x*TILEX+dx;
769     dest_y = FY+y*TILEY+dy;
770
771     if (mask_mode == USE_MASKING)
772     {
773       XSetClipOrigin(display,clip_gc[PIX_HEROES],dest_x-src_x,dest_y-src_y);
774       XCopyArea(display,pix[PIX_HEROES],drawto_field,clip_gc[PIX_HEROES],
775                 src_x,src_y, width,height, dest_x,dest_y);
776     }
777     else
778       XCopyArea(display,pix[PIX_HEROES],drawto_field,gc,
779                 src_x,src_y, width,height, dest_x,dest_y);
780   }
781
782 #if DEBUG
783   if (!IN_SCR_FIELD(x,y))
784   {
785     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
786     printf("DrawGraphicShifted(): This should never happen!\n");
787     return;
788   }
789 #endif
790
791   MarkTileDirty(x,y);
792 }
793
794 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
795                                 int cut_mode)
796 {
797   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
798 }
799
800 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
801                               int cut_mode)
802 {
803   int ux = UNSCROLLX(x), uy = UNSCROLLY(y);
804   int graphic = el2gfx(element);
805   int phase4 = ABS(MovPos[ux][uy])/(TILEX/4);
806   int phase  = phase4 / 2;
807   int dir = MovDir[ux][uy];
808
809   if (element==EL_PACMAN || element==EL_KAEFER || element==EL_FLIEGER)
810   {
811     graphic += 4*!phase;
812
813     if (dir == MV_UP)
814       graphic += 1;
815     else if (dir == MV_LEFT)
816       graphic += 2;
817     else if (dir == MV_DOWN)
818       graphic += 3;
819   }
820   else if (element==EL_MAULWURF || element==EL_PINGUIN ||
821            element==EL_SCHWEIN || element==EL_DRACHE)
822   {
823     if (dir==MV_LEFT)
824       graphic = (element==EL_MAULWURF ? GFX_MAULWURF_LEFT :
825                  element==EL_PINGUIN ? GFX_PINGUIN_LEFT :
826                  element==EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
827     else if (dir==MV_RIGHT)
828       graphic = (element==EL_MAULWURF ? GFX_MAULWURF_RIGHT :
829                  element==EL_PINGUIN ? GFX_PINGUIN_RIGHT :
830                  element==EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
831     else if (dir==MV_UP)
832       graphic = (element==EL_MAULWURF ? GFX_MAULWURF_UP :
833                  element==EL_PINGUIN ? GFX_PINGUIN_UP :
834                  element==EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
835     else
836       graphic = (element==EL_MAULWURF ? GFX_MAULWURF_DOWN :
837                  element==EL_PINGUIN ? GFX_PINGUIN_DOWN :
838                  element==EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
839
840     graphic += phase4;
841   }
842   else if (element==EL_SONDE)
843   {
844     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
845   }
846   else if (element==EL_BUTTERFLY || element==EL_FIREFLY)
847   {
848     graphic += !phase;
849   }
850   else if ((element==EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode)
851   {
852     graphic += phase * (element==EL_FELSBROCKEN ? 2 : 1);
853   }
854   else if ((element==EL_SIEB_LEER || element==EL_SIEB2_LEER ||
855             element==EL_SIEB_VOLL || element==EL_SIEB2_VOLL) && SiebAktiv)
856   {
857     graphic += 3-(SiebAktiv%8)/2;
858   }
859   else if (IS_AMOEBOID(element))
860   {
861     graphic = (element==EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
862     graphic += (x+2*y) % 4;
863   }
864   else if (element==EL_MAUER_LEBT)
865   {
866     BOOL links_massiv = FALSE, rechts_massiv = FALSE;
867
868     if (!IN_LEV_FIELD(ux-1,uy) || IS_MAUER(Feld[ux-1][uy]))
869       links_massiv = TRUE;
870     if (!IN_LEV_FIELD(ux+1,uy) || IS_MAUER(Feld[ux+1][uy]))
871       rechts_massiv = TRUE;
872
873     if (links_massiv && rechts_massiv)
874       graphic = GFX_MAUERWERK;
875     else if (links_massiv)
876       graphic = GFX_MAUER_R;
877     else if (rechts_massiv)
878       graphic = GFX_MAUER_L;
879   }
880
881   if (dx || dy)
882     DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, NO_MASKING);
883   else
884     DrawGraphic(x,y, graphic);
885 }
886
887 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
888                              int cut_mode)
889 {
890   if (IN_LEV_FIELD(x,y) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
891     DrawScreenElementShifted(SCROLLX(x),SCROLLY(y), dx,dy, element, cut_mode);
892 }
893
894 void ErdreichAnbroeckeln(int x, int y)
895 {
896   int i, width, height, cx,cy;
897   int ux = UNSCROLLX(x), uy = UNSCROLLY(y);
898   int element, graphic;
899   int snip = 4;
900   static int xy[4][2] =
901   {
902     { 0,-1 },
903     { -1,0 },
904     { +1,0 },
905     { 0,+1 }
906   };
907
908   if (!IN_LEV_FIELD(ux,uy))
909     return;
910
911   element = Feld[ux][uy];
912
913   if (element==EL_ERDREICH)
914   {
915     if (!IN_SCR_FIELD(x,y))
916       return;
917
918     graphic = GFX_ERDENRAND;
919
920     for(i=0;i<4;i++)
921     {
922       int uxx,uyy;
923
924       uxx = ux+xy[i][0];
925       uyy = uy+xy[i][1];
926       if (!IN_LEV_FIELD(uxx,uyy))
927         element = EL_BETON;
928       else
929         element = Feld[uxx][uyy];
930
931       if (element==EL_ERDREICH)
932         continue;
933
934       if (i==1 || i==2)
935       {
936         width = snip;
937         height = TILEY;
938         cx = (i==2 ? TILEX-snip : 0);
939         cy = 0;
940       }
941       else
942       {
943         width = TILEX;
944         height = snip;
945         cx = 0;
946         cy = (i==3 ? TILEY-snip : 0);
947       }
948
949       XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
950                 SX+(graphic % GFX_PER_LINE)*TILEX+cx,
951                 SY+(graphic / GFX_PER_LINE)*TILEY+cy,
952                 width,height, FX+x*TILEX+cx,FY+y*TILEY+cy);
953     }
954
955     MarkTileDirty(x,y);
956   }
957   else
958   {
959     graphic = GFX_ERDENRAND;
960
961     for(i=0;i<4;i++)
962     {
963       int xx,yy,uxx,uyy;
964
965       xx = x+xy[i][0];
966       yy = y+xy[i][1];
967       uxx = ux+xy[i][0];
968       uyy = uy+xy[i][1];
969
970       if (!IN_LEV_FIELD(uxx,uyy) || Feld[uxx][uyy]!=EL_ERDREICH ||
971           !IN_SCR_FIELD(xx,yy))
972         continue;
973
974       if (i==1 || i==2)
975       {
976         width = snip;
977         height = TILEY;
978         cx = (i==1 ? TILEX-snip : 0);
979         cy = 0;
980       }
981       else
982       {
983         width = TILEX;
984         height = snip;
985         cx = 0;
986         cy = (i==0 ? TILEY-snip : 0);
987       }
988
989       XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
990                 SX+(graphic % GFX_PER_LINE)*TILEX+cx,
991                 SY+(graphic / GFX_PER_LINE)*TILEY+cy,
992                 width,height, FX+xx*TILEX+cx,FY+yy*TILEY+cy);
993
994       MarkTileDirty(xx,yy);
995     }
996   }
997 }
998
999 void DrawScreenElement(int x, int y, int element)
1000 {
1001   DrawScreenElementShifted(x,y, 0,0, element, NO_CUTTING);
1002   ErdreichAnbroeckeln(x,y);
1003 }
1004
1005 void DrawLevelElement(int x, int y, int element)
1006 {
1007   if (IN_LEV_FIELD(x,y) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1008     DrawScreenElement(SCROLLX(x),SCROLLY(y),element);
1009 }
1010
1011 void DrawScreenField(int x, int y)
1012 {
1013   int ux = UNSCROLLX(x), uy = UNSCROLLY(y);
1014   int element;
1015
1016   if (!IN_LEV_FIELD(ux,uy))
1017   {
1018     DrawScreenElement(x,y,EL_BETON);
1019     return;
1020   }
1021
1022   element = Feld[ux][uy];
1023
1024   if (IS_MOVING(ux,uy))
1025   {
1026     int horiz_move = (MovDir[ux][uy]==MV_LEFT || MovDir[ux][uy]==MV_RIGHT);
1027     BOOL cut_mode = NO_CUTTING;
1028
1029     if (Store[ux][uy]==EL_MORAST_LEER ||
1030         Store[ux][uy]==EL_SIEB_LEER ||
1031         Store[ux][uy]==EL_SIEB2_LEER ||
1032         Store[ux][uy]==EL_AMOEBE_NASS)
1033       cut_mode = CUT_ABOVE;
1034     else if (Store[ux][uy]==EL_MORAST_VOLL ||
1035         Store[ux][uy]==EL_SIEB_VOLL ||
1036         Store[ux][uy]==EL_SIEB2_VOLL ||
1037         Store[ux][uy]==EL_SALZSAEURE)
1038       cut_mode = CUT_BELOW;
1039
1040     if (cut_mode==CUT_ABOVE)
1041       DrawScreenElementShifted(x,y, 0,0, Store[ux][uy], NO_CUTTING);
1042     else
1043       DrawScreenElement(x,y,EL_LEERRAUM);
1044
1045     if (horiz_move)
1046       DrawScreenElementShifted(x,y, MovPos[ux][uy],0, element, NO_CUTTING);
1047     else
1048       DrawScreenElementShifted(x,y, 0,MovPos[ux][uy], element, cut_mode);
1049   }
1050   else if (IS_BLOCKED(ux,uy))
1051   {
1052     int oldx,oldy;
1053     int sx, sy;
1054     int horiz_move;
1055     BOOL cut_mode = NO_CUTTING;
1056
1057     Blocked2Moving(ux,uy,&oldx,&oldy);
1058     sx = SCROLLX(oldx);
1059     sy = SCROLLY(oldy);
1060     horiz_move = (MovDir[oldx][oldy]==MV_LEFT || MovDir[oldx][oldy]==MV_RIGHT);
1061
1062     if (Store[oldx][oldy]==EL_MORAST_LEER ||
1063         Store[oldx][oldy]==EL_SIEB_LEER ||
1064         Store[oldx][oldy]==EL_SIEB2_LEER ||
1065         Store[oldx][oldy]==EL_AMOEBE_NASS)
1066       cut_mode = CUT_ABOVE;
1067
1068     DrawScreenElement(x,y,EL_LEERRAUM);
1069     element = Feld[oldx][oldy];
1070
1071     if (horiz_move)
1072       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1073     else
1074       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1075   }
1076   else if (IS_DRAWABLE(element))
1077     DrawScreenElement(x,y,element);
1078   else
1079     DrawScreenElement(x,y,EL_LEERRAUM);
1080 }
1081
1082 void DrawLevelField(int x, int y)
1083 {
1084   if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1085     DrawScreenField(SCROLLX(x),SCROLLY(y));
1086   else if (IS_MOVING(x,y))
1087   {
1088     int newx,newy;
1089
1090     Moving2Blocked(x,y,&newx,&newy);
1091     if (IN_SCR_FIELD(SCROLLX(newx),SCROLLY(newy)))
1092       DrawScreenField(SCROLLX(newx),SCROLLY(newy));
1093   }
1094   else if (IS_BLOCKED(x,y))
1095   {
1096     int oldx,oldy;
1097
1098     Blocked2Moving(x,y,&oldx,&oldy);
1099     if (IN_SCR_FIELD(SCROLLX(oldx),SCROLLY(oldy)))
1100       DrawScreenField(SCROLLX(oldx),SCROLLY(oldy));
1101   }
1102 }
1103
1104 void DrawMiniElement(int x, int y, int element)
1105 {
1106   int graphic;
1107
1108   if (!element)
1109   {
1110     DrawMiniGraphic(x,y,-1);
1111     return;
1112   }
1113
1114   graphic = el2gfx(element);
1115   DrawMiniGraphic(x,y,graphic);
1116 }
1117
1118 void DrawMiniElementOrWall(int x, int y, int scroll_x, int scroll_y)
1119 {
1120   if (x+scroll_x<-1 || x+scroll_x>lev_fieldx ||
1121       y+scroll_y<-1 || y+scroll_y>lev_fieldy)
1122     DrawMiniElement(x,y,EL_LEERRAUM);
1123   else if (x+scroll_x==-1 || x+scroll_x==lev_fieldx ||
1124            y+scroll_y==-1 || y+scroll_y==lev_fieldy)
1125     DrawMiniElement(x,y,EL_BETON);
1126   else
1127     DrawMiniElement(x,y,Feld[x+scroll_x][y+scroll_y]);
1128 }
1129
1130 void DrawMicroElement(int xpos, int ypos, int element)
1131 {
1132   int graphic;
1133
1134   if (element==EL_LEERRAUM)
1135     return;
1136
1137   graphic = el2gfx(element);
1138
1139   XCopyArea(display,pix[PIX_BACK],drawto,gc,
1140             MICRO_GFX_STARTX+(graphic % MICRO_GFX_PER_LINE)*MICRO_TILEX,
1141             MICRO_GFX_STARTY+(graphic / MICRO_GFX_PER_LINE)*MICRO_TILEY,
1142             MICRO_TILEX,MICRO_TILEY, xpos,ypos);
1143 }
1144
1145 void DrawLevel()
1146 {
1147   int x,y;
1148
1149   ClearWindow();
1150
1151   for(x=BX1; x<=BX2; x++)
1152     for(y=BY1; y<=BY2; y++)
1153       DrawScreenField(x,y);
1154
1155   if (soft_scrolling_on)
1156     XCopyArea(display,fieldbuffer,backbuffer,gc,
1157               FX,FY, SXSIZE,SYSIZE,
1158               SX,SY);
1159
1160   redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
1161 }
1162
1163 void DrawMiniLevel(int scroll_x, int scroll_y)
1164 {
1165   int x,y;
1166
1167   ClearWindow();
1168
1169   for(x=0;x<2*SCR_FIELDX;x++)
1170     for(y=0;y<2*SCR_FIELDY;y++)
1171       DrawMiniElementOrWall(x,y,scroll_x,scroll_y);
1172
1173   redraw_mask |= REDRAW_FIELD;
1174 }
1175
1176 void DrawMicroLevel(int xpos, int ypos)
1177 {
1178   int x,y;
1179
1180   XFillRectangle(display,drawto,gc,
1181                  xpos-MICRO_TILEX,ypos-MICRO_TILEY,
1182                  MICRO_TILEX*(STD_LEV_FIELDX+2),
1183                  MICRO_TILEY*(STD_LEV_FIELDY+2));
1184   if (lev_fieldx < STD_LEV_FIELDX)
1185     xpos += (STD_LEV_FIELDX - lev_fieldx)/2 * MICRO_TILEX;
1186   if (lev_fieldy < STD_LEV_FIELDY)
1187     ypos += (STD_LEV_FIELDY - lev_fieldy)/2 * MICRO_TILEY;
1188
1189   for(x=-1;x<=STD_LEV_FIELDX;x++)
1190     for(y=-1;y<=STD_LEV_FIELDY;y++)
1191       if (x>=0 && x<lev_fieldx && y>=0 && y<lev_fieldy)
1192         DrawMicroElement(xpos+MICRO_TILEX*x,ypos+MICRO_TILEY*y,
1193                          Feld[x][y]=Ur[x][y]);
1194       else if (x>=-1 && x<lev_fieldx+1 && y>=-1 && y<lev_fieldy+1)
1195         DrawMicroElement(xpos+MICRO_TILEX*x,ypos+MICRO_TILEY*y,
1196                          EL_BETON);
1197
1198   XFillRectangle(display,drawto,gc, SX,MICROLABEL_YPOS, SXSIZE,FONT4_YSIZE);
1199
1200   if (level.name)
1201   {
1202     int len = strlen(level.name);
1203     int lxpos = SX+(SXSIZE-len*FONT4_XSIZE)/2;
1204     int lypos = MICROLABEL_YPOS;
1205
1206     DrawText(lxpos,lypos,level.name,FS_SMALL,FC_SPECIAL2);
1207   }
1208
1209   redraw_mask |= REDRAW_MICROLEV;
1210 }
1211
1212 int AYS_in_range(int x, int y)
1213 {
1214   if (y>DY+249 && y<DY+278)
1215   {
1216     if (x>DX+1 && x<DX+48)
1217       return(1);
1218     else if (x>DX+51 && x<DX+98) 
1219       return(2);
1220   }
1221   return(0);
1222 }
1223
1224 BOOL AreYouSure(char *text, unsigned int ays_state)
1225 {
1226   int mx,my, ty, result = -1;
1227   unsigned int old_door_state;
1228
1229   old_door_state = GetDoorState();
1230
1231   CloseDoor(DOOR_CLOSE_1);
1232
1233   /* Alten Türinhalt sichern */
1234   XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1235             DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1236             DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1);
1237
1238   /* Fragetext schreiben */
1239   XFillRectangle(display,pix[PIX_DB_DOOR],gc,
1240                  DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1,DXSIZE,DYSIZE);
1241
1242   for(ty=0;ty<13;ty++)
1243   {
1244     int tx,tl,tc;
1245     char txt[256];
1246
1247     if (!(*text))
1248       break;
1249     for(tl=0,tx=0;tx<7;tl++,tx++)
1250     {
1251       tc=*(text+tx);
1252       if (!tc || tc==32)
1253         break;
1254     }
1255     if (!tl)
1256     { 
1257       text++; 
1258       ty--; 
1259       continue; 
1260     }
1261     sprintf(txt,text); 
1262     txt[tl]=0;
1263     DrawTextExt(pix[PIX_DB_DOOR],gc,
1264                 DOOR_GFX_PAGEX1+51-(tl*14)/2,SY+ty*16,txt,FS_SMALL,FC_YELLOW);
1265     text+=(tl+(tc==32));
1266   }
1267
1268   if (ays_state & AYS_ASK)
1269     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1270               DOOR_GFX_PAGEX4,OK_BUTTON_GFX_YPOS,
1271               DXSIZE,OK_BUTTON_YSIZE,
1272               DOOR_GFX_PAGEX1,OK_BUTTON_YPOS);
1273   else if (ays_state & AYS_CONFIRM)
1274     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1275               DOOR_GFX_PAGEX4,CONFIRM_BUTTON_GFX_YPOS,
1276               DXSIZE,CONFIRM_BUTTON_YSIZE,
1277               DOOR_GFX_PAGEX1,CONFIRM_BUTTON_YPOS);
1278
1279   OpenDoor(DOOR_OPEN_1);
1280   ClearEventQueue();
1281
1282   if (!(ays_state & AYS_ASK) && !(ays_state & AYS_CONFIRM))
1283     return(FALSE);
1284
1285   if (game_status != MAINMENU)
1286     InitAnimation();
1287
1288   button_status = MB_RELEASED;
1289
1290   while(result<0)
1291   {
1292     DoAnimation();
1293     Delay(10000);
1294
1295     if (XPending(display))
1296     {
1297       XEvent event;
1298
1299       XNextEvent(display, &event);
1300       switch(event.type)
1301       {
1302         case Expose:
1303           HandleExposeEvent((XExposeEvent *) &event);
1304           break;
1305         case UnmapNotify:
1306           SleepWhileUnmapped();
1307           break;
1308         case ButtonPress:
1309         case ButtonRelease:
1310         case MotionNotify:
1311         {
1312           int choice;
1313
1314           if (event.type == MotionNotify)
1315           {
1316             motion_status = TRUE;
1317             mx = ((XMotionEvent *) &event)->x;
1318             my = ((XMotionEvent *) &event)->y;
1319           }
1320           else
1321           {
1322             motion_status = FALSE;
1323             mx = ((XButtonEvent *) &event)->x;
1324             my = ((XButtonEvent *) &event)->y;
1325             if (event.type==ButtonPress)
1326               button_status = ((XButtonEvent *) &event)->button;
1327             else
1328               button_status = MB_RELEASED;
1329           }
1330
1331           if (ays_state & AYS_ASK)
1332             choice = CheckChooseButtons(mx,my,button_status);
1333           else
1334             choice = CheckConfirmButton(mx,my,button_status);
1335
1336           switch(choice)
1337           {
1338             case BUTTON_OK:
1339               result = TRUE;
1340               break;
1341             case BUTTON_NO:
1342               result = FALSE;
1343               break;
1344             case BUTTON_CONFIRM:
1345               result = TRUE|FALSE;
1346               break;
1347             default:
1348               break;
1349           }
1350           break;
1351         }
1352         case KeyPress:
1353           switch(XLookupKeysym((XKeyEvent *)&event,
1354                                ((XKeyEvent *)&event)->state))
1355           {
1356             case XK_Return:
1357               result = 1;
1358               break;
1359             case XK_Escape:
1360               result = 0;
1361               break;
1362           }
1363           break;
1364         case KeyRelease:
1365           key_joystick_mapping = 0;
1366           break;
1367         case FocusIn:
1368         case FocusOut:
1369           HandleFocusEvent((XFocusChangeEvent *) &event);
1370           break;
1371         case ClientMessage:
1372           HandleClientMessageEvent((XClientMessageEvent *) &event);
1373           break;
1374         default:
1375           break;
1376       }
1377     }
1378     else if (JoystickButton() == JOY_BUTTON_NEW_PRESSED)
1379     {
1380       int joy=Joystick();
1381
1382       if (joy & JOY_BUTTON_1)
1383         result = 1;
1384       else if (joy & JOY_BUTTON_2)
1385         result = 0;
1386     }
1387   }
1388
1389   if (game_status != MAINMENU)
1390     StopAnimation();
1391
1392   if (!(ays_state & AYS_STAY_OPEN))
1393   {
1394     CloseDoor(DOOR_CLOSE_1);
1395
1396     if (!(ays_state & AYS_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1397     {
1398       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1399                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1400                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1401       OpenDoor(DOOR_OPEN_1);
1402     }
1403   }
1404
1405   return(result);
1406 }
1407
1408 unsigned int OpenDoor(unsigned int door_state)
1409 {
1410   unsigned int new_door_state;
1411
1412   if (door_state & DOOR_COPY_BACK)
1413   {
1414     XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1415               DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE+VYSIZE,
1416               DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1417     door_state &= ~DOOR_COPY_BACK;
1418   }
1419
1420   new_door_state = MoveDoor(door_state);
1421
1422   return(new_door_state);
1423 }
1424
1425 unsigned int CloseDoor(unsigned int door_state)
1426 {
1427   unsigned int new_door_state;
1428
1429   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
1430             DX,DY, DXSIZE,DYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1431   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
1432             VX,VY, VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1433
1434   new_door_state = MoveDoor(door_state);
1435
1436   return(new_door_state);
1437 }
1438
1439 unsigned int GetDoorState()
1440 {
1441   return(MoveDoor(DOOR_GET_STATE));
1442 }
1443
1444 unsigned int MoveDoor(unsigned int door_state)
1445 {
1446   static unsigned int door1 = DOOR_OPEN_1;
1447   static unsigned int door2 = DOOR_CLOSE_2;
1448   static long door_delay = 0;
1449   int x, start, stepsize = 2;
1450   long door_delay_value = stepsize * 5000;
1451
1452   if (door_state == DOOR_GET_STATE)
1453     return(door1 | door2);
1454
1455   if (door1==DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1456     door_state &= ~DOOR_OPEN_1;
1457   else if (door1==DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1458     door_state &= ~DOOR_CLOSE_1;
1459   if (door2==DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1460     door_state &= ~DOOR_OPEN_2;
1461   else if (door2==DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1462     door_state &= ~DOOR_CLOSE_2;
1463
1464   if (quick_doors)
1465   {
1466     stepsize = 20;
1467     door_delay_value = 0;
1468     StopSound(SND_OEFFNEN);
1469   }
1470
1471   if (door_state & DOOR_ACTION)
1472   {
1473     if (!(door_state & DOOR_NO_DELAY))
1474       PlaySoundStereo(SND_OEFFNEN,PSND_MAX_RIGHT);
1475
1476     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1477
1478     for(x=start; x<=DXSIZE; x+=stepsize)
1479     {
1480       while(!DelayReached(&door_delay, door_delay_value/10000))
1481         Delay(1000);
1482
1483       if (door_state & DOOR_ACTION_1)
1484       {
1485         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1486         int j = (DXSIZE - i)/3;
1487
1488         XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
1489                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1+i/2,
1490                   DXSIZE,DYSIZE-i/2, DX,DY);
1491
1492         XFillRectangle(display,drawto,gc,DX,DY+DYSIZE-i/2,DXSIZE,i/2);
1493
1494         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1495                        DX-i,(DY+j)-DOOR_GFX_PAGEY1);
1496         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1497                   DXSIZE,DOOR_GFX_PAGEY1, i,77, DX+DXSIZE-i,DY+j);
1498         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1499                   DXSIZE,DOOR_GFX_PAGEY1+140, i,63, DX+DXSIZE-i,DY+140+j);
1500         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1501                        DX-DXSIZE+i,DY-(DOOR_GFX_PAGEY1+j));
1502         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1503                   DXSIZE-i,DOOR_GFX_PAGEY1+j, i,77-j, DX,DY);
1504         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1505                   DXSIZE-i,DOOR_GFX_PAGEY1+140, i,63, DX,DY+140-j);
1506
1507         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1508                   DXSIZE-i,DOOR_GFX_PAGEY1+77, i,63,
1509                   DX,DY+77-j);
1510         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1511                   DXSIZE-i,DOOR_GFX_PAGEY1+203, i,77,
1512                   DX,DY+203-j);
1513         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1514                        DX-i,(DY+j)-DOOR_GFX_PAGEY1);
1515         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1516                   DXSIZE,DOOR_GFX_PAGEY1+77, i,63,
1517                   DX+DXSIZE-i,DY+77+j);
1518         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1519                   DXSIZE,DOOR_GFX_PAGEY1+203, i,77-j,
1520                   DX+DXSIZE-i,DY+203+j);
1521
1522         redraw_mask |= REDRAW_DOOR_1;
1523       }
1524
1525       if (door_state & DOOR_ACTION_2)
1526       {
1527         int i = (door_state & DOOR_OPEN_2 ? VXSIZE-x : x);
1528         int j = (VXSIZE - i)/3;
1529
1530         XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
1531                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2+i/2,
1532                   VXSIZE,VYSIZE-i/2, VX,VY);
1533
1534         XFillRectangle(display,drawto,gc,VX,VY+VYSIZE-i/2,VXSIZE,i/2);
1535
1536         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1537                        VX-i,(VY+j)-DOOR_GFX_PAGEY2);
1538         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1539                   VXSIZE,DOOR_GFX_PAGEY2, i,VYSIZE/2, VX+VXSIZE-i,VY+j);
1540         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1541                        VX-VXSIZE+i,VY-(DOOR_GFX_PAGEY2+j));
1542         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1543                   VXSIZE-i,DOOR_GFX_PAGEY2+j, i,VYSIZE/2-j, VX,VY);
1544
1545         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1546                   VXSIZE-i,DOOR_GFX_PAGEY2+VYSIZE/2, i,VYSIZE/2,
1547                   VX,VY+VYSIZE/2-j);
1548         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1549                        VX-i,(VY+j)-DOOR_GFX_PAGEY2);
1550         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1551                   VXSIZE,DOOR_GFX_PAGEY2+VYSIZE/2, i,VYSIZE/2-j,
1552                   VX+VXSIZE-i,VY+VYSIZE/2+j);
1553
1554         redraw_mask |= REDRAW_DOOR_2;
1555       }
1556
1557       BackToFront();
1558
1559       if (game_status == MAINMENU)
1560         DoAnimation();
1561     }
1562   }
1563
1564   if (door_state & DOOR_ACTION_1)
1565     door1 = door_state & DOOR_ACTION_1;
1566   if (door_state & DOOR_ACTION_2)
1567     door2 = door_state & DOOR_ACTION_2;
1568
1569   return(door1 | door2);
1570 }
1571
1572 int ReadPixel(Drawable d, int x, int y)
1573 {
1574   static XImage *pixelimage;
1575
1576   pixelimage = XGetImage(display, d, x,y, 1,1, AllPlanes, ZPixmap);
1577   return(XGetPixel(pixelimage,0,0));
1578 }
1579
1580 int el2gfx(int element)
1581 {
1582   switch(element)
1583   {
1584     case EL_LEERRAUM:           return(-1);
1585     case EL_ERDREICH:           return(GFX_ERDREICH);
1586     case EL_MAUERWERK:          return(GFX_MAUERWERK);
1587     case EL_FELSBODEN:          return(GFX_FELSBODEN);
1588     case EL_FELSBROCKEN:        return(GFX_FELSBROCKEN);
1589     case EL_SCHLUESSEL:         return(GFX_SCHLUESSEL);
1590     case EL_EDELSTEIN:          return(GFX_EDELSTEIN);
1591     case EL_AUSGANG_ZU:         return(GFX_AUSGANG_ZU);
1592     case EL_AUSGANG_ACT:        return(GFX_AUSGANG_ACT);
1593     case EL_AUSGANG_AUF:        return(GFX_AUSGANG_AUF);
1594     case EL_SPIELFIGUR:         return(GFX_SPIELFIGUR);
1595     case EL_SPIELER1:           return(GFX_SPIELER1);
1596     case EL_SPIELER2:           return(GFX_SPIELER2);
1597     case EL_SPIELER3:           return(GFX_SPIELER3);
1598     case EL_SPIELER4:           return(GFX_SPIELER4);
1599     case EL_KAEFER:             return(GFX_KAEFER);
1600     case EL_KAEFER_R:           return(GFX_KAEFER_R);
1601     case EL_KAEFER_O:           return(GFX_KAEFER_O);
1602     case EL_KAEFER_L:           return(GFX_KAEFER_L);
1603     case EL_KAEFER_U:           return(GFX_KAEFER_U);
1604     case EL_FLIEGER:            return(GFX_FLIEGER);
1605     case EL_FLIEGER_R:          return(GFX_FLIEGER_R);
1606     case EL_FLIEGER_O:          return(GFX_FLIEGER_O);
1607     case EL_FLIEGER_L:          return(GFX_FLIEGER_L);
1608     case EL_FLIEGER_U:          return(GFX_FLIEGER_U);
1609     case EL_BUTTERFLY:          return(GFX_BUTTERFLY);
1610     case EL_BUTTERFLY_R:        return(GFX_BUTTERFLY_R);
1611     case EL_BUTTERFLY_O:        return(GFX_BUTTERFLY_O);
1612     case EL_BUTTERFLY_L:        return(GFX_BUTTERFLY_L);
1613     case EL_BUTTERFLY_U:        return(GFX_BUTTERFLY_U);
1614     case EL_FIREFLY:            return(GFX_FIREFLY);
1615     case EL_FIREFLY_R:          return(GFX_FIREFLY_R);
1616     case EL_FIREFLY_O:          return(GFX_FIREFLY_O);
1617     case EL_FIREFLY_L:          return(GFX_FIREFLY_L);
1618     case EL_FIREFLY_U:          return(GFX_FIREFLY_U);
1619     case EL_MAMPFER:            return(GFX_MAMPFER);
1620     case EL_ROBOT:              return(GFX_ROBOT);
1621     case EL_BETON:              return(GFX_BETON);
1622     case EL_DIAMANT:            return(GFX_DIAMANT);
1623     case EL_MORAST_LEER:        return(GFX_MORAST_LEER);
1624     case EL_MORAST_VOLL:        return(GFX_MORAST_VOLL);
1625     case EL_TROPFEN:            return(GFX_TROPFEN);
1626     case EL_BOMBE:              return(GFX_BOMBE);
1627     case EL_SIEB_LEER:          return(GFX_SIEB_LEER);
1628     case EL_SIEB_VOLL:          return(GFX_SIEB_VOLL);
1629     case EL_SIEB_TOT:           return(GFX_SIEB_TOT);
1630     case EL_SALZSAEURE:         return(GFX_SALZSAEURE);
1631     case EL_AMOEBE_TOT:         return(GFX_AMOEBE_TOT);
1632     case EL_AMOEBE_NASS:        return(GFX_AMOEBE_NASS);
1633     case EL_AMOEBE_NORM:        return(GFX_AMOEBE_NORM);
1634     case EL_AMOEBE_VOLL:        return(GFX_AMOEBE_VOLL);
1635     case EL_AMOEBE_BD:          return(GFX_AMOEBE_BD);
1636     case EL_AMOEBA2DIAM:        return(GFX_AMOEBA2DIAM);
1637     case EL_KOKOSNUSS:          return(GFX_KOKOSNUSS);
1638     case EL_LIFE:               return(GFX_LIFE);
1639     case EL_LIFE_ASYNC:         return(GFX_LIFE_ASYNC);
1640     case EL_DYNAMIT:            return(GFX_DYNAMIT);
1641     case EL_BADEWANNE:          return(GFX_BADEWANNE);
1642     case EL_BADEWANNE1:         return(GFX_BADEWANNE1);
1643     case EL_BADEWANNE2:         return(GFX_BADEWANNE2);
1644     case EL_BADEWANNE3:         return(GFX_BADEWANNE3);
1645     case EL_BADEWANNE4:         return(GFX_BADEWANNE4);
1646     case EL_BADEWANNE5:         return(GFX_BADEWANNE5);
1647     case EL_ABLENK_AUS:         return(GFX_ABLENK_AUS);
1648     case EL_ABLENK_EIN:         return(GFX_ABLENK_EIN);
1649     case EL_SCHLUESSEL1:        return(GFX_SCHLUESSEL1);
1650     case EL_SCHLUESSEL2:        return(GFX_SCHLUESSEL2);
1651     case EL_SCHLUESSEL3:        return(GFX_SCHLUESSEL3);
1652     case EL_SCHLUESSEL4:        return(GFX_SCHLUESSEL4);
1653     case EL_PFORTE1:            return(GFX_PFORTE1);
1654     case EL_PFORTE2:            return(GFX_PFORTE2);
1655     case EL_PFORTE3:            return(GFX_PFORTE3);
1656     case EL_PFORTE4:            return(GFX_PFORTE4);
1657     case EL_PFORTE1X:           return(GFX_PFORTE1X);
1658     case EL_PFORTE2X:           return(GFX_PFORTE2X);
1659     case EL_PFORTE3X:           return(GFX_PFORTE3X);
1660     case EL_PFORTE4X:           return(GFX_PFORTE4X);
1661     case EL_DYNAMIT_AUS:        return(GFX_DYNAMIT_AUS);
1662     case EL_PACMAN:             return(GFX_PACMAN);
1663     case EL_PACMAN_R:           return(GFX_PACMAN_R);
1664     case EL_PACMAN_O:           return(GFX_PACMAN_O);
1665     case EL_PACMAN_L:           return(GFX_PACMAN_L);
1666     case EL_PACMAN_U:           return(GFX_PACMAN_U);
1667     case EL_UNSICHTBAR:         return(GFX_UNSICHTBAR);
1668     case EL_ERZ_EDEL:           return(GFX_ERZ_EDEL);
1669     case EL_ERZ_DIAM:           return(GFX_ERZ_DIAM);
1670     case EL_BIRNE_AUS:          return(GFX_BIRNE_AUS);
1671     case EL_BIRNE_EIN:          return(GFX_BIRNE_EIN);
1672     case EL_ZEIT_VOLL:          return(GFX_ZEIT_VOLL);
1673     case EL_ZEIT_LEER:          return(GFX_ZEIT_LEER);
1674     case EL_MAUER_LEBT:         return(GFX_MAUER_LEBT);
1675     case EL_EDELSTEIN_BD:       return(GFX_EDELSTEIN_BD);
1676     case EL_EDELSTEIN_GELB:     return(GFX_EDELSTEIN_GELB);
1677     case EL_EDELSTEIN_ROT:      return(GFX_EDELSTEIN_ROT);
1678     case EL_EDELSTEIN_LILA:     return(GFX_EDELSTEIN_LILA);
1679     case EL_ERZ_EDEL_BD:        return(GFX_ERZ_EDEL_BD);
1680     case EL_ERZ_EDEL_GELB:      return(GFX_ERZ_EDEL_GELB);
1681     case EL_ERZ_EDEL_ROT:       return(GFX_ERZ_EDEL_ROT);
1682     case EL_ERZ_EDEL_LILA:      return(GFX_ERZ_EDEL_LILA);
1683     case EL_MAMPFER2:           return(GFX_MAMPFER2);
1684     case EL_SIEB2_LEER:         return(GFX_SIEB2_LEER);
1685     case EL_SIEB2_VOLL:         return(GFX_SIEB2_VOLL);
1686     case EL_SIEB2_TOT:          return(GFX_SIEB2_TOT);
1687     case EL_DYNABOMB:           return(GFX_DYNABOMB);
1688     case EL_DYNABOMB_NR:        return(GFX_DYNABOMB_NR);
1689     case EL_DYNABOMB_SZ:        return(GFX_DYNABOMB_SZ);
1690     case EL_DYNABOMB_XL:        return(GFX_DYNABOMB_XL);
1691     case EL_SOKOBAN_OBJEKT:     return(GFX_SOKOBAN_OBJEKT);
1692     case EL_SOKOBAN_FELD_LEER:  return(GFX_SOKOBAN_FELD_LEER);
1693     case EL_SOKOBAN_FELD_VOLL:  return(GFX_SOKOBAN_FELD_VOLL);
1694     case EL_MAULWURF:           return(GFX_MAULWURF);
1695     case EL_PINGUIN:            return(GFX_PINGUIN);
1696     case EL_SCHWEIN:            return(GFX_SCHWEIN);
1697     case EL_DRACHE:             return(GFX_DRACHE);
1698     case EL_SONDE:              return(GFX_SONDE);
1699     case EL_PFEIL_L:            return(GFX_PFEIL_L);
1700     case EL_PFEIL_R:            return(GFX_PFEIL_R);
1701     case EL_PFEIL_O:            return(GFX_PFEIL_O);
1702     case EL_PFEIL_U:            return(GFX_PFEIL_U);
1703     default:
1704     {
1705       if (IS_CHAR(element))
1706         return(GFX_CHAR_START + (element-EL_CHAR_START));
1707       else
1708         return(-1);
1709     }
1710   }
1711 }