rnd-19990214-3
[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 #if 0
1866   XFillRectangle(display, pix[PIX_DB_DOOR], gc,
1867                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
1868 #else
1869   XFillRectangle(display, drawto, gc, DX, DY, DXSIZE, DYSIZE);
1870 #endif
1871
1872   /* write text for request */
1873   for(ty=0; ty<13; ty++)
1874   {
1875     int tx, tl, tc;
1876     char txt[256];
1877
1878     if (!*text)
1879       break;
1880
1881     for(tl=0,tx=0; tx<7; tl++,tx++)
1882     {
1883       tc = *(text + tx);
1884       if (!tc || tc == 32)
1885         break;
1886     }
1887     if (!tl)
1888     { 
1889       text++; 
1890       ty--; 
1891       continue; 
1892     }
1893     sprintf(txt, text); 
1894     txt[tl] = 0;
1895 #if 0
1896     DrawTextExt(pix[PIX_DB_DOOR], gc,
1897                 DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
1898                 txt, FS_SMALL, FC_YELLOW);
1899 #else
1900     DrawTextExt(drawto, gc,
1901                 DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
1902                 txt, FS_SMALL, FC_YELLOW);
1903 #endif
1904     text += tl + (tc == 32 ? 1 : 0);
1905   }
1906
1907 #if 0
1908   if (req_state & REQ_ASK)
1909   {
1910     DrawYesNoButton(BUTTON_OK, DB_INIT);
1911     DrawYesNoButton(BUTTON_NO, DB_INIT);
1912   }
1913   else if (req_state & REQ_CONFIRM)
1914   {
1915     DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
1916   }
1917   else if (req_state & REQ_PLAYER)
1918   {
1919     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1920     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1921     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1922     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1923   }
1924 #else
1925
1926   if (req_state & REQ_ASK)
1927   {
1928     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1929     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1930   }
1931   else if (req_state & REQ_CONFIRM)
1932   {
1933     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1934   }
1935   else if (req_state & REQ_PLAYER)
1936   {
1937     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1938     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1939     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1940     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1941   }
1942
1943   /* copy request gadgets to door backbuffer */
1944   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
1945             DX, DY, DXSIZE, DYSIZE,
1946             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1947
1948 #endif
1949
1950   OpenDoor(DOOR_OPEN_1);
1951   ClearEventQueue();
1952
1953   if (!(req_state & REQUEST_WAIT_FOR))
1954     return(FALSE);
1955
1956   if (game_status != MAINMENU)
1957     InitAnimation();
1958
1959   button_status = MB_RELEASED;
1960
1961   request_gadget_id = -1;
1962
1963   while(result < 0)
1964   {
1965     if (XPending(display))
1966     {
1967       XEvent event;
1968
1969       XNextEvent(display, &event);
1970
1971       switch(event.type)
1972       {
1973         case ButtonPress:
1974         case ButtonRelease:
1975         case MotionNotify:
1976         {
1977
1978 #if 0
1979           int choice;
1980 #endif
1981
1982           if (event.type == MotionNotify)
1983           {
1984             Window root, child;
1985             int root_x, root_y;
1986             int win_x, win_y;
1987             unsigned int mask;
1988
1989             if (!XQueryPointer(display, window, &root, &child,
1990                                &root_x, &root_y, &win_x, &win_y, &mask))
1991               continue;
1992
1993             if (!button_status)
1994               continue;
1995
1996             motion_status = TRUE;
1997             mx = ((XMotionEvent *) &event)->x;
1998             my = ((XMotionEvent *) &event)->y;
1999           }
2000           else
2001           {
2002             motion_status = FALSE;
2003             mx = ((XButtonEvent *) &event)->x;
2004             my = ((XButtonEvent *) &event)->y;
2005             if (event.type==ButtonPress)
2006               button_status = ((XButtonEvent *) &event)->button;
2007             else
2008               button_status = MB_RELEASED;
2009           }
2010
2011
2012
2013 #if 0
2014           if (req_state & REQ_ASK)
2015             choice = CheckYesNoButtons(mx,my,button_status);
2016           else if (req_state & REQ_CONFIRM)
2017             choice = CheckConfirmButton(mx,my,button_status);
2018           else
2019             choice = CheckPlayerButtons(mx,my,button_status);
2020
2021           switch(choice)
2022           {
2023             case BUTTON_OK:
2024               result = TRUE;
2025               break;
2026             case BUTTON_NO:
2027               result = FALSE;
2028               break;
2029             case BUTTON_CONFIRM:
2030               result = TRUE | FALSE;
2031               break;
2032
2033             case BUTTON_PLAYER_1:
2034               result = 1;
2035               break;
2036             case BUTTON_PLAYER_2:
2037               result = 2;
2038               break;
2039             case BUTTON_PLAYER_3:
2040               result = 3;
2041               break;
2042             case BUTTON_PLAYER_4:
2043               result = 4;
2044               break;
2045
2046             default:
2047               break;
2048           }
2049 #else
2050
2051           /* this sets 'request_gadget_id' */
2052           HandleGadgets(mx, my, button_status);
2053
2054           switch(request_gadget_id)
2055           {
2056             case TOOL_CTRL_ID_YES:
2057               result = TRUE;
2058               break;
2059             case TOOL_CTRL_ID_NO:
2060               result = FALSE;
2061               break;
2062             case TOOL_CTRL_ID_CONFIRM:
2063               result = TRUE | FALSE;
2064               break;
2065
2066             case TOOL_CTRL_ID_PLAYER_1:
2067               result = 1;
2068               break;
2069             case TOOL_CTRL_ID_PLAYER_2:
2070               result = 2;
2071               break;
2072             case TOOL_CTRL_ID_PLAYER_3:
2073               result = 3;
2074               break;
2075             case TOOL_CTRL_ID_PLAYER_4:
2076               result = 4;
2077               break;
2078
2079             default:
2080               break;
2081           }
2082 #endif
2083
2084           break;
2085         }
2086
2087         case KeyPress:
2088           switch(XLookupKeysym((XKeyEvent *)&event,
2089                                ((XKeyEvent *)&event)->state))
2090           {
2091             case XK_Return:
2092               result = 1;
2093               break;
2094
2095             case XK_Escape:
2096               result = 0;
2097               break;
2098
2099             default:
2100               break;
2101           }
2102           if (req_state & REQ_PLAYER)
2103             result = 0;
2104           break;
2105
2106         case KeyRelease:
2107           key_joystick_mapping = 0;
2108           break;
2109
2110         default:
2111           HandleOtherEvents(&event);
2112           break;
2113       }
2114     }
2115     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2116     {
2117       int joy = AnyJoystick();
2118
2119       if (joy & JOY_BUTTON_1)
2120         result = 1;
2121       else if (joy & JOY_BUTTON_2)
2122         result = 0;
2123     }
2124
2125     DoAnimation();
2126
2127     /* don't eat all CPU time */
2128     Delay(10);
2129   }
2130
2131   if (game_status != MAINMENU)
2132     StopAnimation();
2133
2134   UnmapToolButtons();
2135
2136   if (!(req_state & REQ_STAY_OPEN))
2137   {
2138     CloseDoor(DOOR_CLOSE_1);
2139
2140     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2141     {
2142       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
2143                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2144                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2145       OpenDoor(DOOR_OPEN_1);
2146     }
2147   }
2148
2149   RemapAllGadgets();
2150
2151 #ifndef MSDOS
2152   /* continue network game after request */
2153   if (options.network &&
2154       game_status == PLAYING &&
2155       req_state & REQUEST_WAIT_FOR)
2156     SendToServer_ContinuePlaying();
2157 #endif
2158
2159   return(result);
2160 }
2161
2162 unsigned int OpenDoor(unsigned int door_state)
2163 {
2164   unsigned int new_door_state;
2165
2166   if (door_state & DOOR_COPY_BACK)
2167   {
2168     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
2169               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2170               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2171     door_state &= ~DOOR_COPY_BACK;
2172   }
2173
2174   new_door_state = MoveDoor(door_state);
2175
2176   return(new_door_state);
2177 }
2178
2179 unsigned int CloseDoor(unsigned int door_state)
2180 {
2181   unsigned int new_door_state;
2182
2183   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
2184             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2185   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
2186             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2187
2188   new_door_state = MoveDoor(door_state);
2189
2190   return(new_door_state);
2191 }
2192
2193 unsigned int GetDoorState()
2194 {
2195   return(MoveDoor(DOOR_GET_STATE));
2196 }
2197
2198 unsigned int MoveDoor(unsigned int door_state)
2199 {
2200   static int door1 = DOOR_OPEN_1;
2201   static int door2 = DOOR_CLOSE_2;
2202   static unsigned long door_delay = 0;
2203   int x, start, stepsize = 2;
2204   unsigned long door_delay_value = stepsize * 5;
2205
2206   if (door_state == DOOR_GET_STATE)
2207     return(door1 | door2);
2208
2209   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2210     door_state &= ~DOOR_OPEN_1;
2211   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2212     door_state &= ~DOOR_CLOSE_1;
2213   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2214     door_state &= ~DOOR_OPEN_2;
2215   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2216     door_state &= ~DOOR_CLOSE_2;
2217
2218   if (setup.quick_doors)
2219   {
2220     stepsize = 20;
2221     door_delay_value = 0;
2222     StopSound(SND_OEFFNEN);
2223   }
2224
2225   if (door_state & DOOR_ACTION)
2226   {
2227     if (!(door_state & DOOR_NO_DELAY))
2228       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
2229
2230     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2231
2232     for(x=start; x<=DXSIZE; x+=stepsize)
2233     {
2234       WaitUntilDelayReached(&door_delay, door_delay_value);
2235
2236       if (door_state & DOOR_ACTION_1)
2237       {
2238         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2239         int j = (DXSIZE - i) / 3;
2240
2241         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2242                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2243                   DXSIZE,DYSIZE - i/2, DX, DY);
2244
2245         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2246
2247         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2248                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2249         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2250                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
2251         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2252                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
2253                   DY + 140 + j);
2254         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2255                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2256         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2257                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
2258         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2259                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
2260
2261         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2262                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2263                   DX, DY + 77 - j);
2264         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2265                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2266                   DX, DY + 203 - j);
2267         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2268                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2269         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2270                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2271                   DX + DXSIZE - i, DY + 77 + j);
2272         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2273                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2274                   DX + DXSIZE - i, DY + 203 + j);
2275
2276         redraw_mask |= REDRAW_DOOR_1;
2277       }
2278
2279       if (door_state & DOOR_ACTION_2)
2280       {
2281         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2282         int j = (VXSIZE - i) / 3;
2283
2284         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2285                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2286                   VXSIZE, VYSIZE - i/2, VX, VY);
2287
2288         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2289
2290         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2291                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2292         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2293                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
2294         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2295                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2296         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2297                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
2298
2299         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2300                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
2301                   VX, VY + VYSIZE / 2 - j);
2302         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2303                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2304         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2305                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
2306                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2307
2308         redraw_mask |= REDRAW_DOOR_2;
2309       }
2310
2311
2312
2313 #if 1
2314       BackToFront();
2315 #else
2316       XCopyArea(display, drawto, window, gc, DX, DY, DXSIZE, DYSIZE, DX, DY);
2317 #endif
2318
2319
2320
2321       if (game_status == MAINMENU)
2322         DoAnimation();
2323     }
2324   }
2325
2326   if (setup.quick_doors)
2327     StopSound(SND_OEFFNEN);
2328
2329   if (door_state & DOOR_ACTION_1)
2330     door1 = door_state & DOOR_ACTION_1;
2331   if (door_state & DOOR_ACTION_2)
2332     door2 = door_state & DOOR_ACTION_2;
2333
2334   return(door1 | door2);
2335 }
2336
2337 int ReadPixel(Drawable d, int x, int y)
2338 {
2339   XImage *pixel_image;
2340   unsigned long pixel_value;
2341
2342   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
2343   pixel_value = XGetPixel(pixel_image, 0, 0);
2344
2345   XDestroyImage(pixel_image);
2346
2347   return pixel_value;
2348 }
2349
2350 /* ---------- new tool button stuff ---------------------------------------- */
2351
2352 /* graphic position values for tool buttons */
2353 #define TOOL_BUTTON_YES_XPOS            2
2354 #define TOOL_BUTTON_YES_YPOS            250
2355 #define TOOL_BUTTON_YES_GFX_YPOS        0
2356 #define TOOL_BUTTON_YES_XSIZE           46
2357 #define TOOL_BUTTON_YES_YSIZE           28
2358 #define TOOL_BUTTON_NO_XPOS             52
2359 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2360 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2361 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2362 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2363 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2364 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2365 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2366 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2367 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2368 #define TOOL_BUTTON_PLAYER_XSIZE        30
2369 #define TOOL_BUTTON_PLAYER_YSIZE        30
2370 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2371 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2372 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2373 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2374 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2375                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2376 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2377                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2378 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2379                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2380 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2381                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2382 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2383                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2384 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2385                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2386 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2387                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2388 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2389                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2390
2391 static struct
2392 {
2393   int xpos, ypos;
2394   int x, y;
2395   int width, height;
2396   int gadget_id;
2397   char *infotext;
2398 } toolbutton_info[NUM_TOOL_BUTTONS] =
2399 {
2400   {
2401     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2402     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2403     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2404     TOOL_CTRL_ID_YES,
2405     "yes"
2406   },
2407   {
2408     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2409     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2410     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2411     TOOL_CTRL_ID_NO,
2412     "no"
2413   },
2414   {
2415     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2416     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2417     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2418     TOOL_CTRL_ID_CONFIRM,
2419     "confirm"
2420   },
2421   {
2422     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2423     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2424     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2425     TOOL_CTRL_ID_PLAYER_1,
2426     "player 1"
2427   },
2428   {
2429     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2430     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2431     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2432     TOOL_CTRL_ID_PLAYER_2,
2433     "player 2"
2434   },
2435   {
2436     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2437     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2438     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2439     TOOL_CTRL_ID_PLAYER_3,
2440     "player 3"
2441   },
2442   {
2443     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2444     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2445     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2446     TOOL_CTRL_ID_PLAYER_4,
2447     "player 4"
2448   }
2449 };
2450
2451 void CreateToolButtons()
2452 {
2453   int i;
2454
2455   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2456   {
2457     Pixmap gd_pixmap = pix[PIX_DOOR];
2458     Pixmap deco_pixmap = None;
2459     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2460     struct GadgetInfo *gi;
2461     unsigned long event_mask;
2462     int gd_xoffset, gd_yoffset;
2463     int gd_x1, gd_x2, gd_y;
2464     int id = i;
2465
2466     event_mask = GD_EVENT_RELEASED;
2467
2468     gd_xoffset = toolbutton_info[i].xpos;
2469     gd_yoffset = toolbutton_info[i].ypos;
2470     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2471     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2472     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2473
2474     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2475     {
2476       getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
2477                            &deco_pixmap, &deco_x, &deco_y);
2478       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2479       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2480     }
2481
2482     gi = CreateGadget(GDI_CUSTOM_ID, id,
2483                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2484                       GDI_X, DX + toolbutton_info[i].x,
2485                       GDI_Y, DY + toolbutton_info[i].y,
2486                       GDI_WIDTH, toolbutton_info[i].width,
2487                       GDI_HEIGHT, toolbutton_info[i].height,
2488                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2489                       GDI_STATE, GD_BUTTON_UNPRESSED,
2490                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
2491                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
2492                       GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
2493                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2494                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2495                       GDI_DECORATION_SHIFTING, 1, 1,
2496                       GDI_EVENT_MASK, event_mask,
2497                       GDI_CALLBACK_ACTION, HandleToolButtons,
2498                       GDI_END);
2499
2500     if (gi == NULL)
2501       Error(ERR_EXIT, "cannot create gadget");
2502
2503     tool_gadget[id] = gi;
2504   }
2505 }
2506
2507 static void UnmapToolButtons()
2508 {
2509   int i;
2510
2511   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2512     UnmapGadget(tool_gadget[i]);
2513 }
2514
2515 static void HandleToolButtons(struct GadgetInfo *gi)
2516 {
2517   request_gadget_id = gi->custom_id;
2518
2519
2520 #if 0
2521   int id = gi->custom_id;
2522
2523   if (game_status != PLAYING)
2524     return;
2525
2526   switch (id)
2527   {
2528     case GAME_CTRL_ID_STOP:
2529       if (AllPlayersGone)
2530       {
2531         CloseDoor(DOOR_CLOSE_1);
2532         game_status = MAINMENU;
2533         DrawMainMenu();
2534         break;
2535       }
2536
2537       if (Request("Do you really want to quit the game ?",
2538                   REQ_ASK | REQ_STAY_CLOSED))
2539       { 
2540 #ifndef MSDOS
2541         if (options.network)
2542           SendToServer_StopPlaying();
2543         else
2544 #endif
2545         {
2546           game_status = MAINMENU;
2547           DrawMainMenu();
2548         }
2549       }
2550       else
2551         OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2552       break;
2553
2554     case GAME_CTRL_ID_PAUSE:
2555       if (options.network)
2556       {
2557 #ifndef MSDOS
2558         if (tape.pausing)
2559           SendToServer_ContinuePlaying();
2560         else
2561           SendToServer_PausePlaying();
2562 #endif
2563       }
2564       else
2565         TapeTogglePause();
2566       break;
2567
2568     case GAME_CTRL_ID_PLAY:
2569       if (tape.pausing)
2570       {
2571 #ifndef MSDOS
2572         if (options.network)
2573           SendToServer_ContinuePlaying();
2574         else
2575 #endif
2576         {
2577           tape.pausing = FALSE;
2578           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
2579         }
2580       }
2581       break;
2582
2583     case SOUND_CTRL_ID_MUSIC:
2584       if (setup.sound_music)
2585       { 
2586         setup.sound_music = FALSE;
2587         FadeSound(background_loop[level_nr % num_bg_loops]);
2588       }
2589       else if (sound_loops_allowed)
2590       { 
2591         setup.sound = setup.sound_music = TRUE;
2592         PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
2593       }
2594       break;
2595
2596     case SOUND_CTRL_ID_LOOPS:
2597       if (setup.sound_loops)
2598         setup.sound_loops = FALSE;
2599       else if (sound_loops_allowed)
2600         setup.sound = setup.sound_loops = TRUE;
2601       break;
2602
2603     case SOUND_CTRL_ID_SIMPLE:
2604       if (setup.sound_simple)
2605         setup.sound_simple = FALSE;
2606       else if (sound_status==SOUND_AVAILABLE)
2607         setup.sound = setup.sound_simple = TRUE;
2608       break;
2609
2610     default:
2611       break;
2612   }
2613 #endif
2614
2615
2616
2617 }
2618
2619 int el2gfx(int element)
2620 {
2621   switch(element)
2622   {
2623     case EL_LEERRAUM:           return -1;
2624     case EL_ERDREICH:           return GFX_ERDREICH;
2625     case EL_MAUERWERK:          return GFX_MAUERWERK;
2626     case EL_FELSBODEN:          return GFX_FELSBODEN;
2627     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
2628     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
2629     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
2630     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
2631     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
2632     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
2633     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
2634     case EL_SPIELER1:           return GFX_SPIELER1;
2635     case EL_SPIELER2:           return GFX_SPIELER2;
2636     case EL_SPIELER3:           return GFX_SPIELER3;
2637     case EL_SPIELER4:           return GFX_SPIELER4;
2638     case EL_KAEFER:             return GFX_KAEFER;
2639     case EL_KAEFER_R:           return GFX_KAEFER_R;
2640     case EL_KAEFER_O:           return GFX_KAEFER_O;
2641     case EL_KAEFER_L:           return GFX_KAEFER_L;
2642     case EL_KAEFER_U:           return GFX_KAEFER_U;
2643     case EL_FLIEGER:            return GFX_FLIEGER;
2644     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
2645     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
2646     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
2647     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
2648     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
2649     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
2650     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
2651     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
2652     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
2653     case EL_FIREFLY:            return GFX_FIREFLY;
2654     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
2655     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
2656     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
2657     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
2658     case EL_MAMPFER:            return GFX_MAMPFER;
2659     case EL_ROBOT:              return GFX_ROBOT;
2660     case EL_BETON:              return GFX_BETON;
2661     case EL_DIAMANT:            return GFX_DIAMANT;
2662     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2663     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2664     case EL_TROPFEN:            return GFX_TROPFEN;
2665     case EL_BOMBE:              return GFX_BOMBE;
2666     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
2667     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
2668     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
2669     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
2670     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2671     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2672     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2673     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2674     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2675     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2676     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2677     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2678     case EL_LIFE:               return GFX_LIFE;
2679     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2680     case EL_DYNAMIT:            return GFX_DYNAMIT;
2681     case EL_BADEWANNE:          return GFX_BADEWANNE;
2682     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2683     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2684     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2685     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2686     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2687     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2688     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2689     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2690     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2691     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2692     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2693     case EL_PFORTE1:            return GFX_PFORTE1;
2694     case EL_PFORTE2:            return GFX_PFORTE2;
2695     case EL_PFORTE3:            return GFX_PFORTE3;
2696     case EL_PFORTE4:            return GFX_PFORTE4;
2697     case EL_PFORTE1X:           return GFX_PFORTE1X;
2698     case EL_PFORTE2X:           return GFX_PFORTE2X;
2699     case EL_PFORTE3X:           return GFX_PFORTE3X;
2700     case EL_PFORTE4X:           return GFX_PFORTE4X;
2701     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
2702     case EL_PACMAN:             return GFX_PACMAN;
2703     case EL_PACMAN_R:           return GFX_PACMAN_R;
2704     case EL_PACMAN_O:           return GFX_PACMAN_O;
2705     case EL_PACMAN_L:           return GFX_PACMAN_L;
2706     case EL_PACMAN_U:           return GFX_PACMAN_U;
2707     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2708     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2709     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2710     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2711     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2712     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2713     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2714     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2715     case EL_MAUER_X:            return GFX_MAUER_X;
2716     case EL_MAUER_Y:            return GFX_MAUER_Y;
2717     case EL_MAUER_XY:           return GFX_MAUER_XY;
2718     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2719     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2720     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2721     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2722     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2723     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2724     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2725     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2726     case EL_MAMPFER2:           return GFX_MAMPFER2;
2727     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
2728     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
2729     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
2730     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
2731     case EL_DYNABOMB:           return GFX_DYNABOMB;
2732     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2733     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2734     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2735     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2736     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2737     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2738     case EL_MAULWURF:           return GFX_MAULWURF;
2739     case EL_PINGUIN:            return GFX_PINGUIN;
2740     case EL_SCHWEIN:            return GFX_SCHWEIN;
2741     case EL_DRACHE:             return GFX_DRACHE;
2742     case EL_SONDE:              return GFX_SONDE;
2743     case EL_PFEIL_L:            return GFX_PFEIL_L;
2744     case EL_PFEIL_R:            return GFX_PFEIL_R;
2745     case EL_PFEIL_O:            return GFX_PFEIL_O;
2746     case EL_PFEIL_U:            return GFX_PFEIL_U;
2747     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2748     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2749     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2750     case EL_SP_ZONK:            return GFX_SP_ZONK;
2751       /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2752     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2753     case EL_BLACK_ORB:          return GFX_BLACK_ORB;
2754     case EL_EM_GATE_1:          return GFX_EM_GATE_1;
2755     case EL_EM_GATE_2:          return GFX_EM_GATE_2;
2756     case EL_EM_GATE_3:          return GFX_EM_GATE_3;
2757     case EL_EM_GATE_4:          return GFX_EM_GATE_4;
2758     case EL_EM_GATE_1X:         return GFX_EM_GATE_1X;
2759     case EL_EM_GATE_2X:         return GFX_EM_GATE_2X;
2760     case EL_EM_GATE_3X:         return GFX_EM_GATE_3X;
2761     case EL_EM_GATE_4X:         return GFX_EM_GATE_4X;
2762     case EL_EM_KEY_1_FILE:      return GFX_EM_KEY_1;
2763     case EL_EM_KEY_2_FILE:      return GFX_EM_KEY_2;
2764     case EL_EM_KEY_3_FILE:      return GFX_EM_KEY_3;
2765     case EL_EM_KEY_4_FILE:      return GFX_EM_KEY_4;
2766     case EL_EM_KEY_1:           return GFX_EM_KEY_1;
2767     case EL_EM_KEY_2:           return GFX_EM_KEY_2;
2768     case EL_EM_KEY_3:           return GFX_EM_KEY_3;
2769     case EL_EM_KEY_4:           return GFX_EM_KEY_4;
2770
2771     default:
2772     {
2773       if (IS_CHAR(element))
2774         return GFX_CHAR_START + (element - EL_CHAR_START);
2775       else if (element >= EL_SP_START && element <= EL_SP_END)
2776       {
2777         int nr_element = element - EL_SP_START;
2778         int gfx_per_line = 8;
2779         int nr_graphic =
2780           (nr_element / gfx_per_line) * MORE_PER_LINE +
2781           (nr_element % gfx_per_line);
2782
2783         return GFX_START_ROCKSMORE + nr_graphic;
2784       }
2785       else
2786         return -1;
2787     }
2788   }
2789 }