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