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