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