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