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