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