rnd-20060812-2-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "tools.h"
17 #include "game.h"
18 #include "events.h"
19 #include "cartoons.h"
20 #include "network.h"
21 #include "tape.h"
22
23
24 /* select level set with EMC X11 graphics before activating EM GFX debugging */
25 #define DEBUG_EM_GFX    0
26
27 /* tool button identifiers */
28 #define TOOL_CTRL_ID_YES        0
29 #define TOOL_CTRL_ID_NO         1
30 #define TOOL_CTRL_ID_CONFIRM    2
31 #define TOOL_CTRL_ID_PLAYER_1   3
32 #define TOOL_CTRL_ID_PLAYER_2   4
33 #define TOOL_CTRL_ID_PLAYER_3   5
34 #define TOOL_CTRL_ID_PLAYER_4   6
35
36 #define NUM_TOOL_BUTTONS        7
37
38 /* forward declaration for internal use */
39 static void UnmapToolButtons();
40 static void HandleToolButtons(struct GadgetInfo *);
41 static int el_act_dir2crm(int, int, int);
42 static int el_act2crm(int, int);
43
44 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
45 static int request_gadget_id = -1;
46
47 static char *print_if_not_empty(int element)
48 {
49   static char *s = NULL;
50   char *token_name = element_info[element].token_name;
51
52   if (s != NULL)
53     free(s);
54
55   s = checked_malloc(strlen(token_name) + 10 + 1);
56
57   if (element != EL_EMPTY)
58     sprintf(s, "%d\t['%s']", element, token_name);
59   else
60     sprintf(s, "%d", element);
61
62   return s;
63 }
64
65 void DumpTile(int x, int y)
66 {
67   int sx = SCREENX(x);
68   int sy = SCREENY(y);
69
70   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
71   {
72     x--;
73     y--;
74   }
75
76   printf_line("-", 79);
77   printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
78   printf_line("-", 79);
79
80   if (!IN_LEV_FIELD(x, y))
81   {
82     printf("(not in level field)\n");
83     printf("\n");
84
85     return;
86   }
87
88   printf("  Feld:        %d\t['%s']\n", Feld[x][y],
89          element_info[Feld[x][y]].token_name);
90   printf("  Back:        %s\n", print_if_not_empty(Back[x][y]));
91   printf("  Store:       %s\n", print_if_not_empty(Store[x][y]));
92   printf("  Store2:      %s\n", print_if_not_empty(Store2[x][y]));
93   printf("  StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
94   printf("  MovPos:      %d\n", MovPos[x][y]);
95   printf("  MovDir:      %d\n", MovDir[x][y]);
96   printf("  MovDelay:    %d\n", MovDelay[x][y]);
97   printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
98   printf("  CustomValue: %d\n", CustomValue[x][y]);
99   printf("  GfxElement:  %d\n", GfxElement[x][y]);
100   printf("  GfxAction:   %d\n", GfxAction[x][y]);
101   printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
102   printf("\n");
103 }
104
105 void SetDrawtoField(int mode)
106 {
107   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
108   {
109     FX = TILEX;
110     FY = TILEY;
111     BX1 = -1;
112     BY1 = -1;
113     BX2 = SCR_FIELDX;
114     BY2 = SCR_FIELDY;
115     redraw_x1 = 1;
116     redraw_y1 = 1;
117
118     drawto_field = fieldbuffer;
119   }
120   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
121   {
122     FX = SX;
123     FY = SY;
124     BX1 = 0;
125     BY1 = 0;
126     BX2 = SCR_FIELDX - 1;
127     BY2 = SCR_FIELDY - 1;
128     redraw_x1 = 0;
129     redraw_y1 = 0;
130
131     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
132   }
133 }
134
135 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
136 {
137   if (game_status == GAME_MODE_PLAYING &&
138       level.game_engine_type == GAME_ENGINE_TYPE_EM)
139   {
140     /* currently there is no partial redraw -- always redraw whole playfield */
141
142     RedrawPlayfield_EM(TRUE);
143   }
144   else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
145   {
146     if (force_redraw)
147     {
148       x = gfx.sx - TILEX;
149       y = gfx.sy - TILEY;
150       width = gfx.sxsize + 2 * TILEX;
151       height = gfx.sysize + 2 * TILEY;
152     }
153
154     if (force_redraw || setup.direct_draw)
155     {
156       int xx, yy;
157       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
158       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
159
160       if (setup.direct_draw)
161         SetDrawtoField(DRAW_BACKBUFFER);
162
163       for (xx = BX1; xx <= BX2; xx++)
164         for (yy = BY1; yy <= BY2; yy++)
165           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
166             DrawScreenField(xx, yy);
167       DrawAllPlayers();
168
169       if (setup.direct_draw)
170         SetDrawtoField(DRAW_DIRECT);
171     }
172
173     if (setup.soft_scrolling)
174     {
175       int fx = FX, fy = FY;
176
177       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
178       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
179
180       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
181     }
182   }
183
184   BlitBitmap(drawto, window, x, y, width, height, x, y);
185 }
186
187 void BackToFront()
188 {
189   int x,y;
190   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
191
192   if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
193     redraw_mask &= ~REDRAW_MAIN;
194
195   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
196     redraw_mask |= REDRAW_FIELD;
197
198   if (redraw_mask & REDRAW_FIELD)
199     redraw_mask &= ~REDRAW_TILES;
200
201   if (redraw_mask == REDRAW_NONE)
202     return;
203
204   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
205   {
206     static boolean last_frame_skipped = FALSE;
207     boolean skip_even_when_not_scrolling = TRUE;
208     boolean just_scrolling = (ScreenMovDir != 0);
209     boolean verbose = FALSE;
210
211     if (global.fps_slowdown_factor > 1 &&
212         (FrameCounter % global.fps_slowdown_factor) &&
213         (just_scrolling || skip_even_when_not_scrolling))
214     {
215       redraw_mask &= ~REDRAW_MAIN;
216
217       last_frame_skipped = TRUE;
218
219       if (verbose)
220         printf("FRAME SKIPPED\n");
221     }
222     else
223     {
224       if (last_frame_skipped)
225         redraw_mask |= REDRAW_FIELD;
226
227       last_frame_skipped = FALSE;
228
229       if (verbose)
230         printf("frame not skipped\n");
231     }
232   }
233
234   /* synchronize X11 graphics at this point; if we would synchronize the
235      display immediately after the buffer switching (after the XFlush),
236      this could mean that we have to wait for the graphics to complete,
237      although we could go on doing calculations for the next frame */
238
239   SyncDisplay();
240
241   if (redraw_mask & REDRAW_ALL)
242   {
243     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
244
245     redraw_mask = REDRAW_NONE;
246   }
247
248   if (redraw_mask & REDRAW_FIELD)
249   {
250     if (game_status != GAME_MODE_PLAYING ||
251         redraw_mask & REDRAW_FROM_BACKBUFFER)
252     {
253       BlitBitmap(backbuffer, window,
254                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
255     }
256     else
257     {
258       int fx = FX, fy = FY;
259
260       if (setup.soft_scrolling)
261       {
262         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
263         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
264       }
265
266       if (setup.soft_scrolling ||
267           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
268           ABS(ScreenMovPos) == ScrollStepSize ||
269           redraw_tiles > REDRAWTILES_THRESHOLD)
270       {
271         BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
272
273 #if 0
274 #ifdef DEBUG
275         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
276                ScreenGfxPos,
277                (setup.soft_scrolling ?
278                 "setup.soft_scrolling" :
279                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
280                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
281                 ABS(ScreenGfxPos) == ScrollStepSize ?
282                 "ABS(ScreenGfxPos) == ScrollStepSize" :
283                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
284 #endif
285 #endif
286       }
287     }
288
289     redraw_mask &= ~REDRAW_MAIN;
290   }
291
292   if (redraw_mask & REDRAW_DOORS)
293   {
294     if (redraw_mask & REDRAW_DOOR_1)
295       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
296
297     if (redraw_mask & REDRAW_DOOR_2)
298       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
299
300     if (redraw_mask & REDRAW_DOOR_3)
301       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
302
303     redraw_mask &= ~REDRAW_DOORS;
304   }
305
306   if (redraw_mask & REDRAW_MICROLEVEL)
307   {
308     BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
309                SX, SY + 10 * TILEY);
310
311     redraw_mask &= ~REDRAW_MICROLEVEL;
312   }
313
314   if (redraw_mask & REDRAW_TILES)
315   {
316     for (x = 0; x < SCR_FIELDX; x++)
317       for (y = 0 ; y < SCR_FIELDY; y++)
318         if (redraw[redraw_x1 + x][redraw_y1 + y])
319           BlitBitmap(buffer, window,
320                      FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
321                      SX + x * TILEX, SY + y * TILEY);
322   }
323
324   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
325   {
326     char text[100];
327     char info1[100];
328
329     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
330     if (!global.fps_slowdown)
331       info1[0] = '\0';
332
333     sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
334     DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
335   }
336
337   FlushDisplay();
338
339   for (x = 0; x < MAX_BUF_XSIZE; x++)
340     for (y = 0; y < MAX_BUF_YSIZE; y++)
341       redraw[x][y] = 0;
342   redraw_tiles = 0;
343   redraw_mask = REDRAW_NONE;
344 }
345
346 void FadeToFront()
347 {
348 #if 0
349   long fading_delay = 300;
350
351   if (setup.fading && (redraw_mask & REDRAW_FIELD))
352   {
353 #endif
354
355 #if 0
356     int x,y;
357
358     ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
359     FlushDisplay();
360
361     for (i = 0; i < 2 * FULL_SYSIZE; i++)
362     {
363       for (y = 0; y < FULL_SYSIZE; y++)
364       {
365         BlitBitmap(backbuffer, window,
366                    REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
367       }
368       FlushDisplay();
369       Delay(10);
370     }
371 #endif
372
373 #if 0
374     for (i = 1; i < FULL_SYSIZE; i+=2)
375       BlitBitmap(backbuffer, window,
376                  REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
377     FlushDisplay();
378     Delay(fading_delay);
379 #endif
380
381 #if 0
382     SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
383     BlitBitmapMasked(backbuffer, window,
384                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
385                      REAL_SX,REAL_SY);
386     FlushDisplay();
387     Delay(fading_delay);
388
389     SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
390     BlitBitmapMasked(backbuffer, window,
391                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
392                      REAL_SX,REAL_SY);
393     FlushDisplay();
394     Delay(fading_delay);
395
396     SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
397     BlitBitmapMasked(backbuffer, window,
398                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
399                      REAL_SX,REAL_SY);
400     FlushDisplay();
401     Delay(fading_delay);
402
403     SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
404     BlitBitmapMasked(backbuffer, window,
405                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
406                      REAL_SX,REAL_SY);
407     FlushDisplay();
408     Delay(fading_delay);
409
410     redraw_mask &= ~REDRAW_MAIN;
411   }
412 #endif
413
414   BackToFront();
415 }
416
417 void FadeIn(int fade_delay)
418 {
419   if (fade_delay == 0)
420   {
421     BackToFront();
422
423     return;
424   }
425
426   FadeScreen(NULL, FADE_MODE_FADE_IN, fade_delay, 0);
427
428   redraw_mask = REDRAW_NONE;
429 }
430
431 void FadeOut(int fade_delay, int post_delay)
432 {
433   if (fade_delay == 0)
434   {
435     ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
436     BackToFront();
437
438     return;
439   }
440
441   FadeScreen(NULL, FADE_MODE_FADE_OUT, fade_delay, post_delay);
442
443   redraw_mask = REDRAW_NONE;
444 }
445
446 void FadeCross(int fade_delay)
447 {
448   if (fade_delay == 0)
449   {
450     BlitBitmap(bitmap_db_title, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
451     BackToFront();
452
453     return;
454   }
455
456   FadeScreen(bitmap_db_title, FADE_MODE_CROSSFADE, fade_delay, 0);
457
458   redraw_mask = REDRAW_NONE;
459 }
460
461 void SetMainBackgroundImageIfDefined(int graphic)
462 {
463   if (graphic_info[graphic].bitmap)
464     SetMainBackgroundImage(graphic);
465 }
466
467 void SetMainBackgroundImage(int graphic)
468 {
469   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
470                           graphic_info[graphic].bitmap ?
471                           graphic_info[graphic].bitmap :
472                           graphic_info[IMG_BACKGROUND].bitmap);
473 }
474
475 void SetDoorBackgroundImage(int graphic)
476 {
477   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
478                           graphic_info[graphic].bitmap ?
479                           graphic_info[graphic].bitmap :
480                           graphic_info[IMG_BACKGROUND].bitmap);
481 }
482
483 void 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 (player->is_pushing && player->is_moving)
2061         GfxFrame[jx][jy] = player->StepFrame;
2062
2063       DrawLevelField(jx, jy);
2064     }
2065   }
2066
2067   /* ----------------------------------------------------------------------- */
2068   /* draw player himself                                                     */
2069   /* ----------------------------------------------------------------------- */
2070
2071   graphic = getPlayerGraphic(player, move_dir);
2072
2073   /* in the case of changed player action or direction, prevent the current
2074      animation frame from being restarted for identical animations */
2075   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2076     player->Frame = last_player_frame;
2077
2078   frame = getGraphicAnimationFrame(graphic, player->Frame);
2079
2080   if (player->GfxPos)
2081   {
2082     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2083       sxx = player->GfxPos;
2084     else
2085       syy = player->GfxPos;
2086   }
2087
2088   if (!setup.soft_scrolling && ScreenMovPos)
2089     sxx = syy = 0;
2090
2091   if (player_is_opaque)
2092     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2093   else
2094     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2095
2096   if (SHIELD_ON(player))
2097   {
2098     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2099                    IMG_SHIELD_NORMAL_ACTIVE);
2100     int frame = getGraphicAnimationFrame(graphic, -1);
2101
2102     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2103   }
2104
2105   /* ----------------------------------------------------------------------- */
2106   /* draw things the player is pushing, if needed                            */
2107   /* ----------------------------------------------------------------------- */
2108
2109 #if 0
2110   printf("::: %d, %d [%d, %d] [%d]\n",
2111          player->is_pushing, player_is_moving, player->GfxAction,
2112          player->is_moving, player_is_moving);
2113 #endif
2114
2115 #if 1
2116   if (player->is_pushing && player->is_moving)
2117   {
2118     int px = SCREENX(jx), py = SCREENY(jy);
2119     int pxx = (TILEX - ABS(sxx)) * dx;
2120     int pyy = (TILEY - ABS(syy)) * dy;
2121
2122     int graphic;
2123     int frame;
2124
2125     if (!IS_MOVING(jx, jy))             /* push movement already finished */
2126       element = Feld[next_jx][next_jy];
2127
2128     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2129     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2130
2131     /* draw background element under pushed element (like the Sokoban field) */
2132     if (Back[next_jx][next_jy])
2133       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2134
2135     /* masked drawing is needed for EMC style (double) movement graphics */
2136     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2137   }
2138 #endif
2139
2140   /* ----------------------------------------------------------------------- */
2141   /* draw things in front of player (active dynamite or dynabombs)           */
2142   /* ----------------------------------------------------------------------- */
2143
2144   if (IS_ACTIVE_BOMB(element))
2145   {
2146     graphic = el2img(element);
2147     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2148
2149     if (game.emulation == EMU_SUPAPLEX)
2150       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2151     else
2152       DrawGraphicThruMask(sx, sy, graphic, frame);
2153   }
2154
2155   if (player_is_moving && last_element == EL_EXPLOSION)
2156   {
2157     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2158                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
2159     int graphic = el_act2img(element, ACTION_EXPLODING);
2160     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2161     int phase = ExplodePhase[last_jx][last_jy] - 1;
2162     int frame = getGraphicAnimationFrame(graphic, phase - delay);
2163
2164     if (phase >= delay)
2165       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2166   }
2167
2168   /* ----------------------------------------------------------------------- */
2169   /* draw elements the player is just walking/passing through/under          */
2170   /* ----------------------------------------------------------------------- */
2171
2172   if (player_is_moving)
2173   {
2174     /* handle the field the player is leaving ... */
2175     if (IS_ACCESSIBLE_INSIDE(last_element))
2176       DrawLevelField(last_jx, last_jy);
2177     else if (IS_ACCESSIBLE_UNDER(last_element))
2178       DrawLevelFieldThruMask(last_jx, last_jy);
2179   }
2180
2181   /* do not redraw accessible elements if the player is just pushing them */
2182   if (!player_is_moving || !player->is_pushing)
2183   {
2184     /* ... and the field the player is entering */
2185     if (IS_ACCESSIBLE_INSIDE(element))
2186       DrawLevelField(jx, jy);
2187     else if (IS_ACCESSIBLE_UNDER(element))
2188       DrawLevelFieldThruMask(jx, jy);
2189   }
2190
2191   if (setup.direct_draw)
2192   {
2193     int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2194     int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2195     int x_size = TILEX * (1 + ABS(jx - last_jx));
2196     int y_size = TILEY * (1 + ABS(jy - last_jy));
2197
2198     BlitBitmap(drawto_field, window,
2199                dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2200     SetDrawtoField(DRAW_DIRECT);
2201   }
2202
2203   MarkTileDirty(sx, sy);
2204 }
2205
2206 /* ------------------------------------------------------------------------- */
2207
2208 void WaitForEventToContinue()
2209 {
2210   boolean still_wait = TRUE;
2211
2212   /* simulate releasing mouse button over last gadget, if still pressed */
2213   if (button_status)
2214     HandleGadgets(-1, -1, 0);
2215
2216   button_status = MB_RELEASED;
2217
2218   while (still_wait)
2219   {
2220     if (PendingEvent())
2221     {
2222       Event event;
2223
2224       NextEvent(&event);
2225
2226       switch (event.type)
2227       {
2228         case EVENT_BUTTONPRESS:
2229         case EVENT_KEYPRESS:
2230           still_wait = FALSE;
2231           break;
2232
2233         case EVENT_KEYRELEASE:
2234           ClearPlayerAction();
2235           break;
2236
2237         default:
2238           HandleOtherEvents(&event);
2239           break;
2240       }
2241     }
2242     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2243     {
2244       still_wait = FALSE;
2245     }
2246
2247     DoAnimation();
2248
2249     /* don't eat all CPU time */
2250     Delay(10);
2251   }
2252 }
2253
2254 #define MAX_REQUEST_LINES               13
2255 #define MAX_REQUEST_LINE_FONT1_LEN      7
2256 #define MAX_REQUEST_LINE_FONT2_LEN      10
2257
2258 boolean Request(char *text, unsigned int req_state)
2259 {
2260   int mx, my, ty, result = -1;
2261   unsigned int old_door_state;
2262   int last_game_status = game_status;   /* save current game status */
2263   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2264   int font_nr = FONT_TEXT_2;
2265   int max_word_len = 0;
2266   char *text_ptr;
2267
2268   for (text_ptr = text; *text_ptr; text_ptr++)
2269   {
2270     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2271
2272     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2273     {
2274       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2275       font_nr = FONT_LEVEL_NUMBER;
2276
2277       break;
2278     }
2279   }
2280
2281   if (game_status == GAME_MODE_PLAYING &&
2282       level.game_engine_type == GAME_ENGINE_TYPE_EM)
2283     BlitScreenToBitmap_EM(backbuffer);
2284
2285   /* disable deactivated drawing when quick-loading level tape recording */
2286   if (tape.playing && tape.deactivate_display)
2287     TapeDeactivateDisplayOff(TRUE);
2288
2289   SetMouseCursor(CURSOR_DEFAULT);
2290
2291 #if defined(NETWORK_AVALIABLE)
2292   /* pause network game while waiting for request to answer */
2293   if (options.network &&
2294       game_status == GAME_MODE_PLAYING &&
2295       req_state & REQUEST_WAIT_FOR_INPUT)
2296     SendToServer_PausePlaying();
2297 #endif
2298
2299   old_door_state = GetDoorState();
2300
2301   /* simulate releasing mouse button over last gadget, if still pressed */
2302   if (button_status)
2303     HandleGadgets(-1, -1, 0);
2304
2305   UnmapAllGadgets();
2306
2307   if (old_door_state & DOOR_OPEN_1)
2308   {
2309     CloseDoor(DOOR_CLOSE_1);
2310
2311     /* save old door content */
2312     BlitBitmap(bitmap_db_door, bitmap_db_door,
2313                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2314                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2315   }
2316
2317 #if 1
2318   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2319 #endif
2320
2321   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2322
2323   /* clear door drawing field */
2324   DrawBackground(DX, DY, DXSIZE, DYSIZE);
2325
2326   /* force DOOR font on preview level */
2327   game_status = GAME_MODE_PSEUDO_DOOR;
2328
2329   /* write text for request */
2330   for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2331   {
2332     char text_line[max_request_line_len + 1];
2333     int tx, tl, tc = 0;
2334
2335     if (!*text)
2336       break;
2337
2338     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2339     {
2340       tc = *(text + tx);
2341       if (!tc || tc == ' ')
2342         break;
2343     }
2344
2345     if (!tl)
2346     { 
2347       text++; 
2348       ty--; 
2349       continue; 
2350     }
2351
2352     strncpy(text_line, text, tl);
2353     text_line[tl] = 0;
2354
2355     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2356              DY + 8 + ty * (getFontHeight(font_nr) + 2),
2357              text_line, font_nr);
2358
2359     text += tl + (tc == ' ' ? 1 : 0);
2360   }
2361
2362   game_status = last_game_status;       /* restore current game status */
2363
2364   if (req_state & REQ_ASK)
2365   {
2366     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2367     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2368   }
2369   else if (req_state & REQ_CONFIRM)
2370   {
2371     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2372   }
2373   else if (req_state & REQ_PLAYER)
2374   {
2375     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2376     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2377     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2378     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2379   }
2380
2381   /* copy request gadgets to door backbuffer */
2382   BlitBitmap(drawto, bitmap_db_door,
2383              DX, DY, DXSIZE, DYSIZE,
2384              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2385
2386   OpenDoor(DOOR_OPEN_1);
2387
2388   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2389   {
2390     if (game_status == GAME_MODE_PLAYING)
2391     {
2392       SetPanelBackground();
2393       SetDrawBackgroundMask(REDRAW_DOOR_1);
2394     }
2395     else
2396     {
2397       SetDrawBackgroundMask(REDRAW_FIELD);
2398     }
2399
2400     return FALSE;
2401   }
2402
2403   if (game_status != GAME_MODE_MAIN)
2404     InitAnimation();
2405
2406   button_status = MB_RELEASED;
2407
2408   request_gadget_id = -1;
2409
2410   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2411
2412   while (result < 0)
2413   {
2414     if (PendingEvent())
2415     {
2416       Event event;
2417
2418       NextEvent(&event);
2419
2420       switch(event.type)
2421       {
2422         case EVENT_BUTTONPRESS:
2423         case EVENT_BUTTONRELEASE:
2424         case EVENT_MOTIONNOTIFY:
2425         {
2426           if (event.type == EVENT_MOTIONNOTIFY)
2427           {
2428             if (!PointerInWindow(window))
2429               continue; /* window and pointer are on different screens */
2430
2431             if (!button_status)
2432               continue;
2433
2434             motion_status = TRUE;
2435             mx = ((MotionEvent *) &event)->x;
2436             my = ((MotionEvent *) &event)->y;
2437           }
2438           else
2439           {
2440             motion_status = FALSE;
2441             mx = ((ButtonEvent *) &event)->x;
2442             my = ((ButtonEvent *) &event)->y;
2443             if (event.type == EVENT_BUTTONPRESS)
2444               button_status = ((ButtonEvent *) &event)->button;
2445             else
2446               button_status = MB_RELEASED;
2447           }
2448
2449           /* this sets 'request_gadget_id' */
2450           HandleGadgets(mx, my, button_status);
2451
2452           switch(request_gadget_id)
2453           {
2454             case TOOL_CTRL_ID_YES:
2455               result = TRUE;
2456               break;
2457             case TOOL_CTRL_ID_NO:
2458               result = FALSE;
2459               break;
2460             case TOOL_CTRL_ID_CONFIRM:
2461               result = TRUE | FALSE;
2462               break;
2463
2464             case TOOL_CTRL_ID_PLAYER_1:
2465               result = 1;
2466               break;
2467             case TOOL_CTRL_ID_PLAYER_2:
2468               result = 2;
2469               break;
2470             case TOOL_CTRL_ID_PLAYER_3:
2471               result = 3;
2472               break;
2473             case TOOL_CTRL_ID_PLAYER_4:
2474               result = 4;
2475               break;
2476
2477             default:
2478               break;
2479           }
2480
2481           break;
2482         }
2483
2484         case EVENT_KEYPRESS:
2485           switch(GetEventKey((KeyEvent *)&event, TRUE))
2486           {
2487             case KSYM_Return:
2488               result = 1;
2489               break;
2490
2491             case KSYM_Escape:
2492               result = 0;
2493               break;
2494
2495             default:
2496               break;
2497           }
2498           if (req_state & REQ_PLAYER)
2499             result = 0;
2500           break;
2501
2502         case EVENT_KEYRELEASE:
2503           ClearPlayerAction();
2504           break;
2505
2506         default:
2507           HandleOtherEvents(&event);
2508           break;
2509       }
2510     }
2511     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2512     {
2513       int joy = AnyJoystick();
2514
2515       if (joy & JOY_BUTTON_1)
2516         result = 1;
2517       else if (joy & JOY_BUTTON_2)
2518         result = 0;
2519     }
2520
2521     DoAnimation();
2522
2523     /* don't eat all CPU time */
2524     Delay(10);
2525   }
2526
2527   if (game_status != GAME_MODE_MAIN)
2528     StopAnimation();
2529
2530   UnmapToolButtons();
2531
2532   if (!(req_state & REQ_STAY_OPEN))
2533   {
2534     CloseDoor(DOOR_CLOSE_1);
2535
2536     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2537         (req_state & REQ_REOPEN))
2538       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2539   }
2540
2541   RemapAllGadgets();
2542
2543   if (game_status == GAME_MODE_PLAYING)
2544   {
2545     SetPanelBackground();
2546     SetDrawBackgroundMask(REDRAW_DOOR_1);
2547   }
2548   else
2549   {
2550     SetDrawBackgroundMask(REDRAW_FIELD);
2551   }
2552
2553 #if defined(NETWORK_AVALIABLE)
2554   /* continue network game after request */
2555   if (options.network &&
2556       game_status == GAME_MODE_PLAYING &&
2557       req_state & REQUEST_WAIT_FOR_INPUT)
2558     SendToServer_ContinuePlaying();
2559 #endif
2560
2561   /* restore deactivated drawing when quick-loading level tape recording */
2562   if (tape.playing && tape.deactivate_display)
2563     TapeDeactivateDisplayOn();
2564
2565   return result;
2566 }
2567
2568 unsigned int OpenDoor(unsigned int door_state)
2569 {
2570   if (door_state & DOOR_COPY_BACK)
2571   {
2572     if (door_state & DOOR_OPEN_1)
2573       BlitBitmap(bitmap_db_door, bitmap_db_door,
2574                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2575                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2576
2577     if (door_state & DOOR_OPEN_2)
2578       BlitBitmap(bitmap_db_door, bitmap_db_door,
2579                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2580                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2581
2582     door_state &= ~DOOR_COPY_BACK;
2583   }
2584
2585   return MoveDoor(door_state);
2586 }
2587
2588 unsigned int CloseDoor(unsigned int door_state)
2589 {
2590   unsigned int old_door_state = GetDoorState();
2591
2592   if (!(door_state & DOOR_NO_COPY_BACK))
2593   {
2594     if (old_door_state & DOOR_OPEN_1)
2595       BlitBitmap(backbuffer, bitmap_db_door,
2596                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2597
2598     if (old_door_state & DOOR_OPEN_2)
2599       BlitBitmap(backbuffer, bitmap_db_door,
2600                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2601
2602     door_state &= ~DOOR_NO_COPY_BACK;
2603   }
2604
2605   return MoveDoor(door_state);
2606 }
2607
2608 unsigned int GetDoorState()
2609 {
2610   return MoveDoor(DOOR_GET_STATE);
2611 }
2612
2613 unsigned int SetDoorState(unsigned int door_state)
2614 {
2615   return MoveDoor(door_state | DOOR_SET_STATE);
2616 }
2617
2618 unsigned int MoveDoor(unsigned int door_state)
2619 {
2620   static int door1 = DOOR_OPEN_1;
2621   static int door2 = DOOR_CLOSE_2;
2622   unsigned long door_delay = 0;
2623   unsigned long door_delay_value;
2624   int stepsize = 1;
2625
2626   if (door_1.width < 0 || door_1.width > DXSIZE)
2627     door_1.width = DXSIZE;
2628   if (door_1.height < 0 || door_1.height > DYSIZE)
2629     door_1.height = DYSIZE;
2630   if (door_2.width < 0 || door_2.width > VXSIZE)
2631     door_2.width = VXSIZE;
2632   if (door_2.height < 0 || door_2.height > VYSIZE)
2633     door_2.height = VYSIZE;
2634
2635   if (door_state == DOOR_GET_STATE)
2636     return (door1 | door2);
2637
2638   if (door_state & DOOR_SET_STATE)
2639   {
2640     if (door_state & DOOR_ACTION_1)
2641       door1 = door_state & DOOR_ACTION_1;
2642     if (door_state & DOOR_ACTION_2)
2643       door2 = door_state & DOOR_ACTION_2;
2644
2645     return (door1 | door2);
2646   }
2647
2648   if (!(door_state & DOOR_FORCE_REDRAW))
2649   {
2650     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2651       door_state &= ~DOOR_OPEN_1;
2652     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2653       door_state &= ~DOOR_CLOSE_1;
2654     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2655       door_state &= ~DOOR_OPEN_2;
2656     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2657       door_state &= ~DOOR_CLOSE_2;
2658   }
2659
2660   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2661                       door_2.step_delay);
2662
2663   if (setup.quick_doors)
2664   {
2665     stepsize = 20;              /* must be choosen to always draw last frame */
2666     door_delay_value = 0;
2667   }
2668
2669   if (global.autoplay_leveldir)
2670   {
2671     door_state |= DOOR_NO_DELAY;
2672     door_state &= ~DOOR_CLOSE_ALL;
2673   }
2674
2675   if (door_state & DOOR_ACTION)
2676   {
2677     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2678     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2679     boolean door_1_done = (!handle_door_1);
2680     boolean door_2_done = (!handle_door_2);
2681     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2682     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2683     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2684     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2685     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2686     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2687     int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
2688     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2689     int door_skip = max_door_size - door_size;
2690 #if 1
2691     int end = door_size;
2692 #else
2693     int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
2694                DYSIZE : DXSIZE);
2695 #endif
2696 #if 1
2697     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2698 #else
2699     int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
2700 #endif
2701     int k;
2702
2703     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2704     {
2705       /* opening door sound has priority over simultaneously closing door */
2706       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2707         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2708       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2709         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2710     }
2711
2712     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
2713     {
2714       int x = k;
2715       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2716       GC gc = bitmap->stored_clip_gc;
2717
2718       if (door_state & DOOR_ACTION_1)
2719       {
2720         int a = MIN(x * door_1.step_offset, end);
2721         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
2722         int i = p + door_skip;
2723
2724         if (door_1.anim_mode & ANIM_STATIC_PANEL)
2725         {
2726           BlitBitmap(bitmap_db_door, drawto,
2727                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
2728                      DXSIZE, DYSIZE, DX, DY);
2729         }
2730         else if (x <= a)
2731         {
2732           BlitBitmap(bitmap_db_door, drawto,
2733                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
2734                      DXSIZE, DYSIZE - p / 2, DX, DY);
2735
2736           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
2737         }
2738
2739         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
2740         {
2741           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
2742           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
2743           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
2744           int dst2_x = DX,              dst2_y = DY;
2745           int width = i, height = DYSIZE;
2746
2747           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2748           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2749                            dst1_x, dst1_y);
2750
2751           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2752           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2753                            dst2_x, dst2_y);
2754         }
2755         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
2756         {
2757           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
2758           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
2759           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
2760           int dst2_x = DX,              dst2_y = DY;
2761           int width = DXSIZE, height = i;
2762
2763           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2764           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2765                            dst1_x, dst1_y);
2766
2767           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2768           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2769                            dst2_x, dst2_y);
2770         }
2771         else if (x <= DXSIZE)   /* ANIM_DEFAULT */
2772         {
2773           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
2774
2775           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2776           BlitBitmapMasked(bitmap, drawto,
2777                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2778                            DX + DXSIZE - i, DY + j);
2779           BlitBitmapMasked(bitmap, drawto,
2780                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2781                            DX + DXSIZE - i, DY + 140 + j);
2782           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
2783                         DY - (DOOR_GFX_PAGEY1 + j));
2784           BlitBitmapMasked(bitmap, drawto,
2785                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2786                            DX, DY);
2787           BlitBitmapMasked(bitmap, drawto,
2788                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2789                            DX, DY + 140 - j);
2790
2791           BlitBitmapMasked(bitmap, drawto,
2792                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2793                            DX, DY + 77 - j);
2794           BlitBitmapMasked(bitmap, drawto,
2795                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2796                            DX, DY + 203 - j);
2797           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2798           BlitBitmapMasked(bitmap, drawto,
2799                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2800                            DX + DXSIZE - i, DY + 77 + j);
2801           BlitBitmapMasked(bitmap, drawto,
2802                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2803                            DX + DXSIZE - i, DY + 203 + j);
2804         }
2805
2806         redraw_mask |= REDRAW_DOOR_1;
2807         door_1_done = (a == end);
2808       }
2809
2810       if (door_state & DOOR_ACTION_2)
2811       {
2812 #if 1
2813         int a = MIN(x * door_2.step_offset, door_size);
2814         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
2815         int i = p + door_skip;
2816 #else
2817         int a = MIN(x * door_2.step_offset, door_size_2);
2818         int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
2819         int i = p + door_skip;
2820 #endif
2821
2822         if (door_2.anim_mode & ANIM_STATIC_PANEL)
2823         {
2824           BlitBitmap(bitmap_db_door, drawto,
2825                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
2826                      VXSIZE, VYSIZE, VX, VY);
2827         }
2828         else if (x <= VYSIZE)
2829         {
2830           BlitBitmap(bitmap_db_door, drawto,
2831                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
2832                      VXSIZE, VYSIZE - p / 2, VX, VY);
2833
2834           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
2835         }
2836
2837         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
2838         {
2839           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
2840           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
2841           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
2842           int dst2_x = VX,              dst2_y = VY;
2843           int width = i, height = VYSIZE;
2844
2845           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2846           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2847                            dst1_x, dst1_y);
2848
2849           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2850           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2851                            dst2_x, dst2_y);
2852         }
2853         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
2854         {
2855           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
2856           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
2857           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
2858           int dst2_x = VX,              dst2_y = VY;
2859           int width = VXSIZE, height = i;
2860
2861           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
2862           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
2863                            dst1_x, dst1_y);
2864
2865           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
2866           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
2867                            dst2_x, dst2_y);
2868         }
2869         else if (x <= VXSIZE)   /* ANIM_DEFAULT */
2870         {
2871           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
2872
2873           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2874           BlitBitmapMasked(bitmap, drawto,
2875                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2876                            VX + VXSIZE - i, VY + j);
2877           SetClipOrigin(bitmap, gc,
2878                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2879           BlitBitmapMasked(bitmap, drawto,
2880                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2881                            VX, VY);
2882
2883           BlitBitmapMasked(bitmap, drawto,
2884                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2885                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2886           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2887           BlitBitmapMasked(bitmap, drawto,
2888                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2889                            i, VYSIZE / 2 - j,
2890                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2891         }
2892
2893         redraw_mask |= REDRAW_DOOR_2;
2894         door_2_done = (a == VXSIZE);
2895       }
2896
2897       if (!(door_state & DOOR_NO_DELAY))
2898       {
2899         BackToFront();
2900
2901         if (game_status == GAME_MODE_MAIN)
2902           DoAnimation();
2903
2904         WaitUntilDelayReached(&door_delay, door_delay_value);
2905       }
2906     }
2907   }
2908
2909   if (door_state & DOOR_ACTION_1)
2910     door1 = door_state & DOOR_ACTION_1;
2911   if (door_state & DOOR_ACTION_2)
2912     door2 = door_state & DOOR_ACTION_2;
2913
2914   return (door1 | door2);
2915 }
2916
2917 void DrawSpecialEditorDoor()
2918 {
2919   /* draw bigger toolbox window */
2920   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2921              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2922              EX - 4, EY - 12);
2923   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2924              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
2925              EX - 6, EY - 4);
2926
2927   redraw_mask |= REDRAW_ALL;
2928 }
2929
2930 void UndrawSpecialEditorDoor()
2931 {
2932   /* draw normal tape recorder window */
2933   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2934              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
2935              EX - 6, EY - 12);
2936
2937   redraw_mask |= REDRAW_ALL;
2938 }
2939
2940
2941 /* ---------- new tool button stuff ---------------------------------------- */
2942
2943 /* graphic position values for tool buttons */
2944 #define TOOL_BUTTON_YES_XPOS            2
2945 #define TOOL_BUTTON_YES_YPOS            250
2946 #define TOOL_BUTTON_YES_GFX_YPOS        0
2947 #define TOOL_BUTTON_YES_XSIZE           46
2948 #define TOOL_BUTTON_YES_YSIZE           28
2949 #define TOOL_BUTTON_NO_XPOS             52
2950 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2951 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2952 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2953 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2954 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2955 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2956 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2957 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2958 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2959 #define TOOL_BUTTON_PLAYER_XSIZE        30
2960 #define TOOL_BUTTON_PLAYER_YSIZE        30
2961 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2962 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2963 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2964 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2965 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2966                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2967 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2968                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2969 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2970                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2971 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2972                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2973 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2974                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2975 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2976                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2977 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2978                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2979 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2980                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2981
2982 static struct
2983 {
2984   int xpos, ypos;
2985   int x, y;
2986   int width, height;
2987   int gadget_id;
2988   char *infotext;
2989 } toolbutton_info[NUM_TOOL_BUTTONS] =
2990 {
2991   {
2992     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2993     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2994     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2995     TOOL_CTRL_ID_YES,
2996     "yes"
2997   },
2998   {
2999     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
3000     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
3001     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
3002     TOOL_CTRL_ID_NO,
3003     "no"
3004   },
3005   {
3006     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
3007     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
3008     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
3009     TOOL_CTRL_ID_CONFIRM,
3010     "confirm"
3011   },
3012   {
3013     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3014     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
3015     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3016     TOOL_CTRL_ID_PLAYER_1,
3017     "player 1"
3018   },
3019   {
3020     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3021     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
3022     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3023     TOOL_CTRL_ID_PLAYER_2,
3024     "player 2"
3025   },
3026   {
3027     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3028     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
3029     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3030     TOOL_CTRL_ID_PLAYER_3,
3031     "player 3"
3032   },
3033   {
3034     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3035     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
3036     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3037     TOOL_CTRL_ID_PLAYER_4,
3038     "player 4"
3039   }
3040 };
3041
3042 void CreateToolButtons()
3043 {
3044   int i;
3045
3046   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3047   {
3048     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3049     Bitmap *deco_bitmap = None;
3050     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3051     struct GadgetInfo *gi;
3052     unsigned long event_mask;
3053     int gd_xoffset, gd_yoffset;
3054     int gd_x1, gd_x2, gd_y;
3055     int id = i;
3056
3057     event_mask = GD_EVENT_RELEASED;
3058
3059     gd_xoffset = toolbutton_info[i].xpos;
3060     gd_yoffset = toolbutton_info[i].ypos;
3061     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3062     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3063     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3064
3065     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3066     {
3067       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3068
3069       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3070                            &deco_bitmap, &deco_x, &deco_y);
3071       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3072       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3073     }
3074
3075     gi = CreateGadget(GDI_CUSTOM_ID, id,
3076                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
3077                       GDI_X, DX + toolbutton_info[i].x,
3078                       GDI_Y, DY + toolbutton_info[i].y,
3079                       GDI_WIDTH, toolbutton_info[i].width,
3080                       GDI_HEIGHT, toolbutton_info[i].height,
3081                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3082                       GDI_STATE, GD_BUTTON_UNPRESSED,
3083                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3084                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3085                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3086                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3087                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3088                       GDI_DECORATION_SHIFTING, 1, 1,
3089                       GDI_EVENT_MASK, event_mask,
3090                       GDI_CALLBACK_ACTION, HandleToolButtons,
3091                       GDI_END);
3092
3093     if (gi == NULL)
3094       Error(ERR_EXIT, "cannot create gadget");
3095
3096     tool_gadget[id] = gi;
3097   }
3098 }
3099
3100 void FreeToolButtons()
3101 {
3102   int i;
3103
3104   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3105     FreeGadget(tool_gadget[i]);
3106 }
3107
3108 static void UnmapToolButtons()
3109 {
3110   int i;
3111
3112   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3113     UnmapGadget(tool_gadget[i]);
3114 }
3115
3116 static void HandleToolButtons(struct GadgetInfo *gi)
3117 {
3118   request_gadget_id = gi->custom_id;
3119 }
3120
3121 static struct Mapping_EM_to_RND_object
3122 {
3123   int element_em;
3124   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
3125   boolean is_backside;                  /* backside of moving element */
3126
3127   int element_rnd;
3128   int action;
3129   int direction;
3130 }
3131 em_object_mapping_list[] =
3132 {
3133   {
3134     Xblank,                             TRUE,   FALSE,
3135     EL_EMPTY,                           -1, -1
3136   },
3137   {
3138     Yacid_splash_eB,                    FALSE,  FALSE,
3139     EL_ACID_SPLASH_RIGHT,               -1, -1
3140   },
3141   {
3142     Yacid_splash_wB,                    FALSE,  FALSE,
3143     EL_ACID_SPLASH_LEFT,                -1, -1
3144   },
3145
3146 #ifdef EM_ENGINE_BAD_ROLL
3147   {
3148     Xstone_force_e,                     FALSE,  FALSE,
3149     EL_ROCK,                            -1, MV_BIT_RIGHT
3150   },
3151   {
3152     Xstone_force_w,                     FALSE,  FALSE,
3153     EL_ROCK,                            -1, MV_BIT_LEFT
3154   },
3155   {
3156     Xnut_force_e,                       FALSE,  FALSE,
3157     EL_NUT,                             -1, MV_BIT_RIGHT
3158   },
3159   {
3160     Xnut_force_w,                       FALSE,  FALSE,
3161     EL_NUT,                             -1, MV_BIT_LEFT
3162   },
3163   {
3164     Xspring_force_e,                    FALSE,  FALSE,
3165     EL_SPRING,                          -1, MV_BIT_RIGHT
3166   },
3167   {
3168     Xspring_force_w,                    FALSE,  FALSE,
3169     EL_SPRING,                          -1, MV_BIT_LEFT
3170   },
3171   {
3172     Xemerald_force_e,                   FALSE,  FALSE,
3173     EL_EMERALD,                         -1, MV_BIT_RIGHT
3174   },
3175   {
3176     Xemerald_force_w,                   FALSE,  FALSE,
3177     EL_EMERALD,                         -1, MV_BIT_LEFT
3178   },
3179   {
3180     Xdiamond_force_e,                   FALSE,  FALSE,
3181     EL_DIAMOND,                         -1, MV_BIT_RIGHT
3182   },
3183   {
3184     Xdiamond_force_w,                   FALSE,  FALSE,
3185     EL_DIAMOND,                         -1, MV_BIT_LEFT
3186   },
3187   {
3188     Xbomb_force_e,                      FALSE,  FALSE,
3189     EL_BOMB,                            -1, MV_BIT_RIGHT
3190   },
3191   {
3192     Xbomb_force_w,                      FALSE,  FALSE,
3193     EL_BOMB,                            -1, MV_BIT_LEFT
3194   },
3195 #endif  /* EM_ENGINE_BAD_ROLL */
3196
3197   {
3198     Xstone,                             TRUE,   FALSE,
3199     EL_ROCK,                            -1, -1
3200   },
3201   {
3202     Xstone_pause,                       FALSE,  FALSE,
3203     EL_ROCK,                            -1, -1
3204   },
3205   {
3206     Xstone_fall,                        FALSE,  FALSE,
3207     EL_ROCK,                            -1, -1
3208   },
3209   {
3210     Ystone_s,                           FALSE,  FALSE,
3211     EL_ROCK,                            ACTION_FALLING, -1
3212   },
3213   {
3214     Ystone_sB,                          FALSE,  TRUE,
3215     EL_ROCK,                            ACTION_FALLING, -1
3216   },
3217   {
3218     Ystone_e,                           FALSE,  FALSE,
3219     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3220   },
3221   {
3222     Ystone_eB,                          FALSE,  TRUE,
3223     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3224   },
3225   {
3226     Ystone_w,                           FALSE,  FALSE,
3227     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3228   },
3229   {
3230     Ystone_wB,                          FALSE,  TRUE,
3231     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3232   },
3233   {
3234     Xnut,                               TRUE,   FALSE,
3235     EL_NUT,                             -1, -1
3236   },
3237   {
3238     Xnut_pause,                         FALSE,  FALSE,
3239     EL_NUT,                             -1, -1
3240   },
3241   {
3242     Xnut_fall,                          FALSE,  FALSE,
3243     EL_NUT,                             -1, -1
3244   },
3245   {
3246     Ynut_s,                             FALSE,  FALSE,
3247     EL_NUT,                             ACTION_FALLING, -1
3248   },
3249   {
3250     Ynut_sB,                            FALSE,  TRUE,
3251     EL_NUT,                             ACTION_FALLING, -1
3252   },
3253   {
3254     Ynut_e,                             FALSE,  FALSE,
3255     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3256   },
3257   {
3258     Ynut_eB,                            FALSE,  TRUE,
3259     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3260   },
3261   {
3262     Ynut_w,                             FALSE,  FALSE,
3263     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3264   },
3265   {
3266     Ynut_wB,                            FALSE,  TRUE,
3267     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3268   },
3269   {
3270     Xbug_n,                             TRUE,   FALSE,
3271     EL_BUG_UP,                          -1, -1
3272   },
3273   {
3274     Xbug_e,                             TRUE,   FALSE,
3275     EL_BUG_RIGHT,                       -1, -1
3276   },
3277   {
3278     Xbug_s,                             TRUE,   FALSE,
3279     EL_BUG_DOWN,                        -1, -1
3280   },
3281   {
3282     Xbug_w,                             TRUE,   FALSE,
3283     EL_BUG_LEFT,                        -1, -1
3284   },
3285   {
3286     Xbug_gon,                           FALSE,  FALSE,
3287     EL_BUG_UP,                          -1, -1
3288   },
3289   {
3290     Xbug_goe,                           FALSE,  FALSE,
3291     EL_BUG_RIGHT,                       -1, -1
3292   },
3293   {
3294     Xbug_gos,                           FALSE,  FALSE,
3295     EL_BUG_DOWN,                        -1, -1
3296   },
3297   {
3298     Xbug_gow,                           FALSE,  FALSE,
3299     EL_BUG_LEFT,                        -1, -1
3300   },
3301   {
3302     Ybug_n,                             FALSE,  FALSE,
3303     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3304   },
3305   {
3306     Ybug_nB,                            FALSE,  TRUE,
3307     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3308   },
3309   {
3310     Ybug_e,                             FALSE,  FALSE,
3311     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3312   },
3313   {
3314     Ybug_eB,                            FALSE,  TRUE,
3315     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3316   },
3317   {
3318     Ybug_s,                             FALSE,  FALSE,
3319     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3320   },
3321   {
3322     Ybug_sB,                            FALSE,  TRUE,
3323     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3324   },
3325   {
3326     Ybug_w,                             FALSE,  FALSE,
3327     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3328   },
3329   {
3330     Ybug_wB,                            FALSE,  TRUE,
3331     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3332   },
3333   {
3334     Ybug_w_n,                           FALSE,  FALSE,
3335     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3336   },
3337   {
3338     Ybug_n_e,                           FALSE,  FALSE,
3339     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3340   },
3341   {
3342     Ybug_e_s,                           FALSE,  FALSE,
3343     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3344   },
3345   {
3346     Ybug_s_w,                           FALSE,  FALSE,
3347     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3348   },
3349   {
3350     Ybug_e_n,                           FALSE,  FALSE,
3351     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3352   },
3353   {
3354     Ybug_s_e,                           FALSE,  FALSE,
3355     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3356   },
3357   {
3358     Ybug_w_s,                           FALSE,  FALSE,
3359     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3360   },
3361   {
3362     Ybug_n_w,                           FALSE,  FALSE,
3363     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3364   },
3365   {
3366     Ybug_stone,                         FALSE,  FALSE,
3367     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
3368   },
3369   {
3370     Ybug_spring,                        FALSE,  FALSE,
3371     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
3372   },
3373   {
3374     Xtank_n,                            TRUE,   FALSE,
3375     EL_SPACESHIP_UP,                    -1, -1
3376   },
3377   {
3378     Xtank_e,                            TRUE,   FALSE,
3379     EL_SPACESHIP_RIGHT,                 -1, -1
3380   },
3381   {
3382     Xtank_s,                            TRUE,   FALSE,
3383     EL_SPACESHIP_DOWN,                  -1, -1
3384   },
3385   {
3386     Xtank_w,                            TRUE,   FALSE,
3387     EL_SPACESHIP_LEFT,                  -1, -1
3388   },
3389   {
3390     Xtank_gon,                          FALSE,  FALSE,
3391     EL_SPACESHIP_UP,                    -1, -1
3392   },
3393   {
3394     Xtank_goe,                          FALSE,  FALSE,
3395     EL_SPACESHIP_RIGHT,                 -1, -1
3396   },
3397   {
3398     Xtank_gos,                          FALSE,  FALSE,
3399     EL_SPACESHIP_DOWN,                  -1, -1
3400   },
3401   {
3402     Xtank_gow,                          FALSE,  FALSE,
3403     EL_SPACESHIP_LEFT,                  -1, -1
3404   },
3405   {
3406     Ytank_n,                            FALSE,  FALSE,
3407     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3408   },
3409   {
3410     Ytank_nB,                           FALSE,  TRUE,
3411     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3412   },
3413   {
3414     Ytank_e,                            FALSE,  FALSE,
3415     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3416   },
3417   {
3418     Ytank_eB,                           FALSE,  TRUE,
3419     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3420   },
3421   {
3422     Ytank_s,                            FALSE,  FALSE,
3423     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3424   },
3425   {
3426     Ytank_sB,                           FALSE,  TRUE,
3427     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3428   },
3429   {
3430     Ytank_w,                            FALSE,  FALSE,
3431     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3432   },
3433   {
3434     Ytank_wB,                           FALSE,  TRUE,
3435     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3436   },
3437   {
3438     Ytank_w_n,                          FALSE,  FALSE,
3439     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3440   },
3441   {
3442     Ytank_n_e,                          FALSE,  FALSE,
3443     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3444   },
3445   {
3446     Ytank_e_s,                          FALSE,  FALSE,
3447     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3448   },
3449   {
3450     Ytank_s_w,                          FALSE,  FALSE,
3451     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3452   },
3453   {
3454     Ytank_e_n,                          FALSE,  FALSE,
3455     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3456   },
3457   {
3458     Ytank_s_e,                          FALSE,  FALSE,
3459     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3460   },
3461   {
3462     Ytank_w_s,                          FALSE,  FALSE,
3463     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3464   },
3465   {
3466     Ytank_n_w,                          FALSE,  FALSE,
3467     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3468   },
3469   {
3470     Ytank_stone,                        FALSE,  FALSE,
3471     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
3472   },
3473   {
3474     Ytank_spring,                       FALSE,  FALSE,
3475     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
3476   },
3477   {
3478     Xandroid,                           TRUE,   FALSE,
3479     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
3480   },
3481   {
3482     Xandroid_1_n,                       FALSE,  FALSE,
3483     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
3484   },
3485   {
3486     Xandroid_2_n,                       FALSE,  FALSE,
3487     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
3488   },
3489   {
3490     Xandroid_1_e,                       FALSE,  FALSE,
3491     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
3492   },
3493   {
3494     Xandroid_2_e,                       FALSE,  FALSE,
3495     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
3496   },
3497   {
3498     Xandroid_1_w,                       FALSE,  FALSE,
3499     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
3500   },
3501   {
3502     Xandroid_2_w,                       FALSE,  FALSE,
3503     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
3504   },
3505   {
3506     Xandroid_1_s,                       FALSE,  FALSE,
3507     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
3508   },
3509   {
3510     Xandroid_2_s,                       FALSE,  FALSE,
3511     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
3512   },
3513   {
3514     Yandroid_n,                         FALSE,  FALSE,
3515     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
3516   },
3517   {
3518     Yandroid_nB,                        FALSE,  TRUE,
3519     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
3520   },
3521   {
3522     Yandroid_ne,                        FALSE,  FALSE,
3523     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
3524   },
3525   {
3526     Yandroid_neB,                       FALSE,  TRUE,
3527     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
3528   },
3529   {
3530     Yandroid_e,                         FALSE,  FALSE,
3531     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
3532   },
3533   {
3534     Yandroid_eB,                        FALSE,  TRUE,
3535     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
3536   },
3537   {
3538     Yandroid_se,                        FALSE,  FALSE,
3539     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
3540   },
3541   {
3542     Yandroid_seB,                       FALSE,  TRUE,
3543     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3544   },
3545   {
3546     Yandroid_s,                         FALSE,  FALSE,
3547     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
3548   },
3549   {
3550     Yandroid_sB,                        FALSE,  TRUE,
3551     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
3552   },
3553   {
3554     Yandroid_sw,                        FALSE,  FALSE,
3555     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
3556   },
3557   {
3558     Yandroid_swB,                       FALSE,  TRUE,
3559     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
3560   },
3561   {
3562     Yandroid_w,                         FALSE,  FALSE,
3563     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
3564   },
3565   {
3566     Yandroid_wB,                        FALSE,  TRUE,
3567     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
3568   },
3569   {
3570     Yandroid_nw,                        FALSE,  FALSE,
3571     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
3572   },
3573   {
3574     Yandroid_nwB,                       FALSE,  TRUE,
3575     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
3576   },
3577   {
3578     Xspring,                            TRUE,   FALSE,
3579     EL_SPRING,                          -1, -1
3580   },
3581   {
3582     Xspring_pause,                      FALSE,  FALSE,
3583     EL_SPRING,                          -1, -1
3584   },
3585   {
3586     Xspring_e,                          FALSE,  FALSE,
3587     EL_SPRING,                          -1, -1
3588   },
3589   {
3590     Xspring_w,                          FALSE,  FALSE,
3591     EL_SPRING,                          -1, -1
3592   },
3593   {
3594     Xspring_fall,                       FALSE,  FALSE,
3595     EL_SPRING,                          -1, -1
3596   },
3597   {
3598     Yspring_s,                          FALSE,  FALSE,
3599     EL_SPRING,                          ACTION_FALLING, -1
3600   },
3601   {
3602     Yspring_sB,                         FALSE,  TRUE,
3603     EL_SPRING,                          ACTION_FALLING, -1
3604   },
3605   {
3606     Yspring_e,                          FALSE,  FALSE,
3607     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
3608   },
3609   {
3610     Yspring_eB,                         FALSE,  TRUE,
3611     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
3612   },
3613   {
3614     Yspring_w,                          FALSE,  FALSE,
3615     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
3616   },
3617   {
3618     Yspring_wB,                         FALSE,  TRUE,
3619     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
3620   },
3621   {
3622     Yspring_kill_e,                     FALSE,  FALSE,
3623     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
3624   },
3625   {
3626     Yspring_kill_eB,                    FALSE,  TRUE,
3627     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
3628   },
3629   {
3630     Yspring_kill_w,                     FALSE,  FALSE,
3631     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
3632   },
3633   {
3634     Yspring_kill_wB,                    FALSE,  TRUE,
3635     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
3636   },
3637   {
3638     Xeater_n,                           TRUE,   FALSE,
3639     EL_YAMYAM_UP,                       -1, -1
3640   },
3641   {
3642     Xeater_e,                           TRUE,   FALSE,
3643     EL_YAMYAM_RIGHT,                    -1, -1
3644   },
3645   {
3646     Xeater_w,                           TRUE,   FALSE,
3647     EL_YAMYAM_LEFT,                     -1, -1
3648   },
3649   {
3650     Xeater_s,                           TRUE,   FALSE,
3651     EL_YAMYAM_DOWN,                     -1, -1
3652   },
3653   {
3654     Yeater_n,                           FALSE,  FALSE,
3655     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
3656   },
3657   {
3658     Yeater_nB,                          FALSE,  TRUE,
3659     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
3660   },
3661   {
3662     Yeater_e,                           FALSE,  FALSE,
3663     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
3664   },
3665   {
3666     Yeater_eB,                          FALSE,  TRUE,
3667     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
3668   },
3669   {
3670     Yeater_s,                           FALSE,  FALSE,
3671     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
3672   },
3673   {
3674     Yeater_sB,                          FALSE,  TRUE,
3675     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
3676   },
3677   {
3678     Yeater_w,                           FALSE,  FALSE,
3679     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
3680   },
3681   {
3682     Yeater_wB,                          FALSE,  TRUE,
3683     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
3684   },
3685   {
3686     Yeater_stone,                       FALSE,  FALSE,
3687     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
3688   },
3689   {
3690     Yeater_spring,                      FALSE,  FALSE,
3691     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
3692   },
3693   {
3694     Xalien,                             TRUE,   FALSE,
3695     EL_ROBOT,                           -1, -1
3696   },
3697   {
3698     Xalien_pause,                       FALSE,  FALSE,
3699     EL_ROBOT,                           -1, -1
3700   },
3701   {
3702     Yalien_n,                           FALSE,  FALSE,
3703     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
3704   },
3705   {
3706     Yalien_nB,                          FALSE,  TRUE,
3707     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
3708   },
3709   {
3710     Yalien_e,                           FALSE,  FALSE,
3711     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
3712   },
3713   {
3714     Yalien_eB,                          FALSE,  TRUE,
3715     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
3716   },
3717   {
3718     Yalien_s,                           FALSE,  FALSE,
3719     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
3720   },
3721   {
3722     Yalien_sB,                          FALSE,  TRUE,
3723     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
3724   },
3725   {
3726     Yalien_w,                           FALSE,  FALSE,
3727     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
3728   },
3729   {
3730     Yalien_wB,                          FALSE,  TRUE,
3731     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
3732   },
3733   {
3734     Yalien_stone,                       FALSE,  FALSE,
3735     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
3736   },
3737   {
3738     Yalien_spring,                      FALSE,  FALSE,
3739     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
3740   },
3741   {
3742     Xemerald,                           TRUE,   FALSE,
3743     EL_EMERALD,                         -1, -1
3744   },
3745   {
3746     Xemerald_pause,                     FALSE,  FALSE,
3747     EL_EMERALD,                         -1, -1
3748   },
3749   {
3750     Xemerald_fall,                      FALSE,  FALSE,
3751     EL_EMERALD,                         -1, -1
3752   },
3753   {
3754     Xemerald_shine,                     FALSE,  FALSE,
3755     EL_EMERALD,                         ACTION_TWINKLING, -1
3756   },
3757   {
3758     Yemerald_s,                         FALSE,  FALSE,
3759     EL_EMERALD,                         ACTION_FALLING, -1
3760   },
3761   {
3762     Yemerald_sB,                        FALSE,  TRUE,
3763     EL_EMERALD,                         ACTION_FALLING, -1
3764   },
3765   {
3766     Yemerald_e,                         FALSE,  FALSE,
3767     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
3768   },
3769   {
3770     Yemerald_eB,                        FALSE,  TRUE,
3771     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
3772   },
3773   {
3774     Yemerald_w,                         FALSE,  FALSE,
3775     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
3776   },
3777   {
3778     Yemerald_wB,                        FALSE,  TRUE,
3779     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
3780   },
3781   {
3782     Yemerald_eat,                       FALSE,  FALSE,
3783     EL_EMERALD,                         ACTION_COLLECTING, -1
3784   },
3785   {
3786     Yemerald_stone,                     FALSE,  FALSE,
3787     EL_NUT,                             ACTION_BREAKING, -1
3788   },
3789   {
3790     Xdiamond,                           TRUE,   FALSE,
3791     EL_DIAMOND,                         -1, -1
3792   },
3793   {
3794     Xdiamond_pause,                     FALSE,  FALSE,
3795     EL_DIAMOND,                         -1, -1
3796   },
3797   {
3798     Xdiamond_fall,                      FALSE,  FALSE,
3799     EL_DIAMOND,                         -1, -1
3800   },
3801   {
3802     Xdiamond_shine,                     FALSE,  FALSE,
3803     EL_DIAMOND,                         ACTION_TWINKLING, -1
3804   },
3805   {
3806     Ydiamond_s,                         FALSE,  FALSE,
3807     EL_DIAMOND,                         ACTION_FALLING, -1
3808   },
3809   {
3810     Ydiamond_sB,                        FALSE,  TRUE,
3811     EL_DIAMOND,                         ACTION_FALLING, -1
3812   },
3813   {
3814     Ydiamond_e,                         FALSE,  FALSE,
3815     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
3816   },
3817   {
3818     Ydiamond_eB,                        FALSE,  TRUE,
3819     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
3820   },
3821   {
3822     Ydiamond_w,                         FALSE,  FALSE,
3823     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
3824   },
3825   {
3826     Ydiamond_wB,                        FALSE,  TRUE,
3827     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
3828   },
3829   {
3830     Ydiamond_eat,                       FALSE,  FALSE,
3831     EL_DIAMOND,                         ACTION_COLLECTING, -1
3832   },
3833   {
3834     Ydiamond_stone,                     FALSE,  FALSE,
3835     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
3836   },
3837   {
3838     Xdrip_fall,                         TRUE,   FALSE,
3839     EL_AMOEBA_DROP,                     -1, -1
3840   },
3841   {
3842     Xdrip_stretch,                      FALSE,  FALSE,
3843     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
3844   },
3845   {
3846     Xdrip_stretchB,                     FALSE,  TRUE,
3847     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
3848   },
3849   {
3850     Xdrip_eat,                          FALSE,  FALSE,
3851     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
3852   },
3853   {
3854     Ydrip_s1,                           FALSE,  FALSE,
3855     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
3856   },
3857   {
3858     Ydrip_s1B,                          FALSE,  TRUE,
3859     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
3860   },
3861   {
3862     Ydrip_s2,                           FALSE,  FALSE,
3863     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
3864   },
3865   {
3866     Ydrip_s2B,                          FALSE,  TRUE,
3867     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
3868   },
3869   {
3870     Xbomb,                              TRUE,   FALSE,
3871     EL_BOMB,                            -1, -1
3872   },
3873   {
3874     Xbomb_pause,                        FALSE,  FALSE,
3875     EL_BOMB,                            -1, -1
3876   },
3877   {
3878     Xbomb_fall,                         FALSE,  FALSE,
3879     EL_BOMB,                            -1, -1
3880   },
3881   {
3882     Ybomb_s,                            FALSE,  FALSE,
3883     EL_BOMB,                            ACTION_FALLING, -1
3884   },
3885   {
3886     Ybomb_sB,                           FALSE,  TRUE,
3887     EL_BOMB,                            ACTION_FALLING, -1
3888   },
3889   {
3890     Ybomb_e,                            FALSE,  FALSE,
3891     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
3892   },
3893   {
3894     Ybomb_eB,                           FALSE,  TRUE,
3895     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
3896   },
3897   {
3898     Ybomb_w,                            FALSE,  FALSE,
3899     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
3900   },
3901   {
3902     Ybomb_wB,                           FALSE,  TRUE,
3903     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
3904   },
3905   {
3906     Ybomb_eat,                          FALSE,  FALSE,
3907     EL_BOMB,                            ACTION_ACTIVATING, -1
3908   },
3909   {
3910     Xballoon,                           TRUE,   FALSE,
3911     EL_BALLOON,                         -1, -1
3912   },
3913   {
3914     Yballoon_n,                         FALSE,  FALSE,
3915     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
3916   },
3917   {
3918     Yballoon_nB,                        FALSE,  TRUE,
3919     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
3920   },
3921   {
3922     Yballoon_e,                         FALSE,  FALSE,
3923     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
3924   },
3925   {
3926     Yballoon_eB,                        FALSE,  TRUE,
3927     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
3928   },
3929   {
3930     Yballoon_s,                         FALSE,  FALSE,
3931     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
3932   },
3933   {
3934     Yballoon_sB,                        FALSE,  TRUE,
3935     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
3936   },
3937   {
3938     Yballoon_w,                         FALSE,  FALSE,
3939     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
3940   },
3941   {
3942     Yballoon_wB,                        FALSE,  TRUE,
3943     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
3944   },
3945   {
3946     Xgrass,                             TRUE,   FALSE,
3947     EL_EMC_GRASS,                       -1, -1
3948   },
3949   {
3950     Ygrass_nB,                          FALSE,  FALSE,
3951     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
3952   },
3953   {
3954     Ygrass_eB,                          FALSE,  FALSE,
3955     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
3956   },
3957   {
3958     Ygrass_sB,                          FALSE,  FALSE,
3959     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
3960   },
3961   {
3962     Ygrass_wB,                          FALSE,  FALSE,
3963     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
3964   },
3965   {
3966     Xdirt,                              TRUE,   FALSE,
3967     EL_SAND,                            -1, -1
3968   },
3969   {
3970     Ydirt_nB,                           FALSE,  FALSE,
3971     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
3972   },
3973   {
3974     Ydirt_eB,                           FALSE,  FALSE,
3975     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
3976   },
3977   {
3978     Ydirt_sB,                           FALSE,  FALSE,
3979     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
3980   },
3981   {
3982     Ydirt_wB,                           FALSE,  FALSE,
3983     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
3984   },
3985   {
3986     Xacid_ne,                           TRUE,   FALSE,
3987     EL_ACID_POOL_TOPRIGHT,              -1, -1
3988   },
3989   {
3990     Xacid_se,                           TRUE,   FALSE,
3991     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
3992   },
3993   {
3994     Xacid_s,                            TRUE,   FALSE,
3995     EL_ACID_POOL_BOTTOM,                -1, -1
3996   },
3997   {
3998     Xacid_sw,                           TRUE,   FALSE,
3999     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
4000   },
4001   {
4002     Xacid_nw,                           TRUE,   FALSE,
4003     EL_ACID_POOL_TOPLEFT,               -1, -1
4004   },
4005   {
4006     Xacid_1,                            TRUE,   FALSE,
4007     EL_ACID,                            -1, -1
4008   },
4009   {
4010     Xacid_2,                            FALSE,  FALSE,
4011     EL_ACID,                            -1, -1
4012   },
4013   {
4014     Xacid_3,                            FALSE,  FALSE,
4015     EL_ACID,                            -1, -1
4016   },
4017   {
4018     Xacid_4,                            FALSE,  FALSE,
4019     EL_ACID,                            -1, -1
4020   },
4021   {
4022     Xacid_5,                            FALSE,  FALSE,
4023     EL_ACID,                            -1, -1
4024   },
4025   {
4026     Xacid_6,                            FALSE,  FALSE,
4027     EL_ACID,                            -1, -1
4028   },
4029   {
4030     Xacid_7,                            FALSE,  FALSE,
4031     EL_ACID,                            -1, -1
4032   },
4033   {
4034     Xacid_8,                            FALSE,  FALSE,
4035     EL_ACID,                            -1, -1
4036   },
4037   {
4038     Xball_1,                            TRUE,   FALSE,
4039     EL_EMC_MAGIC_BALL,                  -1, -1
4040   },
4041   {
4042     Xball_1B,                           FALSE,  FALSE,
4043     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4044   },
4045   {
4046     Xball_2,                            FALSE,  FALSE,
4047     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4048   },
4049   {
4050     Xball_2B,                           FALSE,  FALSE,
4051     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4052   },
4053   {
4054     Yball_eat,                          FALSE,  FALSE,
4055     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
4056   },
4057   {
4058     Ykey_1_eat,                         FALSE,  FALSE,
4059     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
4060   },
4061   {
4062     Ykey_2_eat,                         FALSE,  FALSE,
4063     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
4064   },
4065   {
4066     Ykey_3_eat,                         FALSE,  FALSE,
4067     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
4068   },
4069   {
4070     Ykey_4_eat,                         FALSE,  FALSE,
4071     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
4072   },
4073   {
4074     Ykey_5_eat,                         FALSE,  FALSE,
4075     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
4076   },
4077   {
4078     Ykey_6_eat,                         FALSE,  FALSE,
4079     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
4080   },
4081   {
4082     Ykey_7_eat,                         FALSE,  FALSE,
4083     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
4084   },
4085   {
4086     Ykey_8_eat,                         FALSE,  FALSE,
4087     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
4088   },
4089   {
4090     Ylenses_eat,                        FALSE,  FALSE,
4091     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
4092   },
4093   {
4094     Ymagnify_eat,                       FALSE,  FALSE,
4095     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
4096   },
4097   {
4098     Ygrass_eat,                         FALSE,  FALSE,
4099     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
4100   },
4101   {
4102     Ydirt_eat,                          FALSE,  FALSE,
4103     EL_SAND,                            ACTION_SNAPPING, -1
4104   },
4105   {
4106     Xgrow_ns,                           TRUE,   FALSE,
4107     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
4108   },
4109   {
4110     Ygrow_ns_eat,                       FALSE,  FALSE,
4111     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
4112   },
4113   {
4114     Xgrow_ew,                           TRUE,   FALSE,
4115     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
4116   },
4117   {
4118     Ygrow_ew_eat,                       FALSE,  FALSE,
4119     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
4120   },
4121   {
4122     Xwonderwall,                        TRUE,   FALSE,
4123     EL_MAGIC_WALL,                      -1, -1
4124   },
4125   {
4126     XwonderwallB,                       FALSE,  FALSE,
4127     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
4128   },
4129   {
4130     Xamoeba_1,                          TRUE,   FALSE,
4131     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4132   },
4133   {
4134     Xamoeba_2,                          FALSE,  FALSE,
4135     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4136   },
4137   {
4138     Xamoeba_3,                          FALSE,  FALSE,
4139     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4140   },
4141   {
4142     Xamoeba_4,                          FALSE,  FALSE,
4143     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4144   },
4145   {
4146     Xamoeba_5,                          TRUE,   FALSE,
4147     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4148   },
4149   {
4150     Xamoeba_6,                          FALSE,  FALSE,
4151     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4152   },
4153   {
4154     Xamoeba_7,                          FALSE,  FALSE,
4155     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4156   },
4157   {
4158     Xamoeba_8,                          FALSE,  FALSE,
4159     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4160   },
4161   {
4162     Xdoor_1,                            TRUE,   FALSE,
4163     EL_EM_GATE_1,                       -1, -1
4164   },
4165   {
4166     Xdoor_2,                            TRUE,   FALSE,
4167     EL_EM_GATE_2,                       -1, -1
4168   },
4169   {
4170     Xdoor_3,                            TRUE,   FALSE,
4171     EL_EM_GATE_3,                       -1, -1
4172   },
4173   {
4174     Xdoor_4,                            TRUE,   FALSE,
4175     EL_EM_GATE_4,                       -1, -1
4176   },
4177   {
4178     Xdoor_5,                            TRUE,   FALSE,
4179     EL_EMC_GATE_5,                      -1, -1
4180   },
4181   {
4182     Xdoor_6,                            TRUE,   FALSE,
4183     EL_EMC_GATE_6,                      -1, -1
4184   },
4185   {
4186     Xdoor_7,                            TRUE,   FALSE,
4187     EL_EMC_GATE_7,                      -1, -1
4188   },
4189   {
4190     Xdoor_8,                            TRUE,   FALSE,
4191     EL_EMC_GATE_8,                      -1, -1
4192   },
4193   {
4194     Xkey_1,                             TRUE,   FALSE,
4195     EL_EM_KEY_1,                        -1, -1
4196   },
4197   {
4198     Xkey_2,                             TRUE,   FALSE,
4199     EL_EM_KEY_2,                        -1, -1
4200   },
4201   {
4202     Xkey_3,                             TRUE,   FALSE,
4203     EL_EM_KEY_3,                        -1, -1
4204   },
4205   {
4206     Xkey_4,                             TRUE,   FALSE,
4207     EL_EM_KEY_4,                        -1, -1
4208   },
4209   {
4210     Xkey_5,                             TRUE,   FALSE,
4211     EL_EMC_KEY_5,                       -1, -1
4212   },
4213   {
4214     Xkey_6,                             TRUE,   FALSE,
4215     EL_EMC_KEY_6,                       -1, -1
4216   },
4217   {
4218     Xkey_7,                             TRUE,   FALSE,
4219     EL_EMC_KEY_7,                       -1, -1
4220   },
4221   {
4222     Xkey_8,                             TRUE,   FALSE,
4223     EL_EMC_KEY_8,                       -1, -1
4224   },
4225   {
4226     Xwind_n,                            TRUE,   FALSE,
4227     EL_BALLOON_SWITCH_UP,               -1, -1
4228   },
4229   {
4230     Xwind_e,                            TRUE,   FALSE,
4231     EL_BALLOON_SWITCH_RIGHT,            -1, -1
4232   },
4233   {
4234     Xwind_s,                            TRUE,   FALSE,
4235     EL_BALLOON_SWITCH_DOWN,             -1, -1
4236   },
4237   {
4238     Xwind_w,                            TRUE,   FALSE,
4239     EL_BALLOON_SWITCH_LEFT,             -1, -1
4240   },
4241   {
4242     Xwind_nesw,                         TRUE,   FALSE,
4243     EL_BALLOON_SWITCH_ANY,              -1, -1
4244   },
4245   {
4246     Xwind_stop,                         TRUE,   FALSE,
4247     EL_BALLOON_SWITCH_NONE,             -1, -1
4248   },
4249   {
4250     Xexit,                              TRUE,   FALSE,
4251     EL_EXIT_CLOSED,                     -1, -1
4252   },
4253   {
4254     Xexit_1,                            TRUE,   FALSE,
4255     EL_EXIT_OPEN,                       -1, -1
4256   },
4257   {
4258     Xexit_2,                            FALSE,  FALSE,
4259     EL_EXIT_OPEN,                       -1, -1
4260   },
4261   {
4262     Xexit_3,                            FALSE,  FALSE,
4263     EL_EXIT_OPEN,                       -1, -1
4264   },
4265   {
4266     Xdynamite,                          TRUE,   FALSE,
4267     EL_EM_DYNAMITE,                     -1, -1
4268   },
4269   {
4270     Ydynamite_eat,                      FALSE,  FALSE,
4271     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
4272   },
4273   {
4274     Xdynamite_1,                        TRUE,   FALSE,
4275     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4276   },
4277   {
4278     Xdynamite_2,                        FALSE,  FALSE,
4279     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4280   },
4281   {
4282     Xdynamite_3,                        FALSE,  FALSE,
4283     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4284   },
4285   {
4286     Xdynamite_4,                        FALSE,  FALSE,
4287     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4288   },
4289   {
4290     Xbumper,                            TRUE,   FALSE,
4291     EL_EMC_SPRING_BUMPER,               -1, -1
4292   },
4293   {
4294     XbumperB,                           FALSE,  FALSE,
4295     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
4296   },
4297   {
4298     Xwheel,                             TRUE,   FALSE,
4299     EL_ROBOT_WHEEL,                     -1, -1
4300   },
4301   {
4302     XwheelB,                            FALSE,  FALSE,
4303     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
4304   },
4305   {
4306     Xswitch,                            TRUE,   FALSE,
4307     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
4308   },
4309   {
4310     XswitchB,                           FALSE,  FALSE,
4311     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
4312   },
4313   {
4314     Xsand,                              TRUE,   FALSE,
4315     EL_QUICKSAND_EMPTY,                 -1, -1
4316   },
4317   {
4318     Xsand_stone,                        TRUE,   FALSE,
4319     EL_QUICKSAND_FULL,                  -1, -1
4320   },
4321   {
4322     Xsand_stonein_1,                    FALSE,  TRUE,
4323     EL_ROCK,                            ACTION_FILLING, -1
4324   },
4325   {
4326     Xsand_stonein_2,                    FALSE,  TRUE,
4327     EL_ROCK,                            ACTION_FILLING, -1
4328   },
4329   {
4330     Xsand_stonein_3,                    FALSE,  TRUE,
4331     EL_ROCK,                            ACTION_FILLING, -1
4332   },
4333   {
4334     Xsand_stonein_4,                    FALSE,  TRUE,
4335     EL_ROCK,                            ACTION_FILLING, -1
4336   },
4337   {
4338     Xsand_stonesand_1,                  FALSE,  FALSE,
4339     EL_QUICKSAND_FULL,                  -1, -1
4340   },
4341   {
4342     Xsand_stonesand_2,                  FALSE,  FALSE,
4343     EL_QUICKSAND_FULL,                  -1, -1
4344   },
4345   {
4346     Xsand_stonesand_3,                  FALSE,  FALSE,
4347     EL_QUICKSAND_FULL,                  -1, -1
4348   },
4349   {
4350     Xsand_stonesand_4,                  FALSE,  FALSE,
4351     EL_QUICKSAND_FULL,                  -1, -1
4352   },
4353   {
4354     Xsand_stoneout_1,                   FALSE,  FALSE,
4355     EL_ROCK,                            ACTION_EMPTYING, -1
4356   },
4357   {
4358     Xsand_stoneout_2,                   FALSE,  FALSE,
4359     EL_ROCK,                            ACTION_EMPTYING, -1
4360   },
4361   {
4362     Xsand_sandstone_1,                  FALSE,  FALSE,
4363     EL_QUICKSAND_FULL,                  -1, -1
4364   },
4365   {
4366     Xsand_sandstone_2,                  FALSE,  FALSE,
4367     EL_QUICKSAND_FULL,                  -1, -1
4368   },
4369   {
4370     Xsand_sandstone_3,                  FALSE,  FALSE,
4371     EL_QUICKSAND_FULL,                  -1, -1
4372   },
4373   {
4374     Xsand_sandstone_4,                  FALSE,  FALSE,
4375     EL_QUICKSAND_FULL,                  -1, -1
4376   },
4377   {
4378     Xplant,                             TRUE,   FALSE,
4379     EL_EMC_PLANT,                       -1, -1
4380   },
4381   {
4382     Yplant,                             FALSE,  FALSE,
4383     EL_EMC_PLANT,                       -1, -1
4384   },
4385   {
4386     Xlenses,                            TRUE,   FALSE,
4387     EL_EMC_LENSES,                      -1, -1
4388   },
4389   {
4390     Xmagnify,                           TRUE,   FALSE,
4391     EL_EMC_MAGNIFIER,                   -1, -1
4392   },
4393   {
4394     Xdripper,                           TRUE,   FALSE,
4395     EL_EMC_DRIPPER,                     -1, -1
4396   },
4397   {
4398     XdripperB,                          FALSE,  FALSE,
4399     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
4400   },
4401   {
4402     Xfake_blank,                        TRUE,   FALSE,
4403     EL_INVISIBLE_WALL,                  -1, -1
4404   },
4405   {
4406     Xfake_blankB,                       FALSE,  FALSE,
4407     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
4408   },
4409   {
4410     Xfake_grass,                        TRUE,   FALSE,
4411     EL_EMC_FAKE_GRASS,                  -1, -1
4412   },
4413   {
4414     Xfake_grassB,                       FALSE,  FALSE,
4415     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
4416   },
4417   {
4418     Xfake_door_1,                       TRUE,   FALSE,
4419     EL_EM_GATE_1_GRAY,                  -1, -1
4420   },
4421   {
4422     Xfake_door_2,                       TRUE,   FALSE,
4423     EL_EM_GATE_2_GRAY,                  -1, -1
4424   },
4425   {
4426     Xfake_door_3,                       TRUE,   FALSE,
4427     EL_EM_GATE_3_GRAY,                  -1, -1
4428   },
4429   {
4430     Xfake_door_4,                       TRUE,   FALSE,
4431     EL_EM_GATE_4_GRAY,                  -1, -1
4432   },
4433   {
4434     Xfake_door_5,                       TRUE,   FALSE,
4435     EL_EMC_GATE_5_GRAY,                 -1, -1
4436   },
4437   {
4438     Xfake_door_6,                       TRUE,   FALSE,
4439     EL_EMC_GATE_6_GRAY,                 -1, -1
4440   },
4441   {
4442     Xfake_door_7,                       TRUE,   FALSE,
4443     EL_EMC_GATE_7_GRAY,                 -1, -1
4444   },
4445   {
4446     Xfake_door_8,                       TRUE,   FALSE,
4447     EL_EMC_GATE_8_GRAY,                 -1, -1
4448   },
4449   {
4450     Xfake_acid_1,                       TRUE,   FALSE,
4451     EL_EMC_FAKE_ACID,                   -1, -1
4452   },
4453   {
4454     Xfake_acid_2,                       FALSE,  FALSE,
4455     EL_EMC_FAKE_ACID,                   -1, -1
4456   },
4457   {
4458     Xfake_acid_3,                       FALSE,  FALSE,
4459     EL_EMC_FAKE_ACID,                   -1, -1
4460   },
4461   {
4462     Xfake_acid_4,                       FALSE,  FALSE,
4463     EL_EMC_FAKE_ACID,                   -1, -1
4464   },
4465   {
4466     Xfake_acid_5,                       FALSE,  FALSE,
4467     EL_EMC_FAKE_ACID,                   -1, -1
4468   },
4469   {
4470     Xfake_acid_6,                       FALSE,  FALSE,
4471     EL_EMC_FAKE_ACID,                   -1, -1
4472   },
4473   {
4474     Xfake_acid_7,                       FALSE,  FALSE,
4475     EL_EMC_FAKE_ACID,                   -1, -1
4476   },
4477   {
4478     Xfake_acid_8,                       FALSE,  FALSE,
4479     EL_EMC_FAKE_ACID,                   -1, -1
4480   },
4481   {
4482     Xsteel_1,                           TRUE,   FALSE,
4483     EL_STEELWALL,                       -1, -1
4484   },
4485   {
4486     Xsteel_2,                           TRUE,   FALSE,
4487     EL_EMC_STEELWALL_2,                 -1, -1
4488   },
4489   {
4490     Xsteel_3,                           TRUE,   FALSE,
4491     EL_EMC_STEELWALL_3,                 -1, -1
4492   },
4493   {
4494     Xsteel_4,                           TRUE,   FALSE,
4495     EL_EMC_STEELWALL_4,                 -1, -1
4496   },
4497   {
4498     Xwall_1,                            TRUE,   FALSE,
4499     EL_WALL,                            -1, -1
4500   },
4501   {
4502     Xwall_2,                            TRUE,   FALSE,
4503     EL_EMC_WALL_14,                     -1, -1
4504   },
4505   {
4506     Xwall_3,                            TRUE,   FALSE,
4507     EL_EMC_WALL_15,                     -1, -1
4508   },
4509   {
4510     Xwall_4,                            TRUE,   FALSE,
4511     EL_EMC_WALL_16,                     -1, -1
4512   },
4513   {
4514     Xround_wall_1,                      TRUE,   FALSE,
4515     EL_WALL_SLIPPERY,                   -1, -1
4516   },
4517   {
4518     Xround_wall_2,                      TRUE,   FALSE,
4519     EL_EMC_WALL_SLIPPERY_2,             -1, -1
4520   },
4521   {
4522     Xround_wall_3,                      TRUE,   FALSE,
4523     EL_EMC_WALL_SLIPPERY_3,             -1, -1
4524   },
4525   {
4526     Xround_wall_4,                      TRUE,   FALSE,
4527     EL_EMC_WALL_SLIPPERY_4,             -1, -1
4528   },
4529   {
4530     Xdecor_1,                           TRUE,   FALSE,
4531     EL_EMC_WALL_8,                      -1, -1
4532   },
4533   {
4534     Xdecor_2,                           TRUE,   FALSE,
4535     EL_EMC_WALL_6,                      -1, -1
4536   },
4537   {
4538     Xdecor_3,                           TRUE,   FALSE,
4539     EL_EMC_WALL_4,                      -1, -1
4540   },
4541   {
4542     Xdecor_4,                           TRUE,   FALSE,
4543     EL_EMC_WALL_7,                      -1, -1
4544   },
4545   {
4546     Xdecor_5,                           TRUE,   FALSE,
4547     EL_EMC_WALL_5,                      -1, -1
4548   },
4549   {
4550     Xdecor_6,                           TRUE,   FALSE,
4551     EL_EMC_WALL_9,                      -1, -1
4552   },
4553   {
4554     Xdecor_7,                           TRUE,   FALSE,
4555     EL_EMC_WALL_10,                     -1, -1
4556   },
4557   {
4558     Xdecor_8,                           TRUE,   FALSE,
4559     EL_EMC_WALL_1,                      -1, -1
4560   },
4561   {
4562     Xdecor_9,                           TRUE,   FALSE,
4563     EL_EMC_WALL_2,                      -1, -1
4564   },
4565   {
4566     Xdecor_10,                          TRUE,   FALSE,
4567     EL_EMC_WALL_3,                      -1, -1
4568   },
4569   {
4570     Xdecor_11,                          TRUE,   FALSE,
4571     EL_EMC_WALL_11,                     -1, -1
4572   },
4573   {
4574     Xdecor_12,                          TRUE,   FALSE,
4575     EL_EMC_WALL_12,                     -1, -1
4576   },
4577   {
4578     Xalpha_0,                           TRUE,   FALSE,
4579     EL_CHAR('0'),                       -1, -1
4580   },
4581   {
4582     Xalpha_1,                           TRUE,   FALSE,
4583     EL_CHAR('1'),                       -1, -1
4584   },
4585   {
4586     Xalpha_2,                           TRUE,   FALSE,
4587     EL_CHAR('2'),                       -1, -1
4588   },
4589   {
4590     Xalpha_3,                           TRUE,   FALSE,
4591     EL_CHAR('3'),                       -1, -1
4592   },
4593   {
4594     Xalpha_4,                           TRUE,   FALSE,
4595     EL_CHAR('4'),                       -1, -1
4596   },
4597   {
4598     Xalpha_5,                           TRUE,   FALSE,
4599     EL_CHAR('5'),                       -1, -1
4600   },
4601   {
4602     Xalpha_6,                           TRUE,   FALSE,
4603     EL_CHAR('6'),                       -1, -1
4604   },
4605   {
4606     Xalpha_7,                           TRUE,   FALSE,
4607     EL_CHAR('7'),                       -1, -1
4608   },
4609   {
4610     Xalpha_8,                           TRUE,   FALSE,
4611     EL_CHAR('8'),                       -1, -1
4612   },
4613   {
4614     Xalpha_9,                           TRUE,   FALSE,
4615     EL_CHAR('9'),                       -1, -1
4616   },
4617   {
4618     Xalpha_excla,                       TRUE,   FALSE,
4619     EL_CHAR('!'),                       -1, -1
4620   },
4621   {
4622     Xalpha_quote,                       TRUE,   FALSE,
4623     EL_CHAR('"'),                       -1, -1
4624   },
4625   {
4626     Xalpha_comma,                       TRUE,   FALSE,
4627     EL_CHAR(','),                       -1, -1
4628   },
4629   {
4630     Xalpha_minus,                       TRUE,   FALSE,
4631     EL_CHAR('-'),                       -1, -1
4632   },
4633   {
4634     Xalpha_perio,                       TRUE,   FALSE,
4635     EL_CHAR('.'),                       -1, -1
4636   },
4637   {
4638     Xalpha_colon,                       TRUE,   FALSE,
4639     EL_CHAR(':'),                       -1, -1
4640   },
4641   {
4642     Xalpha_quest,                       TRUE,   FALSE,
4643     EL_CHAR('?'),                       -1, -1
4644   },
4645   {
4646     Xalpha_a,                           TRUE,   FALSE,
4647     EL_CHAR('A'),                       -1, -1
4648   },
4649   {
4650     Xalpha_b,                           TRUE,   FALSE,
4651     EL_CHAR('B'),                       -1, -1
4652   },
4653   {
4654     Xalpha_c,                           TRUE,   FALSE,
4655     EL_CHAR('C'),                       -1, -1
4656   },
4657   {
4658     Xalpha_d,                           TRUE,   FALSE,
4659     EL_CHAR('D'),                       -1, -1
4660   },
4661   {
4662     Xalpha_e,                           TRUE,   FALSE,
4663     EL_CHAR('E'),                       -1, -1
4664   },
4665   {
4666     Xalpha_f,                           TRUE,   FALSE,
4667     EL_CHAR('F'),                       -1, -1
4668   },
4669   {
4670     Xalpha_g,                           TRUE,   FALSE,
4671     EL_CHAR('G'),                       -1, -1
4672   },
4673   {
4674     Xalpha_h,                           TRUE,   FALSE,
4675     EL_CHAR('H'),                       -1, -1
4676   },
4677   {
4678     Xalpha_i,                           TRUE,   FALSE,
4679     EL_CHAR('I'),                       -1, -1
4680   },
4681   {
4682     Xalpha_j,                           TRUE,   FALSE,
4683     EL_CHAR('J'),                       -1, -1
4684   },
4685   {
4686     Xalpha_k,                           TRUE,   FALSE,
4687     EL_CHAR('K'),                       -1, -1
4688   },
4689   {
4690     Xalpha_l,                           TRUE,   FALSE,
4691     EL_CHAR('L'),                       -1, -1
4692   },
4693   {
4694     Xalpha_m,                           TRUE,   FALSE,
4695     EL_CHAR('M'),                       -1, -1
4696   },
4697   {
4698     Xalpha_n,                           TRUE,   FALSE,
4699     EL_CHAR('N'),                       -1, -1
4700   },
4701   {
4702     Xalpha_o,                           TRUE,   FALSE,
4703     EL_CHAR('O'),                       -1, -1
4704   },
4705   {
4706     Xalpha_p,                           TRUE,   FALSE,
4707     EL_CHAR('P'),                       -1, -1
4708   },
4709   {
4710     Xalpha_q,                           TRUE,   FALSE,
4711     EL_CHAR('Q'),                       -1, -1
4712   },
4713   {
4714     Xalpha_r,                           TRUE,   FALSE,
4715     EL_CHAR('R'),                       -1, -1
4716   },
4717   {
4718     Xalpha_s,                           TRUE,   FALSE,
4719     EL_CHAR('S'),                       -1, -1
4720   },
4721   {
4722     Xalpha_t,                           TRUE,   FALSE,
4723     EL_CHAR('T'),                       -1, -1
4724   },
4725   {
4726     Xalpha_u,                           TRUE,   FALSE,
4727     EL_CHAR('U'),                       -1, -1
4728   },
4729   {
4730     Xalpha_v,                           TRUE,   FALSE,
4731     EL_CHAR('V'),                       -1, -1
4732   },
4733   {
4734     Xalpha_w,                           TRUE,   FALSE,
4735     EL_CHAR('W'),                       -1, -1
4736   },
4737   {
4738     Xalpha_x,                           TRUE,   FALSE,
4739     EL_CHAR('X'),                       -1, -1
4740   },
4741   {
4742     Xalpha_y,                           TRUE,   FALSE,
4743     EL_CHAR('Y'),                       -1, -1
4744   },
4745   {
4746     Xalpha_z,                           TRUE,   FALSE,
4747     EL_CHAR('Z'),                       -1, -1
4748   },
4749   {
4750     Xalpha_arrow_e,                     TRUE,   FALSE,
4751     EL_CHAR('>'),                       -1, -1
4752   },
4753   {
4754     Xalpha_arrow_w,                     TRUE,   FALSE,
4755     EL_CHAR('<'),                       -1, -1
4756   },
4757   {
4758     Xalpha_copyr,                       TRUE,   FALSE,
4759     EL_CHAR('©'),                       -1, -1
4760   },
4761
4762   {
4763     Xboom_bug,                          FALSE,  FALSE,
4764     EL_BUG,                             ACTION_EXPLODING, -1
4765   },
4766   {
4767     Xboom_bomb,                         FALSE,  FALSE,
4768     EL_BOMB,                            ACTION_EXPLODING, -1
4769   },
4770   {
4771     Xboom_android,                      FALSE,  FALSE,
4772     EL_EMC_ANDROID,                     ACTION_OTHER, -1
4773   },
4774   {
4775     Xboom_1,                            FALSE,  FALSE,
4776     EL_DEFAULT,                         ACTION_EXPLODING, -1
4777   },
4778   {
4779     Xboom_2,                            FALSE,  FALSE,
4780     EL_DEFAULT,                         ACTION_EXPLODING, -1
4781   },
4782   {
4783     Znormal,                            FALSE,  FALSE,
4784     EL_EMPTY,                           -1, -1
4785   },
4786   {
4787     Zdynamite,                          FALSE,  FALSE,
4788     EL_EMPTY,                           -1, -1
4789   },
4790   {
4791     Zplayer,                            FALSE,  FALSE,
4792     EL_EMPTY,                           -1, -1
4793   },
4794   {
4795     ZBORDER,                            FALSE,  FALSE,
4796     EL_EMPTY,                           -1, -1
4797   },
4798
4799   {
4800     -1,                                 FALSE,  FALSE,
4801     -1,                                 -1, -1
4802   }
4803 };
4804
4805 static struct Mapping_EM_to_RND_player
4806 {
4807   int action_em;
4808   int player_nr;
4809
4810   int element_rnd;
4811   int action;
4812   int direction;
4813 }
4814 em_player_mapping_list[] =
4815 {
4816   {
4817     SPR_walk + 0,                       0,
4818     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
4819   },
4820   {
4821     SPR_walk + 1,                       0,
4822     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
4823   },
4824   {
4825     SPR_walk + 2,                       0,
4826     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
4827   },
4828   {
4829     SPR_walk + 3,                       0,
4830     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
4831   },
4832   {
4833     SPR_push + 0,                       0,
4834     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
4835   },
4836   {
4837     SPR_push + 1,                       0,
4838     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
4839   },
4840   {
4841     SPR_push + 2,                       0,
4842     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
4843   },
4844   {
4845     SPR_push + 3,                       0,
4846     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
4847   },
4848   {
4849     SPR_spray + 0,                      0,
4850     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
4851   },
4852   {
4853     SPR_spray + 1,                      0,
4854     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
4855   },
4856   {
4857     SPR_spray + 2,                      0,
4858     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
4859   },
4860   {
4861     SPR_spray + 3,                      0,
4862     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
4863   },
4864   {
4865     SPR_walk + 0,                       1,
4866     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
4867   },
4868   {
4869     SPR_walk + 1,                       1,
4870     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
4871   },
4872   {
4873     SPR_walk + 2,                       1,
4874     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
4875   },
4876   {
4877     SPR_walk + 3,                       1,
4878     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
4879   },
4880   {
4881     SPR_push + 0,                       1,
4882     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
4883   },
4884   {
4885     SPR_push + 1,                       1,
4886     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
4887   },
4888   {
4889     SPR_push + 2,                       1,
4890     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
4891   },
4892   {
4893     SPR_push + 3,                       1,
4894     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
4895   },
4896   {
4897     SPR_spray + 0,                      1,
4898     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
4899   },
4900   {
4901     SPR_spray + 1,                      1,
4902     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
4903   },
4904   {
4905     SPR_spray + 2,                      1,
4906     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
4907   },
4908   {
4909     SPR_spray + 3,                      1,
4910     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
4911   },
4912   {
4913     SPR_still,                          0,
4914     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
4915   },
4916   {
4917     SPR_still,                          1,
4918     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
4919   },
4920   {
4921     SPR_walk + 0,                       2,
4922     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
4923   },
4924   {
4925     SPR_walk + 1,                       2,
4926     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
4927   },
4928   {
4929     SPR_walk + 2,                       2,
4930     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
4931   },
4932   {
4933     SPR_walk + 3,                       2,
4934     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
4935   },
4936   {
4937     SPR_push + 0,                       2,
4938     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
4939   },
4940   {
4941     SPR_push + 1,                       2,
4942     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
4943   },
4944   {
4945     SPR_push + 2,                       2,
4946     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
4947   },
4948   {
4949     SPR_push + 3,                       2,
4950     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
4951   },
4952   {
4953     SPR_spray + 0,                      2,
4954     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
4955   },
4956   {
4957     SPR_spray + 1,                      2,
4958     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
4959   },
4960   {
4961     SPR_spray + 2,                      2,
4962     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
4963   },
4964   {
4965     SPR_spray + 3,                      2,
4966     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
4967   },
4968   {
4969     SPR_walk + 0,                       3,
4970     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
4971   },
4972   {
4973     SPR_walk + 1,                       3,
4974     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
4975   },
4976   {
4977     SPR_walk + 2,                       3,
4978     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
4979   },
4980   {
4981     SPR_walk + 3,                       3,
4982     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
4983   },
4984   {
4985     SPR_push + 0,                       3,
4986     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
4987   },
4988   {
4989     SPR_push + 1,                       3,
4990     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
4991   },
4992   {
4993     SPR_push + 2,                       3,
4994     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
4995   },
4996   {
4997     SPR_push + 3,                       3,
4998     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
4999   },
5000   {
5001     SPR_spray + 0,                      3,
5002     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
5003   },
5004   {
5005     SPR_spray + 1,                      3,
5006     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5007   },
5008   {
5009     SPR_spray + 2,                      3,
5010     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
5011   },
5012   {
5013     SPR_spray + 3,                      3,
5014     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
5015   },
5016   {
5017     SPR_still,                          2,
5018     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
5019   },
5020   {
5021     SPR_still,                          3,
5022     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
5023   },
5024
5025   {
5026     -1,                                 -1,
5027     -1,                                 -1, -1
5028   }
5029 };
5030
5031 int map_element_RND_to_EM(int element_rnd)
5032 {
5033   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5034   static boolean mapping_initialized = FALSE;
5035
5036   if (!mapping_initialized)
5037   {
5038     int i;
5039
5040     /* return "Xalpha_quest" for all undefined elements in mapping array */
5041     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5042       mapping_RND_to_EM[i] = Xalpha_quest;
5043
5044     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5045       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5046         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5047           em_object_mapping_list[i].element_em;
5048
5049     mapping_initialized = TRUE;
5050   }
5051
5052   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5053     return mapping_RND_to_EM[element_rnd];
5054
5055   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5056
5057   return EL_UNKNOWN;
5058 }
5059
5060 int map_element_EM_to_RND(int element_em)
5061 {
5062   static unsigned short mapping_EM_to_RND[TILE_MAX];
5063   static boolean mapping_initialized = FALSE;
5064
5065   if (!mapping_initialized)
5066   {
5067     int i;
5068
5069     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5070     for (i = 0; i < TILE_MAX; i++)
5071       mapping_EM_to_RND[i] = EL_UNKNOWN;
5072
5073     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5074       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5075         em_object_mapping_list[i].element_rnd;
5076
5077     mapping_initialized = TRUE;
5078   }
5079
5080   if (element_em >= 0 && element_em < TILE_MAX)
5081     return mapping_EM_to_RND[element_em];
5082
5083   Error(ERR_WARN, "invalid EM level element %d", element_em);
5084
5085   return EL_UNKNOWN;
5086 }
5087
5088 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5089 {
5090   struct LevelInfo_EM *level_em = level->native_em_level;
5091   struct LEVEL *lev = level_em->lev;
5092   int i, j;
5093
5094   for (i = 0; i < TILE_MAX; i++)
5095     lev->android_array[i] = Xblank;
5096
5097   for (i = 0; i < level->num_android_clone_elements; i++)
5098   {
5099     int element_rnd = level->android_clone_element[i];
5100     int element_em = map_element_RND_to_EM(element_rnd);
5101
5102     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5103       if (em_object_mapping_list[j].element_rnd == element_rnd)
5104         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5105   }
5106 }
5107
5108 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5109 {
5110   struct LevelInfo_EM *level_em = level->native_em_level;
5111   struct LEVEL *lev = level_em->lev;
5112   int i, j;
5113
5114   level->num_android_clone_elements = 0;
5115
5116   for (i = 0; i < TILE_MAX; i++)
5117   {
5118     int element_em = lev->android_array[i];
5119     int element_rnd;
5120     boolean element_found = FALSE;
5121
5122     if (element_em == Xblank)
5123       continue;
5124
5125     element_rnd = map_element_EM_to_RND(element_em);
5126
5127     for (j = 0; j < level->num_android_clone_elements; j++)
5128       if (level->android_clone_element[j] == element_rnd)
5129         element_found = TRUE;
5130
5131     if (!element_found)
5132     {
5133       level->android_clone_element[level->num_android_clone_elements++] =
5134         element_rnd;
5135
5136       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5137         break;
5138     }
5139   }
5140
5141   if (level->num_android_clone_elements == 0)
5142   {
5143     level->num_android_clone_elements = 1;
5144     level->android_clone_element[0] = EL_EMPTY;
5145   }
5146 }
5147
5148 int map_direction_RND_to_EM(int direction)
5149 {
5150   return (direction == MV_UP    ? 0 :
5151           direction == MV_RIGHT ? 1 :
5152           direction == MV_DOWN  ? 2 :
5153           direction == MV_LEFT  ? 3 :
5154           -1);
5155 }
5156
5157 int map_direction_EM_to_RND(int direction)
5158 {
5159   return (direction == 0 ? MV_UP    :
5160           direction == 1 ? MV_RIGHT :
5161           direction == 2 ? MV_DOWN  :
5162           direction == 3 ? MV_LEFT  :
5163           MV_NONE);
5164 }
5165
5166 int get_next_element(int element)
5167 {
5168   switch(element)
5169   {
5170     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
5171     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
5172     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
5173     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
5174     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
5175     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
5176     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
5177
5178     default:                            return element;
5179   }
5180 }
5181
5182 #if 0
5183 int el_act_dir2img(int element, int action, int direction)
5184 {
5185   element = GFX_ELEMENT(element);
5186
5187   if (direction == MV_NONE)
5188     return element_info[element].graphic[action];
5189
5190   direction = MV_DIR_TO_BIT(direction);
5191
5192   return element_info[element].direction_graphic[action][direction];
5193 }
5194 #else
5195 int el_act_dir2img(int element, int action, int direction)
5196 {
5197   element = GFX_ELEMENT(element);
5198   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5199
5200   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5201   return element_info[element].direction_graphic[action][direction];
5202 }
5203 #endif
5204
5205 #if 0
5206 static int el_act_dir2crm(int element, int action, int direction)
5207 {
5208   element = GFX_ELEMENT(element);
5209
5210   if (direction == MV_NONE)
5211     return element_info[element].crumbled[action];
5212
5213   direction = MV_DIR_TO_BIT(direction);
5214
5215   return element_info[element].direction_crumbled[action][direction];
5216 }
5217 #else
5218 static int el_act_dir2crm(int element, int action, int direction)
5219 {
5220   element = GFX_ELEMENT(element);
5221   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5222
5223   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5224   return element_info[element].direction_crumbled[action][direction];
5225 }
5226 #endif
5227
5228 int el_act2img(int element, int action)
5229 {
5230   element = GFX_ELEMENT(element);
5231
5232   return element_info[element].graphic[action];
5233 }
5234
5235 int el_act2crm(int element, int action)
5236 {
5237   element = GFX_ELEMENT(element);
5238
5239   return element_info[element].crumbled[action];
5240 }
5241
5242 int el_dir2img(int element, int direction)
5243 {
5244   element = GFX_ELEMENT(element);
5245
5246   return el_act_dir2img(element, ACTION_DEFAULT, direction);
5247 }
5248
5249 int el2baseimg(int element)
5250 {
5251   return element_info[element].graphic[ACTION_DEFAULT];
5252 }
5253
5254 int el2img(int element)
5255 {
5256   element = GFX_ELEMENT(element);
5257
5258   return element_info[element].graphic[ACTION_DEFAULT];
5259 }
5260
5261 int el2edimg(int element)
5262 {
5263   element = GFX_ELEMENT(element);
5264
5265   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5266 }
5267
5268 int el2preimg(int element)
5269 {
5270   element = GFX_ELEMENT(element);
5271
5272   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5273 }
5274
5275 int font2baseimg(int font_nr)
5276 {
5277   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5278 }
5279
5280 #if 0
5281 void setCenteredPlayerNr_EM(int centered_player_nr)
5282 {
5283   game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
5284 }
5285
5286 int getCenteredPlayerNr_EM()
5287 {
5288 #if 0
5289   if (game.centered_player_nr_next >= 0 &&
5290       !native_em_level.ply[game.centered_player_nr_next]->alive)
5291     game.centered_player_nr_next = game.centered_player_nr;
5292 #endif
5293
5294   if (game.centered_player_nr != game.centered_player_nr_next)
5295     game.centered_player_nr = game.centered_player_nr_next;
5296
5297   return game.centered_player_nr;
5298 }
5299
5300 void setSetCenteredPlayer_EM(boolean set_centered_player)
5301 {
5302   game.set_centered_player = set_centered_player;
5303 }
5304
5305 boolean getSetCenteredPlayer_EM()
5306 {
5307   return game.set_centered_player;
5308 }
5309 #endif
5310
5311 int getNumActivePlayers_EM()
5312 {
5313   int num_players = 0;
5314   int i;
5315
5316   if (!tape.playing)
5317     return -1;
5318
5319   for (i = 0; i < MAX_PLAYERS; i++)
5320     if (tape.player_participates[i])
5321       num_players++;
5322
5323   return num_players;
5324 }
5325
5326 #if 1
5327 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5328 {
5329   int game_frame_delay_value;
5330
5331   game_frame_delay_value =
5332     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5333      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5334      GameFrameDelay);
5335
5336   if (tape.playing && tape.warp_forward && !tape.pausing)
5337     game_frame_delay_value = 0;
5338
5339   return game_frame_delay_value;
5340 }
5341 #endif
5342
5343 unsigned int InitRND(long seed)
5344 {
5345   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5346     return InitEngineRND_EM(seed);
5347   else
5348     return InitEngineRND(seed);
5349 }
5350
5351 void InitGraphicInfo_EM(void)
5352 {
5353   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5354   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5355   int i, j, p;
5356
5357 #if DEBUG_EM_GFX
5358   int num_em_gfx_errors = 0;
5359
5360   if (graphic_info_em_object[0][0].bitmap == NULL)
5361   {
5362     /* EM graphics not yet initialized in em_open_all() */
5363
5364     return;
5365   }
5366
5367   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5368 #endif
5369
5370   /* always start with reliable default values */
5371   for (i = 0; i < TILE_MAX; i++)
5372   {
5373     object_mapping[i].element_rnd = EL_UNKNOWN;
5374     object_mapping[i].is_backside = FALSE;
5375     object_mapping[i].action = ACTION_DEFAULT;
5376     object_mapping[i].direction = MV_NONE;
5377   }
5378
5379   /* always start with reliable default values */
5380   for (p = 0; p < MAX_PLAYERS; p++)
5381   {
5382     for (i = 0; i < SPR_MAX; i++)
5383     {
5384       player_mapping[p][i].element_rnd = EL_UNKNOWN;
5385       player_mapping[p][i].action = ACTION_DEFAULT;
5386       player_mapping[p][i].direction = MV_NONE;
5387     }
5388   }
5389
5390   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5391   {
5392     int e = em_object_mapping_list[i].element_em;
5393
5394     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5395     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5396
5397     if (em_object_mapping_list[i].action != -1)
5398       object_mapping[e].action = em_object_mapping_list[i].action;
5399
5400     if (em_object_mapping_list[i].direction != -1)
5401       object_mapping[e].direction =
5402         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5403   }
5404
5405   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5406   {
5407     int a = em_player_mapping_list[i].action_em;
5408     int p = em_player_mapping_list[i].player_nr;
5409
5410     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5411
5412     if (em_player_mapping_list[i].action != -1)
5413       player_mapping[p][a].action = em_player_mapping_list[i].action;
5414
5415     if (em_player_mapping_list[i].direction != -1)
5416       player_mapping[p][a].direction =
5417         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5418   }
5419
5420   for (i = 0; i < TILE_MAX; i++)
5421   {
5422     int element = object_mapping[i].element_rnd;
5423     int action = object_mapping[i].action;
5424     int direction = object_mapping[i].direction;
5425     boolean is_backside = object_mapping[i].is_backside;
5426     boolean action_removing = (action == ACTION_DIGGING ||
5427                                action == ACTION_SNAPPING ||
5428                                action == ACTION_COLLECTING);
5429     boolean action_exploding = ((action == ACTION_EXPLODING ||
5430                                  action == ACTION_SMASHED_BY_ROCK ||
5431                                  action == ACTION_SMASHED_BY_SPRING) &&
5432                                 element != EL_DIAMOND);
5433     boolean action_active = (action == ACTION_ACTIVE);
5434     boolean action_other = (action == ACTION_OTHER);
5435
5436     for (j = 0; j < 8; j++)
5437     {
5438       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5439                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5440                                j < 7 ? element :
5441                                i == Xdrip_stretch ? element :
5442                                i == Xdrip_stretchB ? element :
5443                                i == Ydrip_s1 ? element :
5444                                i == Ydrip_s1B ? element :
5445                                i == Xball_1B ? element :
5446                                i == Xball_2 ? element :
5447                                i == Xball_2B ? element :
5448                                i == Yball_eat ? element :
5449                                i == Ykey_1_eat ? element :
5450                                i == Ykey_2_eat ? element :
5451                                i == Ykey_3_eat ? element :
5452                                i == Ykey_4_eat ? element :
5453                                i == Ykey_5_eat ? element :
5454                                i == Ykey_6_eat ? element :
5455                                i == Ykey_7_eat ? element :
5456                                i == Ykey_8_eat ? element :
5457                                i == Ylenses_eat ? element :
5458                                i == Ymagnify_eat ? element :
5459                                i == Ygrass_eat ? element :
5460                                i == Ydirt_eat ? element :
5461                                i == Yemerald_stone ? EL_EMERALD :
5462                                i == Ydiamond_stone ? EL_ROCK :
5463                                i == Xsand_stonein_1 ? element :
5464                                i == Xsand_stonein_2 ? element :
5465                                i == Xsand_stonein_3 ? element :
5466                                i == Xsand_stonein_4 ? element :
5467                                is_backside ? EL_EMPTY :
5468                                action_removing ? EL_EMPTY :
5469                                element);
5470       int effective_action = (j < 7 ? action :
5471                               i == Xdrip_stretch ? action :
5472                               i == Xdrip_stretchB ? action :
5473                               i == Ydrip_s1 ? action :
5474                               i == Ydrip_s1B ? action :
5475                               i == Xball_1B ? action :
5476                               i == Xball_2 ? action :
5477                               i == Xball_2B ? action :
5478                               i == Yball_eat ? action :
5479                               i == Ykey_1_eat ? action :
5480                               i == Ykey_2_eat ? action :
5481                               i == Ykey_3_eat ? action :
5482                               i == Ykey_4_eat ? action :
5483                               i == Ykey_5_eat ? action :
5484                               i == Ykey_6_eat ? action :
5485                               i == Ykey_7_eat ? action :
5486                               i == Ykey_8_eat ? action :
5487                               i == Ylenses_eat ? action :
5488                               i == Ymagnify_eat ? action :
5489                               i == Ygrass_eat ? action :
5490                               i == Ydirt_eat ? action :
5491                               i == Xsand_stonein_1 ? action :
5492                               i == Xsand_stonein_2 ? action :
5493                               i == Xsand_stonein_3 ? action :
5494                               i == Xsand_stonein_4 ? action :
5495                               i == Xsand_stoneout_1 ? action :
5496                               i == Xsand_stoneout_2 ? action :
5497                               i == Xboom_android ? ACTION_EXPLODING :
5498                               action_exploding ? ACTION_EXPLODING :
5499                               action_active ? action :
5500                               action_other ? action :
5501                               ACTION_DEFAULT);
5502       int graphic = (el_act_dir2img(effective_element, effective_action,
5503                                     direction));
5504       int crumbled = (el_act_dir2crm(effective_element, effective_action,
5505                                      direction));
5506       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5507       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5508       boolean has_action_graphics = (graphic != base_graphic);
5509       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5510       struct GraphicInfo *g = &graphic_info[graphic];
5511       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5512       Bitmap *src_bitmap;
5513       int src_x, src_y;
5514       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5515       boolean special_animation = (action != ACTION_DEFAULT &&
5516                                    g->anim_frames == 3 &&
5517                                    g->anim_delay == 2 &&
5518                                    g->anim_mode & ANIM_LINEAR);
5519       int sync_frame = (i == Xdrip_stretch ? 7 :
5520                         i == Xdrip_stretchB ? 7 :
5521                         i == Ydrip_s2 ? j + 8 :
5522                         i == Ydrip_s2B ? j + 8 :
5523                         i == Xacid_1 ? 0 :
5524                         i == Xacid_2 ? 10 :
5525                         i == Xacid_3 ? 20 :
5526                         i == Xacid_4 ? 30 :
5527                         i == Xacid_5 ? 40 :
5528                         i == Xacid_6 ? 50 :
5529                         i == Xacid_7 ? 60 :
5530                         i == Xacid_8 ? 70 :
5531                         i == Xfake_acid_1 ? 0 :
5532                         i == Xfake_acid_2 ? 10 :
5533                         i == Xfake_acid_3 ? 20 :
5534                         i == Xfake_acid_4 ? 30 :
5535                         i == Xfake_acid_5 ? 40 :
5536                         i == Xfake_acid_6 ? 50 :
5537                         i == Xfake_acid_7 ? 60 :
5538                         i == Xfake_acid_8 ? 70 :
5539                         i == Xball_2 ? 7 :
5540                         i == Xball_2B ? j + 8 :
5541                         i == Yball_eat ? j + 1 :
5542                         i == Ykey_1_eat ? j + 1 :
5543                         i == Ykey_2_eat ? j + 1 :
5544                         i == Ykey_3_eat ? j + 1 :
5545                         i == Ykey_4_eat ? j + 1 :
5546                         i == Ykey_5_eat ? j + 1 :
5547                         i == Ykey_6_eat ? j + 1 :
5548                         i == Ykey_7_eat ? j + 1 :
5549                         i == Ykey_8_eat ? j + 1 :
5550                         i == Ylenses_eat ? j + 1 :
5551                         i == Ymagnify_eat ? j + 1 :
5552                         i == Ygrass_eat ? j + 1 :
5553                         i == Ydirt_eat ? j + 1 :
5554                         i == Xamoeba_1 ? 0 :
5555                         i == Xamoeba_2 ? 1 :
5556                         i == Xamoeba_3 ? 2 :
5557                         i == Xamoeba_4 ? 3 :
5558                         i == Xamoeba_5 ? 0 :
5559                         i == Xamoeba_6 ? 1 :
5560                         i == Xamoeba_7 ? 2 :
5561                         i == Xamoeba_8 ? 3 :
5562                         i == Xexit_2 ? j + 8 :
5563                         i == Xexit_3 ? j + 16 :
5564                         i == Xdynamite_1 ? 0 :
5565                         i == Xdynamite_2 ? 8 :
5566                         i == Xdynamite_3 ? 16 :
5567                         i == Xdynamite_4 ? 24 :
5568                         i == Xsand_stonein_1 ? j + 1 :
5569                         i == Xsand_stonein_2 ? j + 9 :
5570                         i == Xsand_stonein_3 ? j + 17 :
5571                         i == Xsand_stonein_4 ? j + 25 :
5572                         i == Xsand_stoneout_1 && j == 0 ? 0 :
5573                         i == Xsand_stoneout_1 && j == 1 ? 0 :
5574                         i == Xsand_stoneout_1 && j == 2 ? 1 :
5575                         i == Xsand_stoneout_1 && j == 3 ? 2 :
5576                         i == Xsand_stoneout_1 && j == 4 ? 2 :
5577                         i == Xsand_stoneout_1 && j == 5 ? 3 :
5578                         i == Xsand_stoneout_1 && j == 6 ? 4 :
5579                         i == Xsand_stoneout_1 && j == 7 ? 4 :
5580                         i == Xsand_stoneout_2 && j == 0 ? 5 :
5581                         i == Xsand_stoneout_2 && j == 1 ? 6 :
5582                         i == Xsand_stoneout_2 && j == 2 ? 7 :
5583                         i == Xsand_stoneout_2 && j == 3 ? 8 :
5584                         i == Xsand_stoneout_2 && j == 4 ? 9 :
5585                         i == Xsand_stoneout_2 && j == 5 ? 11 :
5586                         i == Xsand_stoneout_2 && j == 6 ? 13 :
5587                         i == Xsand_stoneout_2 && j == 7 ? 15 :
5588                         i == Xboom_bug && j == 1 ? 2 :
5589                         i == Xboom_bug && j == 2 ? 2 :
5590                         i == Xboom_bug && j == 3 ? 4 :
5591                         i == Xboom_bug && j == 4 ? 4 :
5592                         i == Xboom_bug && j == 5 ? 2 :
5593                         i == Xboom_bug && j == 6 ? 2 :
5594                         i == Xboom_bug && j == 7 ? 0 :
5595                         i == Xboom_bomb && j == 1 ? 2 :
5596                         i == Xboom_bomb && j == 2 ? 2 :
5597                         i == Xboom_bomb && j == 3 ? 4 :
5598                         i == Xboom_bomb && j == 4 ? 4 :
5599                         i == Xboom_bomb && j == 5 ? 2 :
5600                         i == Xboom_bomb && j == 6 ? 2 :
5601                         i == Xboom_bomb && j == 7 ? 0 :
5602                         i == Xboom_android && j == 7 ? 6 :
5603                         i == Xboom_1 && j == 1 ? 2 :
5604                         i == Xboom_1 && j == 2 ? 2 :
5605                         i == Xboom_1 && j == 3 ? 4 :
5606                         i == Xboom_1 && j == 4 ? 4 :
5607                         i == Xboom_1 && j == 5 ? 6 :
5608                         i == Xboom_1 && j == 6 ? 6 :
5609                         i == Xboom_1 && j == 7 ? 8 :
5610                         i == Xboom_2 && j == 0 ? 8 :
5611                         i == Xboom_2 && j == 1 ? 8 :
5612                         i == Xboom_2 && j == 2 ? 10 :
5613                         i == Xboom_2 && j == 3 ? 10 :
5614                         i == Xboom_2 && j == 4 ? 10 :
5615                         i == Xboom_2 && j == 5 ? 12 :
5616                         i == Xboom_2 && j == 6 ? 12 :
5617                         i == Xboom_2 && j == 7 ? 12 :
5618                         special_animation && j == 4 ? 3 :
5619                         effective_action != action ? 0 :
5620                         j);
5621
5622 #if DEBUG_EM_GFX
5623       Bitmap *debug_bitmap = g_em->bitmap;
5624       int debug_src_x = g_em->src_x;
5625       int debug_src_y = g_em->src_y;
5626 #endif
5627
5628       int frame = getAnimationFrame(g->anim_frames,
5629                                     g->anim_delay,
5630                                     g->anim_mode,
5631                                     g->anim_start_frame,
5632                                     sync_frame);
5633
5634       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5635                           g->double_movement && is_backside);
5636
5637       g_em->bitmap = src_bitmap;
5638       g_em->src_x = src_x;
5639       g_em->src_y = src_y;
5640       g_em->src_offset_x = 0;
5641       g_em->src_offset_y = 0;
5642       g_em->dst_offset_x = 0;
5643       g_em->dst_offset_y = 0;
5644       g_em->width  = TILEX;
5645       g_em->height = TILEY;
5646
5647       g_em->crumbled_bitmap = NULL;
5648       g_em->crumbled_src_x = 0;
5649       g_em->crumbled_src_y = 0;
5650       g_em->crumbled_border_size = 0;
5651
5652       g_em->has_crumbled_graphics = FALSE;
5653       g_em->preserve_background = FALSE;
5654
5655 #if 0
5656       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5657         printf("::: empty crumbled: %d [%s], %d, %d\n",
5658                effective_element, element_info[effective_element].token_name,
5659                effective_action, direction);
5660 #endif
5661
5662       /* if element can be crumbled, but certain action graphics are just empty
5663          space (like snapping sand with the original R'n'D graphics), do not
5664          treat these empty space graphics as crumbled graphics in EMC engine */
5665       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5666       {
5667         getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5668
5669         g_em->has_crumbled_graphics = TRUE;
5670         g_em->crumbled_bitmap = src_bitmap;
5671         g_em->crumbled_src_x = src_x;
5672         g_em->crumbled_src_y = src_y;
5673         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5674       }
5675
5676 #if 0
5677       if (element == EL_ROCK &&
5678           effective_action == ACTION_FILLING)
5679         printf("::: has_action_graphics == %d\n", has_action_graphics);
5680 #endif
5681
5682       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5683                                    effective_action == ACTION_MOVING  ||
5684                                    effective_action == ACTION_PUSHING ||
5685                                    effective_action == ACTION_EATING)) ||
5686           (!has_action_graphics && (effective_action == ACTION_FILLING ||
5687                                     effective_action == ACTION_EMPTYING)))
5688       {
5689         int move_dir =
5690           (effective_action == ACTION_FALLING ||
5691            effective_action == ACTION_FILLING ||
5692            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5693         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5694         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
5695         int num_steps = (i == Ydrip_s1  ? 16 :
5696                          i == Ydrip_s1B ? 16 :
5697                          i == Ydrip_s2  ? 16 :
5698                          i == Ydrip_s2B ? 16 :
5699                          i == Xsand_stonein_1 ? 32 :
5700                          i == Xsand_stonein_2 ? 32 :
5701                          i == Xsand_stonein_3 ? 32 :
5702                          i == Xsand_stonein_4 ? 32 :
5703                          i == Xsand_stoneout_1 ? 16 :
5704                          i == Xsand_stoneout_2 ? 16 : 8);
5705         int cx = ABS(dx) * (TILEX / num_steps);
5706         int cy = ABS(dy) * (TILEY / num_steps);
5707         int step_frame = (i == Ydrip_s2         ? j + 8 :
5708                           i == Ydrip_s2B        ? j + 8 :
5709                           i == Xsand_stonein_2  ? j + 8 :
5710                           i == Xsand_stonein_3  ? j + 16 :
5711                           i == Xsand_stonein_4  ? j + 24 :
5712                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5713         int step = (is_backside ? step_frame : num_steps - step_frame);
5714
5715         if (is_backside)        /* tile where movement starts */
5716         {
5717           if (dx < 0 || dy < 0)
5718           {
5719             g_em->src_offset_x = cx * step;
5720             g_em->src_offset_y = cy * step;
5721           }
5722           else
5723           {
5724             g_em->dst_offset_x = cx * step;
5725             g_em->dst_offset_y = cy * step;
5726           }
5727         }
5728         else                    /* tile where movement ends */
5729         {
5730           if (dx < 0 || dy < 0)
5731           {
5732             g_em->dst_offset_x = cx * step;
5733             g_em->dst_offset_y = cy * step;
5734           }
5735           else
5736           {
5737             g_em->src_offset_x = cx * step;
5738             g_em->src_offset_y = cy * step;
5739           }
5740         }
5741
5742         g_em->width  = TILEX - cx * step;
5743         g_em->height = TILEY - cy * step;
5744       }
5745
5746 #if 1
5747       /* create unique graphic identifier to decide if tile must be redrawn */
5748       /* bit 31 - 16 (16 bit): EM style graphic
5749          bit 15 - 12 ( 4 bit): EM style frame
5750          bit 11 -  6 ( 6 bit): graphic width
5751          bit  5 -  0 ( 6 bit): graphic height */
5752       g_em->unique_identifier =
5753         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
5754 #else
5755       /* create unique graphic identifier to decide if tile must be redrawn */
5756       /* bit 31 - 16 (16 bit): EM style element
5757          bit 15 - 12 ( 4 bit): EM style frame
5758          bit 11 -  6 ( 6 bit): graphic width
5759          bit  5 -  0 ( 6 bit): graphic height */
5760       g_em->unique_identifier =
5761         (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
5762 #endif
5763
5764 #if 0
5765       if (effective_element == EL_ROCK)
5766         printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
5767                effective_action, j, graphic, frame, g_em->unique_identifier);
5768 #endif
5769
5770 #if DEBUG_EM_GFX
5771
5772 #if 1
5773       /* skip check for EMC elements not contained in original EMC artwork */
5774       if (element == EL_EMC_FAKE_ACID)
5775         continue;
5776 #endif
5777
5778       if (g_em->bitmap != debug_bitmap ||
5779           g_em->src_x != debug_src_x ||
5780           g_em->src_y != debug_src_y ||
5781           g_em->src_offset_x != 0 ||
5782           g_em->src_offset_y != 0 ||
5783           g_em->dst_offset_x != 0 ||
5784           g_em->dst_offset_y != 0 ||
5785           g_em->width != TILEX ||
5786           g_em->height != TILEY)
5787       {
5788         static int last_i = -1;
5789
5790         if (i != last_i)
5791         {
5792           printf("\n");
5793           last_i = i;
5794         }
5795
5796         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
5797                i, element, element_info[element].token_name,
5798                element_action_info[effective_action].suffix, direction);
5799
5800         if (element != effective_element)
5801           printf(" [%d ('%s')]",
5802                  effective_element,
5803                  element_info[effective_element].token_name);
5804
5805         printf("\n");
5806
5807         if (g_em->bitmap != debug_bitmap)
5808           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
5809                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
5810
5811         if (g_em->src_x != debug_src_x ||
5812             g_em->src_y != debug_src_y)
5813           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5814                  j, (is_backside ? 'B' : 'F'),
5815                  g_em->src_x, g_em->src_y,
5816                  g_em->src_x / 32, g_em->src_y / 32,
5817                  debug_src_x, debug_src_y,
5818                  debug_src_x / 32, debug_src_y / 32);
5819
5820         if (g_em->src_offset_x != 0 ||
5821             g_em->src_offset_y != 0 ||
5822             g_em->dst_offset_x != 0 ||
5823             g_em->dst_offset_y != 0)
5824           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
5825                  j, is_backside,
5826                  g_em->src_offset_x, g_em->src_offset_y,
5827                  g_em->dst_offset_x, g_em->dst_offset_y);
5828
5829         if (g_em->width != TILEX ||
5830             g_em->height != TILEY)
5831           printf("    %d (%d): size %d,%d should be %d,%d\n",
5832                  j, is_backside,
5833                  g_em->width, g_em->height, TILEX, TILEY);
5834
5835         num_em_gfx_errors++;
5836       }
5837 #endif
5838
5839     }
5840   }
5841
5842   for (i = 0; i < TILE_MAX; i++)
5843   {
5844     for (j = 0; j < 8; j++)
5845     {
5846       int element = object_mapping[i].element_rnd;
5847       int action = object_mapping[i].action;
5848       int direction = object_mapping[i].direction;
5849       boolean is_backside = object_mapping[i].is_backside;
5850 #if 1
5851       int graphic_action  = el_act_dir2img(element, action, direction);
5852       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
5853 #else
5854       int graphic_action  = element_info[element].graphic[action];
5855       int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
5856 #endif
5857
5858       if ((action == ACTION_SMASHED_BY_ROCK ||
5859            action == ACTION_SMASHED_BY_SPRING ||
5860            action == ACTION_EATING) &&
5861           graphic_action == graphic_default)
5862       {
5863         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
5864                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
5865                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
5866                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
5867                  Xspring);
5868
5869         /* no separate animation for "smashed by rock" -- use rock instead */
5870         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5871         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
5872
5873         g_em->bitmap            = g_xx->bitmap;
5874         g_em->src_x             = g_xx->src_x;
5875         g_em->src_y             = g_xx->src_y;
5876         g_em->src_offset_x      = g_xx->src_offset_x;
5877         g_em->src_offset_y      = g_xx->src_offset_y;
5878         g_em->dst_offset_x      = g_xx->dst_offset_x;
5879         g_em->dst_offset_y      = g_xx->dst_offset_y;
5880         g_em->width             = g_xx->width;
5881         g_em->height            = g_xx->height;
5882 #if 1
5883         g_em->unique_identifier = g_xx->unique_identifier;
5884 #endif
5885
5886         if (!is_backside)
5887           g_em->preserve_background = TRUE;
5888       }
5889     }
5890   }
5891
5892   for (p = 0; p < MAX_PLAYERS; p++)
5893   {
5894     for (i = 0; i < SPR_MAX; i++)
5895     {
5896       int element = player_mapping[p][i].element_rnd;
5897       int action = player_mapping[p][i].action;
5898       int direction = player_mapping[p][i].direction;
5899
5900       for (j = 0; j < 8; j++)
5901       {
5902         int effective_element = element;
5903         int effective_action = action;
5904         int graphic = (direction == MV_NONE ?
5905                        el_act2img(effective_element, effective_action) :
5906                        el_act_dir2img(effective_element, effective_action,
5907                                       direction));
5908         struct GraphicInfo *g = &graphic_info[graphic];
5909         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
5910         Bitmap *src_bitmap;
5911         int src_x, src_y;
5912         int sync_frame = j;
5913
5914 #if DEBUG_EM_GFX
5915         Bitmap *debug_bitmap = g_em->bitmap;
5916         int debug_src_x = g_em->src_x;
5917         int debug_src_y = g_em->src_y;
5918 #endif
5919
5920         int frame = getAnimationFrame(g->anim_frames,
5921                                       g->anim_delay,
5922                                       g->anim_mode,
5923                                       g->anim_start_frame,
5924                                       sync_frame);
5925
5926         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
5927
5928         g_em->bitmap = src_bitmap;
5929         g_em->src_x = src_x;
5930         g_em->src_y = src_y;
5931         g_em->src_offset_x = 0;
5932         g_em->src_offset_y = 0;
5933         g_em->dst_offset_x = 0;
5934         g_em->dst_offset_y = 0;
5935         g_em->width  = TILEX;
5936         g_em->height = TILEY;
5937
5938 #if DEBUG_EM_GFX
5939
5940 #if 1
5941         /* skip check for EMC elements not contained in original EMC artwork */
5942         if (element == EL_PLAYER_3 ||
5943             element == EL_PLAYER_4)
5944           continue;
5945 #endif
5946
5947         if (g_em->bitmap != debug_bitmap ||
5948             g_em->src_x != debug_src_x ||
5949             g_em->src_y != debug_src_y)
5950         {
5951           static int last_i = -1;
5952
5953           if (i != last_i)
5954           {
5955             printf("\n");
5956             last_i = i;
5957           }
5958
5959           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
5960                  p, i, element, element_info[element].token_name,
5961                  element_action_info[effective_action].suffix, direction);
5962
5963           if (element != effective_element)
5964             printf(" [%d ('%s')]",
5965                    effective_element,
5966                    element_info[effective_element].token_name);
5967
5968           printf("\n");
5969
5970           if (g_em->bitmap != debug_bitmap)
5971             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
5972                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
5973
5974           if (g_em->src_x != debug_src_x ||
5975               g_em->src_y != debug_src_y)
5976             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
5977                    j,
5978                    g_em->src_x, g_em->src_y,
5979                    g_em->src_x / 32, g_em->src_y / 32,
5980                    debug_src_x, debug_src_y,
5981                    debug_src_x / 32, debug_src_y / 32);
5982
5983           num_em_gfx_errors++;
5984         }
5985 #endif
5986
5987       }
5988     }
5989   }
5990
5991 #if DEBUG_EM_GFX
5992   printf("\n");
5993   printf("::: [%d errors found]\n", num_em_gfx_errors);
5994
5995   exit(0);
5996 #endif
5997 }
5998
5999 void PlayMenuSound()
6000 {
6001   int sound = menu.sound[game_status];
6002
6003   if (sound == SND_UNDEFINED)
6004     return;
6005
6006   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6007       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6008     return;
6009
6010   if (IS_LOOP_SOUND(sound))
6011     PlaySoundLoop(sound);
6012   else
6013     PlaySound(sound);
6014 }
6015
6016 void PlayMenuSoundStereo(int sound, int stereo_position)
6017 {
6018   if (sound == SND_UNDEFINED)
6019     return;
6020
6021   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6022       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6023     return;
6024
6025   if (IS_LOOP_SOUND(sound))
6026     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6027   else
6028     PlaySoundStereo(sound, stereo_position);
6029 }
6030
6031 void PlayMenuSoundIfLoop()
6032 {
6033   int sound = menu.sound[game_status];
6034
6035   if (sound == SND_UNDEFINED)
6036     return;
6037
6038   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6039       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6040     return;
6041
6042   if (IS_LOOP_SOUND(sound))
6043     PlaySoundLoop(sound);
6044 }
6045
6046 void PlayMenuMusic()
6047 {
6048   int music = menu.music[game_status];
6049
6050   if (music == MUS_UNDEFINED)
6051     return;
6052
6053   PlayMusic(music);
6054 }
6055
6056 void ToggleFullscreenIfNeeded()
6057 {
6058   if (setup.fullscreen != video.fullscreen_enabled ||
6059       setup.fullscreen_mode != video.fullscreen_mode_current)
6060   {
6061     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6062
6063     /* save backbuffer content which gets lost when toggling fullscreen mode */
6064     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6065
6066     if (setup.fullscreen && video.fullscreen_enabled)
6067     {
6068       /* keep fullscreen mode, but change screen mode */
6069       video.fullscreen_mode_current = setup.fullscreen_mode;
6070       video.fullscreen_enabled = FALSE;
6071     }
6072
6073     /* toggle fullscreen */
6074     ChangeVideoModeIfNeeded(setup.fullscreen);
6075     setup.fullscreen = video.fullscreen_enabled;
6076
6077     /* restore backbuffer content from temporary backbuffer backup bitmap */
6078     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6079
6080     FreeBitmap(tmp_backbuffer);
6081
6082     redraw_mask = REDRAW_ALL;
6083   }
6084 }