rnd-19990127-1
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  tools.c                                                 *
12 ***********************************************************/
13
14 #include <stdarg.h>
15
16 #ifdef __FreeBSD__
17 #include <machine/joystick.h>
18 #endif
19
20 #include "tools.h"
21 #include "game.h"
22 #include "events.h"
23 #include "sound.h"
24 #include "misc.h"
25 #include "buttons.h"
26 #include "joystick.h"
27 #include "cartoons.h"
28 #include "network.h"
29
30 #ifdef MSDOS
31 extern boolean wait_for_vsync;
32 #endif
33
34 /* tool button identifiers */
35 #define TOOL_CTRL_ID_YES        0
36 #define TOOL_CTRL_ID_NO         1
37 #define TOOL_CTRL_ID_CONFIRM    2
38 #define TOOL_CTRL_ID_PLAYER_1   3
39 #define TOOL_CTRL_ID_PLAYER_2   4
40 #define TOOL_CTRL_ID_PLAYER_3   5
41 #define TOOL_CTRL_ID_PLAYER_4   6
42
43 #define NUM_TOOL_BUTTONS        7
44
45 /* forward declaration for internal use */
46 static void UnmapToolButtons();
47 static void HandleToolButtons(struct GadgetInfo *);
48
49 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
50 static int request_gadget_id = -1;
51
52 void SetDrawtoField(int mode)
53 {
54   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
55   {
56     FX = TILEX;
57     FY = TILEY;
58     BX1 = -1;
59     BY1 = -1;
60     BX2 = SCR_FIELDX;
61     BY2 = SCR_FIELDY;
62     redraw_x1 = 1;
63     redraw_y1 = 1;
64
65     drawto_field = fieldbuffer;
66   }
67   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
68   {
69     FX = SX;
70     FY = SY;
71     BX1 = 0;
72     BY1 = 0;
73     BX2 = SCR_FIELDX - 1;
74     BY2 = SCR_FIELDY - 1;
75     redraw_x1 = 0;
76     redraw_y1 = 0;
77
78     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
79   }
80 }
81
82 void BackToFront()
83 {
84   int x,y;
85   Drawable buffer = (drawto_field == window ? backbuffer : drawto_field);
86
87   if (setup.direct_draw && game_status == PLAYING)
88     redraw_mask &= ~REDRAW_MAIN;
89
90   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
91     redraw_mask |= REDRAW_FIELD;
92
93   if (redraw_mask & REDRAW_FIELD)
94     redraw_mask &= ~REDRAW_TILES;
95
96   /*
97   if (redraw_mask & REDRAW_FIELD ||
98       (ScreenGfxPos && setup.soft_scrolling && game_status == PLAYING))
99     redraw_mask &= ~REDRAW_TILES;
100   */
101
102   if (!redraw_mask)
103     return;
104
105   /* synchronize X11 graphics at this point; if we would synchronize the
106      display immediately after the buffer switching (after the XFlush),
107      this could mean that we have to wait for the graphics to complete,
108      although we could go on doing calculations for the next frame */
109
110   XSync(display, FALSE);
111
112   /*
113 #ifdef MSDOS
114   wait_for_vsync = TRUE;
115 #endif
116   */
117
118   if (redraw_mask & REDRAW_ALL)
119   {
120     XCopyArea(display,backbuffer,window,gc,
121               0,0, WIN_XSIZE,WIN_YSIZE,
122               0,0);
123     redraw_mask = 0;
124   }
125
126   if (redraw_mask & REDRAW_FIELD)
127   {
128     if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
129     {
130       XCopyArea(display,backbuffer,window,gc,
131                 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
132                 REAL_SX,REAL_SY);
133     }
134     else
135     {
136       int fx = FX, fy = FY;
137
138       if (setup.soft_scrolling)
139       {
140         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
141         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
142       }
143
144       if (setup.soft_scrolling ||
145           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
146           ABS(ScreenMovPos) == ScrollStepSize ||
147           redraw_tiles > REDRAWTILES_THRESHOLD)
148       {
149         XCopyArea(display, buffer, window, gc, fx, fy, SXSIZE, SYSIZE, SX, SY);
150
151 #ifdef DEBUG
152 #if 0
153         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
154                ScreenGfxPos,
155                (setup.soft_scrolling ?
156                 "setup.soft_scrolling" :
157                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
158                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
159                 ABS(ScreenGfxPos) == ScrollStepSize ?
160                 "ABS(ScreenGfxPos) == ScrollStepSize" :
161                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
162 #endif
163 #endif
164       }
165     }
166     redraw_mask &= ~REDRAW_MAIN;
167   }
168
169   if (redraw_mask & REDRAW_DOORS)
170   {
171     if (redraw_mask & REDRAW_DOOR_1)
172       XCopyArea(display,backbuffer,window,gc,
173                 DX,DY, DXSIZE,DYSIZE,
174                 DX,DY);
175     if (redraw_mask & REDRAW_DOOR_2)
176     {
177       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
178         XCopyArea(display,backbuffer,window,gc,
179                   VX,VY, VXSIZE,VYSIZE,
180                   VX,VY);
181       else
182       {
183         if (redraw_mask & REDRAW_VIDEO_1)
184           XCopyArea(display,backbuffer,window,gc,
185                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
186                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
187                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
188         if (redraw_mask & REDRAW_VIDEO_2)
189           XCopyArea(display,backbuffer,window,gc,
190                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
191                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
192                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
193         if (redraw_mask & REDRAW_VIDEO_3)
194           XCopyArea(display,backbuffer,window,gc,
195                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
196                     VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
197                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
198       }
199     }
200     if (redraw_mask & REDRAW_DOOR_3)
201       XCopyArea(display, backbuffer, window, gc,
202                 EX, EY, EXSIZE, EYSIZE,
203                 EX, EY);
204     redraw_mask &= ~REDRAW_DOORS;
205   }
206
207   if (redraw_mask & REDRAW_MICROLEVEL)
208   {
209     XCopyArea(display,backbuffer,window,gc,
210               MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
211               MICROLEV_XPOS, MICROLEV_YPOS);
212     XCopyArea(display,backbuffer,window,gc,
213               SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
214               SX, MICROLABEL_YPOS);
215     redraw_mask &= ~REDRAW_MICROLEVEL;
216   }
217
218   if (redraw_mask & REDRAW_TILES)
219   {
220     for(x=0; x<SCR_FIELDX; x++)
221       for(y=0; y<SCR_FIELDY; y++)
222         if (redraw[redraw_x1 + x][redraw_y1 + y])
223           XCopyArea(display,buffer,window,gc,
224                     FX+x*TILEX,FX+y*TILEY, TILEX,TILEY,
225                     SX+x*TILEX,SY+y*TILEY);
226   }
227
228   XFlush(display);
229
230   for(x=0; x<MAX_BUF_XSIZE; x++)
231     for(y=0; y<MAX_BUF_YSIZE; y++)
232       redraw[x][y] = 0;
233   redraw_tiles = 0;
234   redraw_mask = 0;
235 }
236
237 void FadeToFront()
238 {
239 /*
240   long fading_delay = 300;
241
242   if (setup.fading && (redraw_mask & REDRAW_FIELD))
243   {
244 */
245
246 /*
247     int x,y;
248
249     XFillRectangle(display,window,gc,
250                    REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
251     XFlush(display);
252
253     for(i=0;i<2*FULL_SYSIZE;i++)
254     {
255       for(y=0;y<FULL_SYSIZE;y++)
256       {
257         XCopyArea(display,backbuffer,window,gc,
258                   REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
259       }
260       XFlush(display);
261       Delay(10);
262     }
263 */
264
265 /*
266     for(i=1;i<FULL_SYSIZE;i+=2)
267       XCopyArea(display,backbuffer,window,gc,
268                 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
269     XFlush(display);
270     Delay(fading_delay);
271 */
272
273 /*
274     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
275     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
276               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
277     XFlush(display);
278     Delay(fading_delay);
279
280     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
281     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
282               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
283     XFlush(display);
284     Delay(fading_delay);
285
286     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
287     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
288               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
289     XFlush(display);
290     Delay(fading_delay);
291
292     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,0);
293     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
294               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
295     XFlush(display);
296     Delay(fading_delay);
297
298     redraw_mask &= ~REDRAW_MAIN;
299   }
300 */
301
302   BackToFront();
303 }
304
305 void ClearWindow()
306 {
307   XFillRectangle(display, backbuffer, gc,
308                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
309
310   if (setup.soft_scrolling && game_status == PLAYING)
311   {
312     XFillRectangle(display, fieldbuffer, gc, 0, 0, FXSIZE, FYSIZE);
313     SetDrawtoField(DRAW_BUFFERED);
314   }
315   else
316     SetDrawtoField(DRAW_BACKBUFFER);
317
318   if (setup.direct_draw && game_status == PLAYING)
319   {
320     XFillRectangle(display, window, gc,
321                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
322     SetDrawtoField(DRAW_DIRECT);
323   }
324
325   redraw_mask |= REDRAW_FIELD;
326 }
327
328 void DrawTextFCentered(int y, int font_type, char *format, ...)
329 {
330   char buffer[FULL_SXSIZE / FONT3_XSIZE + 10];
331   int font_xsize;
332   va_list ap;
333
334   font_xsize = (font_type < FC_SPECIAL1 ? FONT2_XSIZE :
335                 font_type < FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
336
337   va_start(ap, format);
338   vsprintf(buffer, format, ap);
339   va_end(ap);
340
341   DrawText(SX + (SXSIZE - strlen(buffer) * font_xsize) / 2, SY + y,
342            buffer, FS_SMALL, font_type);
343 }
344
345 void DrawTextF(int x, int y, int font_type, char *format, ...)
346 {
347   char buffer[FULL_SXSIZE / FONT3_XSIZE + 10];
348   va_list ap;
349
350   va_start(ap, format);
351   vsprintf(buffer, format, ap);
352   va_end(ap);
353
354   DrawText(SX + x, SY + y, buffer, FS_SMALL, font_type);
355 }
356
357 void DrawText(int x, int y, char *text, int font_size, int font_type)
358 {
359   DrawTextExt(drawto, gc, x, y, text, font_size, font_type);
360
361   if (x < DX)
362     redraw_mask |= REDRAW_FIELD;
363   else if (y < VY)
364     redraw_mask |= REDRAW_DOOR_1;
365 }
366
367 void DrawTextExt(Drawable d, GC gc, int x, int y,
368                  char *text, int font_size, int font_type)
369 {
370   int font_width, font_height, font_start;
371   int font_pixmap;
372   boolean print_inverse = FALSE;
373
374   if (font_size != FS_SMALL && font_size != FS_BIG)
375     font_size = FS_SMALL;
376   if (font_type < FC_RED || font_type > FC_SPECIAL2)
377     font_type = FC_RED;
378
379   font_width = (font_size == FS_BIG ? FONT1_XSIZE :
380                 font_type < FC_SPECIAL1 ? FONT2_XSIZE :
381                 font_type < FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
382   font_height = (font_size == FS_BIG ? FONT1_XSIZE :
383                  font_type < FC_SPECIAL2 ? FONT2_XSIZE : FONT4_XSIZE);
384   font_pixmap = (font_size == FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
385   font_start = (font_type * (font_size == FS_BIG ? FONT1_YSIZE : FONT2_YSIZE) *
386                 FONT_LINES_PER_FONT);
387
388   while (*text)
389   {
390     char c = *text++;
391
392     if (c == '~' && font_size == FS_SMALL && font_type <= FC_YELLOW)
393     {
394       print_inverse = TRUE;
395       continue;
396     }
397
398     if (c >= 'a' && c <= 'z')
399       c = 'A' + (c - 'a');
400     else if (c == 'ä' || c == 'Ä')
401       c = 91;
402     else if (c == 'ö' || c == 'Ö')
403       c = 92;
404     else if (c == 'ü' || c == 'Ãœ')
405       c = 93;
406
407     if (c >= 32 && c <= 95)
408     {
409       int src_x = ((c - 32) % FONT_CHARS_PER_LINE) * font_width;
410       int src_y = ((c - 32) / FONT_CHARS_PER_LINE) * font_height + font_start;
411       int dest_x = x, dest_y = y;
412
413       if (print_inverse)
414       {
415         XCopyArea(display, pix[font_pixmap], d, gc,
416                   FONT_CHARS_PER_LINE * font_width,
417                   3 * font_height + font_start,
418                   font_width, font_height, x, y);
419
420         XSetClipOrigin(display, clip_gc[font_pixmap],
421                        dest_x - src_x, dest_y - src_y);
422         XCopyArea(display, pix[font_pixmap], drawto, clip_gc[font_pixmap],
423                   0, 0, font_width, font_height, dest_x, dest_y);
424       }
425       else
426         XCopyArea(display, pix[font_pixmap], d, gc,
427                   src_x, src_y, font_width, font_height, dest_x, dest_y);
428     }
429
430     x += font_width;
431   }
432 }
433
434 void DrawAllPlayers()
435 {
436   int i;
437
438   for(i=0; i<MAX_PLAYERS; i++)
439     if (stored_player[i].active)
440       DrawPlayer(&stored_player[i]);
441 }
442
443 void DrawPlayerField(int x, int y)
444 {
445   if (!IS_PLAYER(x,y))
446     return;
447
448   DrawPlayer(PLAYERINFO(x,y));
449 }
450
451 void DrawPlayer(struct PlayerInfo *player)
452 {
453   int jx = player->jx, jy = player->jy;
454   int last_jx = player->last_jx, last_jy = player->last_jy;
455   int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
456   int sx = SCREENX(jx), sy = SCREENY(jy);
457   int sxx = 0, syy = 0;
458   int element = Feld[jx][jy];
459   int graphic, phase;
460
461   if (!player->active || player->gone ||
462       !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
463     return;
464
465 #if DEBUG
466   if (!IN_LEV_FIELD(jx,jy))
467   {
468     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
469     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
470     printf("DrawPlayerField(): This should never happen!\n");
471     return;
472   }
473 #endif
474
475   if (element == EL_EXPLODING)
476     return;
477
478   /* draw things in the field the player is leaving, if needed */
479
480   if (last_jx != jx || last_jy != jy)
481   {
482     if (Store[last_jx][last_jy])
483     {
484       DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
485       DrawLevelFieldThruMask(last_jx, last_jy);
486     }
487     else if (Feld[last_jx][last_jy] == EL_DYNAMIT)
488       DrawDynamite(last_jx, last_jy);
489     else
490       DrawLevelField(last_jx, last_jy);
491
492     if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
493     {
494       if (player->GfxPos)
495       {
496         if (Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
497           DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FELD_LEER);
498         else
499           DrawLevelElement(next_jx, next_jy, EL_LEERRAUM);
500       }
501       else
502         DrawLevelField(next_jx, next_jy);
503     }
504   }
505
506   if (!IN_SCR_FIELD(sx, sy))
507     return;
508
509   if (setup.direct_draw)
510     SetDrawtoField(DRAW_BUFFERED);
511
512   /* draw things behind the player, if needed */
513
514   if (Store[jx][jy])
515     DrawLevelElement(jx, jy, Store[jx][jy]);
516   else if (element != EL_DYNAMIT && element != EL_DYNABOMB)
517     DrawLevelField(jx, jy);
518
519   /* draw player himself */
520
521   if (player->MovDir == MV_LEFT)
522     graphic = (player->Pushing ? GFX_SPIELER1_PUSH_LEFT : GFX_SPIELER1_LEFT);
523   else if (player->MovDir == MV_RIGHT)
524     graphic = (player->Pushing ? GFX_SPIELER1_PUSH_RIGHT : GFX_SPIELER1_RIGHT);
525   else if (player->MovDir == MV_UP)
526     graphic = GFX_SPIELER1_UP;
527   else  /* MV_DOWN || MV_NO_MOVING */
528     graphic = GFX_SPIELER1_DOWN;
529
530   graphic += player->index_nr * 3*HEROES_PER_LINE;
531   graphic += player->Frame;
532
533   if (player->GfxPos)
534   {
535     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
536       sxx = player->GfxPos;
537     else
538       syy = player->GfxPos;
539   }
540
541   if (!setup.soft_scrolling && ScreenMovPos)
542     sxx = syy = 0;
543
544   DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, NO_CUTTING);
545
546   if (player->Pushing && player->GfxPos)
547   {
548     int px = SCREENX(next_jx), py = SCREENY(next_jy);
549
550     if (Feld[jx][jy] == EL_SOKOBAN_FELD_LEER ||
551         Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
552       DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT,
553                                  NO_CUTTING);
554     else
555     {
556       int element = Feld[next_jx][next_jy];
557       int graphic = el2gfx(element);
558
559       if (element == EL_FELSBROCKEN && sxx)
560       {
561         int phase = (player->GfxPos / (TILEX/4));
562
563         if (player->MovDir == MV_LEFT)
564           graphic += phase;
565         else
566           graphic += (phase+4)%4;
567       }
568
569       DrawGraphicShifted(px, py, sxx, syy, graphic, NO_CUTTING, NO_MASKING);
570     }
571   }
572
573   /* draw things in front of player (EL_DYNAMIT || EL_DYNABOMB) */
574
575   if (element == EL_DYNAMIT || element == EL_DYNABOMB)
576   {
577     graphic = el2gfx(element);
578
579     if (element == EL_DYNAMIT)
580     {
581       if ((phase = (96 - MovDelay[jx][jy]) / 12) > 6)
582         phase = 6;
583     }
584     else
585     {
586       if ((phase = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
587         phase = 7 - phase;
588     }
589
590     if (game_emulation == EMU_SUPAPLEX)
591       DrawGraphic(sx, sy, GFX_SP_DISK_RED);
592     else
593       DrawGraphicThruMask(sx, sy, graphic + phase);
594   }
595
596   if ((last_jx != jx || last_jy != jy) &&
597       Feld[last_jx][last_jy] == EL_EXPLODING)
598   {
599     int phase = Frame[last_jx][last_jy];
600     int delay = 2;
601
602     if (phase > 2)
603       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy),
604                           GFX_EXPLOSION + ((phase - 1) / delay - 1));
605   }
606
607   if (setup.direct_draw)
608   {
609     int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
610     int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
611     int x_size = TILEX * (1 + ABS(jx - last_jx));
612     int y_size = TILEY * (1 + ABS(jy - last_jy));
613
614     XCopyArea(display, drawto_field, window, gc,
615               dest_x, dest_y, x_size, y_size, dest_x, dest_y);
616     SetDrawtoField(DRAW_DIRECT);
617   }
618
619   MarkTileDirty(sx,sy);
620 }
621
622 static int getGraphicAnimationPhase(int frames, int delay, int mode)
623 {
624   int phase;
625
626   if (mode == ANIM_OSCILLATE)
627   {
628     int max_anim_frames = 2 * frames - 2;
629     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
630     phase = (phase < frames ? phase : max_anim_frames - phase);
631   }
632   else
633     phase = (FrameCounter % (delay * frames)) / delay;
634
635   if (mode == ANIM_REVERSE)
636     phase = -phase;
637
638   return(phase);
639 }
640
641 void DrawGraphicAnimationExt(int x, int y, int graphic,
642                              int frames, int delay, int mode, int mask_mode)
643 {
644   int phase = getGraphicAnimationPhase(frames, delay, mode);
645
646   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
647   {
648     if (mask_mode == USE_MASKING)
649       DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic + phase);
650     else
651       DrawGraphic(SCREENX(x), SCREENY(y), graphic + phase);
652   }
653 }
654
655 void DrawGraphicAnimation(int x, int y, int graphic,
656                           int frames, int delay, int mode)
657 {
658   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
659 }
660
661 void DrawGraphicAnimationThruMask(int x, int y, int graphic,
662                                   int frames, int delay, int mode)
663 {
664   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, USE_MASKING);
665 }
666
667 void DrawGraphic(int x, int y, int graphic)
668 {
669 #if DEBUG
670   if (!IN_SCR_FIELD(x,y))
671   {
672     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
673     printf("DrawGraphic(): This should never happen!\n");
674     return;
675   }
676 #endif
677
678   DrawGraphicExt(drawto_field, gc, FX + x*TILEX, FY + y*TILEY, graphic);
679   MarkTileDirty(x,y);
680 }
681
682 void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
683 {
684   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
685   {
686     graphic -= GFX_START_ROCKSSCREEN;
687     XCopyArea(display, pix[PIX_BACK], d, gc,
688               SX + (graphic % GFX_PER_LINE) * TILEX,
689               SY + (graphic / GFX_PER_LINE) * TILEY,
690               TILEX, TILEY, x, y);
691   }
692   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
693   {
694     graphic -= GFX_START_ROCKSMORE;
695     XCopyArea(display, pix[PIX_MORE], d, gc,
696               (graphic % MORE_PER_LINE) * TILEX,
697               (graphic / MORE_PER_LINE) * TILEY,
698               TILEX, TILEY, x, y);
699   }
700   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
701   {
702     graphic -= GFX_START_ROCKSHEROES;
703     XCopyArea(display, pix[PIX_HEROES], d, gc,
704               (graphic % HEROES_PER_LINE) * TILEX,
705               (graphic / HEROES_PER_LINE) * TILEY,
706               TILEX, TILEY, x, y);
707   }
708   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
709   {
710     graphic -= GFX_START_ROCKSFONT;
711     XCopyArea(display, pix[PIX_BIGFONT], d, gc,
712               (graphic % FONT_CHARS_PER_LINE) * TILEX,
713               (graphic / FONT_CHARS_PER_LINE) * TILEY +
714               FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY,
715               TILEX, TILEY, x, y);
716   }
717   else
718     XFillRectangle(display, d, gc, x, y, TILEX, TILEY);
719 }
720
721 void DrawGraphicThruMask(int x, int y, int graphic)
722 {
723 #if DEBUG
724   if (!IN_SCR_FIELD(x,y))
725   {
726     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
727     printf("DrawGraphicThruMask(): This should never happen!\n");
728     return;
729   }
730 #endif
731
732   DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
733   MarkTileDirty(x,y);
734 }
735
736 void DrawGraphicThruMaskExt(Drawable d, int dest_x, int dest_y, int graphic)
737 {
738   int src_x, src_y;
739   int tile = graphic;
740   Pixmap src_pixmap;
741   GC drawing_gc;
742
743   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
744   {
745     src_pixmap = pix[PIX_BACK];
746     drawing_gc = clip_gc[PIX_BACK];
747     graphic -= GFX_START_ROCKSSCREEN;
748     src_x  = SX + (graphic % GFX_PER_LINE) * TILEX;
749     src_y  = SY + (graphic / GFX_PER_LINE) * TILEY;
750   }
751   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
752   {
753     src_pixmap = pix[PIX_MORE];
754     drawing_gc = clip_gc[PIX_MORE];
755     graphic -= GFX_START_ROCKSMORE;
756     src_x  = (graphic % MORE_PER_LINE) * TILEX;
757     src_y  = (graphic / MORE_PER_LINE) * TILEY;
758   }
759   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
760   {
761     src_pixmap = pix[PIX_HEROES];
762     drawing_gc = clip_gc[PIX_HEROES];
763     graphic -= GFX_START_ROCKSHEROES;
764     src_x  = (graphic % HEROES_PER_LINE) * TILEX;
765     src_y  = (graphic / HEROES_PER_LINE) * TILEY;
766   }
767   else
768   {
769     DrawGraphicExt(d, gc, dest_x,dest_y, graphic);
770     return;
771   }
772
773   if (tile_clipmask[tile] != None)
774   {
775     XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
776     XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
777     XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
778               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
779   }
780   else
781   {
782 #if DEBUG
783     printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
784 #endif
785
786     XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y);
787     XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
788               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
789   }
790 }
791
792 void DrawMiniGraphic(int x, int y, int graphic)
793 {
794   DrawMiniGraphicExt(drawto,gc, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
795   MarkTileDirty(x/2, y/2);
796 }
797
798 void getMiniGraphicSource(int graphic, Pixmap *pixmap, int *x, int *y)
799 {
800   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
801   {
802     graphic -= GFX_START_ROCKSSCREEN;
803     *pixmap = pix[PIX_BACK];
804     *x = MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX;
805     *y = MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY;
806   }
807   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
808   {
809     graphic -= GFX_START_ROCKSMORE;
810     *pixmap = pix[PIX_MORE];
811     *x = MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX;
812     *y = MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY;
813   }
814   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
815   {
816     graphic -= GFX_START_ROCKSFONT;
817     *pixmap = pix[PIX_SMALLFONT];
818     *x = (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE;
819     *y = ((graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
820           FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT);
821   }
822   else
823   {
824     *pixmap = pix[PIX_MORE];
825     *x = MINI_MORE_STARTX;
826     *y = MINI_MORE_STARTY;
827   }
828 }
829
830 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
831 {
832   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
833   {
834     graphic -= GFX_START_ROCKSSCREEN;
835     XCopyArea(display, pix[PIX_BACK], d, gc,
836               MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX,
837               MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY,
838               MINI_TILEX, MINI_TILEY, x, y);
839   }
840   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
841   {
842     graphic -= GFX_START_ROCKSMORE;
843     XCopyArea(display, pix[PIX_MORE], d, gc,
844               MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX,
845               MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY,
846               MINI_TILEX, MINI_TILEY, x, y);
847   }
848   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
849   {
850     graphic -= GFX_START_ROCKSFONT;
851     XCopyArea(display, pix[PIX_SMALLFONT], d, gc,
852               (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE,
853               (graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
854               FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT,
855               MINI_TILEX, MINI_TILEY, x, y);
856   }
857   else
858     XFillRectangle(display, d, gc, x, y, MINI_TILEX, MINI_TILEY);
859 }
860
861 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
862                         int cut_mode, int mask_mode)
863 {
864   int width = TILEX, height = TILEY;
865   int cx = 0, cy = 0;
866   int src_x, src_y, dest_x, dest_y;
867   int tile = graphic;
868   Pixmap src_pixmap;
869   GC drawing_gc;
870
871   if (graphic < 0)
872   {
873     DrawGraphic(x, y, graphic);
874     return;
875   }
876
877   if (dx || dy)                 /* Verschiebung der Grafik? */
878   {
879     if (x < BX1)                /* Element kommt von links ins Bild */
880     {
881       x = BX1;
882       width = dx;
883       cx = TILEX - dx;
884       dx = 0;
885     }
886     else if (x > BX2)           /* Element kommt von rechts ins Bild */
887     {
888       x = BX2;
889       width = -dx;
890       dx = TILEX + dx;
891     }
892     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
893     {
894       width += dx;
895       cx = -dx;
896       dx = 0;
897     }
898     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
899       width -= dx;
900     else if (dx)                /* allg. Bewegung in x-Richtung */
901       MarkTileDirty(x + SIGN(dx), y);
902
903     if (y < BY1)                /* Element kommt von oben ins Bild */
904     {
905       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
906         return;
907
908       y = BY1;
909       height = dy;
910       cy = TILEY - dy;
911       dy = 0;
912     }
913     else if (y > BY2)           /* Element kommt von unten ins Bild */
914     {
915       y = BY2;
916       height = -dy;
917       dy = TILEY + dy;
918     }
919     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
920     {
921       height += dy;
922       cy = -dy;
923       dy = 0;
924     }
925     else if (dy > 0 && cut_mode == CUT_ABOVE)
926     {
927       if (y == BY2)             /* Element unterhalb des Bildes */
928         return;
929
930       height = dy;
931       cy = TILEY - dy;
932       dy = TILEY;
933       MarkTileDirty(x, y + 1);
934     }                           /* Element verläßt unten das Bild */
935     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
936       height -= dy;
937     else if (dy)                /* allg. Bewegung in y-Richtung */
938       MarkTileDirty(x, y + SIGN(dy));
939   }
940
941   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
942   {
943     src_pixmap = pix[PIX_BACK];
944     drawing_gc = clip_gc[PIX_BACK];
945     graphic -= GFX_START_ROCKSSCREEN;
946     src_x  = SX + (graphic % GFX_PER_LINE) * TILEX + cx;
947     src_y  = SY + (graphic / GFX_PER_LINE) * TILEY + cy;
948   }
949   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
950   {
951     src_pixmap = pix[PIX_MORE];
952     drawing_gc = clip_gc[PIX_MORE];
953     graphic -= GFX_START_ROCKSMORE;
954     src_x  = (graphic % MORE_PER_LINE) * TILEX + cx;
955     src_y  = (graphic / MORE_PER_LINE) * TILEY + cy;
956   }
957   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
958   {
959     src_pixmap = pix[PIX_HEROES];
960     drawing_gc = clip_gc[PIX_HEROES];
961     graphic -= GFX_START_ROCKSHEROES;
962     src_x  = (graphic % HEROES_PER_LINE) * TILEX + cx;
963     src_y  = (graphic / HEROES_PER_LINE) * TILEY + cy;
964   }
965   else  /* big font graphics currently not allowed (and not needed) */
966     return;
967
968   dest_x = FX + x * TILEX + dx;
969   dest_y = FY + y * TILEY + dy;
970
971 #if DEBUG
972   if (!IN_SCR_FIELD(x,y))
973   {
974     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
975     printf("DrawGraphicShifted(): This should never happen!\n");
976     return;
977   }
978 #endif
979
980   if (mask_mode == USE_MASKING)
981   {
982     if (tile_clipmask[tile] != None)
983     {
984       XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
985       XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
986       XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
987                 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
988     }
989     else
990     {
991 #if DEBUG
992       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
993 #endif
994
995       XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
996       XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
997                 src_x, src_y, width, height, dest_x, dest_y);
998     }
999   }
1000   else
1001     XCopyArea(display, src_pixmap, drawto_field, gc,
1002               src_x, src_y, width, height, dest_x, dest_y);
1003
1004   MarkTileDirty(x,y);
1005 }
1006
1007 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1008                                 int cut_mode)
1009 {
1010   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
1011 }
1012
1013 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1014                           int cut_mode, int mask_mode)
1015 {
1016   int ux = LEVELX(x), uy = LEVELY(y);
1017   int graphic = el2gfx(element);
1018   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1019   int phase4 = phase8 / 2;
1020   int phase2  = phase8 / 4;
1021   int dir = MovDir[ux][uy];
1022
1023   if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
1024   {
1025     graphic += 4 * !phase2;
1026
1027     if (dir == MV_UP)
1028       graphic += 1;
1029     else if (dir == MV_LEFT)
1030       graphic += 2;
1031     else if (dir == MV_DOWN)
1032       graphic += 3;
1033   }
1034   else if (element == EL_SP_SNIKSNAK)
1035   {
1036     if (dir == MV_LEFT)
1037       graphic = GFX_SP_SNIKSNAK_LEFT;
1038     else if (dir == MV_RIGHT)
1039       graphic = GFX_SP_SNIKSNAK_RIGHT;
1040     else if (dir == MV_UP)
1041       graphic = GFX_SP_SNIKSNAK_UP;
1042     else
1043       graphic = GFX_SP_SNIKSNAK_DOWN;
1044
1045     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1046   }
1047   else if (element == EL_SP_ELECTRON)
1048   {
1049     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1050   }
1051   else if (element == EL_MAULWURF || element == EL_PINGUIN ||
1052            element == EL_SCHWEIN || element == EL_DRACHE)
1053   {
1054     if (dir == MV_LEFT)
1055       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT :
1056                  element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
1057                  element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1058     else if (dir == MV_RIGHT)
1059       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT :
1060                  element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
1061                  element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1062     else if (dir == MV_UP)
1063       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP :
1064                  element == EL_PINGUIN ? GFX_PINGUIN_UP :
1065                  element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1066     else
1067       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN :
1068                  element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
1069                  element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1070
1071     graphic += phase4;
1072   }
1073   else if (element == EL_SONDE)
1074   {
1075     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1076   }
1077   else if (element == EL_SALZSAEURE)
1078   {
1079     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
1080   }
1081   else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1082   {
1083     graphic += !phase2;
1084   }
1085   else if ((element == EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode)
1086   {
1087     if (element != EL_SP_INFOTRON)
1088       graphic += phase2 * (element == EL_FELSBROCKEN ? 2 : 1);
1089   }
1090   else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
1091            element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
1092   {
1093     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1094   }
1095   else if (IS_AMOEBOID(element))
1096   {
1097     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1098     graphic += (x + 2 * y + 4) % 4;
1099   }
1100   else if (element == EL_MAUER_LEBT)
1101   {
1102     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1103
1104     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1105       links_massiv = TRUE;
1106     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1107       rechts_massiv = TRUE;
1108
1109     if (links_massiv && rechts_massiv)
1110       graphic = GFX_MAUERWERK;
1111     else if (links_massiv)
1112       graphic = GFX_MAUER_R;
1113     else if (rechts_massiv)
1114       graphic = GFX_MAUER_L;
1115   }
1116
1117   if (dx || dy)
1118     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1119   else if (mask_mode == USE_MASKING)
1120     DrawGraphicThruMask(x, y, graphic);
1121   else
1122     DrawGraphic(x, y, graphic);
1123 }
1124
1125 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1126                          int cut_mode, int mask_mode)
1127 {
1128   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1129     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1130                          cut_mode, mask_mode);
1131 }
1132
1133 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1134                               int cut_mode)
1135 {
1136   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1137 }
1138
1139 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1140                              int cut_mode)
1141 {
1142   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1143 }
1144
1145 void DrawScreenElementThruMask(int x, int y, int element)
1146 {
1147   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1148 }
1149
1150 void DrawLevelElementThruMask(int x, int y, int element)
1151 {
1152   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1153 }
1154
1155 void DrawLevelFieldThruMask(int x, int y)
1156 {
1157   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1158 }
1159
1160 void ErdreichAnbroeckeln(int x, int y)
1161 {
1162   int i, width, height, cx,cy;
1163   int ux = LEVELX(x), uy = LEVELY(y);
1164   int element, graphic;
1165   int snip = 4;
1166   static int xy[4][2] =
1167   {
1168     { 0, -1 },
1169     { -1, 0 },
1170     { +1, 0 },
1171     { 0, +1 }
1172   };
1173
1174   if (!IN_LEV_FIELD(ux, uy))
1175     return;
1176
1177   element = Feld[ux][uy];
1178
1179   if (element == EL_ERDREICH)
1180   {
1181     if (!IN_SCR_FIELD(x, y))
1182       return;
1183
1184     graphic = GFX_ERDENRAND;
1185
1186     for(i=0; i<4; i++)
1187     {
1188       int uxx, uyy;
1189
1190       uxx = ux + xy[i][0];
1191       uyy = uy + xy[i][1];
1192       if (!IN_LEV_FIELD(uxx, uyy))
1193         element = EL_BETON;
1194       else
1195         element = Feld[uxx][uyy];
1196
1197       if (element == EL_ERDREICH)
1198         continue;
1199
1200       if (i == 1 || i == 2)
1201       {
1202         width = snip;
1203         height = TILEY;
1204         cx = (i == 2 ? TILEX - snip : 0);
1205         cy = 0;
1206       }
1207       else
1208       {
1209         width = TILEX;
1210         height = snip;
1211         cx = 0;
1212         cy = (i == 3 ? TILEY - snip : 0);
1213       }
1214
1215       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1216                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1217                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1218                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1219     }
1220
1221     MarkTileDirty(x, y);
1222   }
1223   else
1224   {
1225     graphic = GFX_ERDENRAND;
1226
1227     for(i=0; i<4; i++)
1228     {
1229       int xx, yy, uxx, uyy;
1230
1231       xx = x + xy[i][0];
1232       yy = y + xy[i][1];
1233       uxx = ux + xy[i][0];
1234       uyy = uy + xy[i][1];
1235
1236       if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
1237           !IN_SCR_FIELD(xx, yy))
1238         continue;
1239
1240       if (i == 1 || i == 2)
1241       {
1242         width = snip;
1243         height = TILEY;
1244         cx = (i == 1 ? TILEX - snip : 0);
1245         cy = 0;
1246       }
1247       else
1248       {
1249         width = TILEX;
1250         height = snip;
1251         cx = 0;
1252         cy = (i==0 ? TILEY-snip : 0);
1253       }
1254
1255       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1256                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1257                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1258                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1259
1260       MarkTileDirty(xx, yy);
1261     }
1262   }
1263 }
1264
1265 void DrawScreenElement(int x, int y, int element)
1266 {
1267   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1268   ErdreichAnbroeckeln(x, y);
1269 }
1270
1271 void DrawLevelElement(int x, int y, int element)
1272 {
1273   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1274     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1275 }
1276
1277 void DrawScreenField(int x, int y)
1278 {
1279   int ux = LEVELX(x), uy = LEVELY(y);
1280   int element;
1281
1282   if (!IN_LEV_FIELD(ux, uy))
1283   {
1284     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1285       element = EL_LEERRAUM;
1286     else
1287       element = BorderElement;
1288
1289     DrawScreenElement(x, y, element);
1290     return;
1291   }
1292
1293   element = Feld[ux][uy];
1294
1295   if (IS_MOVING(ux, uy))
1296   {
1297     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1298     boolean cut_mode = NO_CUTTING;
1299
1300     if (Store[ux][uy] == EL_MORAST_LEER ||
1301         Store[ux][uy] == EL_SIEB_LEER ||
1302         Store[ux][uy] == EL_SIEB2_LEER ||
1303         Store[ux][uy] == EL_AMOEBE_NASS)
1304       cut_mode = CUT_ABOVE;
1305     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1306              Store[ux][uy] == EL_SIEB_VOLL ||
1307              Store[ux][uy] == EL_SIEB2_VOLL)
1308       cut_mode = CUT_BELOW;
1309
1310     if (cut_mode == CUT_ABOVE)
1311       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1312     else
1313       DrawScreenElement(x, y, EL_LEERRAUM);
1314
1315     if (horiz_move)
1316       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1317     else
1318       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1319
1320     if (Store[ux][uy] == EL_SALZSAEURE)
1321       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1322   }
1323   else if (IS_BLOCKED(ux, uy))
1324   {
1325     int oldx, oldy;
1326     int sx, sy;
1327     int horiz_move;
1328     boolean cut_mode = NO_CUTTING;
1329
1330     Blocked2Moving(ux, uy, &oldx, &oldy);
1331     sx = SCREENX(oldx);
1332     sy = SCREENY(oldy);
1333     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1334                   MovDir[oldx][oldy] == MV_RIGHT);
1335
1336     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1337         Store[oldx][oldy] == EL_SIEB_LEER ||
1338         Store[oldx][oldy] == EL_SIEB2_LEER ||
1339         Store[oldx][oldy] == EL_AMOEBE_NASS)
1340       cut_mode = CUT_ABOVE;
1341
1342     DrawScreenElement(x, y, EL_LEERRAUM);
1343     element = Feld[oldx][oldy];
1344
1345     if (horiz_move)
1346       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1347     else
1348       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1349   }
1350   else if (IS_DRAWABLE(element))
1351     DrawScreenElement(x, y, element);
1352   else
1353     DrawScreenElement(x, y, EL_LEERRAUM);
1354 }
1355
1356 void DrawLevelField(int x, int y)
1357 {
1358   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1359     DrawScreenField(SCREENX(x), SCREENY(y));
1360   else if (IS_MOVING(x, y))
1361   {
1362     int newx,newy;
1363
1364     Moving2Blocked(x, y, &newx, &newy);
1365     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1366       DrawScreenField(SCREENX(newx), SCREENY(newy));
1367   }
1368   else if (IS_BLOCKED(x, y))
1369   {
1370     int oldx, oldy;
1371
1372     Blocked2Moving(x, y, &oldx, &oldy);
1373     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1374       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1375   }
1376 }
1377
1378 void DrawMiniElement(int x, int y, int element)
1379 {
1380   int graphic;
1381
1382   if (!element)
1383   {
1384     DrawMiniGraphic(x, y, -1);
1385     return;
1386   }
1387
1388   graphic = el2gfx(element);
1389   DrawMiniGraphic(x, y, graphic);
1390 }
1391
1392 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1393 {
1394   int x = sx + scroll_x, y = sy + scroll_y;
1395
1396   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1397     DrawMiniElement(sx, sy, EL_LEERRAUM);
1398   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1399     DrawMiniElement(sx, sy, Feld[x][y]);
1400   else if (x == -1 && y == -1)
1401     DrawMiniGraphic(sx, sy, GFX_STEEL_UPPER_LEFT);
1402   else if (x == lev_fieldx && y == -1)
1403     DrawMiniGraphic(sx, sy, GFX_STEEL_UPPER_RIGHT);
1404   else if (x == -1 && y == lev_fieldy)
1405     DrawMiniGraphic(sx, sy, GFX_STEEL_LOWER_LEFT);
1406   else if (x == lev_fieldx && y == lev_fieldy)
1407     DrawMiniGraphic(sx, sy, GFX_STEEL_LOWER_RIGHT);
1408   else if (x == -1 || x == lev_fieldx)
1409     DrawMiniGraphic(sx, sy, GFX_STEEL_VERTICAL);
1410   else if (y == -1 || y == lev_fieldy)
1411     DrawMiniGraphic(sx, sy, GFX_STEEL_HORIZONTAL);
1412 }
1413
1414 void DrawMicroElement(int xpos, int ypos, int element)
1415 {
1416   int graphic;
1417
1418   if (element == EL_LEERRAUM)
1419     return;
1420
1421   graphic = el2gfx(element);
1422
1423   if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1424   {
1425     graphic -= GFX_START_ROCKSMORE;
1426     XCopyArea(display, pix[PIX_MORE], drawto, gc,
1427               MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
1428               MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
1429               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1430   }
1431   else
1432     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1433               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1434               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1435               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1436 }
1437
1438 void DrawLevel()
1439 {
1440   int x,y;
1441
1442   ClearWindow();
1443
1444   for(x=BX1; x<=BX2; x++)
1445     for(y=BY1; y<=BY2; y++)
1446       DrawScreenField(x, y);
1447
1448   if (setup.soft_scrolling)
1449     XCopyArea(display, fieldbuffer, backbuffer, gc,
1450               FX, FY, SXSIZE, SYSIZE, SX, SY);
1451
1452   redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
1453 }
1454
1455 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1456 {
1457   int x,y;
1458
1459   for(x=0; x<size_x; x++)
1460     for(y=0; y<size_y; y++)
1461       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1462
1463   redraw_mask |= REDRAW_FIELD;
1464 }
1465
1466 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1467 {
1468   int x, y;
1469
1470   /* determine border element for this level */
1471   SetBorderElement();
1472
1473   XFillRectangle(display, drawto, gc,
1474                  xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1475
1476   if (lev_fieldx < STD_LEV_FIELDX)
1477     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1478   if (lev_fieldy < STD_LEV_FIELDY)
1479     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1480
1481   xpos += MICRO_TILEX;
1482   ypos += MICRO_TILEY;
1483
1484   for(x=-1; x<=STD_LEV_FIELDX; x++)
1485   {
1486     for(y=-1; y<=STD_LEV_FIELDY; y++)
1487     {
1488       int lx = from_x + x, ly = from_y + y;
1489
1490       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1491         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1492                          Ur[lx][ly]);
1493       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1494         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1495                          BorderElement);
1496     }
1497   }
1498
1499   redraw_mask |= REDRAW_MICROLEVEL;
1500 }
1501
1502 static void DrawMicroLevelLabelExt(int mode)
1503 {
1504   char label_text[100];
1505
1506   XFillRectangle(display, drawto,gc,
1507                  SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1508
1509   strcpy(label_text, (mode == 1 ? level.name :
1510                       mode == 2 ? "created by" :
1511                       mode == 3 ? level.author : ""));
1512
1513   if (strlen(label_text) > 0)
1514   {
1515     int size, lxpos, lypos;
1516
1517     label_text[SXSIZE / FONT4_XSIZE] = '\0';
1518
1519     size = strlen(label_text);
1520     lxpos = SX + (SXSIZE - size * FONT4_XSIZE) / 2;
1521     lypos = MICROLABEL_YPOS;
1522
1523     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1524   }
1525
1526   redraw_mask |= REDRAW_MICROLEVEL;
1527 }
1528
1529 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1530 {
1531   static unsigned long scroll_delay = 0;
1532   static unsigned long label_delay = 0;
1533   static int from_x, from_y, scroll_direction;
1534   static int label_state, label_counter;
1535
1536   if (restart)
1537   {
1538     from_x = from_y = 0;
1539     scroll_direction = MV_RIGHT;
1540     label_state = 1;
1541     label_counter = 0;
1542
1543     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1544     DrawMicroLevelLabelExt(label_state);
1545
1546     /* initialize delay counters */
1547     DelayReached(&scroll_delay, 0);
1548     DelayReached(&label_delay, 0);
1549
1550     return;
1551   }
1552
1553   /* scroll micro level, if needed */
1554   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1555       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1556   {
1557     switch (scroll_direction)
1558     {
1559       case MV_LEFT:
1560         if (from_x > 0)
1561           from_x--;
1562         else
1563           scroll_direction = MV_UP;
1564         break;
1565
1566       case MV_RIGHT:
1567         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1568           from_x++;
1569         else
1570           scroll_direction = MV_DOWN;
1571         break;
1572
1573       case MV_UP:
1574         if (from_y > 0)
1575           from_y--;
1576         else
1577           scroll_direction = MV_RIGHT;
1578         break;
1579
1580       case MV_DOWN:
1581         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1582           from_y++;
1583         else
1584           scroll_direction = MV_LEFT;
1585         break;
1586
1587       default:
1588         break;
1589     }
1590
1591     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1592   }
1593
1594   /* redraw micro level label, if needed */
1595   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1596       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1597       strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
1598       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1599   {
1600     label_counter = (label_counter + 1) % 23;
1601     label_state = (label_counter >= 0 && label_counter <= 7 ? 1 :
1602                    label_counter >= 9 && label_counter <= 12 ? 2 :
1603                    label_counter >= 14 && label_counter <= 21 ? 3 : 0);
1604     DrawMicroLevelLabelExt(label_state);
1605   }
1606 }
1607
1608 int REQ_in_range(int x, int y)
1609 {
1610   if (y > DY+249 && y < DY+278)
1611   {
1612     if (x > DX+1 && x < DX+48)
1613       return 1;
1614     else if (x > DX+51 && x < DX+98) 
1615       return 2;
1616   }
1617   return 0;
1618 }
1619
1620 boolean Request(char *text, unsigned int req_state)
1621 {
1622   int mx, my, ty, result = -1;
1623   unsigned int old_door_state;
1624
1625 #ifndef MSDOS
1626   /* pause network game while waiting for request to answer */
1627   if (options.network &&
1628       game_status == PLAYING &&
1629       req_state & REQUEST_WAIT_FOR)
1630     SendToServer_PausePlaying();
1631 #endif
1632
1633   old_door_state = GetDoorState();
1634
1635   UnmapAllGadgets();
1636
1637   CloseDoor(DOOR_CLOSE_1);
1638
1639   /* save old door content */
1640   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1641             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1642             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1643
1644   /* clear door drawing field */
1645 #if 0
1646   XFillRectangle(display, pix[PIX_DB_DOOR], gc,
1647                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
1648 #else
1649   XFillRectangle(display, drawto, gc, DX, DY, DXSIZE, DYSIZE);
1650 #endif
1651
1652   /* write text for request */
1653   for(ty=0; ty<13; ty++)
1654   {
1655     int tx, tl, tc;
1656     char txt[256];
1657
1658     if (!*text)
1659       break;
1660
1661     for(tl=0,tx=0; tx<7; tl++,tx++)
1662     {
1663       tc = *(text + tx);
1664       if (!tc || tc == 32)
1665         break;
1666     }
1667     if (!tl)
1668     { 
1669       text++; 
1670       ty--; 
1671       continue; 
1672     }
1673     sprintf(txt, text); 
1674     txt[tl] = 0;
1675 #if 0
1676     DrawTextExt(pix[PIX_DB_DOOR], gc,
1677                 DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
1678                 txt, FS_SMALL, FC_YELLOW);
1679 #else
1680     DrawTextExt(drawto, gc,
1681                 DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
1682                 txt, FS_SMALL, FC_YELLOW);
1683 #endif
1684     text += tl + (tc == 32 ? 1 : 0);
1685   }
1686
1687 #if 0
1688   if (req_state & REQ_ASK)
1689   {
1690     DrawYesNoButton(BUTTON_OK, DB_INIT);
1691     DrawYesNoButton(BUTTON_NO, DB_INIT);
1692   }
1693   else if (req_state & REQ_CONFIRM)
1694   {
1695     DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
1696   }
1697   else if (req_state & REQ_PLAYER)
1698   {
1699     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1700     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1701     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1702     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1703   }
1704 #else
1705
1706   if (req_state & REQ_ASK)
1707   {
1708     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1709     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1710   }
1711   else if (req_state & REQ_CONFIRM)
1712   {
1713     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1714   }
1715   else if (req_state & REQ_PLAYER)
1716   {
1717     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1718     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1719     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1720     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1721   }
1722
1723   /* copy request gadgets to door backbuffer */
1724   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
1725             DX, DY, DXSIZE, DYSIZE,
1726             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1727
1728 #endif
1729
1730   OpenDoor(DOOR_OPEN_1);
1731   ClearEventQueue();
1732
1733   if (!(req_state & REQUEST_WAIT_FOR))
1734     return(FALSE);
1735
1736   if (game_status != MAINMENU)
1737     InitAnimation();
1738
1739   button_status = MB_RELEASED;
1740
1741   request_gadget_id = -1;
1742
1743   while(result < 0)
1744   {
1745     if (XPending(display))
1746     {
1747       XEvent event;
1748
1749       XNextEvent(display, &event);
1750
1751       switch(event.type)
1752       {
1753         case ButtonPress:
1754         case ButtonRelease:
1755         case MotionNotify:
1756         {
1757
1758 #if 0
1759           int choice;
1760 #endif
1761
1762           if (event.type == MotionNotify)
1763           {
1764             Window root, child;
1765             int root_x, root_y;
1766             int win_x, win_y;
1767             unsigned int mask;
1768
1769             if (!XQueryPointer(display, window, &root, &child,
1770                                &root_x, &root_y, &win_x, &win_y, &mask))
1771               continue;
1772
1773             if (!button_status)
1774               continue;
1775
1776             motion_status = TRUE;
1777             mx = ((XMotionEvent *) &event)->x;
1778             my = ((XMotionEvent *) &event)->y;
1779           }
1780           else
1781           {
1782             motion_status = FALSE;
1783             mx = ((XButtonEvent *) &event)->x;
1784             my = ((XButtonEvent *) &event)->y;
1785             if (event.type==ButtonPress)
1786               button_status = ((XButtonEvent *) &event)->button;
1787             else
1788               button_status = MB_RELEASED;
1789           }
1790
1791
1792
1793 #if 0
1794           if (req_state & REQ_ASK)
1795             choice = CheckYesNoButtons(mx,my,button_status);
1796           else if (req_state & REQ_CONFIRM)
1797             choice = CheckConfirmButton(mx,my,button_status);
1798           else
1799             choice = CheckPlayerButtons(mx,my,button_status);
1800
1801           switch(choice)
1802           {
1803             case BUTTON_OK:
1804               result = TRUE;
1805               break;
1806             case BUTTON_NO:
1807               result = FALSE;
1808               break;
1809             case BUTTON_CONFIRM:
1810               result = TRUE | FALSE;
1811               break;
1812
1813             case BUTTON_PLAYER_1:
1814               result = 1;
1815               break;
1816             case BUTTON_PLAYER_2:
1817               result = 2;
1818               break;
1819             case BUTTON_PLAYER_3:
1820               result = 3;
1821               break;
1822             case BUTTON_PLAYER_4:
1823               result = 4;
1824               break;
1825
1826             default:
1827               break;
1828           }
1829 #else
1830
1831           /* this sets 'request_gadget_id' */
1832           HandleGadgets(mx, my, button_status);
1833
1834           switch(request_gadget_id)
1835           {
1836             case TOOL_CTRL_ID_YES:
1837               result = TRUE;
1838               break;
1839             case TOOL_CTRL_ID_NO:
1840               result = FALSE;
1841               break;
1842             case TOOL_CTRL_ID_CONFIRM:
1843               result = TRUE | FALSE;
1844               break;
1845
1846             case TOOL_CTRL_ID_PLAYER_1:
1847               result = 1;
1848               break;
1849             case TOOL_CTRL_ID_PLAYER_2:
1850               result = 2;
1851               break;
1852             case TOOL_CTRL_ID_PLAYER_3:
1853               result = 3;
1854               break;
1855             case TOOL_CTRL_ID_PLAYER_4:
1856               result = 4;
1857               break;
1858
1859             default:
1860               break;
1861           }
1862 #endif
1863
1864           break;
1865         }
1866
1867         case KeyPress:
1868           switch(XLookupKeysym((XKeyEvent *)&event,
1869                                ((XKeyEvent *)&event)->state))
1870           {
1871             case XK_Return:
1872               result = 1;
1873               break;
1874
1875             case XK_Escape:
1876               result = 0;
1877               break;
1878
1879             default:
1880               break;
1881           }
1882           if (req_state & REQ_PLAYER)
1883             result = 0;
1884           break;
1885
1886         case KeyRelease:
1887           key_joystick_mapping = 0;
1888           break;
1889
1890         default:
1891           HandleOtherEvents(&event);
1892           break;
1893       }
1894     }
1895     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1896     {
1897       int joy = AnyJoystick();
1898
1899       if (joy & JOY_BUTTON_1)
1900         result = 1;
1901       else if (joy & JOY_BUTTON_2)
1902         result = 0;
1903     }
1904
1905     DoAnimation();
1906
1907     /* don't eat all CPU time */
1908     Delay(10);
1909   }
1910
1911   if (game_status != MAINMENU)
1912     StopAnimation();
1913
1914   UnmapToolButtons();
1915
1916   if (!(req_state & REQ_STAY_OPEN))
1917   {
1918     CloseDoor(DOOR_CLOSE_1);
1919
1920     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1921     {
1922       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1923                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1924                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1925       OpenDoor(DOOR_OPEN_1);
1926     }
1927   }
1928
1929   RemapAllGadgets();
1930
1931 #ifndef MSDOS
1932   /* continue network game after request */
1933   if (options.network &&
1934       game_status == PLAYING &&
1935       req_state & REQUEST_WAIT_FOR)
1936     SendToServer_ContinuePlaying();
1937 #endif
1938
1939   return(result);
1940 }
1941
1942 unsigned int OpenDoor(unsigned int door_state)
1943 {
1944   unsigned int new_door_state;
1945
1946   if (door_state & DOOR_COPY_BACK)
1947   {
1948     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1949               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1950               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1951     door_state &= ~DOOR_COPY_BACK;
1952   }
1953
1954   new_door_state = MoveDoor(door_state);
1955
1956   return(new_door_state);
1957 }
1958
1959 unsigned int CloseDoor(unsigned int door_state)
1960 {
1961   unsigned int new_door_state;
1962
1963   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1964             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1965   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1966             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1967
1968   new_door_state = MoveDoor(door_state);
1969
1970   return(new_door_state);
1971 }
1972
1973 unsigned int GetDoorState()
1974 {
1975   return(MoveDoor(DOOR_GET_STATE));
1976 }
1977
1978 unsigned int MoveDoor(unsigned int door_state)
1979 {
1980   static int door1 = DOOR_OPEN_1;
1981   static int door2 = DOOR_CLOSE_2;
1982   static unsigned long door_delay = 0;
1983   int x, start, stepsize = 2;
1984   unsigned long door_delay_value = stepsize * 5;
1985
1986   if (door_state == DOOR_GET_STATE)
1987     return(door1 | door2);
1988
1989   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1990     door_state &= ~DOOR_OPEN_1;
1991   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1992     door_state &= ~DOOR_CLOSE_1;
1993   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1994     door_state &= ~DOOR_OPEN_2;
1995   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1996     door_state &= ~DOOR_CLOSE_2;
1997
1998   if (setup.quick_doors)
1999   {
2000     stepsize = 20;
2001     door_delay_value = 0;
2002     StopSound(SND_OEFFNEN);
2003   }
2004
2005   if (door_state & DOOR_ACTION)
2006   {
2007     if (!(door_state & DOOR_NO_DELAY))
2008       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
2009
2010     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2011
2012     for(x=start; x<=DXSIZE; x+=stepsize)
2013     {
2014       WaitUntilDelayReached(&door_delay, door_delay_value);
2015
2016       if (door_state & DOOR_ACTION_1)
2017       {
2018         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2019         int j = (DXSIZE - i) / 3;
2020
2021         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2022                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2023                   DXSIZE,DYSIZE - i/2, DX, DY);
2024
2025         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2026
2027         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2028                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2029         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2030                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
2031         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2032                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
2033                   DY + 140 + j);
2034         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2035                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2036         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2037                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
2038         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2039                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
2040
2041         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2042                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2043                   DX, DY + 77 - j);
2044         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2045                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2046                   DX, DY + 203 - j);
2047         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2048                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2049         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2050                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2051                   DX + DXSIZE - i, DY + 77 + j);
2052         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2053                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2054                   DX + DXSIZE - i, DY + 203 + j);
2055
2056         redraw_mask |= REDRAW_DOOR_1;
2057       }
2058
2059       if (door_state & DOOR_ACTION_2)
2060       {
2061         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2062         int j = (VXSIZE - i) / 3;
2063
2064         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2065                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2066                   VXSIZE, VYSIZE - i/2, VX, VY);
2067
2068         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2069
2070         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2071                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2072         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2073                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
2074         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2075                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2076         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2077                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
2078
2079         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2080                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
2081                   VX, VY + VYSIZE / 2 - j);
2082         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2083                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2084         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2085                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
2086                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2087
2088         redraw_mask |= REDRAW_DOOR_2;
2089       }
2090
2091
2092
2093 #if 1
2094       BackToFront();
2095 #else
2096       XCopyArea(display, drawto, window, gc, DX, DY, DXSIZE, DYSIZE, DX, DY);
2097 #endif
2098
2099
2100
2101       if (game_status == MAINMENU)
2102         DoAnimation();
2103     }
2104   }
2105
2106   if (setup.quick_doors)
2107     StopSound(SND_OEFFNEN);
2108
2109   if (door_state & DOOR_ACTION_1)
2110     door1 = door_state & DOOR_ACTION_1;
2111   if (door_state & DOOR_ACTION_2)
2112     door2 = door_state & DOOR_ACTION_2;
2113
2114   return(door1 | door2);
2115 }
2116
2117 int ReadPixel(Drawable d, int x, int y)
2118 {
2119   XImage *pixel_image;
2120   unsigned long pixel_value;
2121
2122   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
2123   pixel_value = XGetPixel(pixel_image, 0, 0);
2124
2125   XDestroyImage(pixel_image);
2126
2127   return pixel_value;
2128 }
2129
2130 /* ---------- new tool button stuff ---------------------------------------- */
2131
2132 /* graphic position values for tool buttons */
2133 #define TOOL_BUTTON_YES_XPOS            2
2134 #define TOOL_BUTTON_YES_YPOS            250
2135 #define TOOL_BUTTON_YES_GFX_YPOS        0
2136 #define TOOL_BUTTON_YES_XSIZE           46
2137 #define TOOL_BUTTON_YES_YSIZE           28
2138 #define TOOL_BUTTON_NO_XPOS             52
2139 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2140 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2141 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2142 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2143 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2144 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2145 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2146 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2147 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2148 #define TOOL_BUTTON_PLAYER_XSIZE        30
2149 #define TOOL_BUTTON_PLAYER_YSIZE        30
2150 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2151 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2152 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2153 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2154 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2155                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2156 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2157                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2158 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2159                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2160 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2161                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2162 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2163                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2164 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2165                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2166 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2167                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2168 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2169                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2170
2171 static struct
2172 {
2173   int xpos, ypos;
2174   int x, y;
2175   int width, height;
2176   int gadget_id;
2177   char *infotext;
2178 } toolbutton_info[NUM_TOOL_BUTTONS] =
2179 {
2180   {
2181     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2182     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2183     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2184     TOOL_CTRL_ID_YES,
2185     "yes"
2186   },
2187   {
2188     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2189     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2190     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2191     TOOL_CTRL_ID_NO,
2192     "no"
2193   },
2194   {
2195     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2196     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2197     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2198     TOOL_CTRL_ID_CONFIRM,
2199     "confirm"
2200   },
2201   {
2202     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2203     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2204     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2205     TOOL_CTRL_ID_PLAYER_1,
2206     "player 1"
2207   },
2208   {
2209     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2210     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2211     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2212     TOOL_CTRL_ID_PLAYER_2,
2213     "player 2"
2214   },
2215   {
2216     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2217     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2218     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2219     TOOL_CTRL_ID_PLAYER_3,
2220     "player 3"
2221   },
2222   {
2223     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2224     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2225     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2226     TOOL_CTRL_ID_PLAYER_4,
2227     "player 4"
2228   }
2229 };
2230
2231 void CreateToolButtons()
2232 {
2233   int i;
2234
2235   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2236   {
2237     Pixmap gd_pixmap = pix[PIX_DOOR];
2238     Pixmap deco_pixmap = 0;
2239     int deco_x, deco_y, deco_xpos, deco_ypos;
2240     struct GadgetInfo *gi;
2241     unsigned long event_mask;
2242     int gd_xoffset, gd_yoffset;
2243     int gd_x1, gd_x2, gd_y;
2244     int id = i;
2245
2246     event_mask = GD_EVENT_RELEASED;
2247
2248     gd_xoffset = toolbutton_info[i].xpos;
2249     gd_yoffset = toolbutton_info[i].ypos;
2250     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2251     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2252     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2253
2254     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2255     {
2256       getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
2257                            &deco_pixmap, &deco_x, &deco_y);
2258       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2259       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2260     }
2261
2262     gi = CreateGadget(GDI_CUSTOM_ID, id,
2263                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2264                       GDI_X, DX + toolbutton_info[i].x,
2265                       GDI_Y, DY + toolbutton_info[i].y,
2266                       GDI_WIDTH, toolbutton_info[i].width,
2267                       GDI_HEIGHT, toolbutton_info[i].height,
2268                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2269                       GDI_STATE, GD_BUTTON_UNPRESSED,
2270                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
2271                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
2272                       GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
2273                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2274                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2275                       GDI_DECORATION_SHIFTING, 1, 1,
2276                       GDI_EVENT_MASK, event_mask,
2277                       GDI_CALLBACK_ACTION, HandleToolButtons,
2278                       GDI_END);
2279
2280     if (gi == NULL)
2281       Error(ERR_EXIT, "cannot create gadget");
2282
2283     tool_gadget[id] = gi;
2284   }
2285 }
2286
2287 static void UnmapToolButtons()
2288 {
2289   int i;
2290
2291   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2292     UnmapGadget(tool_gadget[i]);
2293 }
2294
2295 static void HandleToolButtons(struct GadgetInfo *gi)
2296 {
2297   request_gadget_id = gi->custom_id;
2298
2299
2300 #if 0
2301   int id = gi->custom_id;
2302
2303   if (game_status != PLAYING)
2304     return;
2305
2306   switch (id)
2307   {
2308     case GAME_CTRL_ID_STOP:
2309       if (AllPlayersGone)
2310       {
2311         CloseDoor(DOOR_CLOSE_1);
2312         game_status = MAINMENU;
2313         DrawMainMenu();
2314         break;
2315       }
2316
2317       if (Request("Do you really want to quit the game ?",
2318                   REQ_ASK | REQ_STAY_CLOSED))
2319       { 
2320 #ifndef MSDOS
2321         if (options.network)
2322           SendToServer_StopPlaying();
2323         else
2324 #endif
2325         {
2326           game_status = MAINMENU;
2327           DrawMainMenu();
2328         }
2329       }
2330       else
2331         OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2332       break;
2333
2334     case GAME_CTRL_ID_PAUSE:
2335       if (options.network)
2336       {
2337 #ifndef MSDOS
2338         if (tape.pausing)
2339           SendToServer_ContinuePlaying();
2340         else
2341           SendToServer_PausePlaying();
2342 #endif
2343       }
2344       else
2345         TapeTogglePause();
2346       break;
2347
2348     case GAME_CTRL_ID_PLAY:
2349       if (tape.pausing)
2350       {
2351 #ifndef MSDOS
2352         if (options.network)
2353           SendToServer_ContinuePlaying();
2354         else
2355 #endif
2356         {
2357           tape.pausing = FALSE;
2358           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
2359         }
2360       }
2361       break;
2362
2363     case SOUND_CTRL_ID_MUSIC:
2364       if (setup.sound_music)
2365       { 
2366         setup.sound_music = FALSE;
2367         FadeSound(background_loop[level_nr % num_bg_loops]);
2368       }
2369       else if (sound_loops_allowed)
2370       { 
2371         setup.sound = setup.sound_music = TRUE;
2372         PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
2373       }
2374       break;
2375
2376     case SOUND_CTRL_ID_LOOPS:
2377       if (setup.sound_loops)
2378         setup.sound_loops = FALSE;
2379       else if (sound_loops_allowed)
2380         setup.sound = setup.sound_loops = TRUE;
2381       break;
2382
2383     case SOUND_CTRL_ID_SIMPLE:
2384       if (setup.sound_simple)
2385         setup.sound_simple = FALSE;
2386       else if (sound_status==SOUND_AVAILABLE)
2387         setup.sound = setup.sound_simple = TRUE;
2388       break;
2389
2390     default:
2391       break;
2392   }
2393 #endif
2394
2395
2396
2397 }
2398
2399 int el2gfx(int element)
2400 {
2401   switch(element)
2402   {
2403     case EL_LEERRAUM:           return -1;
2404     case EL_ERDREICH:           return GFX_ERDREICH;
2405     case EL_MAUERWERK:          return GFX_MAUERWERK;
2406     case EL_FELSBODEN:          return GFX_FELSBODEN;
2407     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
2408     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
2409     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
2410     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
2411     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
2412     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
2413     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
2414     case EL_SPIELER1:           return GFX_SPIELER1;
2415     case EL_SPIELER2:           return GFX_SPIELER2;
2416     case EL_SPIELER3:           return GFX_SPIELER3;
2417     case EL_SPIELER4:           return GFX_SPIELER4;
2418     case EL_KAEFER:             return GFX_KAEFER;
2419     case EL_KAEFER_R:           return GFX_KAEFER_R;
2420     case EL_KAEFER_O:           return GFX_KAEFER_O;
2421     case EL_KAEFER_L:           return GFX_KAEFER_L;
2422     case EL_KAEFER_U:           return GFX_KAEFER_U;
2423     case EL_FLIEGER:            return GFX_FLIEGER;
2424     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
2425     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
2426     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
2427     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
2428     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
2429     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
2430     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
2431     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
2432     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
2433     case EL_FIREFLY:            return GFX_FIREFLY;
2434     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
2435     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
2436     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
2437     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
2438     case EL_MAMPFER:            return GFX_MAMPFER;
2439     case EL_ROBOT:              return GFX_ROBOT;
2440     case EL_BETON:              return GFX_BETON;
2441     case EL_DIAMANT:            return GFX_DIAMANT;
2442     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2443     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2444     case EL_TROPFEN:            return GFX_TROPFEN;
2445     case EL_BOMBE:              return GFX_BOMBE;
2446     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
2447     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
2448     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
2449     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
2450     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2451     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2452     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2453     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2454     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2455     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2456     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2457     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2458     case EL_LIFE:               return GFX_LIFE;
2459     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2460     case EL_DYNAMIT:            return GFX_DYNAMIT;
2461     case EL_BADEWANNE:          return GFX_BADEWANNE;
2462     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2463     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2464     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2465     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2466     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2467     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2468     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2469     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2470     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2471     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2472     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2473     case EL_PFORTE1:            return GFX_PFORTE1;
2474     case EL_PFORTE2:            return GFX_PFORTE2;
2475     case EL_PFORTE3:            return GFX_PFORTE3;
2476     case EL_PFORTE4:            return GFX_PFORTE4;
2477     case EL_PFORTE1X:           return GFX_PFORTE1X;
2478     case EL_PFORTE2X:           return GFX_PFORTE2X;
2479     case EL_PFORTE3X:           return GFX_PFORTE3X;
2480     case EL_PFORTE4X:           return GFX_PFORTE4X;
2481     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
2482     case EL_PACMAN:             return GFX_PACMAN;
2483     case EL_PACMAN_R:           return GFX_PACMAN_R;
2484     case EL_PACMAN_O:           return GFX_PACMAN_O;
2485     case EL_PACMAN_L:           return GFX_PACMAN_L;
2486     case EL_PACMAN_U:           return GFX_PACMAN_U;
2487     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2488     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2489     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2490     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2491     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2492     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2493     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2494     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2495     case EL_MAUER_X:            return GFX_MAUER_X;
2496     case EL_MAUER_Y:            return GFX_MAUER_Y;
2497     case EL_MAUER_XY:           return GFX_MAUER_XY;
2498     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2499     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2500     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2501     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2502     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2503     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2504     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2505     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2506     case EL_MAMPFER2:           return GFX_MAMPFER2;
2507     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
2508     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
2509     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
2510     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
2511     case EL_DYNABOMB:           return GFX_DYNABOMB;
2512     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2513     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2514     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2515     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2516     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2517     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2518     case EL_MAULWURF:           return GFX_MAULWURF;
2519     case EL_PINGUIN:            return GFX_PINGUIN;
2520     case EL_SCHWEIN:            return GFX_SCHWEIN;
2521     case EL_DRACHE:             return GFX_DRACHE;
2522     case EL_SONDE:              return GFX_SONDE;
2523     case EL_PFEIL_L:            return GFX_PFEIL_L;
2524     case EL_PFEIL_R:            return GFX_PFEIL_R;
2525     case EL_PFEIL_O:            return GFX_PFEIL_O;
2526     case EL_PFEIL_U:            return GFX_PFEIL_U;
2527     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2528     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2529     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2530     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2531
2532     default:
2533     {
2534       if (IS_CHAR(element))
2535         return GFX_CHAR_START + (element - EL_CHAR_START);
2536       else if (element >= EL_SP_START && element <= EL_SP_END)
2537       {
2538         int nr_element = element - EL_SP_START;
2539         int gfx_per_line = 8;
2540         int nr_graphic =
2541           (nr_element / gfx_per_line) * MORE_PER_LINE +
2542           (nr_element % gfx_per_line);
2543
2544         return GFX_START_ROCKSMORE + nr_graphic;
2545       }
2546       else
2547         return -1;
2548     }
2549   }
2550 }