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