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