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