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