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