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