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