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