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