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