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