rnd-20030111-2-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "tools.h"
17 #include "game.h"
18 #include "events.h"
19 #include "cartoons.h"
20 #include "network.h"
21 #include "tape.h"
22
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES        0
25 #define TOOL_CTRL_ID_NO         1
26 #define TOOL_CTRL_ID_CONFIRM    2
27 #define TOOL_CTRL_ID_PLAYER_1   3
28 #define TOOL_CTRL_ID_PLAYER_2   4
29 #define TOOL_CTRL_ID_PLAYER_3   5
30 #define TOOL_CTRL_ID_PLAYER_4   6
31
32 #define NUM_TOOL_BUTTONS        7
33
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
37
38 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
39 static int request_gadget_id = -1;
40
41 void SetDrawtoField(int mode)
42 {
43   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
44   {
45     FX = TILEX;
46     FY = TILEY;
47     BX1 = -1;
48     BY1 = -1;
49     BX2 = SCR_FIELDX;
50     BY2 = SCR_FIELDY;
51     redraw_x1 = 1;
52     redraw_y1 = 1;
53
54     drawto_field = fieldbuffer;
55   }
56   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
57   {
58     FX = SX;
59     FY = SY;
60     BX1 = 0;
61     BY1 = 0;
62     BX2 = SCR_FIELDX - 1;
63     BY2 = SCR_FIELDY - 1;
64     redraw_x1 = 0;
65     redraw_y1 = 0;
66
67     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
68   }
69 }
70
71 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
72 {
73   if (game_status == PLAYING)
74   {
75     if (force_redraw)
76     {
77       x = gfx.sx - TILEX;
78       y = gfx.sy - TILEY;
79       width = gfx.sxsize + 2 * TILEX;
80       height = gfx.sysize + 2 * TILEY;
81     }
82
83     if (force_redraw || setup.direct_draw)
84     {
85       int xx, yy;
86       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
87       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
88
89       if (setup.direct_draw)
90         SetDrawtoField(DRAW_BACKBUFFER);
91
92       for(xx=BX1; xx<=BX2; xx++)
93         for(yy=BY1; yy<=BY2; yy++)
94           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
95             DrawScreenField(xx, yy);
96       DrawAllPlayers();
97
98       if (setup.direct_draw)
99         SetDrawtoField(DRAW_DIRECT);
100     }
101
102     if (setup.soft_scrolling)
103     {
104       int fx = FX, fy = FY;
105
106       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
107       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
108
109       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
110     }
111   }
112
113   BlitBitmap(drawto, window, x, y, width, height, x, y);
114 }
115
116 void BackToFront()
117 {
118   int x,y;
119   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
120
121   if (setup.direct_draw && game_status == PLAYING)
122     redraw_mask &= ~REDRAW_MAIN;
123
124   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
125     redraw_mask |= REDRAW_FIELD;
126
127   if (redraw_mask & REDRAW_FIELD)
128     redraw_mask &= ~REDRAW_TILES;
129
130   if (redraw_mask == REDRAW_NONE)
131     return;
132
133   if (global.fps_slowdown && game_status == PLAYING)
134   {
135     static boolean last_frame_skipped = FALSE;
136     boolean skip_even_when_not_scrolling = TRUE;
137     boolean just_scrolling = (ScreenMovDir != 0);
138     boolean verbose = FALSE;
139
140     if (global.fps_slowdown_factor > 1 &&
141         (FrameCounter % global.fps_slowdown_factor) &&
142         (just_scrolling || skip_even_when_not_scrolling))
143     {
144       redraw_mask &= ~REDRAW_MAIN;
145
146       last_frame_skipped = TRUE;
147
148       if (verbose)
149         printf("FRAME SKIPPED\n");
150     }
151     else
152     {
153       if (last_frame_skipped)
154         redraw_mask |= REDRAW_FIELD;
155
156       last_frame_skipped = FALSE;
157
158       if (verbose)
159         printf("frame not skipped\n");
160     }
161   }
162
163   /* synchronize X11 graphics at this point; if we would synchronize the
164      display immediately after the buffer switching (after the XFlush),
165      this could mean that we have to wait for the graphics to complete,
166      although we could go on doing calculations for the next frame */
167
168   SyncDisplay();
169
170   if (redraw_mask & REDRAW_ALL)
171   {
172     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
173     redraw_mask = 0;
174   }
175
176   if (redraw_mask & REDRAW_FIELD)
177   {
178     if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
179     {
180       BlitBitmap(backbuffer, window,
181                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
182     }
183     else
184     {
185       int fx = FX, fy = FY;
186
187       if (setup.soft_scrolling)
188       {
189         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
190         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
191       }
192
193       if (setup.soft_scrolling ||
194           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
195           ABS(ScreenMovPos) == ScrollStepSize ||
196           redraw_tiles > REDRAWTILES_THRESHOLD)
197       {
198         BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
199
200 #ifdef DEBUG
201 #if 0
202         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
203                ScreenGfxPos,
204                (setup.soft_scrolling ?
205                 "setup.soft_scrolling" :
206                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
207                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
208                 ABS(ScreenGfxPos) == ScrollStepSize ?
209                 "ABS(ScreenGfxPos) == ScrollStepSize" :
210                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
211 #endif
212 #endif
213       }
214     }
215
216     redraw_mask &= ~REDRAW_MAIN;
217   }
218
219   if (redraw_mask & REDRAW_DOORS)
220   {
221     if (redraw_mask & REDRAW_DOOR_1)
222       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
223     if (redraw_mask & REDRAW_DOOR_2)
224     {
225       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
226         BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
227       else
228       {
229         if (redraw_mask & REDRAW_VIDEO_1)
230           BlitBitmap(backbuffer, window,
231                      VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
232                      VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
233                      VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
234         if (redraw_mask & REDRAW_VIDEO_2)
235           BlitBitmap(backbuffer, window,
236                      VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
237                      VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
238                      VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
239         if (redraw_mask & REDRAW_VIDEO_3)
240           BlitBitmap(backbuffer, window,
241                      VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
242                      VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
243                      VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
244       }
245     }
246     if (redraw_mask & REDRAW_DOOR_3)
247       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
248     redraw_mask &= ~REDRAW_DOORS;
249   }
250
251   if (redraw_mask & REDRAW_MICROLEVEL)
252   {
253     BlitBitmap(backbuffer, window,
254                MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
255                MICROLEV_XPOS, MICROLEV_YPOS);
256     BlitBitmap(backbuffer, window,
257                SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
258                SX, MICROLABEL_YPOS);
259     redraw_mask &= ~REDRAW_MICROLEVEL;
260   }
261
262   if (redraw_mask & REDRAW_TILES)
263   {
264     for(x=0; x<SCR_FIELDX; x++)
265       for(y=0; y<SCR_FIELDY; y++)
266         if (redraw[redraw_x1 + x][redraw_y1 + y])
267           BlitBitmap(buffer, window,
268                      FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
269                      SX + x * TILEX, SY + y * TILEY);
270   }
271
272   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
273   {
274     char text[100];
275     char info1[100];
276
277     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
278     if (!global.fps_slowdown)
279       info1[0] = '\0';
280
281     sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
282     DrawTextExt(window, SX, SY, text, FS_SMALL, FC_YELLOW, FONT_OPAQUE);
283   }
284
285   FlushDisplay();
286
287   for(x=0; x<MAX_BUF_XSIZE; x++)
288     for(y=0; y<MAX_BUF_YSIZE; y++)
289       redraw[x][y] = 0;
290   redraw_tiles = 0;
291   redraw_mask = REDRAW_NONE;
292 }
293
294 void FadeToFront()
295 {
296 #if 0
297   long fading_delay = 300;
298
299   if (setup.fading && (redraw_mask & REDRAW_FIELD))
300   {
301 #endif
302
303 #if 0
304     int x,y;
305
306     ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
307     FlushDisplay();
308
309     for(i=0;i<2*FULL_SYSIZE;i++)
310     {
311       for(y=0;y<FULL_SYSIZE;y++)
312       {
313         BlitBitmap(backbuffer, window,
314                    REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
315       }
316       FlushDisplay();
317       Delay(10);
318     }
319 #endif
320
321 #if 0
322     for(i=1;i<FULL_SYSIZE;i+=2)
323       BlitBitmap(backbuffer, window,
324                  REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
325     FlushDisplay();
326     Delay(fading_delay);
327 #endif
328
329 #if 0
330     SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
331     BlitBitmapMasked(backbuffer, window,
332                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
333                      REAL_SX,REAL_SY);
334     FlushDisplay();
335     Delay(fading_delay);
336
337     SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
338     BlitBitmapMasked(backbuffer, window,
339                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
340                      REAL_SX,REAL_SY);
341     FlushDisplay();
342     Delay(fading_delay);
343
344     SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
345     BlitBitmapMasked(backbuffer, window,
346                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
347                      REAL_SX,REAL_SY);
348     FlushDisplay();
349     Delay(fading_delay);
350
351     SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
352     BlitBitmapMasked(backbuffer, window,
353                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
354                      REAL_SX,REAL_SY);
355     FlushDisplay();
356     Delay(fading_delay);
357
358     redraw_mask &= ~REDRAW_MAIN;
359   }
360 #endif
361
362   BackToFront();
363 }
364
365 void SetMainBackgroundImage(int graphic)
366 {
367   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
368                           new_graphic_info[graphic].bitmap ?
369                           new_graphic_info[graphic].bitmap :
370                           new_graphic_info[IMG_BACKGROUND_DEFAULT].bitmap);
371 }
372
373 void SetDoorBackgroundImage(int graphic)
374 {
375   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
376                           new_graphic_info[graphic].bitmap ?
377                           new_graphic_info[graphic].bitmap :
378                           new_graphic_info[IMG_BACKGROUND_DEFAULT].bitmap);
379 }
380
381 void DrawBackground(int dest_x, int dest_y, int width, int height)
382 {
383   ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
384
385   redraw_mask |= REDRAW_FIELD;
386 }
387
388 void ClearWindow()
389 {
390   DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
391
392   if (setup.soft_scrolling && game_status == PLAYING)
393   {
394     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
395     SetDrawtoField(DRAW_BUFFERED);
396   }
397   else
398     SetDrawtoField(DRAW_BACKBUFFER);
399
400   if (setup.direct_draw && game_status == PLAYING)
401   {
402     ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
403     SetDrawtoField(DRAW_DIRECT);
404   }
405 }
406
407 void MarkTileDirty(int x, int y)
408 {
409   int xx = redraw_x1 + x;
410   int yy = redraw_y1 + y;
411
412   if (!redraw[xx][yy])
413     redraw_tiles++;
414
415   redraw[xx][yy] = TRUE;
416   redraw_mask |= REDRAW_TILES;
417 }
418
419 void SetBorderElement()
420 {
421   int x, y;
422
423   BorderElement = EL_EMPTY;
424
425   for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
426   {
427     for(x=0; x<lev_fieldx; x++)
428     {
429       if (!IS_MASSIVE(Feld[x][y]))
430         BorderElement = EL_STEELWALL;
431
432       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
433         x = lev_fieldx - 2;
434     }
435   }
436 }
437
438 static int getGraphicAnimationPhase(int frames, int delay, int mode)
439 {
440   int phase;
441
442   if (mode & ANIM_PINGPONG)
443   {
444     int max_anim_frames = 2 * frames - 2;
445
446     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
447     phase = (phase < frames ? phase : max_anim_frames - phase);
448   }
449   else
450     phase = (FrameCounter % (delay * frames)) / delay;
451
452   if (mode & ANIM_REVERSE)
453     phase = -phase;
454
455   return phase;
456 }
457
458 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
459 {
460   /* animation synchronized with global frame counter, not move position */
461   if (new_graphic_info[graphic].anim_global_sync || sync_frame < 0)
462     sync_frame = FrameCounter;
463
464   return getAnimationFrame(new_graphic_info[graphic].anim_frames,
465                            new_graphic_info[graphic].anim_delay,
466                            new_graphic_info[graphic].anim_mode,
467                            new_graphic_info[graphic].anim_start_frame,
468                            sync_frame);
469 }
470
471 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
472                                     int graphic, int sync_frame, int mask_mode)
473 {
474   int frame = getGraphicAnimationFrame(graphic, sync_frame);
475
476   if (mask_mode == USE_MASKING)
477     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
478   else
479     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
480 }
481
482 inline boolean DrawGraphicAnimation(int x, int y, int graphic)
483 {
484   int lx = LEVELX(x), ly = LEVELY(y);
485
486   if (!IN_SCR_FIELD(x, y) ||
487       (GfxFrame[lx][ly] % new_graphic_info[graphic].anim_delay) != 0)
488     return FALSE;
489
490   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
491                           graphic, GfxFrame[lx][ly], NO_MASKING);
492   MarkTileDirty(x, y);
493
494   return TRUE;
495 }
496
497 boolean DrawLevelGraphicAnimation(int x, int y, int graphic)
498 {
499   return DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
500 }
501
502 boolean DrawLevelElementAnimation(int x, int y, int element)
503 {
504   return DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
505 }
506
507 void DrawAllPlayers()
508 {
509   int i;
510
511   for(i=0; i<MAX_PLAYERS; i++)
512     if (stored_player[i].active)
513       DrawPlayer(&stored_player[i]);
514 }
515
516 void DrawPlayerField(int x, int y)
517 {
518   if (!IS_PLAYER(x, y))
519     return;
520
521   DrawPlayer(PLAYERINFO(x, y));
522 }
523
524 void DrawPlayer(struct PlayerInfo *player)
525 {
526   int jx = player->jx, jy = player->jy;
527   int last_jx = player->last_jx, last_jy = player->last_jy;
528   int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
529   int sx = SCREENX(jx), sy = SCREENY(jy);
530   int sxx = 0, syy = 0;
531   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
532   int graphic;
533   int frame = 0;
534   boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
535
536   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
537     return;
538
539 #if DEBUG
540   if (!IN_LEV_FIELD(jx,jy))
541   {
542     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
543     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
544     printf("DrawPlayerField(): This should never happen!\n");
545     return;
546   }
547 #endif
548
549   if (element == EL_EXPLOSION)
550     return;
551
552   /* draw things in the field the player is leaving, if needed */
553
554   if (player_is_moving)
555   {
556     if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
557     {
558       DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
559
560       if (last_element == EL_DYNAMITE_ACTIVE)
561         DrawDynamite(last_jx, last_jy);
562       else
563         DrawLevelFieldThruMask(last_jx, last_jy);
564     }
565     else if (last_element == EL_DYNAMITE_ACTIVE)
566       DrawDynamite(last_jx, last_jy);
567     else
568       DrawLevelField(last_jx, last_jy);
569
570     if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
571     {
572       if (player->GfxPos)
573       {
574         if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
575           DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
576         else
577           DrawLevelElement(next_jx, next_jy, EL_EMPTY);
578       }
579       else
580         DrawLevelField(next_jx, next_jy);
581     }
582   }
583
584   if (!IN_SCR_FIELD(sx, sy))
585     return;
586
587   if (setup.direct_draw)
588     SetDrawtoField(DRAW_BUFFERED);
589
590   /* draw things behind the player, if needed */
591
592   if (Store[jx][jy])
593     DrawLevelElement(jx, jy, Store[jx][jy]);
594   else if (!IS_ACTIVE_BOMB(element))
595     DrawLevelField(jx, jy);
596   else
597     DrawLevelElement(jx, jy, EL_EMPTY);
598
599   /* draw player himself */
600
601   if (game.emulation == EMU_SUPAPLEX)
602   {
603     static int last_dir = MV_LEFT;
604     int action = (player->programmed_action ? player->programmed_action :
605                   player->action);
606     boolean action_moving =
607       (player_is_moving ||
608        ((action & (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)) &&
609         !(action & ~(MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN))));
610
611     graphic = IMG_SP_MURPHY;
612
613     if (player->Pushing)
614     {
615       if (player->MovDir == MV_LEFT)
616         graphic = IMG_SP_MURPHY_LEFT_PUSHING;
617       else if (player->MovDir == MV_RIGHT)
618         graphic = IMG_SP_MURPHY_RIGHT_PUSHING;
619       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
620         graphic = IMG_SP_MURPHY_LEFT_PUSHING;
621       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
622         graphic = IMG_SP_MURPHY_RIGHT_PUSHING;
623     }
624     else if (player->snapped)
625     {
626       if (player->MovDir == MV_LEFT)
627         graphic = IMG_SP_MURPHY_LEFT_SNAPPING;
628       else if (player->MovDir == MV_RIGHT)
629         graphic = IMG_SP_MURPHY_RIGHT_SNAPPING;
630       else if (player->MovDir == MV_UP)
631         graphic = IMG_SP_MURPHY_UP_SNAPPING;
632       else if (player->MovDir == MV_DOWN)
633         graphic = IMG_SP_MURPHY_DOWN_SNAPPING;
634     }
635     else if (action_moving)
636     {
637       if (player->MovDir == MV_LEFT)
638         graphic = IMG_SP_MURPHY_LEFT_MOVING;
639       else if (player->MovDir == MV_RIGHT)
640         graphic = IMG_SP_MURPHY_RIGHT_MOVING;
641       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
642         graphic = IMG_SP_MURPHY_LEFT_MOVING;
643       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
644         graphic = IMG_SP_MURPHY_RIGHT_MOVING;
645       else
646         graphic = IMG_SP_MURPHY_LEFT_MOVING;
647
648       frame = getGraphicAnimationFrame(graphic, -1);
649     }
650
651     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
652       last_dir = player->MovDir;
653   }
654   else
655   {
656     if (player->MovDir == MV_LEFT)
657       graphic = (player->Pushing ? IMG_PLAYER1_LEFT_PUSHING :
658                  player->is_moving ? IMG_PLAYER1_LEFT_MOVING :
659                  IMG_PLAYER1_LEFT);
660     else if (player->MovDir == MV_RIGHT)
661       graphic = (player->Pushing ? IMG_PLAYER1_RIGHT_PUSHING :
662                  player->is_moving ? IMG_PLAYER1_RIGHT_MOVING :
663                  IMG_PLAYER1_RIGHT);
664     else if (player->MovDir == MV_UP)
665       graphic = (player->Pushing ? IMG_PLAYER1_UP_PUSHING :
666                  player->is_moving ? IMG_PLAYER1_UP_MOVING :
667                  IMG_PLAYER1_UP);
668     else        /* MV_DOWN || MV_NO_MOVING */
669       graphic = (player->Pushing ? IMG_PLAYER1_DOWN_PUSHING :
670                  player->is_moving ? IMG_PLAYER1_DOWN_MOVING :
671                  IMG_PLAYER1_DOWN);
672
673     graphic = PLAYER_NR_GFX(graphic, player->index_nr);
674
675 #if 0
676     frame = player->Frame;
677 #else
678     frame = getGraphicAnimationFrame(graphic, player->Frame);
679 #endif
680   }
681
682   if (player->GfxPos)
683   {
684     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
685       sxx = player->GfxPos;
686     else
687       syy = player->GfxPos;
688   }
689
690   if (!setup.soft_scrolling && ScreenMovPos)
691     sxx = syy = 0;
692
693 #if 0
694   if (player->Frame)
695     printf("-> %d\n", player->Frame);
696 #endif
697
698   DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
699
700   if (SHIELD_ON(player))
701   {
702     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
703                    IMG_SHIELD_NORMAL_ACTIVE);
704     int frame = getGraphicAnimationFrame(graphic, -1);
705
706     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
707   }
708
709 #if 0
710   if (player->Pushing && player->GfxPos)
711 #else
712   if (player->Pushing && player_is_moving)
713 #endif
714   {
715     int px = SCREENX(next_jx), py = SCREENY(next_jy);
716
717     if ((sxx || syy) &&
718         (element == EL_SOKOBAN_FIELD_EMPTY ||
719          Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
720       DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
721                                  NO_CUTTING);
722     else
723     {
724       int element = Feld[next_jx][next_jy];
725       int graphic = el2img(element);
726 #if 1
727       int frame = 0;
728 #endif
729
730       if ((sxx || syy) && IS_PUSHABLE(element))
731       {
732         graphic = el_dir_act2img(element, player->MovDir, GFX_ACTION_MOVING);
733 #if 1
734         frame = getGraphicAnimationFrame(graphic, player->GfxPos);
735
736         frame = getGraphicAnimationFrame(graphic, player->Frame);
737 #endif
738
739 #if 0
740         printf("-> %d [%d]\n", player->Frame, player->GfxPos);
741 #endif
742
743 #if 0
744         /* !!! FIX !!! */
745         if (player->MovDir == MV_LEFT)
746           frame = 3 - frame;
747 #endif
748
749 #if 0
750         frame = (player->GfxPos / (TILEX / 4));
751
752         if (player->MovDir == MV_RIGHT)
753           frame = (frame + 4) % 4;
754 #endif
755       }
756
757       DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
758                          NO_CUTTING, NO_MASKING);
759     }
760   }
761
762   /* draw things in front of player (active dynamite or dynabombs) */
763
764   if (IS_ACTIVE_BOMB(element))
765   {
766     graphic = el2img(element);
767
768 #if 0
769     if (element == EL_DYNAMITE_ACTIVE)
770     {
771       if ((frame = (96 - MovDelay[jx][jy]) / 12) > 6)
772         frame = 6;
773     }
774     else
775     {
776       if ((frame = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
777         frame = 7 - frame;
778     }
779 #else
780     frame = getGraphicAnimationFrame(graphic, 96 - MovDelay[jx][jy]);
781 #endif
782
783     if (game.emulation == EMU_SUPAPLEX)
784       DrawGraphic(sx, sy, IMG_SP_DISK_RED, 0);
785     else
786       DrawGraphicThruMask(sx, sy, graphic, frame);
787   }
788
789   if (player_is_moving && last_element == EL_EXPLOSION)
790   {
791     int stored = Store[last_jx][last_jy];
792     int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
793                    stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
794                    IMG_SP_EXPLOSION);
795     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
796     int phase = ExplodePhase[last_jx][last_jy] - 1;
797     int frame = getGraphicAnimationFrame(graphic, phase - delay);
798
799     if (phase >= delay)
800       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
801   }
802
803   /* draw elements that stay over the player */
804   /* handle the field the player is leaving ... */
805   if (player_is_moving && IS_OVER_PLAYER(last_element))
806     DrawLevelField(last_jx, last_jy);
807
808   /* ... and the field the player is entering */
809   if (IS_OVER_PLAYER(element))
810     DrawLevelField(jx, jy);
811
812   if (setup.direct_draw)
813   {
814     int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
815     int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
816     int x_size = TILEX * (1 + ABS(jx - last_jx));
817     int y_size = TILEY * (1 + ABS(jy - last_jy));
818
819     BlitBitmap(drawto_field, window,
820                dest_x, dest_y, x_size, y_size, dest_x, dest_y);
821     SetDrawtoField(DRAW_DIRECT);
822   }
823
824   MarkTileDirty(sx,sy);
825 }
826
827 #if 0
828 void getOldGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
829 {
830   if (graphic >= 0 && graphic_info[graphic].bitmap != NULL)
831   {
832     *bitmap = graphic_info[graphic].bitmap;
833     *x = graphic_info[graphic].src_x;
834     *y = graphic_info[graphic].src_y;
835   }
836   else if (graphic >= GFX_START_ROCKSELEMENTS &&
837            graphic <= GFX_END_ROCKSELEMENTS)
838   {
839     graphic -= GFX_START_ROCKSELEMENTS;
840     *bitmap = new_graphic_info[IMG_OLD_PIX_ELEMENTS].bitmap;
841     *x = (graphic % GFX_PER_LINE) * TILEX;
842     *y = (graphic / GFX_PER_LINE) * TILEY;
843   }
844   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
845   {
846     graphic -= GFX_START_ROCKSHEROES;
847     *bitmap = new_graphic_info[IMG_OLD_PIX_HEROES].bitmap;
848     *x = (graphic % HEROES_PER_LINE) * TILEX;
849     *y = (graphic / HEROES_PER_LINE) * TILEY;
850   }
851   else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
852   {
853     graphic -= GFX_START_ROCKSSP;
854     *bitmap = new_graphic_info[IMG_OLD_PIX_SP].bitmap;
855     *x = (graphic % SP_PER_LINE) * TILEX;
856     *y = (graphic / SP_PER_LINE) * TILEY;
857   }
858   else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
859   {
860     graphic -= GFX_START_ROCKSDC;
861     *bitmap = new_graphic_info[IMG_OLD_PIX_DC].bitmap;
862     *x = (graphic % DC_PER_LINE) * TILEX;
863     *y = (graphic / DC_PER_LINE) * TILEY;
864   }
865   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
866   {
867     graphic -= GFX_START_ROCKSMORE;
868     *bitmap = new_graphic_info[IMG_OLD_PIX_MORE].bitmap;
869     *x = (graphic % MORE_PER_LINE) * TILEX;
870     *y = (graphic / MORE_PER_LINE) * TILEY;
871   }
872   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
873   {
874     graphic -= GFX_START_ROCKSFONT;
875     *bitmap = new_graphic_info[IMG_OLD_PIX_FONT_EM].bitmap;
876     *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
877     *y = (graphic / FONT_CHARS_PER_LINE) * TILEY;
878   }
879   else
880   {
881     *bitmap = new_graphic_info[IMG_OLD_PIX_SP].bitmap;
882     *x = 0;
883     *y = 0;
884   }
885 }
886 #endif
887
888 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
889 {
890   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
891   int offset_x = new_graphic_info[graphic].offset_x;
892   int offset_y = new_graphic_info[graphic].offset_y;
893   int src_x = new_graphic_info[graphic].src_x + frame * offset_x;
894   int src_y = new_graphic_info[graphic].src_y + frame * offset_y;
895
896   *bitmap = src_bitmap;
897   *x = src_x;
898   *y = src_y;
899 }
900
901 void DrawGraphic(int x, int y, int graphic, int frame)
902 {
903 #if DEBUG
904   if (!IN_SCR_FIELD(x, y))
905   {
906     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
907     printf("DrawGraphic(): This should never happen!\n");
908     return;
909   }
910 #endif
911
912   DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
913   MarkTileDirty(x, y);
914 }
915
916 #if 0
917 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
918 {
919   Bitmap *src_bitmap;
920   int src_x, src_y;
921
922   getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
923   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
924 }
925 #endif
926
927 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
928                     int frame)
929 {
930 #if 1
931   Bitmap *src_bitmap;
932   int src_x, src_y;
933
934   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
935 #else
936   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
937   int src_x = new_graphic_info[graphic].src_x;
938   int src_y = new_graphic_info[graphic].src_y;
939   int offset_x = new_graphic_info[graphic].offset_x;
940   int offset_y = new_graphic_info[graphic].offset_y;
941
942   src_x += frame * offset_x;
943   src_y += frame * offset_y;
944 #endif
945
946   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
947 }
948
949 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
950 {
951 #if DEBUG
952   if (!IN_SCR_FIELD(x, y))
953   {
954     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
955     printf("DrawGraphicThruMask(): This should never happen!\n");
956     return;
957   }
958 #endif
959
960   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
961                          frame);
962   MarkTileDirty(x, y);
963 }
964
965 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
966                             int frame)
967 {
968 #if 1
969   Bitmap *src_bitmap;
970   int src_x, src_y;
971   GC drawing_gc;
972
973   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
974   drawing_gc = src_bitmap->stored_clip_gc;
975 #else
976   GC drawing_gc = src_bitmap->stored_clip_gc;
977   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
978   int src_x = new_graphic_info[graphic].src_x;
979   int src_y = new_graphic_info[graphic].src_y;
980   int offset_x = new_graphic_info[graphic].offset_x;
981   int offset_y = new_graphic_info[graphic].offset_y;
982
983   src_x += frame * offset_x;
984   src_y += frame * offset_y;
985
986 #endif
987
988   SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
989   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
990 }
991
992 void DrawMiniGraphic(int x, int y, int graphic)
993 {
994   DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
995   MarkTileDirty(x / 2, y / 2);
996 }
997
998 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
999 {
1000   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1001   int mini_startx = 0;
1002   int mini_starty = src_bitmap->height * 2 / 3;
1003   int src_x = mini_startx + new_graphic_info[graphic].src_x / 2;
1004   int src_y = mini_starty + new_graphic_info[graphic].src_y / 2;
1005
1006   if (src_x + MINI_TILEX > src_bitmap->width ||
1007       src_y + MINI_TILEY > src_bitmap->height)
1008   {
1009     /* graphic of desired size seems not to be contained in this image;
1010        dirty workaround: get it from the middle of the normal sized image */
1011
1012     getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1013     src_x += (TILEX / 2 - MINI_TILEX / 2);
1014     src_y += (TILEY / 2 - MINI_TILEY / 2);
1015   }
1016
1017   *bitmap = src_bitmap;
1018   *x = src_x;
1019   *y = src_y;
1020 }
1021
1022 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1023 {
1024   Bitmap *src_bitmap;
1025   int src_x, src_y;
1026
1027   getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1028   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1029 }
1030
1031 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
1032                         int cut_mode, int mask_mode)
1033 {
1034   Bitmap *src_bitmap;
1035   GC drawing_gc;
1036   int src_x;
1037   int src_y;
1038   int offset_x;
1039   int offset_y;
1040
1041   int width = TILEX, height = TILEY;
1042   int cx = 0, cy = 0;
1043   int dest_x, dest_y;
1044
1045   if (graphic < 0)
1046   {
1047     DrawGraphic(x, y, graphic, frame);
1048     return;
1049   }
1050
1051   if (dx || dy)                 /* shifted graphic */
1052   {
1053     if (x < BX1)                /* object enters playfield from the left */
1054     {
1055       x = BX1;
1056       width = dx;
1057       cx = TILEX - dx;
1058       dx = 0;
1059     }
1060     else if (x > BX2)           /* object enters playfield from the right */
1061     {
1062       x = BX2;
1063       width = -dx;
1064       dx = TILEX + dx;
1065     }
1066     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
1067     {
1068       width += dx;
1069       cx = -dx;
1070       dx = 0;
1071     }
1072     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
1073       width -= dx;
1074     else if (dx)                /* general horizontal movement */
1075       MarkTileDirty(x + SIGN(dx), y);
1076
1077     if (y < BY1)                /* object enters playfield from the top */
1078     {
1079       if (cut_mode==CUT_BELOW)  /* object completely above top border */
1080         return;
1081
1082       y = BY1;
1083       height = dy;
1084       cy = TILEY - dy;
1085       dy = 0;
1086     }
1087     else if (y > BY2)           /* object enters playfield from the bottom */
1088     {
1089       y = BY2;
1090       height = -dy;
1091       dy = TILEY + dy;
1092     }
1093     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
1094     {
1095       height += dy;
1096       cy = -dy;
1097       dy = 0;
1098     }
1099     else if (dy > 0 && cut_mode == CUT_ABOVE)
1100     {
1101       if (y == BY2)             /* object completely above bottom border */
1102         return;
1103
1104       height = dy;
1105       cy = TILEY - dy;
1106       dy = TILEY;
1107       MarkTileDirty(x, y + 1);
1108     }                           /* object leaves playfield to the bottom */
1109     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1110       height -= dy;
1111     else if (dy)                /* general vertical movement */
1112       MarkTileDirty(x, y + SIGN(dy));
1113   }
1114
1115   src_bitmap = new_graphic_info[graphic].bitmap;
1116   src_x = new_graphic_info[graphic].src_x;
1117   src_y = new_graphic_info[graphic].src_y;
1118   offset_x = new_graphic_info[graphic].offset_x;
1119   offset_y = new_graphic_info[graphic].offset_y;
1120
1121   drawing_gc = src_bitmap->stored_clip_gc;
1122
1123   src_x += frame * offset_x;
1124   src_y += frame * offset_y;
1125
1126   src_x += cx;
1127   src_y += cy;
1128
1129   dest_x = FX + x * TILEX + dx;
1130   dest_y = FY + y * TILEY + dy;
1131
1132 #if DEBUG
1133   if (!IN_SCR_FIELD(x,y))
1134   {
1135     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1136     printf("DrawGraphicShifted(): This should never happen!\n");
1137     return;
1138   }
1139 #endif
1140
1141   if (mask_mode == USE_MASKING)
1142   {
1143     SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1144     BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1145                      dest_x, dest_y);
1146   }
1147   else
1148     BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1149                dest_x, dest_y);
1150
1151   MarkTileDirty(x,y);
1152 }
1153
1154 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1155                                 int frame, int cut_mode)
1156 {
1157   DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1158 }
1159
1160 #if 0
1161 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1162                           int cut_mode, int mask_mode)
1163 {
1164   int ux = LEVELX(x), uy = LEVELY(y);
1165   int graphic = el2gfx(element);
1166   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1167   int phase4 = phase8 / 2;
1168   int phase2  = phase8 / 4;
1169   int dir = MovDir[ux][uy];
1170
1171   if (element == EL_PACMAN || element == EL_BUG || element == EL_SPACESHIP)
1172   {
1173     graphic += 1 * !phase2;
1174
1175     if (dir == MV_UP)
1176       graphic += 1 * 2;
1177     else if (dir == MV_LEFT)
1178       graphic += 2 * 2;
1179     else if (dir == MV_DOWN)
1180       graphic += 3 * 2;
1181   }
1182   else if (element == EL_SP_SNIKSNAK)
1183   {
1184     if (dir == MV_LEFT)
1185       graphic = GFX_SP_SNIKSNAK_LEFT;
1186     else if (dir == MV_RIGHT)
1187       graphic = GFX_SP_SNIKSNAK_RIGHT;
1188     else if (dir == MV_UP)
1189       graphic = GFX_SP_SNIKSNAK_UP;
1190     else
1191       graphic = GFX_SP_SNIKSNAK_DOWN;
1192
1193     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1194   }
1195   else if (element == EL_SP_ELECTRON)
1196   {
1197     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1198   }
1199   else if (element == EL_MOLE || element == EL_PENGUIN ||
1200            element == EL_PIG || element == EL_DRAGON)
1201   {
1202     if (dir == MV_LEFT)
1203       graphic = (element == EL_MOLE ? GFX_MOLE_LEFT :
1204                  element == EL_PENGUIN ? GFX_PINGUIN_LEFT :
1205                  element == EL_PIG ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1206     else if (dir == MV_RIGHT)
1207       graphic = (element == EL_MOLE ? GFX_MOLE_RIGHT :
1208                  element == EL_PENGUIN ? GFX_PINGUIN_RIGHT :
1209                  element == EL_PIG ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1210     else if (dir == MV_UP)
1211       graphic = (element == EL_MOLE ? GFX_MOLE_UP :
1212                  element == EL_PENGUIN ? GFX_PINGUIN_UP :
1213                  element == EL_PIG ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1214     else
1215       graphic = (element == EL_MOLE ? GFX_MOLE_DOWN :
1216                  element == EL_PENGUIN ? GFX_PINGUIN_DOWN :
1217                  element == EL_PIG ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1218
1219     graphic += phase4;
1220   }
1221   else if (element == EL_SATELLITE)
1222   {
1223     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1224   }
1225   else if (element == EL_ACID)
1226   {
1227     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_LOOP);
1228   }
1229   else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
1230   {
1231     graphic += !phase2;
1232   }
1233   else if (element == EL_BALLOON)
1234   {
1235     graphic += phase4;
1236   }
1237   else if ((element == EL_ROCK ||
1238             element == EL_SP_ZONK ||
1239             element == EL_BD_ROCK ||
1240             element == EL_SP_INFOTRON ||
1241             IS_GEM(element))
1242            && !cut_mode)
1243   {
1244     if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1245     {
1246       if (element == EL_ROCK ||
1247           element == EL_SP_ZONK ||
1248           element == EL_BD_ROCK)
1249       {
1250         if (dir == MV_LEFT)
1251           graphic += (4 - phase4) % 4;
1252         else if (dir == MV_RIGHT)
1253           graphic += phase4;
1254         else
1255           graphic += phase2 * 2;
1256       }
1257       else if (element != EL_SP_INFOTRON)
1258         graphic += phase2;
1259     }
1260   }
1261   else if (element == EL_MAGIC_WALL_ACTIVE ||
1262            element == EL_MAGIC_WALL_EMPTYING ||
1263            element == EL_BD_MAGIC_WALL_ACTIVE ||
1264            element == EL_BD_MAGIC_WALL_EMPTYING ||
1265            element == EL_MAGIC_WALL_FULL ||
1266            element == EL_BD_MAGIC_WALL_FULL)
1267   {
1268     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1269   }
1270   else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1271   {
1272     graphic = (element == EL_AMOEBA_DEAD ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1273     graphic += (x + 2 * y + 4) % 4;
1274   }
1275   else if (element == EL_WALL_GROWING)
1276   {
1277     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1278
1279     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1280       links_massiv = TRUE;
1281     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1282       rechts_massiv = TRUE;
1283
1284     if (links_massiv && rechts_massiv)
1285       graphic = GFX_MAUERWERK;
1286     else if (links_massiv)
1287       graphic = GFX_MAUER_R;
1288     else if (rechts_massiv)
1289       graphic = GFX_MAUER_L;
1290   }
1291 #if 0
1292   else if ((element == EL_INVISIBLE_STEELWALL ||
1293             element == EL_INVISIBLE_WALL ||
1294             element == EL_INVISIBLE_SAND) && game.light_time_left)
1295   {
1296     graphic = (element == EL_INVISIBLE_STEELWALL ? GFX_INVISIBLE_STEEL_ON :
1297                element == EL_INVISIBLE_WALL ? GFX_UNSICHTBAR_ON :
1298                GFX_SAND_INVISIBLE_ON);
1299   }
1300 #endif
1301
1302   if (dx || dy)
1303     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1304   else if (mask_mode == USE_MASKING)
1305     DrawGraphicThruMask(x, y, graphic);
1306   else
1307     DrawGraphic(x, y, graphic);
1308 }
1309 #endif
1310
1311 inline static int getFramePosition(int x, int y)
1312 {
1313   int frame_pos = -1;           /* default: global synchronization */
1314 #if 0
1315   int element = Feld[x][y];
1316
1317   if (element == EL_QUICKSAND_FULL ||
1318       element == EL_MAGIC_WALL_FULL ||
1319       element == EL_BD_MAGIC_WALL_FULL)
1320     frame_pos = -1;
1321   else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
1322     frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1323 #else
1324
1325   frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1326
1327   frame_pos = GfxFrame[x][y];
1328
1329 #endif
1330
1331   return frame_pos;
1332 }
1333
1334 inline static int getGfxAction(int x, int y)
1335 {
1336   int gfx_action = GFX_ACTION_DEFAULT;
1337
1338 #if 0
1339   if (GfxAction[x][y] != GFX_ACTION_DEFAULT)
1340     gfx_action = GfxAction[x][y];
1341   else if (IS_MOVING(x, y))
1342     gfx_action = GFX_ACTION_MOVING;
1343 #else
1344   gfx_action = GfxAction[x][y];
1345 #endif
1346
1347 #if DEBUG
1348   if (gfx_action < 0)
1349     printf("getGfxAction: THIS SHOULD NEVER HAPPEN: GfxAction[%d][%d] == %d\n",
1350            x, y, gfx_action);
1351 #endif
1352
1353   return gfx_action;
1354 }
1355
1356 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1357                           int cut_mode, int mask_mode)
1358 {
1359   int ux = LEVELX(x), uy = LEVELY(y);
1360   int graphic;
1361   int frame;
1362
1363   if (IN_LEV_FIELD(ux, uy))
1364   {
1365     int move_dir = MovDir[ux][uy];
1366     int move_pos = getFramePosition(ux, uy);
1367     int gfx_action = getGfxAction(ux, uy);
1368
1369     graphic = el_dir_act2img(element, move_dir, gfx_action);
1370     frame = getGraphicAnimationFrame(graphic, move_pos);
1371   }
1372   else
1373   {
1374     graphic = el2img(element);
1375     frame = getGraphicAnimationFrame(graphic, 0);
1376   }
1377
1378   if (element == EL_WALL_GROWING)
1379   {
1380     boolean left_stopped = FALSE, right_stopped = FALSE;
1381
1382     if (!IN_LEV_FIELD(ux - 1, uy) || IS_MAUER(Feld[ux - 1][uy]))
1383       left_stopped = TRUE;
1384     if (!IN_LEV_FIELD(ux + 1, uy) || IS_MAUER(Feld[ux + 1][uy]))
1385       right_stopped = TRUE;
1386
1387     if (left_stopped && right_stopped)
1388       graphic = IMG_WALL;
1389     else if (left_stopped)
1390     {
1391       graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1392       frame = new_graphic_info[graphic].anim_frames - 1;
1393     }
1394     else if (right_stopped)
1395     {
1396       graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1397       frame = new_graphic_info[graphic].anim_frames - 1;
1398     }
1399   }
1400   else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1401   {
1402     graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1403                element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1404                element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1405                element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1406                IMG_AMOEBA_DEAD_PART1);
1407
1408     graphic += (x + 2 * y + 4) % 4;
1409   }
1410
1411   if (dx || dy)
1412     DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1413   else if (mask_mode == USE_MASKING)
1414     DrawGraphicThruMask(x, y, graphic, frame);
1415   else
1416     DrawGraphic(x, y, graphic, frame);
1417 }
1418
1419 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1420                          int cut_mode, int mask_mode)
1421 {
1422   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1423     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1424                          cut_mode, mask_mode);
1425 }
1426
1427 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1428                               int cut_mode)
1429 {
1430   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1431 }
1432
1433 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1434                              int cut_mode)
1435 {
1436   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1437 }
1438
1439 #if 0
1440 void DrawOldScreenElementThruMask(int x, int y, int element)
1441 {
1442   DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1443 }
1444
1445 void DrawScreenElementThruMask(int x, int y, int element)
1446 {
1447   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1448 }
1449 #endif
1450
1451 void DrawLevelElementThruMask(int x, int y, int element)
1452 {
1453   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1454 }
1455
1456 void DrawLevelFieldThruMask(int x, int y)
1457 {
1458   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1459 }
1460
1461 void DrawCrumbledSand(int x, int y)
1462 {
1463   Bitmap *src_bitmap;
1464   int src_x, src_y;
1465   int i, width, height, cx,cy;
1466   int ux = LEVELX(x), uy = LEVELY(y);
1467   int element, graphic;
1468   int snip = 4;
1469   static int xy[4][2] =
1470   {
1471     { 0, -1 },
1472     { -1, 0 },
1473     { +1, 0 },
1474     { 0, +1 }
1475   };
1476
1477   if (!IN_LEV_FIELD(ux, uy))
1478     return;
1479
1480   element = Feld[ux][uy];
1481
1482   if (element == EL_SAND ||
1483       element == EL_LANDMINE ||
1484       element == EL_TRAP ||
1485       element == EL_TRAP_ACTIVE)
1486   {
1487     if (!IN_SCR_FIELD(x, y))
1488       return;
1489
1490     graphic = IMG_SAND_CRUMBLED;
1491
1492     src_bitmap = new_graphic_info[graphic].bitmap;
1493     src_x = new_graphic_info[graphic].src_x;
1494     src_y = new_graphic_info[graphic].src_y;
1495
1496     for(i=0; i<4; i++)
1497     {
1498       int uxx, uyy;
1499
1500       uxx = ux + xy[i][0];
1501       uyy = uy + xy[i][1];
1502       if (!IN_LEV_FIELD(uxx, uyy))
1503         element = EL_STEELWALL;
1504       else
1505         element = Feld[uxx][uyy];
1506
1507       if (element == EL_SAND ||
1508           element == EL_LANDMINE ||
1509           element == EL_TRAP ||
1510           element == EL_TRAP_ACTIVE)
1511         continue;
1512
1513       if (i == 1 || i == 2)
1514       {
1515         width = snip;
1516         height = TILEY;
1517         cx = (i == 2 ? TILEX - snip : 0);
1518         cy = 0;
1519       }
1520       else
1521       {
1522         width = TILEX;
1523         height = snip;
1524         cx = 0;
1525         cy = (i == 3 ? TILEY - snip : 0);
1526       }
1527
1528       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1529                  width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1530     }
1531
1532     MarkTileDirty(x, y);
1533   }
1534   else
1535   {
1536     graphic = IMG_SAND_CRUMBLED;
1537
1538     src_bitmap = new_graphic_info[graphic].bitmap;
1539     src_x = new_graphic_info[graphic].src_x;
1540     src_y = new_graphic_info[graphic].src_y;
1541
1542     for(i=0; i<4; i++)
1543     {
1544       int xx, yy, uxx, uyy;
1545
1546       xx = x + xy[i][0];
1547       yy = y + xy[i][1];
1548       uxx = ux + xy[i][0];
1549       uyy = uy + xy[i][1];
1550
1551       if (!IN_LEV_FIELD(uxx, uyy) ||
1552           (Feld[uxx][uyy] != EL_SAND &&
1553            Feld[uxx][uyy] != EL_LANDMINE &&
1554            Feld[uxx][uyy] != EL_TRAP &&
1555            Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1556           !IN_SCR_FIELD(xx, yy))
1557         continue;
1558
1559       if (i == 1 || i == 2)
1560       {
1561         width = snip;
1562         height = TILEY;
1563         cx = (i == 1 ? TILEX - snip : 0);
1564         cy = 0;
1565       }
1566       else
1567       {
1568         width = TILEX;
1569         height = snip;
1570         cx = 0;
1571         cy = (i==0 ? TILEY-snip : 0);
1572       }
1573
1574       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1575                  width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1576
1577       MarkTileDirty(xx, yy);
1578     }
1579   }
1580 }
1581
1582 void DrawScreenElement(int x, int y, int element)
1583 {
1584   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1585   DrawCrumbledSand(x, y);
1586 }
1587
1588 void DrawLevelElement(int x, int y, int element)
1589 {
1590   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1591     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1592 }
1593
1594 void DrawScreenField(int x, int y)
1595 {
1596   int ux = LEVELX(x), uy = LEVELY(y);
1597   int element, content;
1598
1599   if (!IN_LEV_FIELD(ux, uy))
1600   {
1601     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1602       element = EL_EMPTY;
1603     else
1604       element = BorderElement;
1605
1606     DrawScreenElement(x, y, element);
1607     return;
1608   }
1609
1610   element = Feld[ux][uy];
1611   content = Store[ux][uy];
1612
1613   if (IS_MOVING(ux, uy))
1614   {
1615     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1616     boolean cut_mode = NO_CUTTING;
1617
1618     if (element == EL_QUICKSAND_EMPTYING ||
1619         element == EL_MAGIC_WALL_EMPTYING ||
1620         element == EL_BD_MAGIC_WALL_EMPTYING ||
1621         element == EL_AMOEBA_DRIPPING)
1622       cut_mode = CUT_ABOVE;
1623     else if (element == EL_QUICKSAND_FILLING ||
1624              element == EL_MAGIC_WALL_FILLING ||
1625              element == EL_BD_MAGIC_WALL_FILLING)
1626       cut_mode = CUT_BELOW;
1627
1628     if (cut_mode == CUT_ABOVE)
1629       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1630     else
1631       DrawScreenElement(x, y, EL_EMPTY);
1632
1633     if (horiz_move)
1634       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1635     else if (cut_mode == NO_CUTTING)
1636       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1637     else
1638       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1639
1640     if (content == EL_ACID)
1641       DrawLevelElementThruMask(ux, uy + 1, EL_ACID);
1642   }
1643   else if (IS_BLOCKED(ux, uy))
1644   {
1645     int oldx, oldy;
1646     int sx, sy;
1647     int horiz_move;
1648     boolean cut_mode = NO_CUTTING;
1649     int element_old, content_old;
1650
1651     Blocked2Moving(ux, uy, &oldx, &oldy);
1652     sx = SCREENX(oldx);
1653     sy = SCREENY(oldy);
1654     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1655                   MovDir[oldx][oldy] == MV_RIGHT);
1656
1657     element_old = Feld[oldx][oldy];
1658     content_old = Store[oldx][oldy];
1659
1660     if (element_old == EL_QUICKSAND_EMPTYING ||
1661         element_old == EL_MAGIC_WALL_EMPTYING ||
1662         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1663         element_old == EL_AMOEBA_DRIPPING)
1664       cut_mode = CUT_ABOVE;
1665
1666     DrawScreenElement(x, y, EL_EMPTY);
1667
1668     if (horiz_move)
1669       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1670                                NO_CUTTING);
1671     else if (cut_mode == NO_CUTTING)
1672       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1673                                cut_mode);
1674     else
1675       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1676                                cut_mode);
1677   }
1678   else if (IS_DRAWABLE(element))
1679     DrawScreenElement(x, y, element);
1680   else
1681     DrawScreenElement(x, y, EL_EMPTY);
1682 }
1683
1684 void DrawLevelField(int x, int y)
1685 {
1686   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1687     DrawScreenField(SCREENX(x), SCREENY(y));
1688   else if (IS_MOVING(x, y))
1689   {
1690     int newx,newy;
1691
1692     Moving2Blocked(x, y, &newx, &newy);
1693     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1694       DrawScreenField(SCREENX(newx), SCREENY(newy));
1695   }
1696   else if (IS_BLOCKED(x, y))
1697   {
1698     int oldx, oldy;
1699
1700     Blocked2Moving(x, y, &oldx, &oldy);
1701     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1702       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1703   }
1704 }
1705
1706 void DrawMiniElement(int x, int y, int element)
1707 {
1708   int graphic;
1709
1710   graphic = el2img(element);
1711   DrawMiniGraphic(x, y, graphic);
1712 }
1713
1714 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1715 {
1716   int x = sx + scroll_x, y = sy + scroll_y;
1717
1718   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1719     DrawMiniElement(sx, sy, EL_EMPTY);
1720   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1721     DrawMiniElement(sx, sy, Feld[x][y]);
1722   else
1723   {
1724     int steel_type, steel_position;
1725     int border[6][2] =
1726     {
1727       { IMG_STEELWALL_TOPLEFT,          IMG_INVISIBLE_STEELWALL_TOPLEFT     },
1728       { IMG_STEELWALL_TOPRIGHT,         IMG_INVISIBLE_STEELWALL_TOPRIGHT    },
1729       { IMG_STEELWALL_BOTTOMLEFT,       IMG_INVISIBLE_STEELWALL_BOTTOMLEFT  },
1730       { IMG_STEELWALL_BOTTOMRIGHT,      IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1731       { IMG_STEELWALL_VERTICAL,         IMG_INVISIBLE_STEELWALL_VERTICAL    },
1732       { IMG_STEELWALL_HORIZONTAL,       IMG_INVISIBLE_STEELWALL_HORIZONTAL  }
1733     };
1734
1735     steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1736     steel_position = (x == -1 && y == -1                        ? 0 :
1737                       x == lev_fieldx && y == -1                ? 1 :
1738                       x == -1 && y == lev_fieldy                ? 2 :
1739                       x == lev_fieldx && y == lev_fieldy        ? 3 :
1740                       x == -1 || x == lev_fieldx                ? 4 :
1741                       y == -1 || y == lev_fieldy                ? 5 : -1);
1742
1743     if (steel_position != -1)
1744       DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1745   }
1746 }
1747
1748 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1749 {
1750   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1751   int mini_startx = src_bitmap->width * 3 / 4;
1752   int mini_starty = src_bitmap->height * 2 / 3;
1753   int src_x = mini_startx + new_graphic_info[graphic].src_x / 8;
1754   int src_y = mini_starty + new_graphic_info[graphic].src_y / 8;
1755
1756   if (src_x + MICRO_TILEX > src_bitmap->width ||
1757       src_y + MICRO_TILEY > src_bitmap->height)
1758   {
1759     /* graphic of desired size seems not to be contained in this image;
1760        dirty workaround: get it from the middle of the normal sized image */
1761
1762     getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1763     src_x += (TILEX / 2 - MICRO_TILEX / 2);
1764     src_y += (TILEY / 2 - MICRO_TILEY / 2);
1765   }
1766
1767   *bitmap = src_bitmap;
1768   *x = src_x;
1769   *y = src_y;
1770 }
1771
1772 void DrawMicroElement(int xpos, int ypos, int element)
1773 {
1774   Bitmap *src_bitmap;
1775   int src_x, src_y;
1776   int graphic = el2img(element);
1777
1778   getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1779   BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1780              xpos, ypos);
1781 }
1782
1783 void DrawLevel()
1784 {
1785   int x,y;
1786
1787   SetDrawBackgroundMask(REDRAW_NONE);
1788   ClearWindow();
1789
1790   for(x=BX1; x<=BX2; x++)
1791     for(y=BY1; y<=BY2; y++)
1792       DrawScreenField(x, y);
1793
1794   redraw_mask |= REDRAW_FIELD;
1795 }
1796
1797 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1798 {
1799   int x,y;
1800
1801   for(x=0; x<size_x; x++)
1802     for(y=0; y<size_y; y++)
1803       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1804
1805   redraw_mask |= REDRAW_FIELD;
1806 }
1807
1808 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1809 {
1810   int x, y;
1811
1812   DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1813
1814   if (lev_fieldx < STD_LEV_FIELDX)
1815     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1816   if (lev_fieldy < STD_LEV_FIELDY)
1817     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1818
1819   xpos += MICRO_TILEX;
1820   ypos += MICRO_TILEY;
1821
1822   for(x=-1; x<=STD_LEV_FIELDX; x++)
1823   {
1824     for(y=-1; y<=STD_LEV_FIELDY; y++)
1825     {
1826       int lx = from_x + x, ly = from_y + y;
1827
1828       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1829         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1830                          Ur[lx][ly]);
1831       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1832                && BorderElement != EL_EMPTY)
1833         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1834                          BorderElement);
1835     }
1836   }
1837
1838   redraw_mask |= REDRAW_MICROLEVEL;
1839 }
1840
1841 #define MICROLABEL_EMPTY                0
1842 #define MICROLABEL_LEVEL_NAME           1
1843 #define MICROLABEL_CREATED_BY           2
1844 #define MICROLABEL_LEVEL_AUTHOR         3
1845 #define MICROLABEL_IMPORTED_FROM        4
1846 #define MICROLABEL_LEVEL_IMPORT_INFO    5
1847
1848 #define MAX_MICROLABEL_SIZE             (SXSIZE / FONT4_XSIZE)
1849
1850 static void DrawMicroLevelLabelExt(int mode)
1851 {
1852   char label_text[MAX_MICROLABEL_SIZE + 1];
1853
1854   DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1855
1856   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1857                        mode == MICROLABEL_CREATED_BY ? "created by" :
1858                        mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1859                        mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1860                        mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1861                        leveldir_current->imported_from : ""),
1862           MAX_MICROLABEL_SIZE);
1863   label_text[MAX_MICROLABEL_SIZE] = '\0';
1864
1865   if (strlen(label_text) > 0)
1866   {
1867     int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1868     int lypos = MICROLABEL_YPOS;
1869
1870     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1871   }
1872
1873   redraw_mask |= REDRAW_MICROLEVEL;
1874 }
1875
1876 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1877 {
1878   static unsigned long scroll_delay = 0;
1879   static unsigned long label_delay = 0;
1880   static int from_x, from_y, scroll_direction;
1881   static int label_state, label_counter;
1882
1883   if (restart)
1884   {
1885     from_x = from_y = 0;
1886     scroll_direction = MV_RIGHT;
1887     label_state = 1;
1888     label_counter = 0;
1889
1890     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1891     DrawMicroLevelLabelExt(label_state);
1892
1893     /* initialize delay counters */
1894     DelayReached(&scroll_delay, 0);
1895     DelayReached(&label_delay, 0);
1896
1897     return;
1898   }
1899
1900   /* scroll micro level, if needed */
1901   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1902       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1903   {
1904     switch (scroll_direction)
1905     {
1906       case MV_LEFT:
1907         if (from_x > 0)
1908           from_x--;
1909         else
1910           scroll_direction = MV_UP;
1911         break;
1912
1913       case MV_RIGHT:
1914         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1915           from_x++;
1916         else
1917           scroll_direction = MV_DOWN;
1918         break;
1919
1920       case MV_UP:
1921         if (from_y > 0)
1922           from_y--;
1923         else
1924           scroll_direction = MV_RIGHT;
1925         break;
1926
1927       case MV_DOWN:
1928         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1929           from_y++;
1930         else
1931           scroll_direction = MV_LEFT;
1932         break;
1933
1934       default:
1935         break;
1936     }
1937
1938     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1939   }
1940
1941   /* redraw micro level label, if needed */
1942   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1943       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1944       strcmp(level.author, leveldir_current->name) != 0 &&
1945       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1946   {
1947     int max_label_counter = 23;
1948
1949     if (leveldir_current->imported_from != NULL)
1950       max_label_counter += 14;
1951
1952     label_counter = (label_counter + 1) % max_label_counter;
1953     label_state = (label_counter >= 0 && label_counter <= 7 ?
1954                    MICROLABEL_LEVEL_NAME :
1955                    label_counter >= 9 && label_counter <= 12 ?
1956                    MICROLABEL_CREATED_BY :
1957                    label_counter >= 14 && label_counter <= 21 ?
1958                    MICROLABEL_LEVEL_AUTHOR :
1959                    label_counter >= 23 && label_counter <= 26 ?
1960                    MICROLABEL_IMPORTED_FROM :
1961                    label_counter >= 28 && label_counter <= 35 ?
1962                    MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1963     DrawMicroLevelLabelExt(label_state);
1964   }
1965 }
1966
1967 int REQ_in_range(int x, int y)
1968 {
1969   if (y > DY+249 && y < DY+278)
1970   {
1971     if (x > DX+1 && x < DX+48)
1972       return 1;
1973     else if (x > DX+51 && x < DX+98) 
1974       return 2;
1975   }
1976   return 0;
1977 }
1978
1979 #define MAX_REQUEST_LINES               13
1980 #define MAX_REQUEST_LINE_LEN            7
1981
1982 boolean Request(char *text, unsigned int req_state)
1983 {
1984   int mx, my, ty, result = -1;
1985   unsigned int old_door_state;
1986
1987 #if defined(PLATFORM_UNIX)
1988   /* pause network game while waiting for request to answer */
1989   if (options.network &&
1990       game_status == PLAYING &&
1991       req_state & REQUEST_WAIT_FOR)
1992     SendToServer_PausePlaying();
1993 #endif
1994
1995   old_door_state = GetDoorState();
1996
1997   UnmapAllGadgets();
1998
1999   CloseDoor(DOOR_CLOSE_1);
2000
2001   /* save old door content */
2002   BlitBitmap(bitmap_db_door, bitmap_db_door,
2003              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2004              DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2005
2006   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2007
2008   /* clear door drawing field */
2009   DrawBackground(DX, DY, DXSIZE, DYSIZE);
2010
2011   /* write text for request */
2012   for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2013   {
2014     char text_line[MAX_REQUEST_LINE_LEN + 1];
2015     int tx, tl, tc;
2016
2017     if (!*text)
2018       break;
2019
2020     for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2021     {
2022       tc = *(text + tx);
2023       if (!tc || tc == ' ')
2024         break;
2025     }
2026
2027     if (!tl)
2028     { 
2029       text++; 
2030       ty--; 
2031       continue; 
2032     }
2033
2034     strncpy(text_line, text, tl);
2035     text_line[tl] = 0;
2036
2037     DrawText(DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
2038              text_line, FS_SMALL, FC_YELLOW);
2039
2040     text += tl + (tc == ' ' ? 1 : 0);
2041   }
2042
2043   if (req_state & REQ_ASK)
2044   {
2045     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2046     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2047   }
2048   else if (req_state & REQ_CONFIRM)
2049   {
2050     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2051   }
2052   else if (req_state & REQ_PLAYER)
2053   {
2054     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2055     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2056     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2057     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2058   }
2059
2060   /* copy request gadgets to door backbuffer */
2061   BlitBitmap(drawto, bitmap_db_door,
2062              DX, DY, DXSIZE, DYSIZE,
2063              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2064
2065   OpenDoor(DOOR_OPEN_1);
2066
2067 #if 0
2068   ClearEventQueue();
2069 #endif
2070
2071   if (!(req_state & REQUEST_WAIT_FOR))
2072   {
2073     SetDrawBackgroundMask(REDRAW_FIELD);
2074
2075     return FALSE;
2076   }
2077
2078   if (game_status != MAINMENU)
2079     InitAnimation();
2080
2081   button_status = MB_RELEASED;
2082
2083   request_gadget_id = -1;
2084
2085   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2086
2087   while(result < 0)
2088   {
2089     if (PendingEvent())
2090     {
2091       Event event;
2092
2093       NextEvent(&event);
2094
2095       switch(event.type)
2096       {
2097         case EVENT_BUTTONPRESS:
2098         case EVENT_BUTTONRELEASE:
2099         case EVENT_MOTIONNOTIFY:
2100         {
2101           if (event.type == EVENT_MOTIONNOTIFY)
2102           {
2103             if (!PointerInWindow(window))
2104               continue; /* window and pointer are on different screens */
2105
2106             if (!button_status)
2107               continue;
2108
2109             motion_status = TRUE;
2110             mx = ((MotionEvent *) &event)->x;
2111             my = ((MotionEvent *) &event)->y;
2112           }
2113           else
2114           {
2115             motion_status = FALSE;
2116             mx = ((ButtonEvent *) &event)->x;
2117             my = ((ButtonEvent *) &event)->y;
2118             if (event.type == EVENT_BUTTONPRESS)
2119               button_status = ((ButtonEvent *) &event)->button;
2120             else
2121               button_status = MB_RELEASED;
2122           }
2123
2124           /* this sets 'request_gadget_id' */
2125           HandleGadgets(mx, my, button_status);
2126
2127           switch(request_gadget_id)
2128           {
2129             case TOOL_CTRL_ID_YES:
2130               result = TRUE;
2131               break;
2132             case TOOL_CTRL_ID_NO:
2133               result = FALSE;
2134               break;
2135             case TOOL_CTRL_ID_CONFIRM:
2136               result = TRUE | FALSE;
2137               break;
2138
2139             case TOOL_CTRL_ID_PLAYER_1:
2140               result = 1;
2141               break;
2142             case TOOL_CTRL_ID_PLAYER_2:
2143               result = 2;
2144               break;
2145             case TOOL_CTRL_ID_PLAYER_3:
2146               result = 3;
2147               break;
2148             case TOOL_CTRL_ID_PLAYER_4:
2149               result = 4;
2150               break;
2151
2152             default:
2153               break;
2154           }
2155
2156           break;
2157         }
2158
2159         case EVENT_KEYPRESS:
2160           switch(GetEventKey((KeyEvent *)&event, TRUE))
2161           {
2162             case KSYM_Return:
2163               result = 1;
2164               break;
2165
2166             case KSYM_Escape:
2167               result = 0;
2168               break;
2169
2170             default:
2171               break;
2172           }
2173           if (req_state & REQ_PLAYER)
2174             result = 0;
2175           break;
2176
2177         case EVENT_KEYRELEASE:
2178           ClearPlayerAction();
2179           break;
2180
2181         default:
2182           HandleOtherEvents(&event);
2183           break;
2184       }
2185     }
2186     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2187     {
2188       int joy = AnyJoystick();
2189
2190       if (joy & JOY_BUTTON_1)
2191         result = 1;
2192       else if (joy & JOY_BUTTON_2)
2193         result = 0;
2194     }
2195
2196     DoAnimation();
2197
2198     /* don't eat all CPU time */
2199     Delay(10);
2200   }
2201
2202   if (game_status != MAINMENU)
2203     StopAnimation();
2204
2205   UnmapToolButtons();
2206
2207   if (!(req_state & REQ_STAY_OPEN))
2208   {
2209     CloseDoor(DOOR_CLOSE_1);
2210
2211     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2212     {
2213       BlitBitmap(bitmap_db_door, bitmap_db_door,
2214                  DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2215                  DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2216       OpenDoor(DOOR_OPEN_1);
2217     }
2218   }
2219
2220   RemapAllGadgets();
2221
2222   SetDrawBackgroundMask(REDRAW_FIELD);
2223
2224 #if defined(PLATFORM_UNIX)
2225   /* continue network game after request */
2226   if (options.network &&
2227       game_status == PLAYING &&
2228       req_state & REQUEST_WAIT_FOR)
2229     SendToServer_ContinuePlaying();
2230 #endif
2231
2232   return result;
2233 }
2234
2235 unsigned int OpenDoor(unsigned int door_state)
2236 {
2237   unsigned int new_door_state;
2238
2239   if (door_state & DOOR_COPY_BACK)
2240   {
2241     BlitBitmap(bitmap_db_door, bitmap_db_door,
2242                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2243                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2244     door_state &= ~DOOR_COPY_BACK;
2245   }
2246
2247   new_door_state = MoveDoor(door_state);
2248
2249   return(new_door_state);
2250 }
2251
2252 unsigned int CloseDoor(unsigned int door_state)
2253 {
2254   unsigned int new_door_state;
2255
2256   BlitBitmap(backbuffer, bitmap_db_door,
2257              DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2258   BlitBitmap(backbuffer, bitmap_db_door,
2259              VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2260
2261   new_door_state = MoveDoor(door_state);
2262
2263   return(new_door_state);
2264 }
2265
2266 unsigned int GetDoorState()
2267 {
2268   return MoveDoor(DOOR_GET_STATE);
2269 }
2270
2271 unsigned int SetDoorState(unsigned int door_state)
2272 {
2273   return MoveDoor(door_state | DOOR_SET_STATE);
2274 }
2275
2276 unsigned int MoveDoor(unsigned int door_state)
2277 {
2278   static int door1 = DOOR_OPEN_1;
2279   static int door2 = DOOR_CLOSE_2;
2280   static unsigned long door_delay = 0;
2281   int x, start, stepsize = 2;
2282   unsigned long door_delay_value = stepsize * 5;
2283
2284   if (door_state == DOOR_GET_STATE)
2285     return(door1 | door2);
2286
2287   if (door_state & DOOR_SET_STATE)
2288   {
2289     if (door_state & DOOR_ACTION_1)
2290       door1 = door_state & DOOR_ACTION_1;
2291     if (door_state & DOOR_ACTION_2)
2292       door2 = door_state & DOOR_ACTION_2;
2293
2294     return(door1 | door2);
2295   }
2296
2297   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2298     door_state &= ~DOOR_OPEN_1;
2299   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2300     door_state &= ~DOOR_CLOSE_1;
2301   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2302     door_state &= ~DOOR_OPEN_2;
2303   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2304     door_state &= ~DOOR_CLOSE_2;
2305
2306   if (setup.quick_doors)
2307   {
2308     stepsize = 20;
2309     door_delay_value = 0;
2310
2311     StopSound(SND_MENU_DOOR_OPENING);
2312     StopSound(SND_MENU_DOOR_CLOSING);
2313   }
2314
2315   if (global.autoplay_leveldir)
2316   {
2317     door_state |= DOOR_NO_DELAY;
2318     door_state &= ~DOOR_CLOSE_ALL;
2319   }
2320
2321   if (door_state & DOOR_ACTION)
2322   {
2323     if (!(door_state & DOOR_NO_DELAY))
2324     {
2325       /* opening door sound has priority over simultaneously closing door */
2326       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2327         PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2328       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2329         PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2330     }
2331
2332     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2333
2334     for(x=start; x<=DXSIZE; x+=stepsize)
2335     {
2336       Bitmap *bitmap = new_graphic_info[IMG_GLOBAL_DOOR].bitmap;
2337       GC gc = bitmap->stored_clip_gc;
2338
2339       if (!(door_state & DOOR_NO_DELAY))
2340         WaitUntilDelayReached(&door_delay, door_delay_value);
2341
2342       if (door_state & DOOR_ACTION_1)
2343       {
2344         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2345         int j = (DXSIZE - i) / 3;
2346
2347         BlitBitmap(bitmap_db_door, drawto,
2348                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2349                    DXSIZE,DYSIZE - i/2, DX, DY);
2350
2351         ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2352
2353         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2354         BlitBitmapMasked(bitmap, drawto,
2355                          DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2356                          DX + DXSIZE - i, DY + j);
2357         BlitBitmapMasked(bitmap, drawto,
2358                          DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2359                          DX + DXSIZE - i, DY + 140 + j);
2360         SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2361         BlitBitmapMasked(bitmap, drawto,
2362                          DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2363                          DX, DY);
2364         BlitBitmapMasked(bitmap, drawto,
2365                          DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2366                          DX, DY + 140 - j);
2367
2368         BlitBitmapMasked(bitmap, drawto,
2369                          DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2370                          DX, DY + 77 - j);
2371         BlitBitmapMasked(bitmap, drawto,
2372                          DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2373                          DX, DY + 203 - j);
2374         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2375         BlitBitmapMasked(bitmap, drawto,
2376                          DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2377                          DX + DXSIZE - i, DY + 77 + j);
2378         BlitBitmapMasked(bitmap, drawto,
2379                          DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2380                          DX + DXSIZE - i, DY + 203 + j);
2381
2382         redraw_mask |= REDRAW_DOOR_1;
2383       }
2384
2385       if (door_state & DOOR_ACTION_2)
2386       {
2387         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2388         int j = (VXSIZE - i) / 3;
2389
2390         BlitBitmap(bitmap_db_door, drawto,
2391                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2392                    VXSIZE, VYSIZE - i/2, VX, VY);
2393
2394         ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2395
2396         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2397         BlitBitmapMasked(bitmap, drawto,
2398                          VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2399                          VX + VXSIZE-i, VY+j);
2400         SetClipOrigin(bitmap, gc,
2401                       VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2402         BlitBitmapMasked(bitmap, drawto,
2403                          VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2404                          VX, VY);
2405
2406         BlitBitmapMasked(bitmap, drawto,
2407                          VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2408                          i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2409         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2410         BlitBitmapMasked(bitmap, drawto,
2411                          VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2412                          i, VYSIZE / 2 - j,
2413                          VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2414
2415         redraw_mask |= REDRAW_DOOR_2;
2416       }
2417
2418       BackToFront();
2419
2420       if (game_status == MAINMENU)
2421         DoAnimation();
2422     }
2423   }
2424
2425   if (setup.quick_doors)
2426   {
2427     StopSound(SND_MENU_DOOR_OPENING);
2428     StopSound(SND_MENU_DOOR_CLOSING);
2429   }
2430
2431   if (door_state & DOOR_ACTION_1)
2432     door1 = door_state & DOOR_ACTION_1;
2433   if (door_state & DOOR_ACTION_2)
2434     door2 = door_state & DOOR_ACTION_2;
2435
2436   return (door1 | door2);
2437 }
2438
2439 void DrawSpecialEditorDoor()
2440 {
2441   /* draw bigger toolbox window */
2442   BlitBitmap(new_graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2443              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2444              EX - 4, EY - 12);
2445   BlitBitmap(new_graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2446              EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2447              EX - 4, EY - 4);
2448
2449   redraw_mask |= REDRAW_ALL;
2450 }
2451
2452 void UndrawSpecialEditorDoor()
2453 {
2454   /* draw normal tape recorder window */
2455   BlitBitmap(new_graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2456              EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2457              EX - 4, EY - 12);
2458
2459   redraw_mask |= REDRAW_ALL;
2460 }
2461
2462 #ifndef TARGET_SDL
2463 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2464 {
2465   XImage *pixel_image;
2466   unsigned long pixel_value;
2467
2468   pixel_image = XGetImage(display, bitmap->drawable,
2469                           x, y, 1, 1, AllPlanes, ZPixmap);
2470   pixel_value = XGetPixel(pixel_image, 0, 0);
2471
2472   XDestroyImage(pixel_image);
2473
2474   return pixel_value;
2475 }
2476 #endif
2477
2478 /* ---------- new tool button stuff ---------------------------------------- */
2479
2480 /* graphic position values for tool buttons */
2481 #define TOOL_BUTTON_YES_XPOS            2
2482 #define TOOL_BUTTON_YES_YPOS            250
2483 #define TOOL_BUTTON_YES_GFX_YPOS        0
2484 #define TOOL_BUTTON_YES_XSIZE           46
2485 #define TOOL_BUTTON_YES_YSIZE           28
2486 #define TOOL_BUTTON_NO_XPOS             52
2487 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2488 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2489 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2490 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2491 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2492 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2493 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2494 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2495 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2496 #define TOOL_BUTTON_PLAYER_XSIZE        30
2497 #define TOOL_BUTTON_PLAYER_YSIZE        30
2498 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2499 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2500 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2501 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2502 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2503                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2504 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2505                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2506 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2507                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2508 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2509                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2510 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2511                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2512 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2513                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2514 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2515                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2516 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2517                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2518
2519 static struct
2520 {
2521   int xpos, ypos;
2522   int x, y;
2523   int width, height;
2524   int gadget_id;
2525   char *infotext;
2526 } toolbutton_info[NUM_TOOL_BUTTONS] =
2527 {
2528   {
2529     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2530     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2531     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2532     TOOL_CTRL_ID_YES,
2533     "yes"
2534   },
2535   {
2536     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2537     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2538     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2539     TOOL_CTRL_ID_NO,
2540     "no"
2541   },
2542   {
2543     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2544     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2545     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2546     TOOL_CTRL_ID_CONFIRM,
2547     "confirm"
2548   },
2549   {
2550     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2551     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2552     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2553     TOOL_CTRL_ID_PLAYER_1,
2554     "player 1"
2555   },
2556   {
2557     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2558     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2559     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2560     TOOL_CTRL_ID_PLAYER_2,
2561     "player 2"
2562   },
2563   {
2564     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2565     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2566     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2567     TOOL_CTRL_ID_PLAYER_3,
2568     "player 3"
2569   },
2570   {
2571     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2572     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2573     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2574     TOOL_CTRL_ID_PLAYER_4,
2575     "player 4"
2576   }
2577 };
2578
2579 void CreateToolButtons()
2580 {
2581   int i;
2582
2583   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2584   {
2585     Bitmap *gd_bitmap = new_graphic_info[IMG_GLOBAL_DOOR].bitmap;
2586     Bitmap *deco_bitmap = None;
2587     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2588     struct GadgetInfo *gi;
2589     unsigned long event_mask;
2590     int gd_xoffset, gd_yoffset;
2591     int gd_x1, gd_x2, gd_y;
2592     int id = i;
2593
2594     event_mask = GD_EVENT_RELEASED;
2595
2596     gd_xoffset = toolbutton_info[i].xpos;
2597     gd_yoffset = toolbutton_info[i].ypos;
2598     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2599     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2600     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2601
2602     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2603     {
2604       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2605
2606       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2607                            &deco_bitmap, &deco_x, &deco_y);
2608       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2609       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2610     }
2611
2612     gi = CreateGadget(GDI_CUSTOM_ID, id,
2613                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2614                       GDI_X, DX + toolbutton_info[i].x,
2615                       GDI_Y, DY + toolbutton_info[i].y,
2616                       GDI_WIDTH, toolbutton_info[i].width,
2617                       GDI_HEIGHT, toolbutton_info[i].height,
2618                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2619                       GDI_STATE, GD_BUTTON_UNPRESSED,
2620                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2621                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2622                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2623                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2624                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2625                       GDI_DECORATION_SHIFTING, 1, 1,
2626                       GDI_EVENT_MASK, event_mask,
2627                       GDI_CALLBACK_ACTION, HandleToolButtons,
2628                       GDI_END);
2629
2630     if (gi == NULL)
2631       Error(ERR_EXIT, "cannot create gadget");
2632
2633     tool_gadget[id] = gi;
2634   }
2635 }
2636
2637 void FreeToolButtons()
2638 {
2639   int i;
2640
2641   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2642     FreeGadget(tool_gadget[i]);
2643 }
2644
2645 static void UnmapToolButtons()
2646 {
2647   int i;
2648
2649   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2650     UnmapGadget(tool_gadget[i]);
2651 }
2652
2653 static void HandleToolButtons(struct GadgetInfo *gi)
2654 {
2655   request_gadget_id = gi->custom_id;
2656 }
2657
2658 int get_next_element(int element)
2659 {
2660   switch(element)
2661   {
2662     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
2663     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
2664     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
2665     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
2666     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
2667     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
2668     case EL_AMOEBA_DRIPPING:            return EL_AMOEBA_WET;
2669
2670     default:                            return element;
2671   }
2672 }
2673
2674 int el2gfx_OLD(int element)
2675 {
2676   switch(element)
2677   {
2678     case EL_EMPTY:                      return -1;
2679     case EL_SAND:                       return GFX_ERDREICH;
2680     case EL_WALL:                       return GFX_MAUERWERK;
2681     case EL_WALL_CRUMBLED:              return GFX_FELSBODEN;
2682     case EL_ROCK:                       return GFX_FELSBROCKEN;
2683     case EL_EMERALD:                    return GFX_EDELSTEIN;
2684     case EL_EXIT_CLOSED:                return GFX_AUSGANG_ZU;
2685     case EL_EXIT_OPENING:               return GFX_AUSGANG_ACT;
2686     case EL_EXIT_OPEN:                  return GFX_AUSGANG_AUF;
2687     case EL_SP_EXIT_OPEN:               return GFX_SP_EXIT;
2688     case EL_PLAYER1:                    return GFX_SPIELER1;
2689     case EL_PLAYER2:                    return GFX_SPIELER2;
2690     case EL_PLAYER3:                    return GFX_SPIELER3;
2691     case EL_PLAYER4:                    return GFX_SPIELER4;
2692     case EL_BUG:                        return GFX_KAEFER;
2693     case EL_BUG_RIGHT:                  return GFX_KAEFER_RIGHT;
2694     case EL_BUG_UP:                     return GFX_KAEFER_UP;
2695     case EL_BUG_LEFT:                   return GFX_KAEFER_LEFT;
2696     case EL_BUG_DOWN:                   return GFX_KAEFER_DOWN;
2697     case EL_SPACESHIP:                  return GFX_FLIEGER;
2698     case EL_SPACESHIP_RIGHT:            return GFX_FLIEGER_RIGHT;
2699     case EL_SPACESHIP_UP:               return GFX_FLIEGER_UP;
2700     case EL_SPACESHIP_LEFT:             return GFX_FLIEGER_LEFT;
2701     case EL_SPACESHIP_DOWN:             return GFX_FLIEGER_DOWN;
2702     case EL_BD_BUTTERFLY:               return GFX_BUTTERFLY;
2703     case EL_BD_BUTTERFLY_RIGHT:         return GFX_BUTTERFLY_RIGHT;
2704     case EL_BD_BUTTERFLY_UP:            return GFX_BUTTERFLY_UP;
2705     case EL_BD_BUTTERFLY_LEFT:          return GFX_BUTTERFLY_LEFT;
2706     case EL_BD_BUTTERFLY_DOWN:          return GFX_BUTTERFLY_DOWN;
2707     case EL_BD_FIREFLY:                 return GFX_FIREFLY;
2708     case EL_BD_FIREFLY_RIGHT:           return GFX_FIREFLY_RIGHT;
2709     case EL_BD_FIREFLY_UP:              return GFX_FIREFLY_UP;
2710     case EL_BD_FIREFLY_LEFT:            return GFX_FIREFLY_LEFT;
2711     case EL_BD_FIREFLY_DOWN:            return GFX_FIREFLY_DOWN;
2712     case EL_YAMYAM:                     return GFX_MAMPFER;
2713     case EL_ROBOT:                      return GFX_ROBOT;
2714     case EL_STEELWALL:                  return GFX_BETON;
2715     case EL_DIAMOND:                    return GFX_DIAMANT;
2716     case EL_QUICKSAND_EMPTY:            return GFX_MORAST_LEER;
2717     case EL_QUICKSAND_FULL:             return GFX_MORAST_VOLL;
2718     case EL_QUICKSAND_EMPTYING:         return GFX_MORAST_LEER;
2719     case EL_AMOEBA_DROP:                return GFX_TROPFEN;
2720     case EL_BOMB:                       return GFX_BOMBE;
2721     case EL_MAGIC_WALL:                 return GFX_MAGIC_WALL_OFF;
2722     case EL_MAGIC_WALL_ACTIVE:          return GFX_MAGIC_WALL_EMPTY;
2723     case EL_MAGIC_WALL_EMPTYING:        return GFX_MAGIC_WALL_EMPTY;
2724     case EL_MAGIC_WALL_FULL:            return GFX_MAGIC_WALL_FULL;
2725     case EL_MAGIC_WALL_DEAD:            return GFX_MAGIC_WALL_DEAD;
2726     case EL_ACID:                       return GFX_SALZSAEURE;
2727     case EL_AMOEBA_DEAD:                return GFX_AMOEBE_TOT;
2728     case EL_AMOEBA_WET:                 return GFX_AMOEBE_NASS;
2729     case EL_AMOEBA_DRY:                 return GFX_AMOEBE_NORM;
2730     case EL_AMOEBA_FULL:                return GFX_AMOEBE_VOLL;
2731     case EL_BD_AMOEBA:                  return GFX_AMOEBE_BD;
2732     case EL_AMOEBA_TO_DIAMOND:          return GFX_AMOEBA2DIAM;
2733     case EL_AMOEBA_DRIPPING:            return GFX_AMOEBE_NASS;
2734     case EL_NUT:                        return GFX_KOKOSNUSS;
2735     case EL_GAMEOFLIFE:                 return GFX_LIFE;
2736     case EL_BIOMAZE:                    return GFX_LIFE_ASYNC;
2737     case EL_DYNAMITE_ACTIVE:            return GFX_DYNAMIT;
2738     case EL_STONEBLOCK:                 return GFX_BADEWANNE;
2739     case EL_ACIDPOOL_TOPLEFT:           return GFX_BADEWANNE1;
2740     case EL_ACIDPOOL_TOPRIGHT:          return GFX_BADEWANNE2;
2741     case EL_ACIDPOOL_BOTTOMLEFT:        return GFX_BADEWANNE3;
2742     case EL_ACIDPOOL_BOTTOM:            return GFX_BADEWANNE4;
2743     case EL_ACIDPOOL_BOTTOMRIGHT:       return GFX_BADEWANNE5;
2744     case EL_ROBOT_WHEEL:                return GFX_ABLENK_AUS;
2745     case EL_ROBOT_WHEEL_ACTIVE:         return GFX_ABLENK_EIN;
2746     case EL_KEY1:                       return GFX_SCHLUESSEL1;
2747     case EL_KEY2:                       return GFX_SCHLUESSEL2;
2748     case EL_KEY3:                       return GFX_SCHLUESSEL3;
2749     case EL_KEY4:                       return GFX_SCHLUESSEL4;
2750     case EL_GATE1:                      return GFX_PFORTE1;
2751     case EL_GATE2:                      return GFX_PFORTE2;
2752     case EL_GATE3:                      return GFX_PFORTE3;
2753     case EL_GATE4:                      return GFX_PFORTE4;
2754     case EL_GATE1_GRAY:                 return GFX_PFORTE1X;
2755     case EL_GATE2_GRAY:                 return GFX_PFORTE2X;
2756     case EL_GATE3_GRAY:                 return GFX_PFORTE3X;
2757     case EL_GATE4_GRAY:                 return GFX_PFORTE4X;
2758     case EL_DYNAMITE:                   return GFX_DYNAMIT_AUS;
2759     case EL_PACMAN:                     return GFX_PACMAN;
2760     case EL_PACMAN_RIGHT:               return GFX_PACMAN_RIGHT;
2761     case EL_PACMAN_UP:                  return GFX_PACMAN_UP;
2762     case EL_PACMAN_LEFT:                return GFX_PACMAN_LEFT;
2763     case EL_PACMAN_DOWN:                return GFX_PACMAN_DOWN;
2764     case EL_INVISIBLE_WALL:             return GFX_UNSICHTBAR;
2765     case EL_INVISIBLE_WALL_ACTIVE:      return GFX_UNSICHTBAR_ON;
2766     case EL_WALL_EMERALD:               return GFX_ERZ_EDEL;
2767     case EL_WALL_DIAMOND:               return GFX_ERZ_DIAM;
2768     case EL_LAMP:                       return GFX_BIRNE_AUS;
2769     case EL_LAMP_ACTIVE:                return GFX_BIRNE_EIN;
2770     case EL_TIME_ORB_FULL:              return GFX_ZEIT_VOLL;
2771     case EL_TIME_ORB_EMPTY:             return GFX_ZEIT_LEER;
2772     case EL_WALL_GROWING:               return GFX_MAUER_LEBT;
2773     case EL_WALL_GROWING_X:             return GFX_MAUER_X;
2774     case EL_WALL_GROWING_Y:             return GFX_MAUER_Y;
2775     case EL_WALL_GROWING_XY:            return GFX_MAUER_XY;
2776     case EL_BD_DIAMOND:                 return GFX_EDELSTEIN_BD;
2777     case EL_EMERALD_YELLOW:             return GFX_EDELSTEIN_GELB;
2778     case EL_EMERALD_RED:                return GFX_EDELSTEIN_ROT;
2779     case EL_EMERALD_PURPLE:             return GFX_EDELSTEIN_LILA;
2780     case EL_WALL_BD_DIAMOND:            return GFX_ERZ_EDEL_BD;
2781     case EL_WALL_EMERALD_YELLOW:        return GFX_ERZ_EDEL_GELB;
2782     case EL_WALL_EMERALD_RED:           return GFX_ERZ_EDEL_ROT;
2783     case EL_WALL_EMERALD_PURPLE:        return GFX_ERZ_EDEL_LILA;
2784     case EL_DARK_YAMYAM:                return GFX_MAMPFER2;
2785     case EL_BD_MAGIC_WALL:              return GFX_MAGIC_WALL_BD_OFF;
2786     case EL_BD_MAGIC_WALL_ACTIVE:       return GFX_MAGIC_WALL_BD_EMPTY;
2787     case EL_BD_MAGIC_WALL_EMPTYING:     return GFX_MAGIC_WALL_BD_EMPTY;
2788     case EL_BD_MAGIC_WALL_FULL:         return GFX_MAGIC_WALL_BD_FULL;
2789     case EL_BD_MAGIC_WALL_DEAD:         return GFX_MAGIC_WALL_BD_DEAD;
2790     case EL_DYNABOMB_PLAYER1_ACTIVE:    return GFX_DYNABOMB;
2791     case EL_DYNABOMB_PLAYER2_ACTIVE:    return GFX_DYNABOMB;
2792     case EL_DYNABOMB_PLAYER3_ACTIVE:    return GFX_DYNABOMB;
2793     case EL_DYNABOMB_PLAYER4_ACTIVE:    return GFX_DYNABOMB;
2794     case EL_DYNABOMB_NR:                return GFX_DYNABOMB_NR;
2795     case EL_DYNABOMB_SZ:                return GFX_DYNABOMB_SZ;
2796     case EL_DYNABOMB_XL:                return GFX_DYNABOMB_XL;
2797     case EL_SOKOBAN_OBJECT:             return GFX_SOKOBAN_OBJEKT;
2798     case EL_SOKOBAN_FIELD_EMPTY:        return GFX_SOKOBAN_FELD_LEER;
2799     case EL_SOKOBAN_FIELD_FULL:         return GFX_SOKOBAN_FELD_VOLL;
2800     case EL_MOLE:                       return GFX_MOLE;
2801     case EL_PENGUIN:                    return GFX_PINGUIN;
2802     case EL_PIG:                        return GFX_SCHWEIN;
2803     case EL_DRAGON:                     return GFX_DRACHE;
2804     case EL_SATELLITE:                  return GFX_SONDE;
2805     case EL_ARROW_BLUE_LEFT:            return GFX_PFEIL_LEFT;
2806     case EL_ARROW_BLUE_RIGHT:           return GFX_PFEIL_RIGHT;
2807     case EL_ARROW_BLUE_UP:              return GFX_PFEIL_UP;
2808     case EL_ARROW_BLUE_DOWN:            return GFX_PFEIL_DOWN;
2809     case EL_SPEED_PILL:                 return GFX_SPEED_PILL;
2810     case EL_SP_TERMINAL_ACTIVE:         return GFX_SP_TERMINAL;
2811     case EL_SP_BUGGY_BASE_ACTIVE:       return GFX_SP_BUG_ACTIVE;
2812     case EL_SP_ZONK:                    return GFX_SP_ZONK;
2813       /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2814     case EL_INVISIBLE_STEELWALL:        return GFX_INVISIBLE_STEEL;
2815     case EL_INVISIBLE_STEELWALL_ACTIVE: return GFX_INVISIBLE_STEEL_ON;
2816     case EL_BLACK_ORB:                  return GFX_BLACK_ORB;
2817     case EL_EM_GATE1:                   return GFX_EM_GATE_1;
2818     case EL_EM_GATE2:                   return GFX_EM_GATE_2;
2819     case EL_EM_GATE3:                   return GFX_EM_GATE_3;
2820     case EL_EM_GATE4:                   return GFX_EM_GATE_4;
2821     case EL_EM_GATE1_GRAY:              return GFX_EM_GATE_1X;
2822     case EL_EM_GATE2_GRAY:              return GFX_EM_GATE_2X;
2823     case EL_EM_GATE3_GRAY:              return GFX_EM_GATE_3X;
2824     case EL_EM_GATE4_GRAY:              return GFX_EM_GATE_4X;
2825     case EL_EM_KEY1_FILE:               return GFX_EM_KEY_1;
2826     case EL_EM_KEY2_FILE:               return GFX_EM_KEY_2;
2827     case EL_EM_KEY3_FILE:               return GFX_EM_KEY_3;
2828     case EL_EM_KEY4_FILE:               return GFX_EM_KEY_4;
2829     case EL_EM_KEY1:                    return GFX_EM_KEY_1;
2830     case EL_EM_KEY2:                    return GFX_EM_KEY_2;
2831     case EL_EM_KEY3:                    return GFX_EM_KEY_3;
2832     case EL_EM_KEY4:                    return GFX_EM_KEY_4;
2833     case EL_PEARL:                      return GFX_PEARL;
2834     case EL_CRYSTAL:                    return GFX_CRYSTAL;
2835     case EL_WALL_PEARL:                 return GFX_WALL_PEARL;
2836     case EL_WALL_CRYSTAL:               return GFX_WALL_CRYSTAL;
2837     case EL_DOOR_WHITE:                 return GFX_DOOR_WHITE;
2838     case EL_DOOR_WHITE_GRAY:            return GFX_DOOR_WHITE_GRAY;
2839     case EL_KEY_WHITE:                  return GFX_KEY_WHITE;
2840     case EL_SHIELD_NORMAL:              return GFX_SHIELD_PASSIVE;
2841     case EL_SHIELD_DEADLY:              return GFX_SHIELD_ACTIVE;
2842     case EL_EXTRA_TIME:                 return GFX_EXTRA_TIME;
2843     case EL_SWITCHGATE_OPEN:            return GFX_SWITCHGATE_OPEN;
2844     case EL_SWITCHGATE_CLOSED:          return GFX_SWITCHGATE_CLOSED;
2845     case EL_SWITCHGATE_SWITCH_UP:       return GFX_SWITCHGATE_SWITCH_1;
2846     case EL_SWITCHGATE_SWITCH_DOWN:     return GFX_SWITCHGATE_SWITCH_2;
2847     case EL_CONVEYOR_BELT1_LEFT:        return GFX_BELT1_LEFT;
2848     case EL_CONVEYOR_BELT1_MIDDLE:      return GFX_BELT1_MIDDLE;
2849     case EL_CONVEYOR_BELT1_RIGHT:       return GFX_BELT1_RIGHT;
2850     case EL_CONVEYOR_BELT1_LEFT_ACTIVE: return GFX_BELT1_LEFT;
2851     case EL_CONVEYOR_BELT1_MIDDLE_ACTIVE:return GFX_BELT1_MIDDLE;
2852     case EL_CONVEYOR_BELT1_RIGHT_ACTIVE:return GFX_BELT1_RIGHT;
2853     case EL_CONVEYOR_BELT1_SWITCH_LEFT: return GFX_BELT1_SWITCH_LEFT;
2854     case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
2855     case EL_CONVEYOR_BELT1_SWITCH_RIGHT:return GFX_BELT1_SWITCH_RIGHT;
2856     case EL_CONVEYOR_BELT2_LEFT:        return GFX_BELT2_LEFT;
2857     case EL_CONVEYOR_BELT2_MIDDLE:      return GFX_BELT2_MIDDLE;
2858     case EL_CONVEYOR_BELT2_RIGHT:       return GFX_BELT2_RIGHT;
2859     case EL_CONVEYOR_BELT2_LEFT_ACTIVE: return GFX_BELT2_LEFT;
2860     case EL_CONVEYOR_BELT2_MIDDLE_ACTIVE:return GFX_BELT2_MIDDLE;
2861     case EL_CONVEYOR_BELT2_RIGHT_ACTIVE:return GFX_BELT2_RIGHT;
2862     case EL_CONVEYOR_BELT2_SWITCH_LEFT: return GFX_BELT2_SWITCH_LEFT;
2863     case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
2864     case EL_CONVEYOR_BELT2_SWITCH_RIGHT:return GFX_BELT2_SWITCH_RIGHT;
2865     case EL_CONVEYOR_BELT3_LEFT:        return GFX_BELT3_LEFT;
2866     case EL_CONVEYOR_BELT3_MIDDLE:      return GFX_BELT3_MIDDLE;
2867     case EL_CONVEYOR_BELT3_RIGHT:       return GFX_BELT3_RIGHT;
2868     case EL_CONVEYOR_BELT3_LEFT_ACTIVE: return GFX_BELT3_LEFT;
2869     case EL_CONVEYOR_BELT3_MIDDLE_ACTIVE:return GFX_BELT3_MIDDLE;
2870     case EL_CONVEYOR_BELT3_RIGHT_ACTIVE:return GFX_BELT3_RIGHT;
2871     case EL_CONVEYOR_BELT3_SWITCH_LEFT: return GFX_BELT3_SWITCH_LEFT;
2872     case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
2873     case EL_CONVEYOR_BELT3_SWITCH_RIGHT:return GFX_BELT3_SWITCH_RIGHT;
2874     case EL_CONVEYOR_BELT4_LEFT:        return GFX_BELT4_LEFT;
2875     case EL_CONVEYOR_BELT4_MIDDLE:      return GFX_BELT4_MIDDLE;
2876     case EL_CONVEYOR_BELT4_RIGHT:       return GFX_BELT4_RIGHT;
2877     case EL_CONVEYOR_BELT4_LEFT_ACTIVE: return GFX_BELT4_LEFT;
2878     case EL_CONVEYOR_BELT4_MIDDLE_ACTIVE:return GFX_BELT4_MIDDLE;
2879     case EL_CONVEYOR_BELT4_RIGHT_ACTIVE:return GFX_BELT4_RIGHT;
2880     case EL_CONVEYOR_BELT4_SWITCH_LEFT: return GFX_BELT4_SWITCH_LEFT;
2881     case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
2882     case EL_CONVEYOR_BELT4_SWITCH_RIGHT:return GFX_BELT4_SWITCH_RIGHT;
2883     case EL_LANDMINE:                   return GFX_LANDMINE;
2884     case EL_ENVELOPE:                   return GFX_ENVELOPE;
2885     case EL_LIGHT_SWITCH:               return GFX_LIGHT_SWITCH_OFF;
2886     case EL_LIGHT_SWITCH_ACTIVE:        return GFX_LIGHT_SWITCH_ON;
2887     case EL_SIGN_EXCLAMATION:           return GFX_SIGN_EXCLAMATION;
2888     case EL_SIGN_RADIOACTIVITY:         return GFX_SIGN_RADIOACTIVITY;
2889     case EL_SIGN_STOP:                  return GFX_SIGN_STOP;
2890     case EL_SIGN_WHEELCHAIR:            return GFX_SIGN_WHEELCHAIR;
2891     case EL_SIGN_PARKING:               return GFX_SIGN_PARKING;
2892     case EL_SIGN_ONEWAY:                return GFX_SIGN_ONEWAY;
2893     case EL_SIGN_HEART:                 return GFX_SIGN_HEART;
2894     case EL_SIGN_TRIANGLE:              return GFX_SIGN_TRIANGLE;
2895     case EL_SIGN_ROUND:                 return GFX_SIGN_ROUND;
2896     case EL_SIGN_EXIT:                  return GFX_SIGN_EXIT;
2897     case EL_SIGN_YINYANG:               return GFX_SIGN_YINYANG;
2898     case EL_SIGN_OTHER:                 return GFX_SIGN_OTHER;
2899     case EL_MOLE_LEFT:                  return GFX_MOLE_LEFT;
2900     case EL_MOLE_RIGHT:                 return GFX_MOLE_RIGHT;
2901     case EL_MOLE_UP:                    return GFX_MOLE_UP;
2902     case EL_MOLE_DOWN:                  return GFX_MOLE_DOWN;
2903     case EL_STEELWALL_SLANTED:          return GFX_STEEL_SLANTED;
2904     case EL_INVISIBLE_SAND:             return GFX_SAND_INVISIBLE;
2905     case EL_INVISIBLE_SAND_ACTIVE:      return GFX_SAND_INVISIBLE_ON;
2906     case EL_DX_UNKNOWN_15:              return GFX_DX_UNKNOWN_15;
2907     case EL_DX_UNKNOWN_42:              return GFX_DX_UNKNOWN_42;
2908     case EL_TIMEGATE_OPEN:              return GFX_TIMEGATE_OPEN;
2909     case EL_TIMEGATE_CLOSED:            return GFX_TIMEGATE_CLOSED;
2910     case EL_TIMEGATE_SWITCH_ACTIVE:     return GFX_TIMEGATE_SWITCH;
2911     case EL_TIMEGATE_SWITCH:            return GFX_TIMEGATE_SWITCH;
2912     case EL_BALLOON:                    return GFX_BALLOON;
2913     case EL_BALLOON_SEND_LEFT:          return GFX_BALLOON_SEND_LEFT;
2914     case EL_BALLOON_SEND_RIGHT:         return GFX_BALLOON_SEND_RIGHT;
2915     case EL_BALLOON_SEND_UP:            return GFX_BALLOON_SEND_UP;
2916     case EL_BALLOON_SEND_DOWN:          return GFX_BALLOON_SEND_DOWN;
2917     case EL_BALLOON_SEND_ANY_DIRECTION: return GFX_BALLOON_SEND_ANY;
2918     case EL_EMC_STEELWALL1:             return GFX_EMC_STEEL_WALL_1;
2919     case EL_EMC_STEELWALL2:             return GFX_EMC_STEEL_WALL_2;
2920     case EL_EMC_STEELWALL3:             return GFX_EMC_STEEL_WALL_3;
2921     case EL_EMC_STEELWALL4:             return GFX_EMC_STEEL_WALL_4;
2922     case EL_EMC_WALL_PILLAR_UPPER:      return GFX_EMC_WALL_1;
2923     case EL_EMC_WALL_PILLAR_MIDDLE:     return GFX_EMC_WALL_2;
2924     case EL_EMC_WALL_PILLAR_LOWER:      return GFX_EMC_WALL_3;
2925     case EL_EMC_WALL4:                  return GFX_EMC_WALL_4;
2926     case EL_EMC_WALL5:                  return GFX_EMC_WALL_5;
2927     case EL_EMC_WALL6:                  return GFX_EMC_WALL_6;
2928     case EL_EMC_WALL7:                  return GFX_EMC_WALL_7;
2929     case EL_EMC_WALL8:                  return GFX_EMC_WALL_8;
2930     case EL_TUBE_ALL:                   return GFX_TUBE_CROSS;
2931     case EL_TUBE_VERTICAL:              return GFX_TUBE_VERTICAL;
2932     case EL_TUBE_HORIZONTAL:            return GFX_TUBE_HORIZONTAL;
2933     case EL_TUBE_VERTICAL_LEFT:         return GFX_TUBE_VERT_LEFT;
2934     case EL_TUBE_VERTICAL_RIGHT:        return GFX_TUBE_VERT_RIGHT;
2935     case EL_TUBE_HORIZONTAL_UP:         return GFX_TUBE_HORIZ_UP;
2936     case EL_TUBE_HORIZONTAL_DOWN:       return GFX_TUBE_HORIZ_DOWN;
2937     case EL_TUBE_LEFT_UP:               return GFX_TUBE_LEFT_UP;
2938     case EL_TUBE_LEFT_DOWN:             return GFX_TUBE_LEFT_DOWN;
2939     case EL_TUBE_RIGHT_UP:              return GFX_TUBE_RIGHT_UP;
2940     case EL_TUBE_RIGHT_DOWN:            return GFX_TUBE_RIGHT_DOWN;
2941     case EL_SPRING:                     return GFX_SPRING;
2942     case EL_TRAP:                       return GFX_TRAP_INACTIVE;
2943     case EL_TRAP_ACTIVE:                return GFX_TRAP_ACTIVE;
2944     case EL_BD_WALL:                    return GFX_BD_WALL;
2945     case EL_BD_ROCK:                    return GFX_BD_ROCK;
2946     case EL_DX_SUPABOMB:                return GFX_DX_SUPABOMB;
2947     case EL_SP_MURPHY_CLONE:            return GFX_SP_MURPHY_CLONE;
2948
2949     default:
2950     {
2951       if (IS_CHAR(element))
2952         return GFX_CHAR_START + (element - EL_CHAR_START);
2953       else if (element >= EL_SP_START && element <= EL_SP_END)
2954       {
2955         int nr_element = element - EL_SP_START;
2956         int gfx_per_line = 8;
2957         int nr_graphic =
2958           (nr_element / gfx_per_line) * SP_PER_LINE +
2959           (nr_element % gfx_per_line);
2960
2961         return GFX_START_ROCKSSP + nr_graphic;
2962       }
2963       else
2964         return -1;
2965     }
2966   }
2967 }
2968
2969 int el2gfx(int element)
2970 {
2971 #if 1
2972   int graphic_OLD = el2gfx_OLD(element);
2973
2974   return graphic_OLD;
2975 #else
2976
2977   int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2978
2979 #if DEBUG
2980   int graphic_OLD = el2gfx_OLD(element);
2981
2982   if (element >= MAX_NUM_ELEMENTS)
2983   {
2984     Error(ERR_WARN, "el2gfx: element == %d >= MAX_NUM_ELEMENTS", element);
2985   }
2986
2987   if (graphic_NEW != graphic_OLD)
2988   {
2989     Error(ERR_WARN, "el2gfx: graphic_NEW (%d) != graphic_OLD (%d)",
2990           graphic_NEW, graphic_OLD);
2991   }
2992 #endif
2993
2994   return graphic_NEW;
2995 #endif
2996 }
2997
2998 int el2img(int element)
2999 {
3000   int graphic = element_info[element].graphic[GFX_ACTION_DEFAULT];
3001
3002 #if DEBUG
3003   if (graphic < 0)
3004     Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
3005           element, graphic);
3006 #endif
3007
3008   return graphic;
3009 }
3010
3011 int el_dir2img(int element, int direction)
3012 {
3013   return el_dir_act2img(element, direction, GFX_ACTION_DEFAULT);
3014 }
3015
3016 int el_dir_act2img(int element, int direction, int action)
3017 {
3018 #if DEBUG
3019   if (element < 0)
3020   {    
3021     printf("el_dir_act2img: THIS SHOULD NEVER HAPPEN: element == %d\n",
3022            element);
3023
3024     return IMG_EMPTY;
3025   }
3026
3027   if (action < 0)
3028   {    
3029     printf("el_dir_act2img: THIS SHOULD NEVER HAPPEN: action == %d\n",
3030            action);
3031
3032     return IMG_EMPTY;
3033   }
3034 #endif
3035
3036   action = graphics_action_mapping[action];
3037   direction = MV_DIR_BIT(direction);
3038
3039   return element_info[element].direction_graphic[action][direction];
3040 }