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