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