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