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