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