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