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