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