rnd-20060818-1-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "tools.h"
17 #include "game.h"
18 #include "events.h"
19 #include "cartoons.h"
20 #include "network.h"
21 #include "tape.h"
22
23
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX    0
26
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES        0
29 #define TOOL_CTRL_ID_NO         1
30 #define TOOL_CTRL_ID_CONFIRM    2
31 #define TOOL_CTRL_ID_PLAYER_1   3
32 #define TOOL_CTRL_ID_PLAYER_2   4
33 #define TOOL_CTRL_ID_PLAYER_3   5
34 #define TOOL_CTRL_ID_PLAYER_4   6
35
36 #define NUM_TOOL_BUTTONS        7
37
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
43
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
46
47 static char *print_if_not_empty(int element)
48 {
49   static char *s = NULL;
50   char *token_name = element_info[element].token_name;
51
52   if (s != NULL)
53     free(s);
54
55   s = checked_malloc(strlen(token_name) + 10 + 1);
56
57   if (element != EL_EMPTY)
58     sprintf(s, "%d\t['%s']", element, token_name);
59   else
60     sprintf(s, "%d", element);
61
62   return s;
63 }
64
65 void DumpTile(int x, int y)
66 {
67   int sx = SCREENX(x);
68   int sy = SCREENY(y);
69
70   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
71   {
72     x--;
73     y--;
74   }
75
76   printf_line("-", 79);
77   printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
78   printf_line("-", 79);
79
80   if (!IN_LEV_FIELD(x, y))
81   {
82     printf("(not in level field)\n");
83     printf("\n");
84
85     return;
86   }
87
88   printf("  Feld:        %d\t['%s']\n", Feld[x][y],
89          element_info[Feld[x][y]].token_name);
90   printf("  Back:        %s\n", print_if_not_empty(Back[x][y]));
91   printf("  Store:       %s\n", print_if_not_empty(Store[x][y]));
92   printf("  Store2:      %s\n", print_if_not_empty(Store2[x][y]));
93   printf("  StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94   printf("  MovPos:      %d\n", MovPos[x][y]);
95   printf("  MovDir:      %d\n", MovDir[x][y]);
96   printf("  MovDelay:    %d\n", MovDelay[x][y]);
97   printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
98   printf("  CustomValue: %d\n", CustomValue[x][y]);
99   printf("  GfxElement:  %d\n", GfxElement[x][y]);
100   printf("  GfxAction:   %d\n", GfxAction[x][y]);
101   printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
102   printf("\n");
103 }
104
105 void SetDrawtoField(int mode)
106 {
107   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
108   {
109     FX = TILEX;
110     FY = TILEY;
111     BX1 = -1;
112     BY1 = -1;
113     BX2 = SCR_FIELDX;
114     BY2 = SCR_FIELDY;
115     redraw_x1 = 1;
116     redraw_y1 = 1;
117
118     drawto_field = fieldbuffer;
119   }
120   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
121   {
122     FX = SX;
123     FY = SY;
124     BX1 = 0;
125     BY1 = 0;
126     BX2 = SCR_FIELDX - 1;
127     BY2 = SCR_FIELDY - 1;
128     redraw_x1 = 0;
129     redraw_y1 = 0;
130
131     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
132   }
133 }
134
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
136 {
137   if (game_status == GAME_MODE_PLAYING &&
138       level.game_engine_type == GAME_ENGINE_TYPE_EM)
139   {
140     /* currently there is no partial redraw -- always redraw whole playfield */
141
142     RedrawPlayfield_EM(TRUE);
143   }
144   else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
145   {
146     if (force_redraw)
147     {
148       x = gfx.sx - TILEX;
149       y = gfx.sy - TILEY;
150       width = gfx.sxsize + 2 * TILEX;
151       height = gfx.sysize + 2 * TILEY;
152     }
153
154     if (force_redraw || setup.direct_draw)
155     {
156       int xx, yy;
157       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
158       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
159
160       if (setup.direct_draw)
161         SetDrawtoField(DRAW_BACKBUFFER);
162
163       for (xx = BX1; xx <= BX2; xx++)
164         for (yy = BY1; yy <= BY2; yy++)
165           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
166             DrawScreenField(xx, yy);
167       DrawAllPlayers();
168
169       if (setup.direct_draw)
170         SetDrawtoField(DRAW_DIRECT);
171     }
172
173     if (setup.soft_scrolling)
174     {
175       int fx = FX, fy = FY;
176
177       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
178       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
179
180       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
181     }
182   }
183
184   BlitBitmap(drawto, window, x, y, width, height, x, y);
185 }
186
187 void BackToFront()
188 {
189   int x,y;
190   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
191
192   if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
193     redraw_mask &= ~REDRAW_MAIN;
194
195   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
196     redraw_mask |= REDRAW_FIELD;
197
198   if (redraw_mask & REDRAW_FIELD)
199     redraw_mask &= ~REDRAW_TILES;
200
201   if (redraw_mask == REDRAW_NONE)
202     return;
203
204   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
205   {
206     static boolean last_frame_skipped = FALSE;
207     boolean skip_even_when_not_scrolling = TRUE;
208     boolean just_scrolling = (ScreenMovDir != 0);
209     boolean verbose = FALSE;
210
211     if (global.fps_slowdown_factor > 1 &&
212         (FrameCounter % global.fps_slowdown_factor) &&
213         (just_scrolling || skip_even_when_not_scrolling))
214     {
215       redraw_mask &= ~REDRAW_MAIN;
216
217       last_frame_skipped = TRUE;
218
219       if (verbose)
220         printf("FRAME SKIPPED\n");
221     }
222     else
223     {
224       if (last_frame_skipped)
225         redraw_mask |= REDRAW_FIELD;
226
227       last_frame_skipped = FALSE;
228
229       if (verbose)
230         printf("frame not skipped\n");
231     }
232   }
233
234   /* synchronize X11 graphics at this point; if we would synchronize the
235      display immediately after the buffer switching (after the XFlush),
236      this could mean that we have to wait for the graphics to complete,
237      although we could go on doing calculations for the next frame */
238
239   SyncDisplay();
240
241   if (redraw_mask & REDRAW_ALL)
242   {
243     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
244
245     redraw_mask = REDRAW_NONE;
246   }
247
248   if (redraw_mask & REDRAW_FIELD)
249   {
250     if (game_status != GAME_MODE_PLAYING ||
251         redraw_mask & REDRAW_FROM_BACKBUFFER)
252     {
253       BlitBitmap(backbuffer, window,
254                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
255     }
256     else
257     {
258       int fx = FX, fy = FY;
259
260       if (setup.soft_scrolling)
261       {
262         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
263         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
264       }
265
266       if (setup.soft_scrolling ||
267           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
268           ABS(ScreenMovPos) == ScrollStepSize ||
269           redraw_tiles > REDRAWTILES_THRESHOLD)
270       {
271         BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
272
273 #if 0
274 #ifdef DEBUG
275         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
276                ScreenGfxPos,
277                (setup.soft_scrolling ?
278                 "setup.soft_scrolling" :
279                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
280                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
281                 ABS(ScreenGfxPos) == ScrollStepSize ?
282                 "ABS(ScreenGfxPos) == ScrollStepSize" :
283                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
284 #endif
285 #endif
286       }
287     }
288
289     redraw_mask &= ~REDRAW_MAIN;
290   }
291
292   if (redraw_mask & REDRAW_DOORS)
293   {
294     if (redraw_mask & REDRAW_DOOR_1)
295       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
296
297     if (redraw_mask & REDRAW_DOOR_2)
298       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
299
300     if (redraw_mask & REDRAW_DOOR_3)
301       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
302
303     redraw_mask &= ~REDRAW_DOORS;
304   }
305
306   if (redraw_mask & REDRAW_MICROLEVEL)
307   {
308     BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
309                SX, SY + 10 * TILEY);
310
311     redraw_mask &= ~REDRAW_MICROLEVEL;
312   }
313
314   if (redraw_mask & REDRAW_TILES)
315   {
316     for (x = 0; x < SCR_FIELDX; x++)
317       for (y = 0 ; y < SCR_FIELDY; y++)
318         if (redraw[redraw_x1 + x][redraw_y1 + y])
319           BlitBitmap(buffer, window,
320                      FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
321                      SX + x * TILEX, SY + y * TILEY);
322   }
323
324   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
325   {
326     char text[100];
327     char info1[100];
328
329     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
330     if (!global.fps_slowdown)
331       info1[0] = '\0';
332
333     sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
334     DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
335   }
336
337   FlushDisplay();
338
339   for (x = 0; x < MAX_BUF_XSIZE; x++)
340     for (y = 0; y < MAX_BUF_YSIZE; y++)
341       redraw[x][y] = 0;
342   redraw_tiles = 0;
343   redraw_mask = REDRAW_NONE;
344 }
345
346 void FadeToFront()
347 {
348 #if 0
349   long fading_delay = 300;
350
351   if (setup.fading && (redraw_mask & REDRAW_FIELD))
352   {
353 #endif
354
355 #if 0
356     int x,y;
357
358     ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
359     FlushDisplay();
360
361     for (i = 0; i < 2 * FULL_SYSIZE; i++)
362     {
363       for (y = 0; y < FULL_SYSIZE; y++)
364       {
365         BlitBitmap(backbuffer, window,
366                    REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
367       }
368       FlushDisplay();
369       Delay(10);
370     }
371 #endif
372
373 #if 0
374     for (i = 1; i < FULL_SYSIZE; i+=2)
375       BlitBitmap(backbuffer, window,
376                  REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
377     FlushDisplay();
378     Delay(fading_delay);
379 #endif
380
381 #if 0
382     SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
383     BlitBitmapMasked(backbuffer, window,
384                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
385                      REAL_SX,REAL_SY);
386     FlushDisplay();
387     Delay(fading_delay);
388
389     SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
390     BlitBitmapMasked(backbuffer, window,
391                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
392                      REAL_SX,REAL_SY);
393     FlushDisplay();
394     Delay(fading_delay);
395
396     SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
397     BlitBitmapMasked(backbuffer, window,
398                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
399                      REAL_SX,REAL_SY);
400     FlushDisplay();
401     Delay(fading_delay);
402
403     SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
404     BlitBitmapMasked(backbuffer, window,
405                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
406                      REAL_SX,REAL_SY);
407     FlushDisplay();
408     Delay(fading_delay);
409
410     redraw_mask &= ~REDRAW_MAIN;
411   }
412 #endif
413
414   BackToFront();
415 }
416
417 void FadeExt(int fade_mask, int fade_mode)
418 {
419   Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
420   int fade_delay = menu.fade_delay;
421   int post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
422   int x, y, width, height;
423
424   if (fade_mask & REDRAW_ALL)
425   {
426     x = 0;
427     y = 0;
428     width  = WIN_XSIZE;
429     height = WIN_YSIZE;
430   }
431   else if (fade_mask & REDRAW_FIELD)
432   {
433     x = REAL_SX;
434     y = REAL_SY;
435     width  = FULL_SXSIZE;
436     height = FULL_SYSIZE;
437   }
438
439   redraw_mask |= fade_mask;
440
441   if (!setup.fading || fade_delay == 0)
442   {
443     if (fade_mode == FADE_MODE_FADE_OUT)
444       ClearRectangle(backbuffer, x, y, width, height);
445
446     BackToFront();
447
448     return;
449   }
450
451   FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay);
452
453   redraw_mask &= ~fade_mask;
454 }
455
456 void FadeIn(int fade_mask)
457 {
458   FadeExt(fade_mask, FADE_MODE_FADE_IN);
459 }
460
461 void FadeOut(int fade_mask)
462 {
463   FadeExt(fade_mask, FADE_MODE_FADE_OUT);
464 }
465
466 void FadeCross(int fade_mask)
467 {
468   FadeExt(fade_mask, FADE_MODE_CROSSFADE);
469 }
470
471 void FadeCrossSaveBackbuffer()
472 {
473   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
474 }
475
476 void SetMainBackgroundImageIfDefined(int graphic)
477 {
478   if (graphic_info[graphic].bitmap)
479     SetMainBackgroundImage(graphic);
480 }
481
482 void SetMainBackgroundImage(int graphic)
483 {
484   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
485                           graphic_info[graphic].bitmap ?
486                           graphic_info[graphic].bitmap :
487                           graphic_info[IMG_BACKGROUND].bitmap);
488 }
489
490 void SetDoorBackgroundImage(int graphic)
491 {
492   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
493                           graphic_info[graphic].bitmap ?
494                           graphic_info[graphic].bitmap :
495                           graphic_info[IMG_BACKGROUND].bitmap);
496 }
497
498 void SetPanelBackground()
499 {
500   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
501              DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
502
503   SetDoorBackgroundBitmap(bitmap_db_panel);
504 }
505
506 void DrawBackground(int dst_x, int dst_y, int width, int height)
507 {
508 #if 1
509   ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
510 #else
511   ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
512 #endif
513
514   redraw_mask |= REDRAW_FIELD;
515 }
516
517 void ClearWindow()
518 {
519   DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
520
521   if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
522   {
523     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
524     SetDrawtoField(DRAW_BUFFERED);
525   }
526   else
527     SetDrawtoField(DRAW_BACKBUFFER);
528
529   if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
530   {
531     ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
532     SetDrawtoField(DRAW_DIRECT);
533   }
534 }
535
536 void MarkTileDirty(int x, int y)
537 {
538   int xx = redraw_x1 + x;
539   int yy = redraw_y1 + y;
540
541   if (!redraw[xx][yy])
542     redraw_tiles++;
543
544   redraw[xx][yy] = TRUE;
545   redraw_mask |= REDRAW_TILES;
546 }
547
548 void SetBorderElement()
549 {
550   int x, y;
551
552   BorderElement = EL_EMPTY;
553
554   for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
555   {
556     for (x = 0; x < lev_fieldx; x++)
557     {
558       if (!IS_INDESTRUCTIBLE(Feld[x][y]))
559         BorderElement = EL_STEELWALL;
560
561       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
562         x = lev_fieldx - 2;
563     }
564   }
565 }
566
567 void SetRandomAnimationValue(int x, int y)
568 {
569   gfx.anim_random_frame = GfxRandom[x][y];
570 }
571
572 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
573 {
574   /* animation synchronized with global frame counter, not move position */
575   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
576     sync_frame = FrameCounter;
577
578 #if 0
579   if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
580       sync_frame == 0 &&
581       FrameCounter > 10)
582   {
583     int x = 1 / 0;
584
585     printf("::: FOO!\n");
586   }
587 #endif
588
589   return getAnimationFrame(graphic_info[graphic].anim_frames,
590                            graphic_info[graphic].anim_delay,
591                            graphic_info[graphic].anim_mode,
592                            graphic_info[graphic].anim_start_frame,
593                            sync_frame);
594 }
595
596 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
597                                 int *x, int *y, boolean get_backside)
598 {
599   struct GraphicInfo *g = &graphic_info[graphic];
600   int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
601   int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
602
603   *bitmap = g->bitmap;
604
605   if (g->offset_y == 0)         /* frames are ordered horizontally */
606   {
607     int max_width = g->anim_frames_per_line * g->width;
608     int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
609
610     *x = pos % max_width;
611     *y = src_y % g->height + pos / max_width * g->height;
612   }
613   else if (g->offset_x == 0)    /* frames are ordered vertically */
614   {
615     int max_height = g->anim_frames_per_line * g->height;
616     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
617
618     *x = src_x % g->width + pos / max_height * g->width;
619     *y = pos % max_height;
620   }
621   else                          /* frames are ordered diagonally */
622   {
623     *x = src_x + frame * g->offset_x;
624     *y = src_y + frame * g->offset_y;
625   }
626 }
627
628 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
629 {
630   getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
631 }
632
633 void DrawGraphic(int x, int y, int graphic, int frame)
634 {
635 #if DEBUG
636   if (!IN_SCR_FIELD(x, y))
637   {
638     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
639     printf("DrawGraphic(): This should never happen!\n");
640     return;
641   }
642 #endif
643
644   DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
645   MarkTileDirty(x, y);
646 }
647
648 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
649                     int frame)
650 {
651   Bitmap *src_bitmap;
652   int src_x, src_y;
653
654   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
655   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
656 }
657
658 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
659 {
660 #if DEBUG
661   if (!IN_SCR_FIELD(x, y))
662   {
663     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
664     printf("DrawGraphicThruMask(): This should never happen!\n");
665     return;
666   }
667 #endif
668
669   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
670                          frame);
671   MarkTileDirty(x, y);
672 }
673
674 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
675                             int frame)
676 {
677   Bitmap *src_bitmap;
678   int src_x, src_y;
679
680   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
681
682   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
683                 dst_x - src_x, dst_y - src_y);
684   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
685 }
686
687 void DrawMiniGraphic(int x, int y, int graphic)
688 {
689   DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
690   MarkTileDirty(x / 2, y / 2);
691 }
692
693 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
694 {
695   struct GraphicInfo *g = &graphic_info[graphic];
696   int mini_startx = 0;
697   int mini_starty = g->bitmap->height * 2 / 3;
698
699   *bitmap = g->bitmap;
700   *x = mini_startx + g->src_x / 2;
701   *y = mini_starty + g->src_y / 2;
702 }
703
704 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
705 {
706   Bitmap *src_bitmap;
707   int src_x, src_y;
708
709   getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
710   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
711 }
712
713 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
714                                             int graphic, int frame,
715                                             int cut_mode, int mask_mode)
716 {
717   Bitmap *src_bitmap;
718   int src_x, src_y;
719   int dst_x, dst_y;
720   int width = TILEX, height = TILEY;
721   int cx = 0, cy = 0;
722
723   if (dx || dy)                 /* shifted graphic */
724   {
725     if (x < BX1)                /* object enters playfield from the left */
726     {
727       x = BX1;
728       width = dx;
729       cx = TILEX - dx;
730       dx = 0;
731     }
732     else if (x > BX2)           /* object enters playfield from the right */
733     {
734       x = BX2;
735       width = -dx;
736       dx = TILEX + dx;
737     }
738     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
739     {
740       width += dx;
741       cx = -dx;
742       dx = 0;
743     }
744     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
745       width -= dx;
746     else if (dx)                /* general horizontal movement */
747       MarkTileDirty(x + SIGN(dx), y);
748
749     if (y < BY1)                /* object enters playfield from the top */
750     {
751       if (cut_mode==CUT_BELOW)  /* object completely above top border */
752         return;
753
754       y = BY1;
755       height = dy;
756       cy = TILEY - dy;
757       dy = 0;
758     }
759     else if (y > BY2)           /* object enters playfield from the bottom */
760     {
761       y = BY2;
762       height = -dy;
763       dy = TILEY + dy;
764     }
765     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
766     {
767       height += dy;
768       cy = -dy;
769       dy = 0;
770     }
771     else if (dy > 0 && cut_mode == CUT_ABOVE)
772     {
773       if (y == BY2)             /* object completely above bottom border */
774         return;
775
776       height = dy;
777       cy = TILEY - dy;
778       dy = TILEY;
779       MarkTileDirty(x, y + 1);
780     }                           /* object leaves playfield to the bottom */
781     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
782       height -= dy;
783     else if (dy)                /* general vertical movement */
784       MarkTileDirty(x, y + SIGN(dy));
785   }
786
787 #if DEBUG
788   if (!IN_SCR_FIELD(x, y))
789   {
790     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
791     printf("DrawGraphicShifted(): This should never happen!\n");
792     return;
793   }
794 #endif
795
796   if (width > 0 && height > 0)
797   {
798     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
799
800     src_x += cx;
801     src_y += cy;
802
803     dst_x = FX + x * TILEX + dx;
804     dst_y = FY + y * TILEY + dy;
805
806     if (mask_mode == USE_MASKING)
807     {
808       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
809                     dst_x - src_x, dst_y - src_y);
810       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
811                        dst_x, dst_y);
812     }
813     else
814       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
815                  dst_x, dst_y);
816
817     MarkTileDirty(x, y);
818   }
819 }
820
821 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
822                                             int graphic, int frame,
823                                             int cut_mode, int mask_mode)
824 {
825   Bitmap *src_bitmap;
826   int src_x, src_y;
827   int dst_x, dst_y;
828   int width = TILEX, height = TILEY;
829   int x1 = x;
830   int y1 = y;
831   int x2 = x + SIGN(dx);
832   int y2 = y + SIGN(dy);
833   int anim_frames = graphic_info[graphic].anim_frames;
834   int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
835   boolean draw_start_tile = (cut_mode != CUT_ABOVE);    /* only for falling! */
836   boolean draw_end_tile   = (cut_mode != CUT_BELOW);    /* only for falling! */
837
838   /* re-calculate animation frame for two-tile movement animation */
839   frame = getGraphicAnimationFrame(graphic, sync_frame);
840
841   /* check if movement start graphic inside screen area and should be drawn */
842   if (draw_start_tile && IN_SCR_FIELD(x1, y1))
843   {
844     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
845
846     dst_x = FX + x1 * TILEX;
847     dst_y = FY + y1 * TILEY;
848
849     if (mask_mode == USE_MASKING)
850     {
851       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
852                     dst_x - src_x, dst_y - src_y);
853       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
854                        dst_x, dst_y);
855     }
856     else
857       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
858                  dst_x, dst_y);
859
860     MarkTileDirty(x1, y1);
861   }
862
863   /* check if movement end graphic inside screen area and should be drawn */
864   if (draw_end_tile && IN_SCR_FIELD(x2, y2))
865   {
866     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
867
868     dst_x = FX + x2 * TILEX;
869     dst_y = FY + y2 * TILEY;
870
871     if (mask_mode == USE_MASKING)
872     {
873       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
874                     dst_x - src_x, dst_y - src_y);
875       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
876                        dst_x, dst_y);
877     }
878     else
879       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
880                  dst_x, dst_y);
881
882     MarkTileDirty(x2, y2);
883   }
884 }
885
886 static void DrawGraphicShifted(int x, int y, int dx, int dy,
887                                int graphic, int frame,
888                                int cut_mode, int mask_mode)
889 {
890   if (graphic < 0)
891   {
892     DrawGraphic(x, y, graphic, frame);
893
894     return;
895   }
896
897   if (graphic_info[graphic].double_movement)    /* EM style movement images */
898     DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
899   else
900     DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
901 }
902
903 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
904                                 int frame, int cut_mode)
905 {
906   DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
907 }
908
909 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
910                           int cut_mode, int mask_mode)
911 {
912   int lx = LEVELX(x), ly = LEVELY(y);
913   int graphic;
914   int frame;
915
916   if (IN_LEV_FIELD(lx, ly))
917   {
918     SetRandomAnimationValue(lx, ly);
919
920     graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
921     frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
922
923     /* do not use double (EM style) movement graphic when not moving */
924     if (graphic_info[graphic].double_movement && !dx && !dy)
925     {
926       graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
927       frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
928     }
929   }
930   else  /* border element */
931   {
932     graphic = el2img(element);
933     frame = getGraphicAnimationFrame(graphic, -1);
934   }
935
936   if (element == EL_EXPANDABLE_WALL)
937   {
938     boolean left_stopped = FALSE, right_stopped = FALSE;
939
940     if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
941       left_stopped = TRUE;
942     if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
943       right_stopped = TRUE;
944
945     if (left_stopped && right_stopped)
946       graphic = IMG_WALL;
947     else if (left_stopped)
948     {
949       graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
950       frame = graphic_info[graphic].anim_frames - 1;
951     }
952     else if (right_stopped)
953     {
954       graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
955       frame = graphic_info[graphic].anim_frames - 1;
956     }
957   }
958
959   if (dx || dy)
960     DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
961   else if (mask_mode == USE_MASKING)
962     DrawGraphicThruMask(x, y, graphic, frame);
963   else
964     DrawGraphic(x, y, graphic, frame);
965 }
966
967 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
968                          int cut_mode, int mask_mode)
969 {
970   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
971     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
972                          cut_mode, mask_mode);
973 }
974
975 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
976                               int cut_mode)
977 {
978   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
979 }
980
981 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
982                              int cut_mode)
983 {
984   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
985 }
986
987 void DrawLevelElementThruMask(int x, int y, int element)
988 {
989   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
990 }
991
992 void DrawLevelFieldThruMask(int x, int y)
993 {
994   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
995 }
996
997 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
998 {
999   Bitmap *src_bitmap;
1000   int src_x, src_y;
1001   int sx = SCREENX(x), sy = SCREENY(y);
1002   int element;
1003   int width, height, cx, cy, i;
1004   int crumbled_border_size = graphic_info[graphic].border_size;
1005   static int xy[4][2] =
1006   {
1007     { 0, -1 },
1008     { -1, 0 },
1009     { +1, 0 },
1010     { 0, +1 }
1011   };
1012
1013   if (!IN_LEV_FIELD(x, y))
1014     return;
1015
1016   element = TILE_GFX_ELEMENT(x, y);
1017
1018   /* crumble field itself */
1019   if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1020   {
1021     if (!IN_SCR_FIELD(sx, sy))
1022       return;
1023
1024     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1025
1026     for (i = 0; i < 4; i++)
1027     {
1028       int xx = x + xy[i][0];
1029       int yy = y + xy[i][1];
1030
1031       element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1032                  BorderElement);
1033
1034       /* check if neighbour field is of same type */
1035       if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1036         continue;
1037
1038       if (i == 1 || i == 2)
1039       {
1040         width = crumbled_border_size;
1041         height = TILEY;
1042         cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1043         cy = 0;
1044       }
1045       else
1046       {
1047         width = TILEX;
1048         height = crumbled_border_size;
1049         cx = 0;
1050         cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1051       }
1052
1053       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1054                  width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1055     }
1056
1057     MarkTileDirty(sx, sy);
1058   }
1059   else          /* crumble neighbour fields */
1060   {
1061     for (i = 0; i < 4; i++)
1062     {
1063       int xx = x + xy[i][0];
1064       int yy = y + xy[i][1];
1065       int sxx = sx + xy[i][0];
1066       int syy = sy + xy[i][1];
1067
1068 #if 1
1069       if (!IN_LEV_FIELD(xx, yy) ||
1070           !IN_SCR_FIELD(sxx, syy) ||
1071           IS_MOVING(xx, yy))
1072         continue;
1073
1074 #if 1
1075       if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1076         continue;
1077 #endif
1078
1079       element = TILE_GFX_ELEMENT(xx, yy);
1080
1081       if (!GFX_CRUMBLED(element))
1082         continue;
1083 #else
1084       if (!IN_LEV_FIELD(xx, yy) ||
1085           !IN_SCR_FIELD(sxx, syy) ||
1086           !GFX_CRUMBLED(Feld[xx][yy]) ||
1087           IS_MOVING(xx, yy))
1088         continue;
1089 #endif
1090
1091 #if 1
1092       graphic = el_act2crm(element, ACTION_DEFAULT);
1093 #else
1094       graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
1095 #endif
1096       crumbled_border_size = graphic_info[graphic].border_size;
1097
1098       getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1099
1100       if (i == 1 || i == 2)
1101       {
1102         width = crumbled_border_size;
1103         height = TILEY;
1104         cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1105         cy = 0;
1106       }
1107       else
1108       {
1109         width = TILEX;
1110         height = crumbled_border_size;
1111         cx = 0;
1112         cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1113       }
1114
1115       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1116                  width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1117
1118       MarkTileDirty(sxx, syy);
1119     }
1120   }
1121 }
1122
1123 void DrawLevelFieldCrumbledSand(int x, int y)
1124 {
1125   int graphic;
1126
1127   if (!IN_LEV_FIELD(x, y))
1128     return;
1129
1130 #if 1
1131   /* !!! CHECK THIS !!! */
1132
1133   /*
1134   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1135       GFX_CRUMBLED(GfxElement[x][y]))
1136   */
1137
1138   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1139       GfxElement[x][y] != EL_UNDEFINED &&
1140       GFX_CRUMBLED(GfxElement[x][y]))
1141   {
1142     DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1143
1144     return;
1145   }
1146 #endif
1147
1148 #if 1
1149   graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1150 #else
1151   graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1152 #endif
1153
1154   DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1155 }
1156
1157 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1158                                        int step_frame)
1159 {
1160   int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1161   int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1162   int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1163   int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1164   int sx = SCREENX(x), sy = SCREENY(y);
1165
1166   DrawGraphic(sx, sy, graphic1, frame1);
1167   DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1168 }
1169
1170 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1171 {
1172   int sx = SCREENX(x), sy = SCREENY(y);
1173   static int xy[4][2] =
1174   {
1175     { 0, -1 },
1176     { -1, 0 },
1177     { +1, 0 },
1178     { 0, +1 }
1179   };
1180   int i;
1181
1182   for (i = 0; i < 4; i++)
1183   {
1184     int xx = x + xy[i][0];
1185     int yy = y + xy[i][1];
1186     int sxx = sx + xy[i][0];
1187     int syy = sy + xy[i][1];
1188
1189     if (!IN_LEV_FIELD(xx, yy) ||
1190         !IN_SCR_FIELD(sxx, syy) ||
1191         !GFX_CRUMBLED(Feld[xx][yy]) ||
1192         IS_MOVING(xx, yy))
1193       continue;
1194
1195     DrawLevelField(xx, yy);
1196   }
1197 }
1198
1199 static int getBorderElement(int x, int y)
1200 {
1201   int border[7][2] =
1202   {
1203     { EL_STEELWALL_TOPLEFT,             EL_INVISIBLE_STEELWALL_TOPLEFT     },
1204     { EL_STEELWALL_TOPRIGHT,            EL_INVISIBLE_STEELWALL_TOPRIGHT    },
1205     { EL_STEELWALL_BOTTOMLEFT,          EL_INVISIBLE_STEELWALL_BOTTOMLEFT  },
1206     { EL_STEELWALL_BOTTOMRIGHT,         EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1207     { EL_STEELWALL_VERTICAL,            EL_INVISIBLE_STEELWALL_VERTICAL    },
1208     { EL_STEELWALL_HORIZONTAL,          EL_INVISIBLE_STEELWALL_HORIZONTAL  },
1209     { EL_STEELWALL,                     EL_INVISIBLE_STEELWALL             }
1210   };
1211   int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1212   int steel_position = (x == -1         && y == -1              ? 0 :
1213                         x == lev_fieldx && y == -1              ? 1 :
1214                         x == -1         && y == lev_fieldy      ? 2 :
1215                         x == lev_fieldx && y == lev_fieldy      ? 3 :
1216                         x == -1         || x == lev_fieldx      ? 4 :
1217                         y == -1         || y == lev_fieldy      ? 5 : 6);
1218
1219   return border[steel_position][steel_type];
1220 }
1221
1222 void DrawScreenElement(int x, int y, int element)
1223 {
1224   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1225   DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1226 }
1227
1228 void DrawLevelElement(int x, int y, int element)
1229 {
1230   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1231     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1232 }
1233
1234 void DrawScreenField(int x, int y)
1235 {
1236   int lx = LEVELX(x), ly = LEVELY(y);
1237   int element, content;
1238
1239   if (!IN_LEV_FIELD(lx, ly))
1240   {
1241     if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1242       element = EL_EMPTY;
1243     else
1244       element = getBorderElement(lx, ly);
1245
1246     DrawScreenElement(x, y, element);
1247     return;
1248   }
1249
1250   element = Feld[lx][ly];
1251   content = Store[lx][ly];
1252
1253   if (IS_MOVING(lx, ly))
1254   {
1255     int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1256     boolean cut_mode = NO_CUTTING;
1257
1258     if (element == EL_QUICKSAND_EMPTYING ||
1259         element == EL_MAGIC_WALL_EMPTYING ||
1260         element == EL_BD_MAGIC_WALL_EMPTYING ||
1261         element == EL_AMOEBA_DROPPING)
1262       cut_mode = CUT_ABOVE;
1263     else if (element == EL_QUICKSAND_FILLING ||
1264              element == EL_MAGIC_WALL_FILLING ||
1265              element == EL_BD_MAGIC_WALL_FILLING)
1266       cut_mode = CUT_BELOW;
1267
1268     if (cut_mode == CUT_ABOVE)
1269       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1270     else
1271       DrawScreenElement(x, y, EL_EMPTY);
1272
1273     if (horiz_move)
1274       DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1275     else if (cut_mode == NO_CUTTING)
1276       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1277     else
1278       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1279
1280     if (content == EL_ACID)
1281     {
1282       int dir = MovDir[lx][ly];
1283       int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1284       int newly = ly + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
1285
1286       DrawLevelElementThruMask(newlx, newly, EL_ACID);
1287     }
1288   }
1289   else if (IS_BLOCKED(lx, ly))
1290   {
1291     int oldx, oldy;
1292     int sx, sy;
1293     int horiz_move;
1294     boolean cut_mode = NO_CUTTING;
1295     int element_old, content_old;
1296
1297     Blocked2Moving(lx, ly, &oldx, &oldy);
1298     sx = SCREENX(oldx);
1299     sy = SCREENY(oldy);
1300     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1301                   MovDir[oldx][oldy] == MV_RIGHT);
1302
1303     element_old = Feld[oldx][oldy];
1304     content_old = Store[oldx][oldy];
1305
1306     if (element_old == EL_QUICKSAND_EMPTYING ||
1307         element_old == EL_MAGIC_WALL_EMPTYING ||
1308         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1309         element_old == EL_AMOEBA_DROPPING)
1310       cut_mode = CUT_ABOVE;
1311
1312     DrawScreenElement(x, y, EL_EMPTY);
1313
1314     if (horiz_move)
1315       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1316                                NO_CUTTING);
1317     else if (cut_mode == NO_CUTTING)
1318       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1319                                cut_mode);
1320     else
1321       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1322                                cut_mode);
1323   }
1324   else if (IS_DRAWABLE(element))
1325     DrawScreenElement(x, y, element);
1326   else
1327     DrawScreenElement(x, y, EL_EMPTY);
1328 }
1329
1330 void DrawLevelField(int x, int y)
1331 {
1332   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1333     DrawScreenField(SCREENX(x), SCREENY(y));
1334   else if (IS_MOVING(x, y))
1335   {
1336     int newx,newy;
1337
1338     Moving2Blocked(x, y, &newx, &newy);
1339     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1340       DrawScreenField(SCREENX(newx), SCREENY(newy));
1341   }
1342   else if (IS_BLOCKED(x, y))
1343   {
1344     int oldx, oldy;
1345
1346     Blocked2Moving(x, y, &oldx, &oldy);
1347     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1348       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1349   }
1350 }
1351
1352 void DrawMiniElement(int x, int y, int element)
1353 {
1354   int graphic;
1355
1356   graphic = el2edimg(element);
1357   DrawMiniGraphic(x, y, graphic);
1358 }
1359
1360 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1361 {
1362   int x = sx + scroll_x, y = sy + scroll_y;
1363
1364   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1365     DrawMiniElement(sx, sy, EL_EMPTY);
1366   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1367     DrawMiniElement(sx, sy, Feld[x][y]);
1368   else
1369     DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1370 }
1371
1372 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1373                             int x, int y, int xsize, int ysize, int font_nr)
1374 {
1375   int font_width  = getFontWidth(font_nr);
1376   int font_height = getFontHeight(font_nr);
1377   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1378   Bitmap *src_bitmap;
1379   int src_x, src_y;
1380   int dst_x = SX + startx + x * font_width;
1381   int dst_y = SY + starty + y * font_height;
1382   int width  = graphic_info[graphic].width;
1383   int height = graphic_info[graphic].height;
1384   int inner_width  = MAX(width  - 2 * font_width,  font_width);
1385   int inner_height = MAX(height - 2 * font_height, font_height);
1386   int inner_sx = (width >= 3 * font_width ? font_width : 0);
1387   int inner_sy = (height >= 3 * font_height ? font_height : 0);
1388   boolean draw_masked = graphic_info[graphic].draw_masked;
1389
1390   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1391
1392   if (src_bitmap == NULL || width < font_width || height < font_height)
1393   {
1394     ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1395     return;
1396   }
1397
1398   src_x += (x == 0 ? 0 : x == xsize - 1 ? width  - font_width  :
1399             inner_sx + (x - 1) * font_width  % inner_width);
1400   src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1401             inner_sy + (y - 1) * font_height % inner_height);
1402
1403   if (draw_masked)
1404   {
1405     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1406                   dst_x - src_x, dst_y - src_y);
1407     BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1408                      dst_x, dst_y);
1409   }
1410   else
1411     BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1412                dst_x, dst_y);
1413 }
1414
1415 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1416 {
1417   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1418   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1419   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1420   boolean ffwd_delay = (tape.playing && tape.fast_forward);
1421   boolean no_delay = (tape.warp_forward);
1422   unsigned long anim_delay = 0;
1423   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1424   int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1425   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1426   int font_width = getFontWidth(font_nr);
1427   int font_height = getFontHeight(font_nr);
1428   int max_xsize = level.envelope[envelope_nr].xsize;
1429   int max_ysize = level.envelope[envelope_nr].ysize;
1430   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1431   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1432   int xend = max_xsize;
1433   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1434   int xstep = (xstart < xend ? 1 : 0);
1435   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1436   int x, y;
1437
1438   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1439   {
1440     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1441     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1442     int sx = (SXSIZE - xsize * font_width)  / 2;
1443     int sy = (SYSIZE - ysize * font_height) / 2;
1444     int xx, yy;
1445
1446     SetDrawtoField(DRAW_BUFFERED);
1447
1448     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1449
1450     SetDrawtoField(DRAW_BACKBUFFER);
1451
1452     for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1453       DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1454
1455     DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1456                        level.envelope[envelope_nr].text, font_nr, max_xsize,
1457                        xsize - 2, ysize - 2, mask_mode);
1458
1459     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1460     BackToFront();
1461
1462     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1463   }
1464 }
1465
1466 void ShowEnvelope(int envelope_nr)
1467 {
1468   int element = EL_ENVELOPE_1 + envelope_nr;
1469   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1470   int sound_opening = element_info[element].sound[ACTION_OPENING];
1471   int sound_closing = element_info[element].sound[ACTION_CLOSING];
1472   boolean ffwd_delay = (tape.playing && tape.fast_forward);
1473   boolean no_delay = (tape.warp_forward);
1474   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1475   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1476   int anim_mode = graphic_info[graphic].anim_mode;
1477   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1478                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1479
1480   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
1481
1482   PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1483
1484   if (anim_mode == ANIM_DEFAULT)
1485     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1486
1487   AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1488
1489   if (tape.playing)
1490     Delay(wait_delay_value);
1491   else
1492     WaitForEventToContinue();
1493
1494   PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1495
1496   if (anim_mode != ANIM_NONE)
1497     AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1498
1499   if (anim_mode == ANIM_DEFAULT)
1500     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1501
1502   game.envelope_active = FALSE;
1503
1504   SetDrawtoField(DRAW_BUFFERED);
1505
1506   redraw_mask |= REDRAW_FIELD;
1507   BackToFront();
1508 }
1509
1510 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1511                              int tilesize)
1512 {
1513   struct
1514   {
1515     int width_mult, width_div;
1516     int height_mult, height_div;
1517   } offset_calc[4] =
1518   {
1519     { 0, 1,     0, 1    },
1520     { 0, 1,     2, 3    },
1521     { 1, 2,     2, 3    },
1522     { 3, 4,     2, 3    },
1523   };
1524   int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1525                          5 - log_2(tilesize));
1526   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1527   int width_mult = offset_calc[offset_calc_pos].width_mult;
1528   int width_div = offset_calc[offset_calc_pos].width_div;
1529   int height_mult = offset_calc[offset_calc_pos].height_mult;
1530   int height_div = offset_calc[offset_calc_pos].height_div;
1531   int mini_startx = src_bitmap->width * width_mult / width_div;
1532   int mini_starty = src_bitmap->height * height_mult / height_div;
1533   int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1534   int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1535
1536   *bitmap = src_bitmap;
1537   *x = src_x;
1538   *y = src_y;
1539 }
1540
1541 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1542 {
1543   Bitmap *src_bitmap;
1544   int src_x, src_y;
1545   int graphic = el2preimg(element);
1546
1547   getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1548   BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1549 }
1550
1551 void DrawLevel()
1552 {
1553   int x,y;
1554
1555   SetDrawBackgroundMask(REDRAW_NONE);
1556   ClearWindow();
1557
1558   for (x = BX1; x <= BX2; x++)
1559     for (y = BY1; y <= BY2; y++)
1560       DrawScreenField(x, y);
1561
1562   redraw_mask |= REDRAW_FIELD;
1563 }
1564
1565 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1566 {
1567   int x,y;
1568
1569   for (x = 0; x < size_x; x++)
1570     for (y = 0; y < size_y; y++)
1571       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1572
1573   redraw_mask |= REDRAW_FIELD;
1574 }
1575
1576 static void DrawPreviewLevelExt(int from_x, int from_y)
1577 {
1578   boolean show_level_border = (BorderElement != EL_EMPTY);
1579   int dst_x = preview.x;
1580   int dst_y = preview.y;
1581   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1582   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1583   int tile_size = preview.tile_size;
1584   int preview_width  = preview.xsize * tile_size;
1585   int preview_height = preview.ysize * tile_size;
1586   int real_preview_xsize = MIN(level_xsize, preview.xsize);
1587   int real_preview_ysize = MIN(level_ysize, preview.ysize);
1588   int x, y;
1589
1590   DrawBackground(dst_x, dst_y, preview_width, preview_height);
1591
1592   dst_x += (preview_width  - real_preview_xsize * tile_size) / 2;
1593   dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1594
1595   for (x = 0; x < real_preview_xsize; x++)
1596   {
1597     for (y = 0; y < real_preview_ysize; y++)
1598     {
1599       int lx = from_x + x + (show_level_border ? -1 : 0);
1600       int ly = from_y + y + (show_level_border ? -1 : 0);
1601       int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1602                      getBorderElement(lx, ly));
1603
1604       DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1605                          element, tile_size);
1606     }
1607   }
1608
1609   redraw_mask |= REDRAW_MICROLEVEL;
1610 }
1611
1612 #define MICROLABEL_EMPTY                0
1613 #define MICROLABEL_LEVEL_NAME           1
1614 #define MICROLABEL_LEVEL_AUTHOR_HEAD    2
1615 #define MICROLABEL_LEVEL_AUTHOR         3
1616 #define MICROLABEL_IMPORTED_FROM_HEAD   4
1617 #define MICROLABEL_IMPORTED_FROM        5
1618 #define MICROLABEL_IMPORTED_BY_HEAD     6
1619 #define MICROLABEL_IMPORTED_BY          7
1620
1621 static void DrawPreviewLevelLabelExt(int mode)
1622 {
1623   char label_text[MAX_OUTPUT_LINESIZE + 1];
1624   int max_len_label_text;
1625   int font_nr = FONT_TEXT_2;
1626   int i;
1627
1628   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1629       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1630       mode == MICROLABEL_IMPORTED_BY_HEAD)
1631     font_nr = FONT_TEXT_3;
1632
1633   max_len_label_text = SXSIZE / getFontWidth(font_nr);
1634
1635   for (i = 0; i < max_len_label_text; i++)
1636     label_text[i] = ' ';
1637   label_text[max_len_label_text] = '\0';
1638
1639   if (strlen(label_text) > 0)
1640   {
1641     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1642     int lypos = MICROLABEL2_YPOS;
1643
1644     DrawText(lxpos, lypos, label_text, font_nr);
1645   }
1646
1647   strncpy(label_text,
1648           (mode == MICROLABEL_LEVEL_NAME ? level.name :
1649            mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1650            mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1651            mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1652            mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1653            mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1654            mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1655           max_len_label_text);
1656   label_text[max_len_label_text] = '\0';
1657
1658   if (strlen(label_text) > 0)
1659   {
1660     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1661     int lypos = MICROLABEL2_YPOS;
1662
1663     DrawText(lxpos, lypos, label_text, font_nr);
1664   }
1665
1666   redraw_mask |= REDRAW_MICROLEVEL;
1667 }
1668
1669 void DrawPreviewLevel(boolean restart)
1670 {
1671   static unsigned long scroll_delay = 0;
1672   static unsigned long label_delay = 0;
1673   static int from_x, from_y, scroll_direction;
1674   static int label_state, label_counter;
1675   unsigned long scroll_delay_value = preview.step_delay;
1676   boolean show_level_border = (BorderElement != EL_EMPTY);
1677   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1678   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1679   int last_game_status = game_status;           /* save current game status */
1680
1681   /* force PREVIEW font on preview level */
1682   game_status = GAME_MODE_PSEUDO_PREVIEW;
1683
1684   if (restart)
1685   {
1686     from_x = from_y = 0;
1687     scroll_direction = MV_RIGHT;
1688     label_state = 1;
1689     label_counter = 0;
1690
1691     DrawPreviewLevelExt(from_x, from_y);
1692     DrawPreviewLevelLabelExt(label_state);
1693
1694     /* initialize delay counters */
1695     DelayReached(&scroll_delay, 0);
1696     DelayReached(&label_delay, 0);
1697
1698     if (leveldir_current->name)
1699     {
1700       char label_text[MAX_OUTPUT_LINESIZE + 1];
1701       int font_nr = FONT_TEXT_1;
1702       int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1703       int lxpos, lypos;
1704
1705       strncpy(label_text, leveldir_current->name, max_len_label_text);
1706       label_text[max_len_label_text] = '\0';
1707
1708       lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1709       lypos = SY + MICROLABEL1_YPOS;
1710
1711       DrawText(lxpos, lypos, label_text, font_nr);
1712     }
1713
1714     game_status = last_game_status;     /* restore current game status */
1715
1716     return;
1717   }
1718
1719   /* scroll preview level, if needed */
1720   if ((level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1721       DelayReached(&scroll_delay, scroll_delay_value))
1722   {
1723     switch (scroll_direction)
1724     {
1725       case MV_LEFT:
1726         if (from_x > 0)
1727         {
1728           from_x -= preview.step_offset;
1729           from_x = (from_x < 0 ? 0 : from_x);
1730         }
1731         else
1732           scroll_direction = MV_UP;
1733         break;
1734
1735       case MV_RIGHT:
1736         if (from_x < level_xsize - preview.xsize)
1737         {
1738           from_x += preview.step_offset;
1739           from_x = (from_x > level_xsize - preview.xsize ?
1740                     level_xsize - preview.xsize : from_x);
1741         }
1742         else
1743           scroll_direction = MV_DOWN;
1744         break;
1745
1746       case MV_UP:
1747         if (from_y > 0)
1748         {
1749           from_y -= preview.step_offset;
1750           from_y = (from_y < 0 ? 0 : from_y);
1751         }
1752         else
1753           scroll_direction = MV_RIGHT;
1754         break;
1755
1756       case MV_DOWN:
1757         if (from_y < level_ysize - preview.ysize)
1758         {
1759           from_y += preview.step_offset;
1760           from_y = (from_y > level_ysize - preview.ysize ?
1761                     level_ysize - preview.ysize : from_y);
1762         }
1763         else
1764           scroll_direction = MV_LEFT;
1765         break;
1766
1767       default:
1768         break;
1769     }
1770
1771     DrawPreviewLevelExt(from_x, from_y);
1772   }
1773
1774   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
1775   /* redraw micro level label, if needed */
1776   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
1777       !strEqual(level.author, ANONYMOUS_NAME) &&
1778       !strEqual(level.author, leveldir_current->name) &&
1779       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1780   {
1781     int max_label_counter = 23;
1782
1783     if (leveldir_current->imported_from != NULL &&
1784         strlen(leveldir_current->imported_from) > 0)
1785       max_label_counter += 14;
1786     if (leveldir_current->imported_by != NULL &&
1787         strlen(leveldir_current->imported_by) > 0)
1788       max_label_counter += 14;
1789
1790     label_counter = (label_counter + 1) % max_label_counter;
1791     label_state = (label_counter >= 0 && label_counter <= 7 ?
1792                    MICROLABEL_LEVEL_NAME :
1793                    label_counter >= 9 && label_counter <= 12 ?
1794                    MICROLABEL_LEVEL_AUTHOR_HEAD :
1795                    label_counter >= 14 && label_counter <= 21 ?
1796                    MICROLABEL_LEVEL_AUTHOR :
1797                    label_counter >= 23 && label_counter <= 26 ?
1798                    MICROLABEL_IMPORTED_FROM_HEAD :
1799                    label_counter >= 28 && label_counter <= 35 ?
1800                    MICROLABEL_IMPORTED_FROM :
1801                    label_counter >= 37 && label_counter <= 40 ?
1802                    MICROLABEL_IMPORTED_BY_HEAD :
1803                    label_counter >= 42 && label_counter <= 49 ?
1804                    MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
1805
1806     if (leveldir_current->imported_from == NULL &&
1807         (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
1808          label_state == MICROLABEL_IMPORTED_FROM))
1809       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
1810                      MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
1811
1812     DrawPreviewLevelLabelExt(label_state);
1813   }
1814
1815   game_status = last_game_status;       /* restore current game status */
1816 }
1817
1818 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
1819                                     int graphic, int sync_frame, int mask_mode)
1820 {
1821   int frame = getGraphicAnimationFrame(graphic, sync_frame);
1822
1823   if (mask_mode == USE_MASKING)
1824     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
1825   else
1826     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
1827 }
1828
1829 inline void DrawGraphicAnimation(int x, int y, int graphic)
1830 {
1831   int lx = LEVELX(x), ly = LEVELY(y);
1832
1833   if (!IN_SCR_FIELD(x, y))
1834     return;
1835
1836   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1837                           graphic, GfxFrame[lx][ly], NO_MASKING);
1838   MarkTileDirty(x, y);
1839 }
1840
1841 void DrawLevelGraphicAnimation(int x, int y, int graphic)
1842 {
1843   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1844 }
1845
1846 void DrawLevelElementAnimation(int x, int y, int element)
1847 {
1848   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1849
1850   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
1851 }
1852
1853 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
1854 {
1855   int sx = SCREENX(x), sy = SCREENY(y);
1856
1857   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1858     return;
1859
1860   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1861     return;
1862
1863   DrawGraphicAnimation(sx, sy, graphic);
1864
1865 #if 1
1866   if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
1867     DrawLevelFieldCrumbledSand(x, y);
1868 #else
1869   if (GFX_CRUMBLED(Feld[x][y]))
1870     DrawLevelFieldCrumbledSand(x, y);
1871 #endif
1872 }
1873
1874 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
1875 {
1876   int sx = SCREENX(x), sy = SCREENY(y);
1877   int graphic;
1878
1879   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
1880     return;
1881
1882   graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
1883
1884   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
1885     return;
1886
1887   DrawGraphicAnimation(sx, sy, graphic);
1888
1889   if (GFX_CRUMBLED(element))
1890     DrawLevelFieldCrumbledSand(x, y);
1891 }
1892
1893 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
1894 {
1895   if (player->use_murphy)
1896   {
1897     /* this works only because currently only one player can be "murphy" ... */
1898     static int last_horizontal_dir = MV_LEFT;
1899     int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
1900
1901     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
1902       last_horizontal_dir = move_dir;
1903
1904     if (graphic == IMG_SP_MURPHY)       /* undefined => use special graphic */
1905     {
1906       int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
1907
1908       graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
1909     }
1910
1911     return graphic;
1912   }
1913   else
1914     return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
1915 }
1916
1917 static boolean equalGraphics(int graphic1, int graphic2)
1918 {
1919   struct GraphicInfo *g1 = &graphic_info[graphic1];
1920   struct GraphicInfo *g2 = &graphic_info[graphic2];
1921
1922   return (g1->bitmap      == g2->bitmap &&
1923           g1->src_x       == g2->src_x &&
1924           g1->src_y       == g2->src_y &&
1925           g1->anim_frames == g2->anim_frames &&
1926           g1->anim_delay  == g2->anim_delay &&
1927           g1->anim_mode   == g2->anim_mode);
1928 }
1929
1930 void DrawAllPlayers()
1931 {
1932   int i;
1933
1934   for (i = 0; i < MAX_PLAYERS; i++)
1935     if (stored_player[i].active)
1936       DrawPlayer(&stored_player[i]);
1937 }
1938
1939 void DrawPlayerField(int x, int y)
1940 {
1941   if (!IS_PLAYER(x, y))
1942     return;
1943
1944   DrawPlayer(PLAYERINFO(x, y));
1945 }
1946
1947 void DrawPlayer(struct PlayerInfo *player)
1948 {
1949   int jx = player->jx;
1950   int jy = player->jy;
1951   int move_dir = player->MovDir;
1952   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
1953   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
1954   int last_jx = (player->is_moving ? jx - dx : jx);
1955   int last_jy = (player->is_moving ? jy - dy : jy);
1956   int next_jx = jx + dx;
1957   int next_jy = jy + dy;
1958   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
1959   boolean player_is_opaque = FALSE;
1960   int sx = SCREENX(jx), sy = SCREENY(jy);
1961   int sxx = 0, syy = 0;
1962   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
1963   int graphic;
1964   int action = ACTION_DEFAULT;
1965   int last_player_graphic = getPlayerGraphic(player, move_dir);
1966   int last_player_frame = player->Frame;
1967   int frame = 0;
1968
1969 #if 1
1970   /* GfxElement[][] is set to the element the player is digging or collecting;
1971      remove also for off-screen player if the player is not moving anymore */
1972   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
1973     GfxElement[jx][jy] = EL_UNDEFINED;
1974 #endif
1975
1976   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
1977     return;
1978
1979 #if DEBUG
1980   if (!IN_LEV_FIELD(jx, jy))
1981   {
1982     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
1983     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
1984     printf("DrawPlayerField(): This should never happen!\n");
1985     return;
1986   }
1987 #endif
1988
1989   if (element == EL_EXPLOSION)
1990     return;
1991
1992   action = (player->is_pushing    ? ACTION_PUSHING         :
1993             player->is_digging    ? ACTION_DIGGING         :
1994             player->is_collecting ? ACTION_COLLECTING      :
1995             player->is_moving     ? ACTION_MOVING          :
1996             player->is_snapping   ? ACTION_SNAPPING        :
1997             player->is_dropping   ? ACTION_DROPPING        :
1998             player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
1999
2000 #if 1
2001   if (player->is_waiting)
2002     move_dir = player->dir_waiting;
2003 #endif
2004
2005   InitPlayerGfxAnimation(player, action, move_dir);
2006
2007   /* ----------------------------------------------------------------------- */
2008   /* draw things in the field the player is leaving, if needed               */
2009   /* ----------------------------------------------------------------------- */
2010
2011   if (player->is_moving)
2012   {
2013     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2014     {
2015       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2016
2017       if (last_element == EL_DYNAMITE_ACTIVE ||
2018           last_element == EL_EM_DYNAMITE_ACTIVE ||
2019           last_element == EL_SP_DISK_RED_ACTIVE)
2020         DrawDynamite(last_jx, last_jy);
2021       else
2022         DrawLevelFieldThruMask(last_jx, last_jy);
2023     }
2024     else if (last_element == EL_DYNAMITE_ACTIVE ||
2025              last_element == EL_EM_DYNAMITE_ACTIVE ||
2026              last_element == EL_SP_DISK_RED_ACTIVE)
2027       DrawDynamite(last_jx, last_jy);
2028 #if 0
2029     /* !!! this is not enough to prevent flickering of players which are
2030        moving next to each others without a free tile between them -- this
2031        can only be solved by drawing all players layer by layer (first the
2032        background, then the foreground etc.) !!! => TODO */
2033     else if (!IS_PLAYER(last_jx, last_jy))
2034       DrawLevelField(last_jx, last_jy);
2035 #else
2036     else
2037       DrawLevelField(last_jx, last_jy);
2038 #endif
2039
2040     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2041       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2042   }
2043
2044   if (!IN_SCR_FIELD(sx, sy))
2045     return;
2046
2047   if (setup.direct_draw)
2048     SetDrawtoField(DRAW_BUFFERED);
2049
2050   /* ----------------------------------------------------------------------- */
2051   /* draw things behind the player, if needed                                */
2052   /* ----------------------------------------------------------------------- */
2053
2054   if (Back[jx][jy])
2055     DrawLevelElement(jx, jy, Back[jx][jy]);
2056   else if (IS_ACTIVE_BOMB(element))
2057     DrawLevelElement(jx, jy, EL_EMPTY);
2058   else
2059   {
2060     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2061     {
2062       int old_element = GfxElement[jx][jy];
2063       int old_graphic = el_act_dir2img(old_element, action, move_dir);
2064       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2065
2066       if (GFX_CRUMBLED(old_element))
2067         DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2068       else
2069         DrawGraphic(sx, sy, old_graphic, frame);
2070
2071       if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2072         player_is_opaque = TRUE;
2073     }
2074     else
2075     {
2076       GfxElement[jx][jy] = EL_UNDEFINED;
2077
2078       /* make sure that pushed elements are drawn with correct frame rate */
2079 #if 1
2080       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2081
2082       if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2083         GfxFrame[jx][jy] = player->StepFrame;
2084 #else
2085       if (player->is_pushing && player->is_moving)
2086         GfxFrame[jx][jy] = player->StepFrame;
2087 #endif
2088
2089       DrawLevelField(jx, jy);
2090     }
2091   }
2092
2093   /* ----------------------------------------------------------------------- */
2094   /* draw player himself                                                     */
2095   /* ----------------------------------------------------------------------- */
2096
2097   graphic = getPlayerGraphic(player, move_dir);
2098
2099   /* in the case of changed player action or direction, prevent the current
2100      animation frame from being restarted for identical animations */
2101   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2102     player->Frame = last_player_frame;
2103
2104   frame = getGraphicAnimationFrame(graphic, player->Frame);
2105
2106   if (player->GfxPos)
2107   {
2108     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2109       sxx = player->GfxPos;
2110     else
2111       syy = player->GfxPos;
2112   }
2113
2114   if (!setup.soft_scrolling && ScreenMovPos)
2115     sxx = syy = 0;
2116
2117   if (player_is_opaque)
2118     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2119   else
2120     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2121
2122   if (SHIELD_ON(player))
2123   {
2124     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2125                    IMG_SHIELD_NORMAL_ACTIVE);
2126     int frame = getGraphicAnimationFrame(graphic, -1);
2127
2128     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2129   }
2130
2131   /* ----------------------------------------------------------------------- */
2132   /* draw things the player is pushing, if needed                            */
2133   /* ----------------------------------------------------------------------- */
2134
2135 #if 0
2136   printf("::: %d, %d [%d, %d] [%d]\n",
2137          player->is_pushing, player_is_moving, player->GfxAction,
2138          player->is_moving, player_is_moving);
2139 #endif
2140
2141 #if 1
2142   if (player->is_pushing && player->is_moving)
2143   {
2144     int px = SCREENX(jx), py = SCREENY(jy);
2145     int pxx = (TILEX - ABS(sxx)) * dx;
2146     int pyy = (TILEY - ABS(syy)) * dy;
2147     int gfx_frame = GfxFrame[jx][jy];
2148
2149     int graphic;
2150     int sync_frame;
2151     int frame;
2152
2153     if (!IS_MOVING(jx, jy))             /* push movement already finished */
2154     {
2155       element = Feld[next_jx][next_jy];
2156       gfx_frame = GfxFrame[next_jx][next_jy];
2157     }
2158
2159     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2160
2161 #if 1
2162     sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2163     frame = getGraphicAnimationFrame(graphic, sync_frame);
2164 #else
2165     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2166 #endif
2167
2168     /* draw background element under pushed element (like the Sokoban field) */
2169     if (Back[next_jx][next_jy])
2170       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2171
2172     /* masked drawing is needed for EMC style (double) movement graphics */
2173     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2174   }
2175 #endif
2176
2177   /* ----------------------------------------------------------------------- */
2178   /* draw things in front of player (active dynamite or dynabombs)           */
2179   /* ----------------------------------------------------------------------- */
2180
2181   if (IS_ACTIVE_BOMB(element))
2182   {
2183     graphic = el2img(element);
2184     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2185
2186     if (game.emulation == EMU_SUPAPLEX)
2187       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2188     else
2189       DrawGraphicThruMask(sx, sy, graphic, frame);
2190   }
2191
2192   if (player_is_moving && last_element == EL_EXPLOSION)
2193   {
2194     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2195                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
2196     int graphic = el_act2img(element, ACTION_EXPLODING);
2197     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2198     int phase = ExplodePhase[last_jx][last_jy] - 1;
2199     int frame = getGraphicAnimationFrame(graphic, phase - delay);
2200
2201     if (phase >= delay)
2202       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2203   }
2204
2205   /* ----------------------------------------------------------------------- */
2206   /* draw elements the player is just walking/passing through/under          */
2207   /* ----------------------------------------------------------------------- */
2208
2209   if (player_is_moving)
2210   {
2211     /* handle the field the player is leaving ... */
2212     if (IS_ACCESSIBLE_INSIDE(last_element))
2213       DrawLevelField(last_jx, last_jy);
2214     else if (IS_ACCESSIBLE_UNDER(last_element))
2215       DrawLevelFieldThruMask(last_jx, last_jy);
2216   }
2217
2218   /* do not redraw accessible elements if the player is just pushing them */
2219   if (!player_is_moving || !player->is_pushing)
2220   {
2221     /* ... and the field the player is entering */
2222     if (IS_ACCESSIBLE_INSIDE(element))
2223       DrawLevelField(jx, jy);
2224     else if (IS_ACCESSIBLE_UNDER(element))
2225       DrawLevelFieldThruMask(jx, jy);
2226   }
2227
2228   if (setup.direct_draw)
2229   {
2230     int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2231     int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2232     int x_size = TILEX * (1 + ABS(jx - last_jx));
2233     int y_size = TILEY * (1 + ABS(jy - last_jy));
2234
2235     BlitBitmap(drawto_field, window,
2236                dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2237     SetDrawtoField(DRAW_DIRECT);
2238   }
2239
2240   MarkTileDirty(sx, sy);
2241 }
2242
2243 /* ------------------------------------------------------------------------- */
2244
2245 void WaitForEventToContinue()
2246 {
2247   boolean still_wait = TRUE;
2248
2249   /* simulate releasing mouse button over last gadget, if still pressed */
2250   if (button_status)
2251     HandleGadgets(-1, -1, 0);
2252
2253   button_status = MB_RELEASED;
2254
2255   while (still_wait)
2256   {
2257     if (PendingEvent())
2258     {
2259       Event event;
2260
2261       NextEvent(&event);
2262
2263       switch (event.type)
2264       {
2265         case EVENT_BUTTONPRESS:
2266         case EVENT_KEYPRESS:
2267           still_wait = FALSE;
2268           break;
2269
2270         case EVENT_KEYRELEASE:
2271           ClearPlayerAction();
2272           break;
2273
2274         default:
2275           HandleOtherEvents(&event);
2276           break;
2277       }
2278     }
2279     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2280     {
2281       still_wait = FALSE;
2282     }
2283
2284     DoAnimation();
2285
2286     /* don't eat all CPU time */
2287     Delay(10);
2288   }
2289 }
2290
2291 #define MAX_REQUEST_LINES               13
2292 #define MAX_REQUEST_LINE_FONT1_LEN      7
2293 #define MAX_REQUEST_LINE_FONT2_LEN      10
2294
2295 boolean Request(char *text, unsigned int req_state)
2296 {
2297   int mx, my, ty, result = -1;
2298   unsigned int old_door_state;
2299   int last_game_status = game_status;   /* save current game status */
2300   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2301   int font_nr = FONT_TEXT_2;
2302   int max_word_len = 0;
2303   char *text_ptr;
2304
2305   for (text_ptr = text; *text_ptr; text_ptr++)
2306   {
2307     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2308
2309     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2310     {
2311       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2312       font_nr = FONT_LEVEL_NUMBER;
2313
2314       break;
2315     }
2316   }
2317
2318   if (game_status == GAME_MODE_PLAYING &&
2319       level.game_engine_type == GAME_ENGINE_TYPE_EM)
2320     BlitScreenToBitmap_EM(backbuffer);
2321
2322   /* disable deactivated drawing when quick-loading level tape recording */
2323   if (tape.playing && tape.deactivate_display)
2324     TapeDeactivateDisplayOff(TRUE);
2325
2326   SetMouseCursor(CURSOR_DEFAULT);
2327
2328 #if defined(NETWORK_AVALIABLE)
2329   /* pause network game while waiting for request to answer */
2330   if (options.network &&
2331       game_status == GAME_MODE_PLAYING &&
2332       req_state & REQUEST_WAIT_FOR_INPUT)
2333     SendToServer_PausePlaying();
2334 #endif
2335
2336   old_door_state = GetDoorState();
2337
2338   /* simulate releasing mouse button over last gadget, if still pressed */
2339   if (button_status)
2340     HandleGadgets(-1, -1, 0);
2341
2342   UnmapAllGadgets();
2343
2344   if (old_door_state & DOOR_OPEN_1)
2345   {
2346     CloseDoor(DOOR_CLOSE_1);
2347
2348     /* save old door content */
2349     BlitBitmap(bitmap_db_door, bitmap_db_door,
2350                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2351                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2352   }
2353
2354 #if 1
2355   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2356 #endif
2357
2358   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2359
2360   /* clear door drawing field */
2361   DrawBackground(DX, DY, DXSIZE, DYSIZE);
2362
2363   /* force DOOR font on preview level */
2364   game_status = GAME_MODE_PSEUDO_DOOR;
2365
2366   /* write text for request */
2367   for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2368   {
2369     char text_line[max_request_line_len + 1];
2370     int tx, tl, tc = 0;
2371
2372     if (!*text)
2373       break;
2374
2375     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2376     {
2377       tc = *(text + tx);
2378       if (!tc || tc == ' ')
2379         break;
2380     }
2381
2382     if (!tl)
2383     { 
2384       text++; 
2385       ty--; 
2386       continue; 
2387     }
2388
2389     strncpy(text_line, text, tl);
2390     text_line[tl] = 0;
2391
2392     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2393              DY + 8 + ty * (getFontHeight(font_nr) + 2),
2394              text_line, font_nr);
2395
2396     text += tl + (tc == ' ' ? 1 : 0);
2397   }
2398
2399   game_status = last_game_status;       /* restore current game status */
2400
2401   if (req_state & REQ_ASK)
2402   {
2403     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2404     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2405   }
2406   else if (req_state & REQ_CONFIRM)
2407   {
2408     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2409   }
2410   else if (req_state & REQ_PLAYER)
2411   {
2412     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2413     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2414     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2415     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2416   }
2417
2418   /* copy request gadgets to door backbuffer */
2419   BlitBitmap(drawto, bitmap_db_door,
2420              DX, DY, DXSIZE, DYSIZE,
2421              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2422
2423   OpenDoor(DOOR_OPEN_1);
2424
2425   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2426   {
2427     if (game_status == GAME_MODE_PLAYING)
2428     {
2429       SetPanelBackground();
2430       SetDrawBackgroundMask(REDRAW_DOOR_1);
2431     }
2432     else
2433     {
2434       SetDrawBackgroundMask(REDRAW_FIELD);
2435     }
2436
2437     return FALSE;
2438   }
2439
2440   if (game_status != GAME_MODE_MAIN)
2441     InitAnimation();
2442
2443   button_status = MB_RELEASED;
2444
2445   request_gadget_id = -1;
2446
2447   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2448
2449   while (result < 0)
2450   {
2451     if (PendingEvent())
2452     {
2453       Event event;
2454
2455       NextEvent(&event);
2456
2457       switch(event.type)
2458       {
2459         case EVENT_BUTTONPRESS:
2460         case EVENT_BUTTONRELEASE:
2461         case EVENT_MOTIONNOTIFY:
2462         {
2463           if (event.type == EVENT_MOTIONNOTIFY)
2464           {
2465             if (!PointerInWindow(window))
2466               continue; /* window and pointer are on different screens */
2467
2468             if (!button_status)
2469               continue;
2470
2471             motion_status = TRUE;
2472             mx = ((MotionEvent *) &event)->x;
2473             my = ((MotionEvent *) &event)->y;
2474           }
2475           else
2476           {
2477             motion_status = FALSE;
2478             mx = ((ButtonEvent *) &event)->x;
2479             my = ((ButtonEvent *) &event)->y;
2480             if (event.type == EVENT_BUTTONPRESS)
2481               button_status = ((ButtonEvent *) &event)->button;
2482             else
2483               button_status = MB_RELEASED;
2484           }
2485
2486           /* this sets 'request_gadget_id' */
2487           HandleGadgets(mx, my, button_status);
2488
2489           switch(request_gadget_id)
2490           {
2491             case TOOL_CTRL_ID_YES:
2492               result = TRUE;
2493               break;
2494             case TOOL_CTRL_ID_NO:
2495               result = FALSE;
2496               break;
2497             case TOOL_CTRL_ID_CONFIRM:
2498               result = TRUE | FALSE;
2499               break;
2500
2501             case TOOL_CTRL_ID_PLAYER_1:
2502               result = 1;
2503               break;
2504             case TOOL_CTRL_ID_PLAYER_2:
2505               result = 2;
2506               break;
2507             case TOOL_CTRL_ID_PLAYER_3:
2508               result = 3;
2509               break;
2510             case TOOL_CTRL_ID_PLAYER_4:
2511               result = 4;
2512               break;
2513
2514             default:
2515               break;
2516           }
2517
2518           break;
2519         }
2520
2521         case EVENT_KEYPRESS:
2522           switch(GetEventKey((KeyEvent *)&event, TRUE))
2523           {
2524             case KSYM_Return:
2525               result = 1;
2526               break;
2527
2528             case KSYM_Escape:
2529               result = 0;
2530               break;
2531
2532             default:
2533               break;
2534           }
2535           if (req_state & REQ_PLAYER)
2536             result = 0;
2537           break;
2538
2539         case EVENT_KEYRELEASE:
2540           ClearPlayerAction();
2541           break;
2542
2543         default:
2544           HandleOtherEvents(&event);
2545           break;
2546       }
2547     }
2548     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2549     {
2550       int joy = AnyJoystick();
2551
2552       if (joy & JOY_BUTTON_1)
2553         result = 1;
2554       else if (joy & JOY_BUTTON_2)
2555         result = 0;
2556     }
2557
2558     DoAnimation();
2559
2560     /* don't eat all CPU time */
2561     Delay(10);
2562   }
2563
2564   if (game_status != GAME_MODE_MAIN)
2565     StopAnimation();
2566
2567   UnmapToolButtons();
2568
2569   if (!(req_state & REQ_STAY_OPEN))
2570   {
2571     CloseDoor(DOOR_CLOSE_1);
2572
2573     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2574         (req_state & REQ_REOPEN))
2575       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2576   }
2577
2578   RemapAllGadgets();
2579
2580   if (game_status == GAME_MODE_PLAYING)
2581   {
2582     SetPanelBackground();
2583     SetDrawBackgroundMask(REDRAW_DOOR_1);
2584   }
2585   else
2586   {
2587     SetDrawBackgroundMask(REDRAW_FIELD);
2588   }
2589
2590 #if defined(NETWORK_AVALIABLE)
2591   /* continue network game after request */
2592   if (options.network &&
2593       game_status == GAME_MODE_PLAYING &&
2594       req_state & REQUEST_WAIT_FOR_INPUT)
2595     SendToServer_ContinuePlaying();
2596 #endif
2597
2598   /* restore deactivated drawing when quick-loading level tape recording */
2599   if (tape.playing && tape.deactivate_display)
2600     TapeDeactivateDisplayOn();
2601
2602   return result;
2603 }
2604
2605 unsigned int OpenDoor(unsigned int door_state)
2606 {
2607   if (door_state & DOOR_COPY_BACK)
2608   {
2609     if (door_state & DOOR_OPEN_1)
2610       BlitBitmap(bitmap_db_door, bitmap_db_door,
2611                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2612                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2613
2614     if (door_state & DOOR_OPEN_2)
2615       BlitBitmap(bitmap_db_door, bitmap_db_door,
2616                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2617                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2618
2619     door_state &= ~DOOR_COPY_BACK;
2620   }
2621
2622   return MoveDoor(door_state);
2623 }
2624
2625 unsigned int CloseDoor(unsigned int door_state)
2626 {
2627   unsigned int old_door_state = GetDoorState();
2628
2629   if (!(door_state & DOOR_NO_COPY_BACK))
2630   {
2631     if (old_door_state & DOOR_OPEN_1)
2632       BlitBitmap(backbuffer, bitmap_db_door,
2633                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2634
2635     if (old_door_state & DOOR_OPEN_2)
2636       BlitBitmap(backbuffer, bitmap_db_door,
2637                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2638
2639     door_state &= ~DOOR_NO_COPY_BACK;
2640   }
2641
2642   return MoveDoor(door_state);
2643 }
2644
2645 unsigned int GetDoorState()
2646 {
2647   return MoveDoor(DOOR_GET_STATE);
2648 }
2649
2650 unsigned int SetDoorState(unsigned int door_state)
2651 {
2652   return MoveDoor(door_state | DOOR_SET_STATE);
2653 }
2654
2655 unsigned int MoveDoor(unsigned int door_state)
2656 {
2657   static int door1 = DOOR_OPEN_1;
2658   static int door2 = DOOR_CLOSE_2;
2659   unsigned long door_delay = 0;
2660   unsigned long door_delay_value;
2661   int stepsize = 1;
2662
2663   if (door_1.width < 0 || door_1.width > DXSIZE)
2664     door_1.width = DXSIZE;
2665   if (door_1.height < 0 || door_1.height > DYSIZE)
2666     door_1.height = DYSIZE;
2667   if (door_2.width < 0 || door_2.width > VXSIZE)
2668     door_2.width = VXSIZE;
2669   if (door_2.height < 0 || door_2.height > VYSIZE)
2670     door_2.height = VYSIZE;
2671
2672   if (door_state == DOOR_GET_STATE)
2673     return (door1 | door2);
2674
2675   if (door_state & DOOR_SET_STATE)
2676   {
2677     if (door_state & DOOR_ACTION_1)
2678       door1 = door_state & DOOR_ACTION_1;
2679     if (door_state & DOOR_ACTION_2)
2680       door2 = door_state & DOOR_ACTION_2;
2681
2682     return (door1 | door2);
2683   }
2684
2685   if (!(door_state & DOOR_FORCE_REDRAW))
2686   {
2687     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2688       door_state &= ~DOOR_OPEN_1;
2689     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2690       door_state &= ~DOOR_CLOSE_1;
2691     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2692       door_state &= ~DOOR_OPEN_2;
2693     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2694       door_state &= ~DOOR_CLOSE_2;
2695   }
2696
2697   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2698                       door_2.step_delay);
2699
2700   if (setup.quick_doors)
2701   {
2702     stepsize = 20;              /* must be choosen to always draw last frame */
2703     door_delay_value = 0;
2704   }
2705
2706   if (global.autoplay_leveldir)
2707   {
2708     door_state |= DOOR_NO_DELAY;
2709     door_state &= ~DOOR_CLOSE_ALL;
2710   }
2711
2712   if (door_state & DOOR_ACTION)
2713   {
2714     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2715     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2716     boolean door_1_done = (!handle_door_1);
2717     boolean door_2_done = (!handle_door_2);
2718     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2719     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2720     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2721     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2722     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2723     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2724     int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
2725     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2726     int door_skip = max_door_size - door_size;
2727 #if 1
2728     int end = door_size;
2729 #else
2730     int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2731                DYSIZE : DXSIZE);
2732 #endif
2733 #if 1
2734     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2735 #else
2736     int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2737 #endif
2738     int k;
2739
2740     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2741     {
2742       /* opening door sound has priority over simultaneously closing door */
2743       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2744         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2745       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2746         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2747     }
2748
2749     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2750     {
2751       int x = k;
2752       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2753       GC gc = bitmap->stored_clip_gc;
2754
2755       if (door_state & DOOR_ACTION_1)
2756       {
2757         int a = MIN(x * door_1.step_offset, end);
2758         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2759         int i = p + door_skip;
2760
2761         if (door_1.anim_mode & ANIM_STATIC_PANEL)
2762         {
2763           BlitBitmap(bitmap_db_door, drawto,
2764                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2765                      DXSIZE, DYSIZE, DX, DY);
2766         }
2767         else if (x <= a)
2768         {
2769           BlitBitmap(bitmap_db_door, drawto,
2770                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2771                      DXSIZE, DYSIZE - p / 2, DX, DY);
2772
2773           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2774         }
2775
2776         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2777         {
2778           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
2779           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2780           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
2781           int dst2_x = DX,              dst2_y = DY;
2782           int width = i, height = DYSIZE;
2783
2784           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2785           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2786                            dst1_x, dst1_y);
2787
2788           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2789           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2790                            dst2_x, dst2_y);
2791         }
2792         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2793         {
2794           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
2795           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
2796           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2797           int dst2_x = DX,              dst2_y = DY;
2798           int width = DXSIZE, height = i;
2799
2800           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2801           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2802                            dst1_x, dst1_y);
2803
2804           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2805           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2806                            dst2_x, dst2_y);
2807         }
2808         else if (x <= DXSIZE)   /* ANIM_DEFAULT */
2809         {
2810           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2811
2812           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2813           BlitBitmapMasked(bitmap, drawto,
2814                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2815                            DX + DXSIZE - i, DY + j);
2816           BlitBitmapMasked(bitmap, drawto,
2817                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2818                            DX + DXSIZE - i, DY + 140 + j);
2819           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2820                         DY - (DOOR_GFX_PAGEY1 + j));
2821           BlitBitmapMasked(bitmap, drawto,
2822                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2823                            DX, DY);
2824           BlitBitmapMasked(bitmap, drawto,
2825                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2826                            DX, DY + 140 - j);
2827
2828           BlitBitmapMasked(bitmap, drawto,
2829                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2830                            DX, DY + 77 - j);
2831           BlitBitmapMasked(bitmap, drawto,
2832                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2833                            DX, DY + 203 - j);
2834           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2835           BlitBitmapMasked(bitmap, drawto,
2836                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2837                            DX + DXSIZE - i, DY + 77 + j);
2838           BlitBitmapMasked(bitmap, drawto,
2839                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2840                            DX + DXSIZE - i, DY + 203 + j);
2841         }
2842
2843         redraw_mask |= REDRAW_DOOR_1;
2844         door_1_done = (a == end);
2845       }
2846
2847       if (door_state & DOOR_ACTION_2)
2848       {
2849 #if 1
2850         int a = MIN(x * door_2.step_offset, door_size);
2851         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2852         int i = p + door_skip;
2853 #else
2854         int a = MIN(x * door_2.step_offset, door_size_2);
2855         int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2856         int i = p + door_skip;
2857 #endif
2858
2859         if (door_2.anim_mode & ANIM_STATIC_PANEL)
2860         {
2861           BlitBitmap(bitmap_db_door, drawto,
2862                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2863                      VXSIZE, VYSIZE, VX, VY);
2864         }
2865         else if (x <= VYSIZE)
2866         {
2867           BlitBitmap(bitmap_db_door, drawto,
2868                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2869                      VXSIZE, VYSIZE - p / 2, VX, VY);
2870
2871           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2872         }
2873
2874         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2875         {
2876           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
2877           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2878           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
2879           int dst2_x = VX,              dst2_y = VY;
2880           int width = i, height = VYSIZE;
2881
2882           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2883           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2884                            dst1_x, dst1_y);
2885
2886           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2887           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2888                            dst2_x, dst2_y);
2889         }
2890         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2891         {
2892           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
2893           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
2894           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2895           int dst2_x = VX,              dst2_y = VY;
2896           int width = VXSIZE, height = i;
2897
2898           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2899           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2900                            dst1_x, dst1_y);
2901
2902           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2903           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2904                            dst2_x, dst2_y);
2905         }
2906         else if (x <= VXSIZE)   /* ANIM_DEFAULT */
2907         {
2908           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2909
2910           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2911           BlitBitmapMasked(bitmap, drawto,
2912                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2913                            VX + VXSIZE - i, VY + j);
2914           SetClipOrigin(bitmap, gc,
2915                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2916           BlitBitmapMasked(bitmap, drawto,
2917                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2918                            VX, VY);
2919
2920           BlitBitmapMasked(bitmap, drawto,
2921                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2922                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2923           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2924           BlitBitmapMasked(bitmap, drawto,
2925                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2926                            i, VYSIZE / 2 - j,
2927                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2928         }
2929
2930         redraw_mask |= REDRAW_DOOR_2;
2931         door_2_done = (a == VXSIZE);
2932       }
2933
2934       if (!(door_state & DOOR_NO_DELAY))
2935       {
2936         BackToFront();
2937
2938         if (game_status == GAME_MODE_MAIN)
2939           DoAnimation();
2940
2941         WaitUntilDelayReached(&door_delay, door_delay_value);
2942       }
2943     }
2944   }
2945
2946   if (door_state & DOOR_ACTION_1)
2947     door1 = door_state & DOOR_ACTION_1;
2948   if (door_state & DOOR_ACTION_2)
2949     door2 = door_state & DOOR_ACTION_2;
2950
2951   return (door1 | door2);
2952 }
2953
2954 void DrawSpecialEditorDoor()
2955 {
2956   /* draw bigger toolbox window */
2957   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2958              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2959              EX - 4, EY - 12);
2960   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2961              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2962              EX - 6, EY - 4);
2963
2964   redraw_mask |= REDRAW_ALL;
2965 }
2966
2967 void UndrawSpecialEditorDoor()
2968 {
2969   /* draw normal tape recorder window */
2970   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2971              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2972              EX - 6, EY - 12);
2973
2974   redraw_mask |= REDRAW_ALL;
2975 }
2976
2977
2978 /* ---------- new tool button stuff ---------------------------------------- */
2979
2980 /* graphic position values for tool buttons */
2981 #define TOOL_BUTTON_YES_XPOS            2
2982 #define TOOL_BUTTON_YES_YPOS            250
2983 #define TOOL_BUTTON_YES_GFX_YPOS        0
2984 #define TOOL_BUTTON_YES_XSIZE           46
2985 #define TOOL_BUTTON_YES_YSIZE           28
2986 #define TOOL_BUTTON_NO_XPOS             52
2987 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2988 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2989 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2990 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2991 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2992 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2993 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2994 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2995 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2996 #define TOOL_BUTTON_PLAYER_XSIZE        30
2997 #define TOOL_BUTTON_PLAYER_YSIZE        30
2998 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2999 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
3000 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3001 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3002 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3003                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3004 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3005                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3006 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3007                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3008 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3009                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3010 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3011                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3012 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3013                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3014 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3015                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3016 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3017                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3018
3019 static struct
3020 {
3021   int xpos, ypos;
3022   int x, y;
3023   int width, height;
3024   int gadget_id;
3025   char *infotext;
3026 } toolbutton_info[NUM_TOOL_BUTTONS] =
3027 {
3028   {
3029     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
3030     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
3031     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
3032     TOOL_CTRL_ID_YES,
3033     "yes"
3034   },
3035   {
3036     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
3037     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
3038     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
3039     TOOL_CTRL_ID_NO,
3040     "no"
3041   },
3042   {
3043     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
3044     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
3045     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
3046     TOOL_CTRL_ID_CONFIRM,
3047     "confirm"
3048   },
3049   {
3050     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3051     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
3052     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3053     TOOL_CTRL_ID_PLAYER_1,
3054     "player 1"
3055   },
3056   {
3057     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3058     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
3059     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3060     TOOL_CTRL_ID_PLAYER_2,
3061     "player 2"
3062   },
3063   {
3064     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3065     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
3066     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3067     TOOL_CTRL_ID_PLAYER_3,
3068     "player 3"
3069   },
3070   {
3071     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3072     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
3073     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3074     TOOL_CTRL_ID_PLAYER_4,
3075     "player 4"
3076   }
3077 };
3078
3079 void CreateToolButtons()
3080 {
3081   int i;
3082
3083   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3084   {
3085     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3086     Bitmap *deco_bitmap = None;
3087     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3088     struct GadgetInfo *gi;
3089     unsigned long event_mask;
3090     int gd_xoffset, gd_yoffset;
3091     int gd_x1, gd_x2, gd_y;
3092     int id = i;
3093
3094     event_mask = GD_EVENT_RELEASED;
3095
3096     gd_xoffset = toolbutton_info[i].xpos;
3097     gd_yoffset = toolbutton_info[i].ypos;
3098     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3099     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3100     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3101
3102     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3103     {
3104       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3105
3106       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3107                            &deco_bitmap, &deco_x, &deco_y);
3108       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3109       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3110     }
3111
3112     gi = CreateGadget(GDI_CUSTOM_ID, id,
3113                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
3114                       GDI_X, DX + toolbutton_info[i].x,
3115                       GDI_Y, DY + toolbutton_info[i].y,
3116                       GDI_WIDTH, toolbutton_info[i].width,
3117                       GDI_HEIGHT, toolbutton_info[i].height,
3118                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3119                       GDI_STATE, GD_BUTTON_UNPRESSED,
3120                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3121                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3122                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3123                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3124                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3125                       GDI_DECORATION_SHIFTING, 1, 1,
3126                       GDI_EVENT_MASK, event_mask,
3127                       GDI_CALLBACK_ACTION, HandleToolButtons,
3128                       GDI_END);
3129
3130     if (gi == NULL)
3131       Error(ERR_EXIT, "cannot create gadget");
3132
3133     tool_gadget[id] = gi;
3134   }
3135 }
3136
3137 void FreeToolButtons()
3138 {
3139   int i;
3140
3141   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3142     FreeGadget(tool_gadget[i]);
3143 }
3144
3145 static void UnmapToolButtons()
3146 {
3147   int i;
3148
3149   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3150     UnmapGadget(tool_gadget[i]);
3151 }
3152
3153 static void HandleToolButtons(struct GadgetInfo *gi)
3154 {
3155   request_gadget_id = gi->custom_id;
3156 }
3157
3158 static struct Mapping_EM_to_RND_object
3159 {
3160   int element_em;
3161   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
3162   boolean is_backside;                  /* backside of moving element */
3163
3164   int element_rnd;
3165   int action;
3166   int direction;
3167 }
3168 em_object_mapping_list[] =
3169 {
3170   {
3171     Xblank,                             TRUE,   FALSE,
3172     EL_EMPTY,                           -1, -1
3173   },
3174   {
3175     Yacid_splash_eB,                    FALSE,  FALSE,
3176     EL_ACID_SPLASH_RIGHT,               -1, -1
3177   },
3178   {
3179     Yacid_splash_wB,                    FALSE,  FALSE,
3180     EL_ACID_SPLASH_LEFT,                -1, -1
3181   },
3182
3183 #ifdef EM_ENGINE_BAD_ROLL
3184   {
3185     Xstone_force_e,                     FALSE,  FALSE,
3186     EL_ROCK,                            -1, MV_BIT_RIGHT
3187   },
3188   {
3189     Xstone_force_w,                     FALSE,  FALSE,
3190     EL_ROCK,                            -1, MV_BIT_LEFT
3191   },
3192   {
3193     Xnut_force_e,                       FALSE,  FALSE,
3194     EL_NUT,                             -1, MV_BIT_RIGHT
3195   },
3196   {
3197     Xnut_force_w,                       FALSE,  FALSE,
3198     EL_NUT,                             -1, MV_BIT_LEFT
3199   },
3200   {
3201     Xspring_force_e,                    FALSE,  FALSE,
3202     EL_SPRING,                          -1, MV_BIT_RIGHT
3203   },
3204   {
3205     Xspring_force_w,                    FALSE,  FALSE,
3206     EL_SPRING,                          -1, MV_BIT_LEFT
3207   },
3208   {
3209     Xemerald_force_e,                   FALSE,  FALSE,
3210     EL_EMERALD,                         -1, MV_BIT_RIGHT
3211   },
3212   {
3213     Xemerald_force_w,                   FALSE,  FALSE,
3214     EL_EMERALD,                         -1, MV_BIT_LEFT
3215   },
3216   {
3217     Xdiamond_force_e,                   FALSE,  FALSE,
3218     EL_DIAMOND,                         -1, MV_BIT_RIGHT
3219   },
3220   {
3221     Xdiamond_force_w,                   FALSE,  FALSE,
3222     EL_DIAMOND,                         -1, MV_BIT_LEFT
3223   },
3224   {
3225     Xbomb_force_e,                      FALSE,  FALSE,
3226     EL_BOMB,                            -1, MV_BIT_RIGHT
3227   },
3228   {
3229     Xbomb_force_w,                      FALSE,  FALSE,
3230     EL_BOMB,                            -1, MV_BIT_LEFT
3231   },
3232 #endif  /* EM_ENGINE_BAD_ROLL */
3233
3234   {
3235     Xstone,                             TRUE,   FALSE,
3236     EL_ROCK,                            -1, -1
3237   },
3238   {
3239     Xstone_pause,                       FALSE,  FALSE,
3240     EL_ROCK,                            -1, -1
3241   },
3242   {
3243     Xstone_fall,                        FALSE,  FALSE,
3244     EL_ROCK,                            -1, -1
3245   },
3246   {
3247     Ystone_s,                           FALSE,  FALSE,
3248     EL_ROCK,                            ACTION_FALLING, -1
3249   },
3250   {
3251     Ystone_sB,                          FALSE,  TRUE,
3252     EL_ROCK,                            ACTION_FALLING, -1
3253   },
3254   {
3255     Ystone_e,                           FALSE,  FALSE,
3256     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3257   },
3258   {
3259     Ystone_eB,                          FALSE,  TRUE,
3260     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3261   },
3262   {
3263     Ystone_w,                           FALSE,  FALSE,
3264     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3265   },
3266   {
3267     Ystone_wB,                          FALSE,  TRUE,
3268     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3269   },
3270   {
3271     Xnut,                               TRUE,   FALSE,
3272     EL_NUT,                             -1, -1
3273   },
3274   {
3275     Xnut_pause,                         FALSE,  FALSE,
3276     EL_NUT,                             -1, -1
3277   },
3278   {
3279     Xnut_fall,                          FALSE,  FALSE,
3280     EL_NUT,                             -1, -1
3281   },
3282   {
3283     Ynut_s,                             FALSE,  FALSE,
3284     EL_NUT,                             ACTION_FALLING, -1
3285   },
3286   {
3287     Ynut_sB,                            FALSE,  TRUE,
3288     EL_NUT,                             ACTION_FALLING, -1
3289   },
3290   {
3291     Ynut_e,                             FALSE,  FALSE,
3292     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3293   },
3294   {
3295     Ynut_eB,                            FALSE,  TRUE,
3296     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3297   },
3298   {
3299     Ynut_w,                             FALSE,  FALSE,
3300     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3301   },
3302   {
3303     Ynut_wB,                            FALSE,  TRUE,
3304     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3305   },
3306   {
3307     Xbug_n,                             TRUE,   FALSE,
3308     EL_BUG_UP,                          -1, -1
3309   },
3310   {
3311     Xbug_e,                             TRUE,   FALSE,
3312     EL_BUG_RIGHT,                       -1, -1
3313   },
3314   {
3315     Xbug_s,                             TRUE,   FALSE,
3316     EL_BUG_DOWN,                        -1, -1
3317   },
3318   {
3319     Xbug_w,                             TRUE,   FALSE,
3320     EL_BUG_LEFT,                        -1, -1
3321   },
3322   {
3323     Xbug_gon,                           FALSE,  FALSE,
3324     EL_BUG_UP,                          -1, -1
3325   },
3326   {
3327     Xbug_goe,                           FALSE,  FALSE,
3328     EL_BUG_RIGHT,                       -1, -1
3329   },
3330   {
3331     Xbug_gos,                           FALSE,  FALSE,
3332     EL_BUG_DOWN,                        -1, -1
3333   },
3334   {
3335     Xbug_gow,                           FALSE,  FALSE,
3336     EL_BUG_LEFT,                        -1, -1
3337   },
3338   {
3339     Ybug_n,                             FALSE,  FALSE,
3340     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3341   },
3342   {
3343     Ybug_nB,                            FALSE,  TRUE,
3344     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3345   },
3346   {
3347     Ybug_e,                             FALSE,  FALSE,
3348     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3349   },
3350   {
3351     Ybug_eB,                            FALSE,  TRUE,
3352     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3353   },
3354   {
3355     Ybug_s,                             FALSE,  FALSE,
3356     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3357   },
3358   {
3359     Ybug_sB,                            FALSE,  TRUE,
3360     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3361   },
3362   {
3363     Ybug_w,                             FALSE,  FALSE,
3364     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3365   },
3366   {
3367     Ybug_wB,                            FALSE,  TRUE,
3368     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3369   },
3370   {
3371     Ybug_w_n,                           FALSE,  FALSE,
3372     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3373   },
3374   {
3375     Ybug_n_e,                           FALSE,  FALSE,
3376     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3377   },
3378   {
3379     Ybug_e_s,                           FALSE,  FALSE,
3380     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3381   },
3382   {
3383     Ybug_s_w,                           FALSE,  FALSE,
3384     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3385   },
3386   {
3387     Ybug_e_n,                           FALSE,  FALSE,
3388     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3389   },
3390   {
3391     Ybug_s_e,                           FALSE,  FALSE,
3392     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3393   },
3394   {
3395     Ybug_w_s,                           FALSE,  FALSE,
3396     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3397   },
3398   {
3399     Ybug_n_w,                           FALSE,  FALSE,
3400     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3401   },
3402   {
3403     Ybug_stone,                         FALSE,  FALSE,
3404     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
3405   },
3406   {
3407     Ybug_spring,                        FALSE,  FALSE,
3408     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
3409   },
3410   {
3411     Xtank_n,                            TRUE,   FALSE,
3412     EL_SPACESHIP_UP,                    -1, -1
3413   },
3414   {
3415     Xtank_e,                            TRUE,   FALSE,
3416     EL_SPACESHIP_RIGHT,                 -1, -1
3417   },
3418   {
3419     Xtank_s,                            TRUE,   FALSE,
3420     EL_SPACESHIP_DOWN,                  -1, -1
3421   },
3422   {
3423     Xtank_w,                            TRUE,   FALSE,
3424     EL_SPACESHIP_LEFT,                  -1, -1
3425   },
3426   {
3427     Xtank_gon,                          FALSE,  FALSE,
3428     EL_SPACESHIP_UP,                    -1, -1
3429   },
3430   {
3431     Xtank_goe,                          FALSE,  FALSE,
3432     EL_SPACESHIP_RIGHT,                 -1, -1
3433   },
3434   {
3435     Xtank_gos,                          FALSE,  FALSE,
3436     EL_SPACESHIP_DOWN,                  -1, -1
3437   },
3438   {
3439     Xtank_gow,                          FALSE,  FALSE,
3440     EL_SPACESHIP_LEFT,                  -1, -1
3441   },
3442   {
3443     Ytank_n,                            FALSE,  FALSE,
3444     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3445   },
3446   {
3447     Ytank_nB,                           FALSE,  TRUE,
3448     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3449   },
3450   {
3451     Ytank_e,                            FALSE,  FALSE,
3452     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3453   },
3454   {
3455     Ytank_eB,                           FALSE,  TRUE,
3456     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3457   },
3458   {
3459     Ytank_s,                            FALSE,  FALSE,
3460     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3461   },
3462   {
3463     Ytank_sB,                           FALSE,  TRUE,
3464     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3465   },
3466   {
3467     Ytank_w,                            FALSE,  FALSE,
3468     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3469   },
3470   {
3471     Ytank_wB,                           FALSE,  TRUE,
3472     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3473   },
3474   {
3475     Ytank_w_n,                          FALSE,  FALSE,
3476     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3477   },
3478   {
3479     Ytank_n_e,                          FALSE,  FALSE,
3480     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3481   },
3482   {
3483     Ytank_e_s,                          FALSE,  FALSE,
3484     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3485   },
3486   {
3487     Ytank_s_w,                          FALSE,  FALSE,
3488     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3489   },
3490   {
3491     Ytank_e_n,                          FALSE,  FALSE,
3492     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3493   },
3494   {
3495     Ytank_s_e,                          FALSE,  FALSE,
3496     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3497   },
3498   {
3499     Ytank_w_s,                          FALSE,  FALSE,
3500     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3501   },
3502   {
3503     Ytank_n_w,                          FALSE,  FALSE,
3504     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3505   },
3506   {
3507     Ytank_stone,                        FALSE,  FALSE,
3508     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
3509   },
3510   {
3511     Ytank_spring,                       FALSE,  FALSE,
3512     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
3513   },
3514   {
3515     Xandroid,                           TRUE,   FALSE,
3516     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
3517   },
3518   {
3519     Xandroid_1_n,                       FALSE,  FALSE,
3520     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
3521   },
3522   {
3523     Xandroid_2_n,                       FALSE,  FALSE,
3524     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
3525   },
3526   {
3527     Xandroid_1_e,                       FALSE,  FALSE,
3528     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
3529   },
3530   {
3531     Xandroid_2_e,                       FALSE,  FALSE,
3532     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
3533   },
3534   {
3535     Xandroid_1_w,                       FALSE,  FALSE,
3536     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
3537   },
3538   {
3539     Xandroid_2_w,                       FALSE,  FALSE,
3540     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
3541   },
3542   {
3543     Xandroid_1_s,                       FALSE,  FALSE,
3544     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
3545   },
3546   {
3547     Xandroid_2_s,                       FALSE,  FALSE,
3548     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
3549   },
3550   {
3551     Yandroid_n,                         FALSE,  FALSE,
3552     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
3553   },
3554   {
3555     Yandroid_nB,                        FALSE,  TRUE,
3556     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
3557   },
3558   {
3559     Yandroid_ne,                        FALSE,  FALSE,
3560     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
3561   },
3562   {
3563     Yandroid_neB,                       FALSE,  TRUE,
3564     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
3565   },
3566   {
3567     Yandroid_e,                         FALSE,  FALSE,
3568     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
3569   },
3570   {
3571     Yandroid_eB,                        FALSE,  TRUE,
3572     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
3573   },
3574   {
3575     Yandroid_se,                        FALSE,  FALSE,
3576     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
3577   },
3578   {
3579     Yandroid_seB,                       FALSE,  TRUE,
3580     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3581   },
3582   {
3583     Yandroid_s,                         FALSE,  FALSE,
3584     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
3585   },
3586   {
3587     Yandroid_sB,                        FALSE,  TRUE,
3588     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
3589   },
3590   {
3591     Yandroid_sw,                        FALSE,  FALSE,
3592     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
3593   },
3594   {
3595     Yandroid_swB,                       FALSE,  TRUE,
3596     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
3597   },
3598   {
3599     Yandroid_w,                         FALSE,  FALSE,
3600     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
3601   },
3602   {
3603     Yandroid_wB,                        FALSE,  TRUE,
3604     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
3605   },
3606   {
3607     Yandroid_nw,                        FALSE,  FALSE,
3608     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
3609   },
3610   {
3611     Yandroid_nwB,                       FALSE,  TRUE,
3612     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
3613   },
3614   {
3615     Xspring,                            TRUE,   FALSE,
3616     EL_SPRING,                          -1, -1
3617   },
3618   {
3619     Xspring_pause,                      FALSE,  FALSE,
3620     EL_SPRING,                          -1, -1
3621   },
3622   {
3623     Xspring_e,                          FALSE,  FALSE,
3624     EL_SPRING,                          -1, -1
3625   },
3626   {
3627     Xspring_w,                          FALSE,  FALSE,
3628     EL_SPRING,                          -1, -1
3629   },
3630   {
3631     Xspring_fall,                       FALSE,  FALSE,
3632     EL_SPRING,                          -1, -1
3633   },
3634   {
3635     Yspring_s,                          FALSE,  FALSE,
3636     EL_SPRING,                          ACTION_FALLING, -1
3637   },
3638   {
3639     Yspring_sB,                         FALSE,  TRUE,
3640     EL_SPRING,                          ACTION_FALLING, -1
3641   },
3642   {
3643     Yspring_e,                          FALSE,  FALSE,
3644     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
3645   },
3646   {
3647     Yspring_eB,                         FALSE,  TRUE,
3648     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
3649   },
3650   {
3651     Yspring_w,                          FALSE,  FALSE,
3652     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
3653   },
3654   {
3655     Yspring_wB,                         FALSE,  TRUE,
3656     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
3657   },
3658   {
3659     Yspring_kill_e,                     FALSE,  FALSE,
3660     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
3661   },
3662   {
3663     Yspring_kill_eB,                    FALSE,  TRUE,
3664     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
3665   },
3666   {
3667     Yspring_kill_w,                     FALSE,  FALSE,
3668     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
3669   },
3670   {
3671     Yspring_kill_wB,                    FALSE,  TRUE,
3672     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
3673   },
3674   {
3675     Xeater_n,                           TRUE,   FALSE,
3676     EL_YAMYAM_UP,                       -1, -1
3677   },
3678   {
3679     Xeater_e,                           TRUE,   FALSE,
3680     EL_YAMYAM_RIGHT,                    -1, -1
3681   },
3682   {
3683     Xeater_w,                           TRUE,   FALSE,
3684     EL_YAMYAM_LEFT,                     -1, -1
3685   },
3686   {
3687     Xeater_s,                           TRUE,   FALSE,
3688     EL_YAMYAM_DOWN,                     -1, -1
3689   },
3690   {
3691     Yeater_n,                           FALSE,  FALSE,
3692     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
3693   },
3694   {
3695     Yeater_nB,                          FALSE,  TRUE,
3696     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
3697   },
3698   {
3699     Yeater_e,                           FALSE,  FALSE,
3700     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
3701   },
3702   {
3703     Yeater_eB,                          FALSE,  TRUE,
3704     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
3705   },
3706   {
3707     Yeater_s,                           FALSE,  FALSE,
3708     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
3709   },
3710   {
3711     Yeater_sB,                          FALSE,  TRUE,
3712     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
3713   },
3714   {
3715     Yeater_w,                           FALSE,  FALSE,
3716     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
3717   },
3718   {
3719     Yeater_wB,                          FALSE,  TRUE,
3720     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
3721   },
3722   {
3723     Yeater_stone,                       FALSE,  FALSE,
3724     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
3725   },
3726   {
3727     Yeater_spring,                      FALSE,  FALSE,
3728     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
3729   },
3730   {
3731     Xalien,                             TRUE,   FALSE,
3732     EL_ROBOT,                           -1, -1
3733   },
3734   {
3735     Xalien_pause,                       FALSE,  FALSE,
3736     EL_ROBOT,                           -1, -1
3737   },
3738   {
3739     Yalien_n,                           FALSE,  FALSE,
3740     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
3741   },
3742   {
3743     Yalien_nB,                          FALSE,  TRUE,
3744     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
3745   },
3746   {
3747     Yalien_e,                           FALSE,  FALSE,
3748     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
3749   },
3750   {
3751     Yalien_eB,                          FALSE,  TRUE,
3752     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
3753   },
3754   {
3755     Yalien_s,                           FALSE,  FALSE,
3756     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
3757   },
3758   {
3759     Yalien_sB,                          FALSE,  TRUE,
3760     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
3761   },
3762   {
3763     Yalien_w,                           FALSE,  FALSE,
3764     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
3765   },
3766   {
3767     Yalien_wB,                          FALSE,  TRUE,
3768     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
3769   },
3770   {
3771     Yalien_stone,                       FALSE,  FALSE,
3772     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
3773   },
3774   {
3775     Yalien_spring,                      FALSE,  FALSE,
3776     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
3777   },
3778   {
3779     Xemerald,                           TRUE,   FALSE,
3780     EL_EMERALD,                         -1, -1
3781   },
3782   {
3783     Xemerald_pause,                     FALSE,  FALSE,
3784     EL_EMERALD,                         -1, -1
3785   },
3786   {
3787     Xemerald_fall,                      FALSE,  FALSE,
3788     EL_EMERALD,                         -1, -1
3789   },
3790   {
3791     Xemerald_shine,                     FALSE,  FALSE,
3792     EL_EMERALD,                         ACTION_TWINKLING, -1
3793   },
3794   {
3795     Yemerald_s,                         FALSE,  FALSE,
3796     EL_EMERALD,                         ACTION_FALLING, -1
3797   },
3798   {
3799     Yemerald_sB,                        FALSE,  TRUE,
3800     EL_EMERALD,                         ACTION_FALLING, -1
3801   },
3802   {
3803     Yemerald_e,                         FALSE,  FALSE,
3804     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
3805   },
3806   {
3807     Yemerald_eB,                        FALSE,  TRUE,
3808     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
3809   },
3810   {
3811     Yemerald_w,                         FALSE,  FALSE,
3812     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
3813   },
3814   {
3815     Yemerald_wB,                        FALSE,  TRUE,
3816     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
3817   },
3818   {
3819     Yemerald_eat,                       FALSE,  FALSE,
3820     EL_EMERALD,                         ACTION_COLLECTING, -1
3821   },
3822   {
3823     Yemerald_stone,                     FALSE,  FALSE,
3824     EL_NUT,                             ACTION_BREAKING, -1
3825   },
3826   {
3827     Xdiamond,                           TRUE,   FALSE,
3828     EL_DIAMOND,                         -1, -1
3829   },
3830   {
3831     Xdiamond_pause,                     FALSE,  FALSE,
3832     EL_DIAMOND,                         -1, -1
3833   },
3834   {
3835     Xdiamond_fall,                      FALSE,  FALSE,
3836     EL_DIAMOND,                         -1, -1
3837   },
3838   {
3839     Xdiamond_shine,                     FALSE,  FALSE,
3840     EL_DIAMOND,                         ACTION_TWINKLING, -1
3841   },
3842   {
3843     Ydiamond_s,                         FALSE,  FALSE,
3844     EL_DIAMOND,                         ACTION_FALLING, -1
3845   },
3846   {
3847     Ydiamond_sB,                        FALSE,  TRUE,
3848     EL_DIAMOND,                         ACTION_FALLING, -1
3849   },
3850   {
3851     Ydiamond_e,                         FALSE,  FALSE,
3852     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
3853   },
3854   {
3855     Ydiamond_eB,                        FALSE,  TRUE,
3856     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
3857   },
3858   {
3859     Ydiamond_w,                         FALSE,  FALSE,
3860     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
3861   },
3862   {
3863     Ydiamond_wB,                        FALSE,  TRUE,
3864     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
3865   },
3866   {
3867     Ydiamond_eat,                       FALSE,  FALSE,
3868     EL_DIAMOND,                         ACTION_COLLECTING, -1
3869   },
3870   {
3871     Ydiamond_stone,                     FALSE,  FALSE,
3872     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
3873   },
3874   {
3875     Xdrip_fall,                         TRUE,   FALSE,
3876     EL_AMOEBA_DROP,                     -1, -1
3877   },
3878   {
3879     Xdrip_stretch,                      FALSE,  FALSE,
3880     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
3881   },
3882   {
3883     Xdrip_stretchB,                     FALSE,  TRUE,
3884     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
3885   },
3886   {
3887     Xdrip_eat,                          FALSE,  FALSE,
3888     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
3889   },
3890   {
3891     Ydrip_s1,                           FALSE,  FALSE,
3892     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
3893   },
3894   {
3895     Ydrip_s1B,                          FALSE,  TRUE,
3896     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
3897   },
3898   {
3899     Ydrip_s2,                           FALSE,  FALSE,
3900     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
3901   },
3902   {
3903     Ydrip_s2B,                          FALSE,  TRUE,
3904     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
3905   },
3906   {
3907     Xbomb,                              TRUE,   FALSE,
3908     EL_BOMB,                            -1, -1
3909   },
3910   {
3911     Xbomb_pause,                        FALSE,  FALSE,
3912     EL_BOMB,                            -1, -1
3913   },
3914   {
3915     Xbomb_fall,                         FALSE,  FALSE,
3916     EL_BOMB,                            -1, -1
3917   },
3918   {
3919     Ybomb_s,                            FALSE,  FALSE,
3920     EL_BOMB,                            ACTION_FALLING, -1
3921   },
3922   {
3923     Ybomb_sB,                           FALSE,  TRUE,
3924     EL_BOMB,                            ACTION_FALLING, -1
3925   },
3926   {
3927     Ybomb_e,                            FALSE,  FALSE,
3928     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
3929   },
3930   {
3931     Ybomb_eB,                           FALSE,  TRUE,
3932     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
3933   },
3934   {
3935     Ybomb_w,                            FALSE,  FALSE,
3936     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
3937   },
3938   {
3939     Ybomb_wB,                           FALSE,  TRUE,
3940     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
3941   },
3942   {
3943     Ybomb_eat,                          FALSE,  FALSE,
3944     EL_BOMB,                            ACTION_ACTIVATING, -1
3945   },
3946   {
3947     Xballoon,                           TRUE,   FALSE,
3948     EL_BALLOON,                         -1, -1
3949   },
3950   {
3951     Yballoon_n,                         FALSE,  FALSE,
3952     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
3953   },
3954   {
3955     Yballoon_nB,                        FALSE,  TRUE,
3956     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
3957   },
3958   {
3959     Yballoon_e,                         FALSE,  FALSE,
3960     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
3961   },
3962   {
3963     Yballoon_eB,                        FALSE,  TRUE,
3964     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
3965   },
3966   {
3967     Yballoon_s,                         FALSE,  FALSE,
3968     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
3969   },
3970   {
3971     Yballoon_sB,                        FALSE,  TRUE,
3972     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
3973   },
3974   {
3975     Yballoon_w,                         FALSE,  FALSE,
3976     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
3977   },
3978   {
3979     Yballoon_wB,                        FALSE,  TRUE,
3980     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
3981   },
3982   {
3983     Xgrass,                             TRUE,   FALSE,
3984     EL_EMC_GRASS,                       -1, -1
3985   },
3986   {
3987     Ygrass_nB,                          FALSE,  FALSE,
3988     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
3989   },
3990   {
3991     Ygrass_eB,                          FALSE,  FALSE,
3992     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
3993   },
3994   {
3995     Ygrass_sB,                          FALSE,  FALSE,
3996     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
3997   },
3998   {
3999     Ygrass_wB,                          FALSE,  FALSE,
4000     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
4001   },
4002   {
4003     Xdirt,                              TRUE,   FALSE,
4004     EL_SAND,                            -1, -1
4005   },
4006   {
4007     Ydirt_nB,                           FALSE,  FALSE,
4008     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
4009   },
4010   {
4011     Ydirt_eB,                           FALSE,  FALSE,
4012     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
4013   },
4014   {
4015     Ydirt_sB,                           FALSE,  FALSE,
4016     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
4017   },
4018   {
4019     Ydirt_wB,                           FALSE,  FALSE,
4020     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
4021   },
4022   {
4023     Xacid_ne,                           TRUE,   FALSE,
4024     EL_ACID_POOL_TOPRIGHT,              -1, -1
4025   },
4026   {
4027     Xacid_se,                           TRUE,   FALSE,
4028     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
4029   },
4030   {
4031     Xacid_s,                            TRUE,   FALSE,
4032     EL_ACID_POOL_BOTTOM,                -1, -1
4033   },
4034   {
4035     Xacid_sw,                           TRUE,   FALSE,
4036     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
4037   },
4038   {
4039     Xacid_nw,                           TRUE,   FALSE,
4040     EL_ACID_POOL_TOPLEFT,               -1, -1
4041   },
4042   {
4043     Xacid_1,                            TRUE,   FALSE,
4044     EL_ACID,                            -1, -1
4045   },
4046   {
4047     Xacid_2,                            FALSE,  FALSE,
4048     EL_ACID,                            -1, -1
4049   },
4050   {
4051     Xacid_3,                            FALSE,  FALSE,
4052     EL_ACID,                            -1, -1
4053   },
4054   {
4055     Xacid_4,                            FALSE,  FALSE,
4056     EL_ACID,                            -1, -1
4057   },
4058   {
4059     Xacid_5,                            FALSE,  FALSE,
4060     EL_ACID,                            -1, -1
4061   },
4062   {
4063     Xacid_6,                            FALSE,  FALSE,
4064     EL_ACID,                            -1, -1
4065   },
4066   {
4067     Xacid_7,                            FALSE,  FALSE,
4068     EL_ACID,                            -1, -1
4069   },
4070   {
4071     Xacid_8,                            FALSE,  FALSE,
4072     EL_ACID,                            -1, -1
4073   },
4074   {
4075     Xball_1,                            TRUE,   FALSE,
4076     EL_EMC_MAGIC_BALL,                  -1, -1
4077   },
4078   {
4079     Xball_1B,                           FALSE,  FALSE,
4080     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4081   },
4082   {
4083     Xball_2,                            FALSE,  FALSE,
4084     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4085   },
4086   {
4087     Xball_2B,                           FALSE,  FALSE,
4088     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4089   },
4090   {
4091     Yball_eat,                          FALSE,  FALSE,
4092     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
4093   },
4094   {
4095     Ykey_1_eat,                         FALSE,  FALSE,
4096     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
4097   },
4098   {
4099     Ykey_2_eat,                         FALSE,  FALSE,
4100     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
4101   },
4102   {
4103     Ykey_3_eat,                         FALSE,  FALSE,
4104     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
4105   },
4106   {
4107     Ykey_4_eat,                         FALSE,  FALSE,
4108     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
4109   },
4110   {
4111     Ykey_5_eat,                         FALSE,  FALSE,
4112     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
4113   },
4114   {
4115     Ykey_6_eat,                         FALSE,  FALSE,
4116     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
4117   },
4118   {
4119     Ykey_7_eat,                         FALSE,  FALSE,
4120     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
4121   },
4122   {
4123     Ykey_8_eat,                         FALSE,  FALSE,
4124     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
4125   },
4126   {
4127     Ylenses_eat,                        FALSE,  FALSE,
4128     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
4129   },
4130   {
4131     Ymagnify_eat,                       FALSE,  FALSE,
4132     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
4133   },
4134   {
4135     Ygrass_eat,                         FALSE,  FALSE,
4136     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
4137   },
4138   {
4139     Ydirt_eat,                          FALSE,  FALSE,
4140     EL_SAND,                            ACTION_SNAPPING, -1
4141   },
4142   {
4143     Xgrow_ns,                           TRUE,   FALSE,
4144     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
4145   },
4146   {
4147     Ygrow_ns_eat,                       FALSE,  FALSE,
4148     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
4149   },
4150   {
4151     Xgrow_ew,                           TRUE,   FALSE,
4152     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
4153   },
4154   {
4155     Ygrow_ew_eat,                       FALSE,  FALSE,
4156     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
4157   },
4158   {
4159     Xwonderwall,                        TRUE,   FALSE,
4160     EL_MAGIC_WALL,                      -1, -1
4161   },
4162   {
4163     XwonderwallB,                       FALSE,  FALSE,
4164     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
4165   },
4166   {
4167     Xamoeba_1,                          TRUE,   FALSE,
4168     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4169   },
4170   {
4171     Xamoeba_2,                          FALSE,  FALSE,
4172     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4173   },
4174   {
4175     Xamoeba_3,                          FALSE,  FALSE,
4176     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4177   },
4178   {
4179     Xamoeba_4,                          FALSE,  FALSE,
4180     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4181   },
4182   {
4183     Xamoeba_5,                          TRUE,   FALSE,
4184     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4185   },
4186   {
4187     Xamoeba_6,                          FALSE,  FALSE,
4188     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4189   },
4190   {
4191     Xamoeba_7,                          FALSE,  FALSE,
4192     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4193   },
4194   {
4195     Xamoeba_8,                          FALSE,  FALSE,
4196     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4197   },
4198   {
4199     Xdoor_1,                            TRUE,   FALSE,
4200     EL_EM_GATE_1,                       -1, -1
4201   },
4202   {
4203     Xdoor_2,                            TRUE,   FALSE,
4204     EL_EM_GATE_2,                       -1, -1
4205   },
4206   {
4207     Xdoor_3,                            TRUE,   FALSE,
4208     EL_EM_GATE_3,                       -1, -1
4209   },
4210   {
4211     Xdoor_4,                            TRUE,   FALSE,
4212     EL_EM_GATE_4,                       -1, -1
4213   },
4214   {
4215     Xdoor_5,                            TRUE,   FALSE,
4216     EL_EMC_GATE_5,                      -1, -1
4217   },
4218   {
4219     Xdoor_6,                            TRUE,   FALSE,
4220     EL_EMC_GATE_6,                      -1, -1
4221   },
4222   {
4223     Xdoor_7,                            TRUE,   FALSE,
4224     EL_EMC_GATE_7,                      -1, -1
4225   },
4226   {
4227     Xdoor_8,                            TRUE,   FALSE,
4228     EL_EMC_GATE_8,                      -1, -1
4229   },
4230   {
4231     Xkey_1,                             TRUE,   FALSE,
4232     EL_EM_KEY_1,                        -1, -1
4233   },
4234   {
4235     Xkey_2,                             TRUE,   FALSE,
4236     EL_EM_KEY_2,                        -1, -1
4237   },
4238   {
4239     Xkey_3,                             TRUE,   FALSE,
4240     EL_EM_KEY_3,                        -1, -1
4241   },
4242   {
4243     Xkey_4,                             TRUE,   FALSE,
4244     EL_EM_KEY_4,                        -1, -1
4245   },
4246   {
4247     Xkey_5,                             TRUE,   FALSE,
4248     EL_EMC_KEY_5,                       -1, -1
4249   },
4250   {
4251     Xkey_6,                             TRUE,   FALSE,
4252     EL_EMC_KEY_6,                       -1, -1
4253   },
4254   {
4255     Xkey_7,                             TRUE,   FALSE,
4256     EL_EMC_KEY_7,                       -1, -1
4257   },
4258   {
4259     Xkey_8,                             TRUE,   FALSE,
4260     EL_EMC_KEY_8,                       -1, -1
4261   },
4262   {
4263     Xwind_n,                            TRUE,   FALSE,
4264     EL_BALLOON_SWITCH_UP,               -1, -1
4265   },
4266   {
4267     Xwind_e,                            TRUE,   FALSE,
4268     EL_BALLOON_SWITCH_RIGHT,            -1, -1
4269   },
4270   {
4271     Xwind_s,                            TRUE,   FALSE,
4272     EL_BALLOON_SWITCH_DOWN,             -1, -1
4273   },
4274   {
4275     Xwind_w,                            TRUE,   FALSE,
4276     EL_BALLOON_SWITCH_LEFT,             -1, -1
4277   },
4278   {
4279     Xwind_nesw,                         TRUE,   FALSE,
4280     EL_BALLOON_SWITCH_ANY,              -1, -1
4281   },
4282   {
4283     Xwind_stop,                         TRUE,   FALSE,
4284     EL_BALLOON_SWITCH_NONE,             -1, -1
4285   },
4286   {
4287     Xexit,                              TRUE,   FALSE,
4288     EL_EXIT_CLOSED,                     -1, -1
4289   },
4290   {
4291     Xexit_1,                            TRUE,   FALSE,
4292     EL_EXIT_OPEN,                       -1, -1
4293   },
4294   {
4295     Xexit_2,                            FALSE,  FALSE,
4296     EL_EXIT_OPEN,                       -1, -1
4297   },
4298   {
4299     Xexit_3,                            FALSE,  FALSE,
4300     EL_EXIT_OPEN,                       -1, -1
4301   },
4302   {
4303     Xdynamite,                          TRUE,   FALSE,
4304     EL_EM_DYNAMITE,                     -1, -1
4305   },
4306   {
4307     Ydynamite_eat,                      FALSE,  FALSE,
4308     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
4309   },
4310   {
4311     Xdynamite_1,                        TRUE,   FALSE,
4312     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4313   },
4314   {
4315     Xdynamite_2,                        FALSE,  FALSE,
4316     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4317   },
4318   {
4319     Xdynamite_3,                        FALSE,  FALSE,
4320     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4321   },
4322   {
4323     Xdynamite_4,                        FALSE,  FALSE,
4324     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4325   },
4326   {
4327     Xbumper,                            TRUE,   FALSE,
4328     EL_EMC_SPRING_BUMPER,               -1, -1
4329   },
4330   {
4331     XbumperB,                           FALSE,  FALSE,
4332     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
4333   },
4334   {
4335     Xwheel,                             TRUE,   FALSE,
4336     EL_ROBOT_WHEEL,                     -1, -1
4337   },
4338   {
4339     XwheelB,                            FALSE,  FALSE,
4340     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
4341   },
4342   {
4343     Xswitch,                            TRUE,   FALSE,
4344     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
4345   },
4346   {
4347     XswitchB,                           FALSE,  FALSE,
4348     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
4349   },
4350   {
4351     Xsand,                              TRUE,   FALSE,
4352     EL_QUICKSAND_EMPTY,                 -1, -1
4353   },
4354   {
4355     Xsand_stone,                        TRUE,   FALSE,
4356     EL_QUICKSAND_FULL,                  -1, -1
4357   },
4358   {
4359     Xsand_stonein_1,                    FALSE,  TRUE,
4360     EL_ROCK,                            ACTION_FILLING, -1
4361   },
4362   {
4363     Xsand_stonein_2,                    FALSE,  TRUE,
4364     EL_ROCK,                            ACTION_FILLING, -1
4365   },
4366   {
4367     Xsand_stonein_3,                    FALSE,  TRUE,
4368     EL_ROCK,                            ACTION_FILLING, -1
4369   },
4370   {
4371     Xsand_stonein_4,                    FALSE,  TRUE,
4372     EL_ROCK,                            ACTION_FILLING, -1
4373   },
4374   {
4375     Xsand_stonesand_1,                  FALSE,  FALSE,
4376     EL_QUICKSAND_FULL,                  -1, -1
4377   },
4378   {
4379     Xsand_stonesand_2,                  FALSE,  FALSE,
4380     EL_QUICKSAND_FULL,                  -1, -1
4381   },
4382   {
4383     Xsand_stonesand_3,                  FALSE,  FALSE,
4384     EL_QUICKSAND_FULL,                  -1, -1
4385   },
4386   {
4387     Xsand_stonesand_4,                  FALSE,  FALSE,
4388     EL_QUICKSAND_FULL,                  -1, -1
4389   },
4390   {
4391     Xsand_stoneout_1,                   FALSE,  FALSE,
4392     EL_ROCK,                            ACTION_EMPTYING, -1
4393   },
4394   {
4395     Xsand_stoneout_2,                   FALSE,  FALSE,
4396     EL_ROCK,                            ACTION_EMPTYING, -1
4397   },
4398   {
4399     Xsand_sandstone_1,                  FALSE,  FALSE,
4400     EL_QUICKSAND_FULL,                  -1, -1
4401   },
4402   {
4403     Xsand_sandstone_2,                  FALSE,  FALSE,
4404     EL_QUICKSAND_FULL,                  -1, -1
4405   },
4406   {
4407     Xsand_sandstone_3,                  FALSE,  FALSE,
4408     EL_QUICKSAND_FULL,                  -1, -1
4409   },
4410   {
4411     Xsand_sandstone_4,                  FALSE,  FALSE,
4412     EL_QUICKSAND_FULL,                  -1, -1
4413   },
4414   {
4415     Xplant,                             TRUE,   FALSE,
4416     EL_EMC_PLANT,                       -1, -1
4417   },
4418   {
4419     Yplant,                             FALSE,  FALSE,
4420     EL_EMC_PLANT,                       -1, -1
4421   },
4422   {
4423     Xlenses,                            TRUE,   FALSE,
4424     EL_EMC_LENSES,                      -1, -1
4425   },
4426   {
4427     Xmagnify,                           TRUE,   FALSE,
4428     EL_EMC_MAGNIFIER,                   -1, -1
4429   },
4430   {
4431     Xdripper,                           TRUE,   FALSE,
4432     EL_EMC_DRIPPER,                     -1, -1
4433   },
4434   {
4435     XdripperB,                          FALSE,  FALSE,
4436     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
4437   },
4438   {
4439     Xfake_blank,                        TRUE,   FALSE,
4440     EL_INVISIBLE_WALL,                  -1, -1
4441   },
4442   {
4443     Xfake_blankB,                       FALSE,  FALSE,
4444     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
4445   },
4446   {
4447     Xfake_grass,                        TRUE,   FALSE,
4448     EL_EMC_FAKE_GRASS,                  -1, -1
4449   },
4450   {
4451     Xfake_grassB,                       FALSE,  FALSE,
4452     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
4453   },
4454   {
4455     Xfake_door_1,                       TRUE,   FALSE,
4456     EL_EM_GATE_1_GRAY,                  -1, -1
4457   },
4458   {
4459     Xfake_door_2,                       TRUE,   FALSE,
4460     EL_EM_GATE_2_GRAY,                  -1, -1
4461   },
4462   {
4463     Xfake_door_3,                       TRUE,   FALSE,
4464     EL_EM_GATE_3_GRAY,                  -1, -1
4465   },
4466   {
4467     Xfake_door_4,                       TRUE,   FALSE,
4468     EL_EM_GATE_4_GRAY,                  -1, -1
4469   },
4470   {
4471     Xfake_door_5,                       TRUE,   FALSE,
4472     EL_EMC_GATE_5_GRAY,                 -1, -1
4473   },
4474   {
4475     Xfake_door_6,                       TRUE,   FALSE,
4476     EL_EMC_GATE_6_GRAY,                 -1, -1
4477   },
4478   {
4479     Xfake_door_7,                       TRUE,   FALSE,
4480     EL_EMC_GATE_7_GRAY,                 -1, -1
4481   },
4482   {
4483     Xfake_door_8,                       TRUE,   FALSE,
4484     EL_EMC_GATE_8_GRAY,                 -1, -1
4485   },
4486   {
4487     Xfake_acid_1,                       TRUE,   FALSE,
4488     EL_EMC_FAKE_ACID,                   -1, -1
4489   },
4490   {
4491     Xfake_acid_2,                       FALSE,  FALSE,
4492     EL_EMC_FAKE_ACID,                   -1, -1
4493   },
4494   {
4495     Xfake_acid_3,                       FALSE,  FALSE,
4496     EL_EMC_FAKE_ACID,                   -1, -1
4497   },
4498   {
4499     Xfake_acid_4,                       FALSE,  FALSE,
4500     EL_EMC_FAKE_ACID,                   -1, -1
4501   },
4502   {
4503     Xfake_acid_5,                       FALSE,  FALSE,
4504     EL_EMC_FAKE_ACID,                   -1, -1
4505   },
4506   {
4507     Xfake_acid_6,                       FALSE,  FALSE,
4508     EL_EMC_FAKE_ACID,                   -1, -1
4509   },
4510   {
4511     Xfake_acid_7,                       FALSE,  FALSE,
4512     EL_EMC_FAKE_ACID,                   -1, -1
4513   },
4514   {
4515     Xfake_acid_8,                       FALSE,  FALSE,
4516     EL_EMC_FAKE_ACID,                   -1, -1
4517   },
4518   {
4519     Xsteel_1,                           TRUE,   FALSE,
4520     EL_STEELWALL,                       -1, -1
4521   },
4522   {
4523     Xsteel_2,                           TRUE,   FALSE,
4524     EL_EMC_STEELWALL_2,                 -1, -1
4525   },
4526   {
4527     Xsteel_3,                           TRUE,   FALSE,
4528     EL_EMC_STEELWALL_3,                 -1, -1
4529   },
4530   {
4531     Xsteel_4,                           TRUE,   FALSE,
4532     EL_EMC_STEELWALL_4,                 -1, -1
4533   },
4534   {
4535     Xwall_1,                            TRUE,   FALSE,
4536     EL_WALL,                            -1, -1
4537   },
4538   {
4539     Xwall_2,                            TRUE,   FALSE,
4540     EL_EMC_WALL_14,                     -1, -1
4541   },
4542   {
4543     Xwall_3,                            TRUE,   FALSE,
4544     EL_EMC_WALL_15,                     -1, -1
4545   },
4546   {
4547     Xwall_4,                            TRUE,   FALSE,
4548     EL_EMC_WALL_16,                     -1, -1
4549   },
4550   {
4551     Xround_wall_1,                      TRUE,   FALSE,
4552     EL_WALL_SLIPPERY,                   -1, -1
4553   },
4554   {
4555     Xround_wall_2,                      TRUE,   FALSE,
4556     EL_EMC_WALL_SLIPPERY_2,             -1, -1
4557   },
4558   {
4559     Xround_wall_3,                      TRUE,   FALSE,
4560     EL_EMC_WALL_SLIPPERY_3,             -1, -1
4561   },
4562   {
4563     Xround_wall_4,                      TRUE,   FALSE,
4564     EL_EMC_WALL_SLIPPERY_4,             -1, -1
4565   },
4566   {
4567     Xdecor_1,                           TRUE,   FALSE,
4568     EL_EMC_WALL_8,                      -1, -1
4569   },
4570   {
4571     Xdecor_2,                           TRUE,   FALSE,
4572     EL_EMC_WALL_6,                      -1, -1
4573   },
4574   {
4575     Xdecor_3,                           TRUE,   FALSE,
4576     EL_EMC_WALL_4,                      -1, -1
4577   },
4578   {
4579     Xdecor_4,                           TRUE,   FALSE,
4580     EL_EMC_WALL_7,                      -1, -1
4581   },
4582   {
4583     Xdecor_5,                           TRUE,   FALSE,
4584     EL_EMC_WALL_5,                      -1, -1
4585   },
4586   {
4587     Xdecor_6,                           TRUE,   FALSE,
4588     EL_EMC_WALL_9,                      -1, -1
4589   },
4590   {
4591     Xdecor_7,                           TRUE,   FALSE,
4592     EL_EMC_WALL_10,                     -1, -1
4593   },
4594   {
4595     Xdecor_8,                           TRUE,   FALSE,
4596     EL_EMC_WALL_1,                      -1, -1
4597   },
4598   {
4599     Xdecor_9,                           TRUE,   FALSE,
4600     EL_EMC_WALL_2,                      -1, -1
4601   },
4602   {
4603     Xdecor_10,                          TRUE,   FALSE,
4604     EL_EMC_WALL_3,                      -1, -1
4605   },
4606   {
4607     Xdecor_11,                          TRUE,   FALSE,
4608     EL_EMC_WALL_11,                     -1, -1
4609   },
4610   {
4611     Xdecor_12,                          TRUE,   FALSE,
4612     EL_EMC_WALL_12,                     -1, -1
4613   },
4614   {
4615     Xalpha_0,                           TRUE,   FALSE,
4616     EL_CHAR('0'),                       -1, -1
4617   },
4618   {
4619     Xalpha_1,                           TRUE,   FALSE,
4620     EL_CHAR('1'),                       -1, -1
4621   },
4622   {
4623     Xalpha_2,                           TRUE,   FALSE,
4624     EL_CHAR('2'),                       -1, -1
4625   },
4626   {
4627     Xalpha_3,                           TRUE,   FALSE,
4628     EL_CHAR('3'),                       -1, -1
4629   },
4630   {
4631     Xalpha_4,                           TRUE,   FALSE,
4632     EL_CHAR('4'),                       -1, -1
4633   },
4634   {
4635     Xalpha_5,                           TRUE,   FALSE,
4636     EL_CHAR('5'),                       -1, -1
4637   },
4638   {
4639     Xalpha_6,                           TRUE,   FALSE,
4640     EL_CHAR('6'),                       -1, -1
4641   },
4642   {
4643     Xalpha_7,                           TRUE,   FALSE,
4644     EL_CHAR('7'),                       -1, -1
4645   },
4646   {
4647     Xalpha_8,                           TRUE,   FALSE,
4648     EL_CHAR('8'),                       -1, -1
4649   },
4650   {
4651     Xalpha_9,                           TRUE,   FALSE,
4652     EL_CHAR('9'),                       -1, -1
4653   },
4654   {
4655     Xalpha_excla,                       TRUE,   FALSE,
4656     EL_CHAR('!'),                       -1, -1
4657   },
4658   {
4659     Xalpha_quote,                       TRUE,   FALSE,
4660     EL_CHAR('"'),                       -1, -1
4661   },
4662   {
4663     Xalpha_comma,                       TRUE,   FALSE,
4664     EL_CHAR(','),                       -1, -1
4665   },
4666   {
4667     Xalpha_minus,                       TRUE,   FALSE,
4668     EL_CHAR('-'),                       -1, -1
4669   },
4670   {
4671     Xalpha_perio,                       TRUE,   FALSE,
4672     EL_CHAR('.'),                       -1, -1
4673   },
4674   {
4675     Xalpha_colon,                       TRUE,   FALSE,
4676     EL_CHAR(':'),                       -1, -1
4677   },
4678   {
4679     Xalpha_quest,                       TRUE,   FALSE,
4680     EL_CHAR('?'),                       -1, -1
4681   },
4682   {
4683     Xalpha_a,                           TRUE,   FALSE,
4684     EL_CHAR('A'),                       -1, -1
4685   },
4686   {
4687     Xalpha_b,                           TRUE,   FALSE,
4688     EL_CHAR('B'),                       -1, -1
4689   },
4690   {
4691     Xalpha_c,                           TRUE,   FALSE,
4692     EL_CHAR('C'),                       -1, -1
4693   },
4694   {
4695     Xalpha_d,                           TRUE,   FALSE,
4696     EL_CHAR('D'),                       -1, -1
4697   },
4698   {
4699     Xalpha_e,                           TRUE,   FALSE,
4700     EL_CHAR('E'),                       -1, -1
4701   },
4702   {
4703     Xalpha_f,                           TRUE,   FALSE,
4704     EL_CHAR('F'),                       -1, -1
4705   },
4706   {
4707     Xalpha_g,                           TRUE,   FALSE,
4708     EL_CHAR('G'),                       -1, -1
4709   },
4710   {
4711     Xalpha_h,                           TRUE,   FALSE,
4712     EL_CHAR('H'),                       -1, -1
4713   },
4714   {
4715     Xalpha_i,                           TRUE,   FALSE,
4716     EL_CHAR('I'),                       -1, -1
4717   },
4718   {
4719     Xalpha_j,                           TRUE,   FALSE,
4720     EL_CHAR('J'),                       -1, -1
4721   },
4722   {
4723     Xalpha_k,                           TRUE,   FALSE,
4724     EL_CHAR('K'),                       -1, -1
4725   },
4726   {
4727     Xalpha_l,                           TRUE,   FALSE,
4728     EL_CHAR('L'),                       -1, -1
4729   },
4730   {
4731     Xalpha_m,                           TRUE,   FALSE,
4732     EL_CHAR('M'),                       -1, -1
4733   },
4734   {
4735     Xalpha_n,                           TRUE,   FALSE,
4736     EL_CHAR('N'),                       -1, -1
4737   },
4738   {
4739     Xalpha_o,                           TRUE,   FALSE,
4740     EL_CHAR('O'),                       -1, -1
4741   },
4742   {
4743     Xalpha_p,                           TRUE,   FALSE,
4744     EL_CHAR('P'),                       -1, -1
4745   },
4746   {
4747     Xalpha_q,                           TRUE,   FALSE,
4748     EL_CHAR('Q'),                       -1, -1
4749   },
4750   {
4751     Xalpha_r,                           TRUE,   FALSE,
4752     EL_CHAR('R'),                       -1, -1
4753   },
4754   {
4755     Xalpha_s,                           TRUE,   FALSE,
4756     EL_CHAR('S'),                       -1, -1
4757   },
4758   {
4759     Xalpha_t,                           TRUE,   FALSE,
4760     EL_CHAR('T'),                       -1, -1
4761   },
4762   {
4763     Xalpha_u,                           TRUE,   FALSE,
4764     EL_CHAR('U'),                       -1, -1
4765   },
4766   {
4767     Xalpha_v,                           TRUE,   FALSE,
4768     EL_CHAR('V'),                       -1, -1
4769   },
4770   {
4771     Xalpha_w,                           TRUE,   FALSE,
4772     EL_CHAR('W'),                       -1, -1
4773   },
4774   {
4775     Xalpha_x,                           TRUE,   FALSE,
4776     EL_CHAR('X'),                       -1, -1
4777   },
4778   {
4779     Xalpha_y,                           TRUE,   FALSE,
4780     EL_CHAR('Y'),                       -1, -1
4781   },
4782   {
4783     Xalpha_z,                           TRUE,   FALSE,
4784     EL_CHAR('Z'),                       -1, -1
4785   },
4786   {
4787     Xalpha_arrow_e,                     TRUE,   FALSE,
4788     EL_CHAR('>'),                       -1, -1
4789   },
4790   {
4791     Xalpha_arrow_w,                     TRUE,   FALSE,
4792     EL_CHAR('<'),                       -1, -1
4793   },
4794   {
4795     Xalpha_copyr,                       TRUE,   FALSE,
4796     EL_CHAR('©'),                       -1, -1
4797   },
4798
4799   {
4800     Xboom_bug,                          FALSE,  FALSE,
4801     EL_BUG,                             ACTION_EXPLODING, -1
4802   },
4803   {
4804     Xboom_bomb,                         FALSE,  FALSE,
4805     EL_BOMB,                            ACTION_EXPLODING, -1
4806   },
4807   {
4808     Xboom_android,                      FALSE,  FALSE,
4809     EL_EMC_ANDROID,                     ACTION_OTHER, -1
4810   },
4811   {
4812     Xboom_1,                            FALSE,  FALSE,
4813     EL_DEFAULT,                         ACTION_EXPLODING, -1
4814   },
4815   {
4816     Xboom_2,                            FALSE,  FALSE,
4817     EL_DEFAULT,                         ACTION_EXPLODING, -1
4818   },
4819   {
4820     Znormal,                            FALSE,  FALSE,
4821     EL_EMPTY,                           -1, -1
4822   },
4823   {
4824     Zdynamite,                          FALSE,  FALSE,
4825     EL_EMPTY,                           -1, -1
4826   },
4827   {
4828     Zplayer,                            FALSE,  FALSE,
4829     EL_EMPTY,                           -1, -1
4830   },
4831   {
4832     ZBORDER,                            FALSE,  FALSE,
4833     EL_EMPTY,                           -1, -1
4834   },
4835
4836   {
4837     -1,                                 FALSE,  FALSE,
4838     -1,                                 -1, -1
4839   }
4840 };
4841
4842 static struct Mapping_EM_to_RND_player
4843 {
4844   int action_em;
4845   int player_nr;
4846
4847   int element_rnd;
4848   int action;
4849   int direction;
4850 }
4851 em_player_mapping_list[] =
4852 {
4853   {
4854     SPR_walk + 0,                       0,
4855     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
4856   },
4857   {
4858     SPR_walk + 1,                       0,
4859     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
4860   },
4861   {
4862     SPR_walk + 2,                       0,
4863     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
4864   },
4865   {
4866     SPR_walk + 3,                       0,
4867     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
4868   },
4869   {
4870     SPR_push + 0,                       0,
4871     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
4872   },
4873   {
4874     SPR_push + 1,                       0,
4875     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
4876   },
4877   {
4878     SPR_push + 2,                       0,
4879     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
4880   },
4881   {
4882     SPR_push + 3,                       0,
4883     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
4884   },
4885   {
4886     SPR_spray + 0,                      0,
4887     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
4888   },
4889   {
4890     SPR_spray + 1,                      0,
4891     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
4892   },
4893   {
4894     SPR_spray + 2,                      0,
4895     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
4896   },
4897   {
4898     SPR_spray + 3,                      0,
4899     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
4900   },
4901   {
4902     SPR_walk + 0,                       1,
4903     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
4904   },
4905   {
4906     SPR_walk + 1,                       1,
4907     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
4908   },
4909   {
4910     SPR_walk + 2,                       1,
4911     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
4912   },
4913   {
4914     SPR_walk + 3,                       1,
4915     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
4916   },
4917   {
4918     SPR_push + 0,                       1,
4919     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
4920   },
4921   {
4922     SPR_push + 1,                       1,
4923     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
4924   },
4925   {
4926     SPR_push + 2,                       1,
4927     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
4928   },
4929   {
4930     SPR_push + 3,                       1,
4931     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
4932   },
4933   {
4934     SPR_spray + 0,                      1,
4935     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
4936   },
4937   {
4938     SPR_spray + 1,                      1,
4939     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
4940   },
4941   {
4942     SPR_spray + 2,                      1,
4943     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
4944   },
4945   {
4946     SPR_spray + 3,                      1,
4947     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
4948   },
4949   {
4950     SPR_still,                          0,
4951     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
4952   },
4953   {
4954     SPR_still,                          1,
4955     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
4956   },
4957   {
4958     SPR_walk + 0,                       2,
4959     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
4960   },
4961   {
4962     SPR_walk + 1,                       2,
4963     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
4964   },
4965   {
4966     SPR_walk + 2,                       2,
4967     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
4968   },
4969   {
4970     SPR_walk + 3,                       2,
4971     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
4972   },
4973   {
4974     SPR_push + 0,                       2,
4975     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
4976   },
4977   {
4978     SPR_push + 1,                       2,
4979     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
4980   },
4981   {
4982     SPR_push + 2,                       2,
4983     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
4984   },
4985   {
4986     SPR_push + 3,                       2,
4987     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
4988   },
4989   {
4990     SPR_spray + 0,                      2,
4991     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
4992   },
4993   {
4994     SPR_spray + 1,                      2,
4995     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
4996   },
4997   {
4998     SPR_spray + 2,                      2,
4999     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
5000   },
5001   {
5002     SPR_spray + 3,                      2,
5003     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
5004   },
5005   {
5006     SPR_walk + 0,                       3,
5007     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
5008   },
5009   {
5010     SPR_walk + 1,                       3,
5011     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
5012   },
5013   {
5014     SPR_walk + 2,                       3,
5015     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
5016   },
5017   {
5018     SPR_walk + 3,                       3,
5019     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
5020   },
5021   {
5022     SPR_push + 0,                       3,
5023     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
5024   },
5025   {
5026     SPR_push + 1,                       3,
5027     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
5028   },
5029   {
5030     SPR_push + 2,                       3,
5031     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
5032   },
5033   {
5034     SPR_push + 3,                       3,
5035     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
5036   },
5037   {
5038     SPR_spray + 0,                      3,
5039     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
5040   },
5041   {
5042     SPR_spray + 1,                      3,
5043     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5044   },
5045   {
5046     SPR_spray + 2,                      3,
5047     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
5048   },
5049   {
5050     SPR_spray + 3,                      3,
5051     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
5052   },
5053   {
5054     SPR_still,                          2,
5055     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
5056   },
5057   {
5058     SPR_still,                          3,
5059     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
5060   },
5061
5062   {
5063     -1,                                 -1,
5064     -1,                                 -1, -1
5065   }
5066 };
5067
5068 int map_element_RND_to_EM(int element_rnd)
5069 {
5070   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5071   static boolean mapping_initialized = FALSE;
5072
5073   if (!mapping_initialized)
5074   {
5075     int i;
5076
5077     /* return "Xalpha_quest" for all undefined elements in mapping array */
5078     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5079       mapping_RND_to_EM[i] = Xalpha_quest;
5080
5081     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5082       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5083         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5084           em_object_mapping_list[i].element_em;
5085
5086     mapping_initialized = TRUE;
5087   }
5088
5089   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5090     return mapping_RND_to_EM[element_rnd];
5091
5092   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5093
5094   return EL_UNKNOWN;
5095 }
5096
5097 int map_element_EM_to_RND(int element_em)
5098 {
5099   static unsigned short mapping_EM_to_RND[TILE_MAX];
5100   static boolean mapping_initialized = FALSE;
5101
5102   if (!mapping_initialized)
5103   {
5104     int i;
5105
5106     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5107     for (i = 0; i < TILE_MAX; i++)
5108       mapping_EM_to_RND[i] = EL_UNKNOWN;
5109
5110     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5111       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5112         em_object_mapping_list[i].element_rnd;
5113
5114     mapping_initialized = TRUE;
5115   }
5116
5117   if (element_em >= 0 && element_em < TILE_MAX)
5118     return mapping_EM_to_RND[element_em];
5119
5120   Error(ERR_WARN, "invalid EM level element %d", element_em);
5121
5122   return EL_UNKNOWN;
5123 }
5124
5125 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5126 {
5127   struct LevelInfo_EM *level_em = level->native_em_level;
5128   struct LEVEL *lev = level_em->lev;
5129   int i, j;
5130
5131   for (i = 0; i < TILE_MAX; i++)
5132     lev->android_array[i] = Xblank;
5133
5134   for (i = 0; i < level->num_android_clone_elements; i++)
5135   {
5136     int element_rnd = level->android_clone_element[i];
5137     int element_em = map_element_RND_to_EM(element_rnd);
5138
5139     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5140       if (em_object_mapping_list[j].element_rnd == element_rnd)
5141         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5142   }
5143 }
5144
5145 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5146 {
5147   struct LevelInfo_EM *level_em = level->native_em_level;
5148   struct LEVEL *lev = level_em->lev;
5149   int i, j;
5150
5151   level->num_android_clone_elements = 0;
5152
5153   for (i = 0; i < TILE_MAX; i++)
5154   {
5155     int element_em = lev->android_array[i];
5156     int element_rnd;
5157     boolean element_found = FALSE;
5158
5159     if (element_em == Xblank)
5160       continue;
5161
5162     element_rnd = map_element_EM_to_RND(element_em);
5163
5164     for (j = 0; j < level->num_android_clone_elements; j++)
5165       if (level->android_clone_element[j] == element_rnd)
5166         element_found = TRUE;
5167
5168     if (!element_found)
5169     {
5170       level->android_clone_element[level->num_android_clone_elements++] =
5171         element_rnd;
5172
5173       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5174         break;
5175     }
5176   }
5177
5178   if (level->num_android_clone_elements == 0)
5179   {
5180     level->num_android_clone_elements = 1;
5181     level->android_clone_element[0] = EL_EMPTY;
5182   }
5183 }
5184
5185 int map_direction_RND_to_EM(int direction)
5186 {
5187   return (direction == MV_UP    ? 0 :
5188           direction == MV_RIGHT ? 1 :
5189           direction == MV_DOWN  ? 2 :
5190           direction == MV_LEFT  ? 3 :
5191           -1);
5192 }
5193
5194 int map_direction_EM_to_RND(int direction)
5195 {
5196   return (direction == 0 ? MV_UP    :
5197           direction == 1 ? MV_RIGHT :
5198           direction == 2 ? MV_DOWN  :
5199           direction == 3 ? MV_LEFT  :
5200           MV_NONE);
5201 }
5202
5203 int get_next_element(int element)
5204 {
5205   switch(element)
5206   {
5207     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
5208     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
5209     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
5210     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
5211     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
5212     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
5213     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
5214
5215     default:                            return element;
5216   }
5217 }
5218
5219 #if 0
5220 int el_act_dir2img(int element, int action, int direction)
5221 {
5222   element = GFX_ELEMENT(element);
5223
5224   if (direction == MV_NONE)
5225     return element_info[element].graphic[action];
5226
5227   direction = MV_DIR_TO_BIT(direction);
5228
5229   return element_info[element].direction_graphic[action][direction];
5230 }
5231 #else
5232 int el_act_dir2img(int element, int action, int direction)
5233 {
5234   element = GFX_ELEMENT(element);
5235   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5236
5237   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5238   return element_info[element].direction_graphic[action][direction];
5239 }
5240 #endif
5241
5242 #if 0
5243 static int el_act_dir2crm(int element, int action, int direction)
5244 {
5245   element = GFX_ELEMENT(element);
5246
5247   if (direction == MV_NONE)
5248     return element_info[element].crumbled[action];
5249
5250   direction = MV_DIR_TO_BIT(direction);
5251
5252   return element_info[element].direction_crumbled[action][direction];
5253 }
5254 #else
5255 static int el_act_dir2crm(int element, int action, int direction)
5256 {
5257   element = GFX_ELEMENT(element);
5258   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5259
5260   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5261   return element_info[element].direction_crumbled[action][direction];
5262 }
5263 #endif
5264
5265 int el_act2img(int element, int action)
5266 {
5267   element = GFX_ELEMENT(element);
5268
5269   return element_info[element].graphic[action];
5270 }
5271
5272 int el_act2crm(int element, int action)
5273 {
5274   element = GFX_ELEMENT(element);
5275
5276   return element_info[element].crumbled[action];
5277 }
5278
5279 int el_dir2img(int element, int direction)
5280 {
5281   element = GFX_ELEMENT(element);
5282
5283   return el_act_dir2img(element, ACTION_DEFAULT, direction);
5284 }
5285
5286 int el2baseimg(int element)
5287 {
5288   return element_info[element].graphic[ACTION_DEFAULT];
5289 }
5290
5291 int el2img(int element)
5292 {
5293   element = GFX_ELEMENT(element);
5294
5295   return element_info[element].graphic[ACTION_DEFAULT];
5296 }
5297
5298 int el2edimg(int element)
5299 {
5300   element = GFX_ELEMENT(element);
5301
5302   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5303 }
5304
5305 int el2preimg(int element)
5306 {
5307   element = GFX_ELEMENT(element);
5308
5309   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5310 }
5311
5312 int font2baseimg(int font_nr)
5313 {
5314   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5315 }
5316
5317 #if 0
5318 void setCenteredPlayerNr_EM(int centered_player_nr)
5319 {
5320   game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5321 }
5322
5323 int getCenteredPlayerNr_EM()
5324 {
5325 #if 0
5326   if (game.centered_player_nr_next >= 0 &&
5327       !native_em_level.ply[game.centered_player_nr_next]->alive)
5328     game.centered_player_nr_next = game.centered_player_nr;
5329 #endif
5330
5331   if (game.centered_player_nr != game.centered_player_nr_next)
5332     game.centered_player_nr = game.centered_player_nr_next;
5333
5334   return game.centered_player_nr;
5335 }
5336
5337 void setSetCenteredPlayer_EM(boolean set_centered_player)
5338 {
5339   game.set_centered_player = set_centered_player;
5340 }
5341
5342 boolean getSetCenteredPlayer_EM()
5343 {
5344   return game.set_centered_player;
5345 }
5346 #endif
5347
5348 int getNumActivePlayers_EM()
5349 {
5350   int num_players = 0;
5351   int i;
5352
5353   if (!tape.playing)
5354     return -1;
5355
5356   for (i = 0; i < MAX_PLAYERS; i++)
5357     if (tape.player_participates[i])
5358       num_players++;
5359
5360   return num_players;
5361 }
5362
5363 #if 1
5364 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5365 {
5366   int game_frame_delay_value;
5367
5368   game_frame_delay_value =
5369     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5370      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5371      GameFrameDelay);
5372
5373   if (tape.playing && tape.warp_forward && !tape.pausing)
5374     game_frame_delay_value = 0;
5375
5376   return game_frame_delay_value;
5377 }
5378 #endif
5379
5380 unsigned int InitRND(long seed)
5381 {
5382   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5383     return InitEngineRND_EM(seed);
5384   else
5385     return InitEngineRND(seed);
5386 }
5387
5388 void InitGraphicInfo_EM(void)
5389 {
5390   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5391   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5392   int i, j, p;
5393
5394 #if DEBUG_EM_GFX
5395   int num_em_gfx_errors = 0;
5396
5397   if (graphic_info_em_object[0][0].bitmap == NULL)
5398   {
5399     /* EM graphics not yet initialized in em_open_all() */
5400
5401     return;
5402   }
5403
5404   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5405 #endif
5406
5407   /* always start with reliable default values */
5408   for (i = 0; i < TILE_MAX; i++)
5409   {
5410     object_mapping[i].element_rnd = EL_UNKNOWN;
5411     object_mapping[i].is_backside = FALSE;
5412     object_mapping[i].action = ACTION_DEFAULT;
5413     object_mapping[i].direction = MV_NONE;
5414   }
5415
5416   /* always start with reliable default values */
5417   for (p = 0; p < MAX_PLAYERS; p++)
5418   {
5419     for (i = 0; i < SPR_MAX; i++)
5420     {
5421       player_mapping[p][i].element_rnd = EL_UNKNOWN;
5422       player_mapping[p][i].action = ACTION_DEFAULT;
5423       player_mapping[p][i].direction = MV_NONE;
5424     }
5425   }
5426
5427   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5428   {
5429     int e = em_object_mapping_list[i].element_em;
5430
5431     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5432     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5433
5434     if (em_object_mapping_list[i].action != -1)
5435       object_mapping[e].action = em_object_mapping_list[i].action;
5436
5437     if (em_object_mapping_list[i].direction != -1)
5438       object_mapping[e].direction =
5439         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5440   }
5441
5442   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5443   {
5444     int a = em_player_mapping_list[i].action_em;
5445     int p = em_player_mapping_list[i].player_nr;
5446
5447     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5448
5449     if (em_player_mapping_list[i].action != -1)
5450       player_mapping[p][a].action = em_player_mapping_list[i].action;
5451
5452     if (em_player_mapping_list[i].direction != -1)
5453       player_mapping[p][a].direction =
5454         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5455   }
5456
5457   for (i = 0; i < TILE_MAX; i++)
5458   {
5459     int element = object_mapping[i].element_rnd;
5460     int action = object_mapping[i].action;
5461     int direction = object_mapping[i].direction;
5462     boolean is_backside = object_mapping[i].is_backside;
5463     boolean action_removing = (action == ACTION_DIGGING ||
5464                                action == ACTION_SNAPPING ||
5465                                action == ACTION_COLLECTING);
5466     boolean action_exploding = ((action == ACTION_EXPLODING ||
5467                                  action == ACTION_SMASHED_BY_ROCK ||
5468                                  action == ACTION_SMASHED_BY_SPRING) &&
5469                                 element != EL_DIAMOND);
5470     boolean action_active = (action == ACTION_ACTIVE);
5471     boolean action_other = (action == ACTION_OTHER);
5472
5473     for (j = 0; j < 8; j++)
5474     {
5475       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5476                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5477                                j < 7 ? element :
5478                                i == Xdrip_stretch ? element :
5479                                i == Xdrip_stretchB ? element :
5480                                i == Ydrip_s1 ? element :
5481                                i == Ydrip_s1B ? element :
5482                                i == Xball_1B ? element :
5483                                i == Xball_2 ? element :
5484                                i == Xball_2B ? element :
5485                                i == Yball_eat ? element :
5486                                i == Ykey_1_eat ? element :
5487                                i == Ykey_2_eat ? element :
5488                                i == Ykey_3_eat ? element :
5489                                i == Ykey_4_eat ? element :
5490                                i == Ykey_5_eat ? element :
5491                                i == Ykey_6_eat ? element :
5492                                i == Ykey_7_eat ? element :
5493                                i == Ykey_8_eat ? element :
5494                                i == Ylenses_eat ? element :
5495                                i == Ymagnify_eat ? element :
5496                                i == Ygrass_eat ? element :
5497                                i == Ydirt_eat ? element :
5498                                i == Yemerald_stone ? EL_EMERALD :
5499                                i == Ydiamond_stone ? EL_ROCK :
5500                                i == Xsand_stonein_1 ? element :
5501                                i == Xsand_stonein_2 ? element :
5502                                i == Xsand_stonein_3 ? element :
5503                                i == Xsand_stonein_4 ? element :
5504                                is_backside ? EL_EMPTY :
5505                                action_removing ? EL_EMPTY :
5506                                element);
5507       int effective_action = (j < 7 ? action :
5508                               i == Xdrip_stretch ? action :
5509                               i == Xdrip_stretchB ? action :
5510                               i == Ydrip_s1 ? action :
5511                               i == Ydrip_s1B ? action :
5512                               i == Xball_1B ? action :
5513                               i == Xball_2 ? action :
5514                               i == Xball_2B ? action :
5515                               i == Yball_eat ? action :
5516                               i == Ykey_1_eat ? action :
5517                               i == Ykey_2_eat ? action :
5518                               i == Ykey_3_eat ? action :
5519                               i == Ykey_4_eat ? action :
5520                               i == Ykey_5_eat ? action :
5521                               i == Ykey_6_eat ? action :
5522                               i == Ykey_7_eat ? action :
5523                               i == Ykey_8_eat ? action :
5524                               i == Ylenses_eat ? action :
5525                               i == Ymagnify_eat ? action :
5526                               i == Ygrass_eat ? action :
5527                               i == Ydirt_eat ? action :
5528                               i == Xsand_stonein_1 ? action :
5529                               i == Xsand_stonein_2 ? action :
5530                               i == Xsand_stonein_3 ? action :
5531                               i == Xsand_stonein_4 ? action :
5532                               i == Xsand_stoneout_1 ? action :
5533                               i == Xsand_stoneout_2 ? action :
5534                               i == Xboom_android ? ACTION_EXPLODING :
5535                               action_exploding ? ACTION_EXPLODING :
5536                               action_active ? action :
5537                               action_other ? action :
5538                               ACTION_DEFAULT);
5539       int graphic = (el_act_dir2img(effective_element, effective_action,
5540                                     direction));
5541       int crumbled = (el_act_dir2crm(effective_element, effective_action,
5542                                      direction));
5543       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5544       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5545       boolean has_action_graphics = (graphic != base_graphic);
5546       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5547       struct GraphicInfo *g = &graphic_info[graphic];
5548       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5549       Bitmap *src_bitmap;
5550       int src_x, src_y;
5551       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5552       boolean special_animation = (action != ACTION_DEFAULT &&
5553                                    g->anim_frames == 3 &&
5554                                    g->anim_delay == 2 &&
5555                                    g->anim_mode & ANIM_LINEAR);
5556       int sync_frame = (i == Xdrip_stretch ? 7 :
5557                         i == Xdrip_stretchB ? 7 :
5558                         i == Ydrip_s2 ? j + 8 :
5559                         i == Ydrip_s2B ? j + 8 :
5560                         i == Xacid_1 ? 0 :
5561                         i == Xacid_2 ? 10 :
5562                         i == Xacid_3 ? 20 :
5563                         i == Xacid_4 ? 30 :
5564                         i == Xacid_5 ? 40 :
5565                         i == Xacid_6 ? 50 :
5566                         i == Xacid_7 ? 60 :
5567                         i == Xacid_8 ? 70 :
5568                         i == Xfake_acid_1 ? 0 :
5569                         i == Xfake_acid_2 ? 10 :
5570                         i == Xfake_acid_3 ? 20 :
5571                         i == Xfake_acid_4 ? 30 :
5572                         i == Xfake_acid_5 ? 40 :
5573                         i == Xfake_acid_6 ? 50 :
5574                         i == Xfake_acid_7 ? 60 :
5575                         i == Xfake_acid_8 ? 70 :
5576                         i == Xball_2 ? 7 :
5577                         i == Xball_2B ? j + 8 :
5578                         i == Yball_eat ? j + 1 :
5579                         i == Ykey_1_eat ? j + 1 :
5580                         i == Ykey_2_eat ? j + 1 :
5581                         i == Ykey_3_eat ? j + 1 :
5582                         i == Ykey_4_eat ? j + 1 :
5583                         i == Ykey_5_eat ? j + 1 :
5584                         i == Ykey_6_eat ? j + 1 :
5585                         i == Ykey_7_eat ? j + 1 :
5586                         i == Ykey_8_eat ? j + 1 :
5587                         i == Ylenses_eat ? j + 1 :
5588                         i == Ymagnify_eat ? j + 1 :
5589                         i == Ygrass_eat ? j + 1 :
5590                         i == Ydirt_eat ? j + 1 :
5591                         i == Xamoeba_1 ? 0 :
5592                         i == Xamoeba_2 ? 1 :
5593                         i == Xamoeba_3 ? 2 :
5594                         i == Xamoeba_4 ? 3 :
5595                         i == Xamoeba_5 ? 0 :
5596                         i == Xamoeba_6 ? 1 :
5597                         i == Xamoeba_7 ? 2 :
5598                         i == Xamoeba_8 ? 3 :
5599                         i == Xexit_2 ? j + 8 :
5600                         i == Xexit_3 ? j + 16 :
5601                         i == Xdynamite_1 ? 0 :
5602                         i == Xdynamite_2 ? 8 :
5603                         i == Xdynamite_3 ? 16 :
5604                         i == Xdynamite_4 ? 24 :
5605                         i == Xsand_stonein_1 ? j + 1 :
5606                         i == Xsand_stonein_2 ? j + 9 :
5607                         i == Xsand_stonein_3 ? j + 17 :
5608                         i == Xsand_stonein_4 ? j + 25 :
5609                         i == Xsand_stoneout_1 && j == 0 ? 0 :
5610                         i == Xsand_stoneout_1 && j == 1 ? 0 :
5611                         i == Xsand_stoneout_1 && j == 2 ? 1 :
5612                         i == Xsand_stoneout_1 && j == 3 ? 2 :
5613                         i == Xsand_stoneout_1 && j == 4 ? 2 :
5614                         i == Xsand_stoneout_1 && j == 5 ? 3 :
5615                         i == Xsand_stoneout_1 && j == 6 ? 4 :
5616                         i == Xsand_stoneout_1 && j == 7 ? 4 :
5617                         i == Xsand_stoneout_2 && j == 0 ? 5 :
5618                         i == Xsand_stoneout_2 && j == 1 ? 6 :
5619                         i == Xsand_stoneout_2 && j == 2 ? 7 :
5620                         i == Xsand_stoneout_2 && j == 3 ? 8 :
5621                         i == Xsand_stoneout_2 && j == 4 ? 9 :
5622                         i == Xsand_stoneout_2 && j == 5 ? 11 :
5623                         i == Xsand_stoneout_2 && j == 6 ? 13 :
5624                         i == Xsand_stoneout_2 && j == 7 ? 15 :
5625                         i == Xboom_bug && j == 1 ? 2 :
5626                         i == Xboom_bug && j == 2 ? 2 :
5627                         i == Xboom_bug && j == 3 ? 4 :
5628                         i == Xboom_bug && j == 4 ? 4 :
5629                         i == Xboom_bug && j == 5 ? 2 :
5630                         i == Xboom_bug && j == 6 ? 2 :
5631                         i == Xboom_bug && j == 7 ? 0 :
5632                         i == Xboom_bomb && j == 1 ? 2 :
5633                         i == Xboom_bomb && j == 2 ? 2 :
5634                         i == Xboom_bomb && j == 3 ? 4 :
5635                         i == Xboom_bomb && j == 4 ? 4 :
5636                         i == Xboom_bomb && j == 5 ? 2 :
5637                         i == Xboom_bomb && j == 6 ? 2 :
5638                         i == Xboom_bomb && j == 7 ? 0 :
5639                         i == Xboom_android && j == 7 ? 6 :
5640                         i == Xboom_1 && j == 1 ? 2 :
5641                         i == Xboom_1 && j == 2 ? 2 :
5642                         i == Xboom_1 && j == 3 ? 4 :
5643                         i == Xboom_1 && j == 4 ? 4 :
5644                         i == Xboom_1 && j == 5 ? 6 :
5645                         i == Xboom_1 && j == 6 ? 6 :
5646                         i == Xboom_1 && j == 7 ? 8 :
5647                         i == Xboom_2 && j == 0 ? 8 :
5648                         i == Xboom_2 && j == 1 ? 8 :
5649                         i == Xboom_2 && j == 2 ? 10 :
5650                         i == Xboom_2 && j == 3 ? 10 :
5651                         i == Xboom_2 && j == 4 ? 10 :
5652                         i == Xboom_2 && j == 5 ? 12 :
5653                         i == Xboom_2 && j == 6 ? 12 :
5654                         i == Xboom_2 && j == 7 ? 12 :
5655                         special_animation && j == 4 ? 3 :
5656                         effective_action != action ? 0 :
5657                         j);
5658
5659 #if DEBUG_EM_GFX
5660       Bitmap *debug_bitmap = g_em->bitmap;
5661       int debug_src_x = g_em->src_x;
5662       int debug_src_y = g_em->src_y;
5663 #endif
5664
5665       int frame = getAnimationFrame(g->anim_frames,
5666                                     g->anim_delay,
5667                                     g->anim_mode,
5668                                     g->anim_start_frame,
5669                                     sync_frame);
5670
5671       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5672                           g->double_movement && is_backside);
5673
5674       g_em->bitmap = src_bitmap;
5675       g_em->src_x = src_x;
5676       g_em->src_y = src_y;
5677       g_em->src_offset_x = 0;
5678       g_em->src_offset_y = 0;
5679       g_em->dst_offset_x = 0;
5680       g_em->dst_offset_y = 0;
5681       g_em->width  = TILEX;
5682       g_em->height = TILEY;
5683
5684       g_em->crumbled_bitmap = NULL;
5685       g_em->crumbled_src_x = 0;
5686       g_em->crumbled_src_y = 0;
5687       g_em->crumbled_border_size = 0;
5688
5689       g_em->has_crumbled_graphics = FALSE;
5690       g_em->preserve_background = FALSE;
5691
5692 #if 0
5693       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5694         printf("::: empty crumbled: %d [%s], %d, %d\n",
5695                effective_element, element_info[effective_element].token_name,
5696                effective_action, direction);
5697 #endif
5698
5699       /* if element can be crumbled, but certain action graphics are just empty
5700          space (like snapping sand with the original R'n'D graphics), do not
5701          treat these empty space graphics as crumbled graphics in EMC engine */
5702       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5703       {
5704         getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5705
5706         g_em->has_crumbled_graphics = TRUE;
5707         g_em->crumbled_bitmap = src_bitmap;
5708         g_em->crumbled_src_x = src_x;
5709         g_em->crumbled_src_y = src_y;
5710         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5711       }
5712
5713 #if 0
5714       if (element == EL_ROCK &&
5715           effective_action == ACTION_FILLING)
5716         printf("::: has_action_graphics == %d\n", has_action_graphics);
5717 #endif
5718
5719       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5720                                    effective_action == ACTION_MOVING  ||
5721                                    effective_action == ACTION_PUSHING ||
5722                                    effective_action == ACTION_EATING)) ||
5723           (!has_action_graphics && (effective_action == ACTION_FILLING ||
5724                                     effective_action == ACTION_EMPTYING)))
5725       {
5726         int move_dir =
5727           (effective_action == ACTION_FALLING ||
5728            effective_action == ACTION_FILLING ||
5729            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5730         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5731         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
5732         int num_steps = (i == Ydrip_s1  ? 16 :
5733                          i == Ydrip_s1B ? 16 :
5734                          i == Ydrip_s2  ? 16 :
5735                          i == Ydrip_s2B ? 16 :
5736                          i == Xsand_stonein_1 ? 32 :
5737                          i == Xsand_stonein_2 ? 32 :
5738                          i == Xsand_stonein_3 ? 32 :
5739                          i == Xsand_stonein_4 ? 32 :
5740                          i == Xsand_stoneout_1 ? 16 :
5741                          i == Xsand_stoneout_2 ? 16 : 8);
5742         int cx = ABS(dx) * (TILEX / num_steps);
5743         int cy = ABS(dy) * (TILEY / num_steps);
5744         int step_frame = (i == Ydrip_s2         ? j + 8 :
5745                           i == Ydrip_s2B        ? j + 8 :
5746                           i == Xsand_stonein_2  ? j + 8 :
5747                           i == Xsand_stonein_3  ? j + 16 :
5748                           i == Xsand_stonein_4  ? j + 24 :
5749                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5750         int step = (is_backside ? step_frame : num_steps - step_frame);
5751
5752         if (is_backside)        /* tile where movement starts */
5753         {
5754           if (dx < 0 || dy < 0)
5755           {
5756             g_em->src_offset_x = cx * step;
5757             g_em->src_offset_y = cy * step;
5758           }
5759           else
5760           {
5761             g_em->dst_offset_x = cx * step;
5762             g_em->dst_offset_y = cy * step;
5763           }
5764         }
5765         else                    /* tile where movement ends */
5766         {
5767           if (dx < 0 || dy < 0)
5768           {
5769             g_em->dst_offset_x = cx * step;
5770             g_em->dst_offset_y = cy * step;
5771           }
5772           else
5773           {
5774             g_em->src_offset_x = cx * step;
5775             g_em->src_offset_y = cy * step;
5776           }
5777         }
5778
5779         g_em->width  = TILEX - cx * step;
5780         g_em->height = TILEY - cy * step;
5781       }
5782
5783 #if 1
5784       /* create unique graphic identifier to decide if tile must be redrawn */
5785       /* bit 31 - 16 (16 bit): EM style graphic
5786          bit 15 - 12 ( 4 bit): EM style frame
5787          bit 11 -  6 ( 6 bit): graphic width
5788          bit  5 -  0 ( 6 bit): graphic height */
5789       g_em->unique_identifier =
5790         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5791 #else
5792       /* create unique graphic identifier to decide if tile must be redrawn */
5793       /* bit 31 - 16 (16 bit): EM style element
5794          bit 15 - 12 ( 4 bit): EM style frame
5795          bit 11 -  6 ( 6 bit): graphic width
5796          bit  5 -  0 ( 6 bit): graphic height */
5797       g_em->unique_identifier =
5798         (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5799 #endif
5800
5801 #if 0
5802       if (effective_element == EL_ROCK)
5803         printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5804                effective_action, j, graphic, frame, g_em->unique_identifier);
5805 #endif
5806
5807 #if DEBUG_EM_GFX
5808
5809 #if 1
5810       /* skip check for EMC elements not contained in original EMC artwork */
5811       if (element == EL_EMC_FAKE_ACID)
5812         continue;
5813 #endif
5814
5815       if (g_em->bitmap != debug_bitmap ||
5816           g_em->src_x != debug_src_x ||
5817           g_em->src_y != debug_src_y ||
5818           g_em->src_offset_x != 0 ||
5819           g_em->src_offset_y != 0 ||
5820           g_em->dst_offset_x != 0 ||
5821           g_em->dst_offset_y != 0 ||
5822           g_em->width != TILEX ||
5823           g_em->height != TILEY)
5824       {
5825         static int last_i = -1;
5826
5827         if (i != last_i)
5828         {
5829           printf("\n");
5830           last_i = i;
5831         }
5832
5833         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5834                i, element, element_info[element].token_name,
5835                element_action_info[effective_action].suffix, direction);
5836
5837         if (element != effective_element)
5838           printf(" [%d ('%s')]",
5839                  effective_element,
5840                  element_info[effective_element].token_name);
5841
5842         printf("\n");
5843
5844         if (g_em->bitmap != debug_bitmap)
5845           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5846                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5847
5848         if (g_em->src_x != debug_src_x ||
5849             g_em->src_y != debug_src_y)
5850           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5851                  j, (is_backside ? 'B' : 'F'),
5852                  g_em->src_x, g_em->src_y,
5853                  g_em->src_x / 32, g_em->src_y / 32,
5854                  debug_src_x, debug_src_y,
5855                  debug_src_x / 32, debug_src_y / 32);
5856
5857         if (g_em->src_offset_x != 0 ||
5858             g_em->src_offset_y != 0 ||
5859             g_em->dst_offset_x != 0 ||
5860             g_em->dst_offset_y != 0)
5861           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5862                  j, is_backside,
5863                  g_em->src_offset_x, g_em->src_offset_y,
5864                  g_em->dst_offset_x, g_em->dst_offset_y);
5865
5866         if (g_em->width != TILEX ||
5867             g_em->height != TILEY)
5868           printf("    %d (%d): size %d,%d should be %d,%d\n",
5869                  j, is_backside,
5870                  g_em->width, g_em->height, TILEX, TILEY);
5871
5872         num_em_gfx_errors++;
5873       }
5874 #endif
5875
5876     }
5877   }
5878
5879   for (i = 0; i < TILE_MAX; i++)
5880   {
5881     for (j = 0; j < 8; j++)
5882     {
5883       int element = object_mapping[i].element_rnd;
5884       int action = object_mapping[i].action;
5885       int direction = object_mapping[i].direction;
5886       boolean is_backside = object_mapping[i].is_backside;
5887 #if 1
5888       int graphic_action  = el_act_dir2img(element, action, direction);
5889       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5890 #else
5891       int graphic_action  = element_info[element].graphic[action];
5892       int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5893 #endif
5894
5895       if ((action == ACTION_SMASHED_BY_ROCK ||
5896            action == ACTION_SMASHED_BY_SPRING ||
5897            action == ACTION_EATING) &&
5898           graphic_action == graphic_default)
5899       {
5900         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
5901                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5902                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
5903                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5904                  Xspring);
5905
5906         /* no separate animation for "smashed by rock" -- use rock instead */
5907         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5908         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5909
5910         g_em->bitmap            = g_xx->bitmap;
5911         g_em->src_x             = g_xx->src_x;
5912         g_em->src_y             = g_xx->src_y;
5913         g_em->src_offset_x      = g_xx->src_offset_x;
5914         g_em->src_offset_y      = g_xx->src_offset_y;
5915         g_em->dst_offset_x      = g_xx->dst_offset_x;
5916         g_em->dst_offset_y      = g_xx->dst_offset_y;
5917         g_em->width             = g_xx->width;
5918         g_em->height            = g_xx->height;
5919 #if 1
5920         g_em->unique_identifier = g_xx->unique_identifier;
5921 #endif
5922
5923         if (!is_backside)
5924           g_em->preserve_background = TRUE;
5925       }
5926     }
5927   }
5928
5929   for (p = 0; p < MAX_PLAYERS; p++)
5930   {
5931     for (i = 0; i < SPR_MAX; i++)
5932     {
5933       int element = player_mapping[p][i].element_rnd;
5934       int action = player_mapping[p][i].action;
5935       int direction = player_mapping[p][i].direction;
5936
5937       for (j = 0; j < 8; j++)
5938       {
5939         int effective_element = element;
5940         int effective_action = action;
5941         int graphic = (direction == MV_NONE ?
5942                        el_act2img(effective_element, effective_action) :
5943                        el_act_dir2img(effective_element, effective_action,
5944                                       direction));
5945         struct GraphicInfo *g = &graphic_info[graphic];
5946         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5947         Bitmap *src_bitmap;
5948         int src_x, src_y;
5949         int sync_frame = j;
5950
5951 #if DEBUG_EM_GFX
5952         Bitmap *debug_bitmap = g_em->bitmap;
5953         int debug_src_x = g_em->src_x;
5954         int debug_src_y = g_em->src_y;
5955 #endif
5956
5957         int frame = getAnimationFrame(g->anim_frames,
5958                                       g->anim_delay,
5959                                       g->anim_mode,
5960                                       g->anim_start_frame,
5961                                       sync_frame);
5962
5963         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5964
5965         g_em->bitmap = src_bitmap;
5966         g_em->src_x = src_x;
5967         g_em->src_y = src_y;
5968         g_em->src_offset_x = 0;
5969         g_em->src_offset_y = 0;
5970         g_em->dst_offset_x = 0;
5971         g_em->dst_offset_y = 0;
5972         g_em->width  = TILEX;
5973         g_em->height = TILEY;
5974
5975 #if DEBUG_EM_GFX
5976
5977 #if 1
5978         /* skip check for EMC elements not contained in original EMC artwork */
5979         if (element == EL_PLAYER_3 ||
5980             element == EL_PLAYER_4)
5981           continue;
5982 #endif
5983
5984         if (g_em->bitmap != debug_bitmap ||
5985             g_em->src_x != debug_src_x ||
5986             g_em->src_y != debug_src_y)
5987         {
5988           static int last_i = -1;
5989
5990           if (i != last_i)
5991           {
5992             printf("\n");
5993             last_i = i;
5994           }
5995
5996           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5997                  p, i, element, element_info[element].token_name,
5998                  element_action_info[effective_action].suffix, direction);
5999
6000           if (element != effective_element)
6001             printf(" [%d ('%s')]",
6002                    effective_element,
6003                    element_info[effective_element].token_name);
6004
6005           printf("\n");
6006
6007           if (g_em->bitmap != debug_bitmap)
6008             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
6009                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
6010
6011           if (g_em->src_x != debug_src_x ||
6012               g_em->src_y != debug_src_y)
6013             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6014                    j,
6015                    g_em->src_x, g_em->src_y,
6016                    g_em->src_x / 32, g_em->src_y / 32,
6017                    debug_src_x, debug_src_y,
6018                    debug_src_x / 32, debug_src_y / 32);
6019
6020           num_em_gfx_errors++;
6021         }
6022 #endif
6023
6024       }
6025     }
6026   }
6027
6028 #if DEBUG_EM_GFX
6029   printf("\n");
6030   printf("::: [%d errors found]\n", num_em_gfx_errors);
6031
6032   exit(0);
6033 #endif
6034 }
6035
6036 void PlayMenuSound()
6037 {
6038   int sound = menu.sound[game_status];
6039
6040   if (sound == SND_UNDEFINED)
6041     return;
6042
6043   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6044       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6045     return;
6046
6047   if (IS_LOOP_SOUND(sound))
6048     PlaySoundLoop(sound);
6049   else
6050     PlaySound(sound);
6051 }
6052
6053 void PlayMenuSoundStereo(int sound, int stereo_position)
6054 {
6055   if (sound == SND_UNDEFINED)
6056     return;
6057
6058   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6059       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6060     return;
6061
6062   if (IS_LOOP_SOUND(sound))
6063     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6064   else
6065     PlaySoundStereo(sound, stereo_position);
6066 }
6067
6068 void PlayMenuSoundIfLoop()
6069 {
6070   int sound = menu.sound[game_status];
6071
6072   if (sound == SND_UNDEFINED)
6073     return;
6074
6075   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6076       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6077     return;
6078
6079   if (IS_LOOP_SOUND(sound))
6080     PlaySoundLoop(sound);
6081 }
6082
6083 void PlayMenuMusic()
6084 {
6085   int music = menu.music[game_status];
6086
6087   if (music == MUS_UNDEFINED)
6088     return;
6089
6090   PlayMusic(music);
6091 }
6092
6093 void ToggleFullscreenIfNeeded()
6094 {
6095   if (setup.fullscreen != video.fullscreen_enabled ||
6096       setup.fullscreen_mode != video.fullscreen_mode_current)
6097   {
6098     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6099
6100     /* save backbuffer content which gets lost when toggling fullscreen mode */
6101     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6102
6103     if (setup.fullscreen && video.fullscreen_enabled)
6104     {
6105       /* keep fullscreen mode, but change screen mode */
6106       video.fullscreen_mode_current = setup.fullscreen_mode;
6107       video.fullscreen_enabled = FALSE;
6108     }
6109
6110     /* toggle fullscreen */
6111     ChangeVideoModeIfNeeded(setup.fullscreen);
6112     setup.fullscreen = video.fullscreen_enabled;
6113
6114     /* restore backbuffer content from temporary backbuffer backup bitmap */
6115     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6116
6117     FreeBitmap(tmp_backbuffer);
6118
6119     redraw_mask = REDRAW_ALL;
6120   }
6121 }