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