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