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