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