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