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