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