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