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