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