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