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