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