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