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