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