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