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