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