rnd-20070207-2-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "tools.h"
17 #include "game.h"
18 #include "events.h"
19 #include "cartoons.h"
20 #include "network.h"
21 #include "tape.h"
22 #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 #if 1
1616     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1617                    level.envelope[envelope_nr].text, font_nr, max_xsize,
1618                    xsize - 2, ysize - 2, mask_mode,
1619                    level.envelope[envelope_nr].autowrap,
1620                    level.envelope[envelope_nr].centered);
1621 #else
1622     DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1623                        level.envelope[envelope_nr].text, font_nr, max_xsize,
1624                        xsize - 2, ysize - 2, mask_mode);
1625 #endif
1626
1627     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1628     BackToFront();
1629
1630     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1631   }
1632 }
1633
1634 void ShowEnvelope(int envelope_nr)
1635 {
1636   int element = EL_ENVELOPE_1 + envelope_nr;
1637   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1638   int sound_opening = element_info[element].sound[ACTION_OPENING];
1639   int sound_closing = element_info[element].sound[ACTION_CLOSING];
1640   boolean ffwd_delay = (tape.playing && tape.fast_forward);
1641   boolean no_delay = (tape.warp_forward);
1642   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1643   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1644   int anim_mode = graphic_info[graphic].anim_mode;
1645   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1646                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1647
1648   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
1649
1650   PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1651
1652   if (anim_mode == ANIM_DEFAULT)
1653     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1654
1655   AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1656
1657   if (tape.playing)
1658     Delay(wait_delay_value);
1659   else
1660     WaitForEventToContinue();
1661
1662   PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1663
1664   if (anim_mode != ANIM_NONE)
1665     AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1666
1667   if (anim_mode == ANIM_DEFAULT)
1668     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1669
1670   game.envelope_active = FALSE;
1671
1672   SetDrawtoField(DRAW_BUFFERED);
1673
1674   redraw_mask |= REDRAW_FIELD;
1675   BackToFront();
1676 }
1677
1678 void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
1679                              int tilesize)
1680 {
1681   struct
1682   {
1683     int width_mult, width_div;
1684     int height_mult, height_div;
1685   } offset_calc[4] =
1686   {
1687     { 0, 1,     0, 1    },
1688     { 0, 1,     2, 3    },
1689     { 1, 2,     2, 3    },
1690     { 3, 4,     2, 3    },
1691   };
1692   int offset_calc_pos = (tilesize < MICRO_TILESIZE || tilesize > TILESIZE ? 3 :
1693                          5 - log_2(tilesize));
1694   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1695   int width_mult = offset_calc[offset_calc_pos].width_mult;
1696   int width_div = offset_calc[offset_calc_pos].width_div;
1697   int height_mult = offset_calc[offset_calc_pos].height_mult;
1698   int height_div = offset_calc[offset_calc_pos].height_div;
1699   int mini_startx = src_bitmap->width * width_mult / width_div;
1700   int mini_starty = src_bitmap->height * height_mult / height_div;
1701   int src_x = mini_startx + graphic_info[graphic].src_x * tilesize / TILESIZE;
1702   int src_y = mini_starty + graphic_info[graphic].src_y * tilesize / TILESIZE;
1703
1704   *bitmap = src_bitmap;
1705   *x = src_x;
1706   *y = src_y;
1707 }
1708
1709 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1710 {
1711   Bitmap *src_bitmap;
1712   int src_x, src_y;
1713   int graphic = el2preimg(element);
1714
1715   getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
1716   BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1717 }
1718
1719 void DrawLevel()
1720 {
1721   int x,y;
1722
1723   SetDrawBackgroundMask(REDRAW_NONE);
1724   ClearWindow();
1725
1726   for (x = BX1; x <= BX2; x++)
1727     for (y = BY1; y <= BY2; y++)
1728       DrawScreenField(x, y);
1729
1730   redraw_mask |= REDRAW_FIELD;
1731 }
1732
1733 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1734 {
1735   int x,y;
1736
1737   for (x = 0; x < size_x; x++)
1738     for (y = 0; y < size_y; y++)
1739       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1740
1741   redraw_mask |= REDRAW_FIELD;
1742 }
1743
1744 static void DrawPreviewLevelExt(int from_x, int from_y)
1745 {
1746   boolean show_level_border = (BorderElement != EL_EMPTY);
1747   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1748   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1749   int tile_size = preview.tile_size;
1750   int preview_width  = preview.xsize * tile_size;
1751   int preview_height = preview.ysize * tile_size;
1752   int real_preview_xsize = MIN(level_xsize, preview.xsize);
1753   int real_preview_ysize = MIN(level_ysize, preview.ysize);
1754   int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1755   int dst_y = SY + preview.y;
1756   int x, y;
1757
1758   DrawBackground(dst_x, dst_y, preview_width, preview_height);
1759
1760   dst_x += (preview_width  - real_preview_xsize * tile_size) / 2;
1761   dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1762
1763   for (x = 0; x < real_preview_xsize; x++)
1764   {
1765     for (y = 0; y < real_preview_ysize; y++)
1766     {
1767       int lx = from_x + x + (show_level_border ? -1 : 0);
1768       int ly = from_y + y + (show_level_border ? -1 : 0);
1769       int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1770                      getBorderElement(lx, ly));
1771
1772       DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1773                          element, tile_size);
1774     }
1775   }
1776
1777   redraw_mask |= REDRAW_MICROLEVEL;
1778 }
1779
1780 #define MICROLABEL_EMPTY                0
1781 #define MICROLABEL_LEVEL_NAME           1
1782 #define MICROLABEL_LEVEL_AUTHOR_HEAD    2
1783 #define MICROLABEL_LEVEL_AUTHOR         3
1784 #define MICROLABEL_IMPORTED_FROM_HEAD   4
1785 #define MICROLABEL_IMPORTED_FROM        5
1786 #define MICROLABEL_IMPORTED_BY_HEAD     6
1787 #define MICROLABEL_IMPORTED_BY          7
1788
1789 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
1790 {
1791   int max_text_width = SXSIZE;
1792   int font_width = getFontWidth(font_nr);
1793
1794   if (pos->align == ALIGN_CENTER)
1795     max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
1796   else if (pos->align == ALIGN_RIGHT)
1797     max_text_width = pos->x;
1798   else
1799     max_text_width = SXSIZE - pos->x;
1800
1801   return max_text_width / font_width;
1802 }
1803
1804 static void DrawPreviewLevelLabelExt(int mode)
1805 {
1806   struct TextPosInfo *pos = &menu.main.text.level_info_2;
1807   char label_text[MAX_OUTPUT_LINESIZE + 1];
1808   int max_len_label_text;
1809   int font_nr = FONT_TEXT_2;
1810   int i;
1811
1812   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
1813       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
1814       mode == MICROLABEL_IMPORTED_BY_HEAD)
1815     font_nr = FONT_TEXT_3;
1816
1817 #if 1
1818   max_len_label_text = getMaxTextLength(pos, font_nr);
1819 #else
1820   max_len_label_text = SXSIZE / getFontWidth(font_nr);
1821 #endif
1822
1823 #if 1
1824   if (pos->chars != -1)
1825     max_len_label_text = pos->chars;
1826 #endif
1827
1828   for (i = 0; i < max_len_label_text; i++)
1829     label_text[i] = ' ';
1830   label_text[max_len_label_text] = '\0';
1831
1832   if (strlen(label_text) > 0)
1833   {
1834 #if 1
1835     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1836 #else
1837     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1838     int lypos = MICROLABEL2_YPOS;
1839
1840     DrawText(lxpos, lypos, label_text, font_nr);
1841 #endif
1842   }
1843
1844   strncpy(label_text,
1845           (mode == MICROLABEL_LEVEL_NAME ? level.name :
1846            mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1847            mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1848            mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1849            mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1850            mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1851            mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1852           max_len_label_text);
1853   label_text[max_len_label_text] = '\0';
1854
1855   if (strlen(label_text) > 0)
1856   {
1857 #if 1
1858     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1859 #else
1860     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1861     int lypos = MICROLABEL2_YPOS;
1862
1863     DrawText(lxpos, lypos, label_text, font_nr);
1864 #endif
1865   }
1866
1867   redraw_mask |= REDRAW_MICROLEVEL;
1868 }
1869
1870 void DrawPreviewLevel(boolean restart)
1871 {
1872   static unsigned long scroll_delay = 0;
1873   static unsigned long label_delay = 0;
1874   static int from_x, from_y, scroll_direction;
1875   static int label_state, label_counter;
1876   unsigned long scroll_delay_value = preview.step_delay;
1877   boolean show_level_border = (BorderElement != EL_EMPTY);
1878   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1879   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1880   int last_game_status = game_status;           /* save current game status */
1881
1882   /* force PREVIEW font on preview level */
1883   game_status = GAME_MODE_PSEUDO_PREVIEW;
1884
1885   if (restart)
1886   {
1887     from_x = 0;
1888     from_y = 0;
1889
1890     if (preview.anim_mode == ANIM_CENTERED)
1891     {
1892       if (level_xsize > preview.xsize)
1893         from_x = (level_xsize - preview.xsize) / 2;
1894       if (level_ysize > preview.ysize)
1895         from_y = (level_ysize - preview.ysize) / 2;
1896     }
1897
1898     from_x += preview.xoffset;
1899     from_y += preview.yoffset;
1900
1901     scroll_direction = MV_RIGHT;
1902     label_state = 1;
1903     label_counter = 0;
1904
1905     DrawPreviewLevelExt(from_x, from_y);
1906     DrawPreviewLevelLabelExt(label_state);
1907
1908     /* initialize delay counters */
1909     DelayReached(&scroll_delay, 0);
1910     DelayReached(&label_delay, 0);
1911
1912     if (leveldir_current->name)
1913     {
1914       struct TextPosInfo *pos = &menu.main.text.level_info_1;
1915       char label_text[MAX_OUTPUT_LINESIZE + 1];
1916       int font_nr = FONT_TEXT_1;
1917 #if 1
1918       int max_len_label_text = getMaxTextLength(pos, font_nr);
1919 #else
1920       int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1921 #endif
1922 #if 0
1923       int text_width;
1924       int lxpos, lypos;
1925 #endif
1926
1927 #if 1
1928       if (pos->chars != -1)
1929         max_len_label_text = pos->chars;
1930 #endif
1931
1932       strncpy(label_text, leveldir_current->name, max_len_label_text);
1933       label_text[max_len_label_text] = '\0';
1934
1935 #if 1
1936       DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1937 #else
1938       lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1939       lypos = SY + MICROLABEL1_YPOS;
1940
1941       DrawText(lxpos, lypos, label_text, font_nr);
1942 #endif
1943     }
1944
1945     game_status = last_game_status;     /* restore current game status */
1946
1947     return;
1948   }
1949
1950   /* scroll preview level, if needed */
1951   if (preview.anim_mode != ANIM_NONE &&
1952       (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1953       DelayReached(&scroll_delay, scroll_delay_value))
1954   {
1955     switch (scroll_direction)
1956     {
1957       case MV_LEFT:
1958         if (from_x > 0)
1959         {
1960           from_x -= preview.step_offset;
1961           from_x = (from_x < 0 ? 0 : from_x);
1962         }
1963         else
1964           scroll_direction = MV_UP;
1965         break;
1966
1967       case MV_RIGHT:
1968         if (from_x < level_xsize - preview.xsize)
1969         {
1970           from_x += preview.step_offset;
1971           from_x = (from_x > level_xsize - preview.xsize ?
1972                     level_xsize - preview.xsize : from_x);
1973         }
1974         else
1975           scroll_direction = MV_DOWN;
1976         break;
1977
1978       case MV_UP:
1979         if (from_y > 0)
1980         {
1981           from_y -= preview.step_offset;
1982           from_y = (from_y < 0 ? 0 : from_y);
1983         }
1984         else
1985           scroll_direction = MV_RIGHT;
1986         break;
1987
1988       case MV_DOWN:
1989         if (from_y < level_ysize - preview.ysize)
1990         {
1991           from_y += preview.step_offset;
1992           from_y = (from_y > level_ysize - preview.ysize ?
1993                     level_ysize - preview.ysize : from_y);
1994         }
1995         else
1996           scroll_direction = MV_LEFT;
1997         break;
1998
1999       default:
2000         break;
2001     }
2002
2003     DrawPreviewLevelExt(from_x, from_y);
2004   }
2005
2006   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2007   /* redraw micro level label, if needed */
2008   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2009       !strEqual(level.author, ANONYMOUS_NAME) &&
2010       !strEqual(level.author, leveldir_current->name) &&
2011       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2012   {
2013     int max_label_counter = 23;
2014
2015     if (leveldir_current->imported_from != NULL &&
2016         strlen(leveldir_current->imported_from) > 0)
2017       max_label_counter += 14;
2018     if (leveldir_current->imported_by != NULL &&
2019         strlen(leveldir_current->imported_by) > 0)
2020       max_label_counter += 14;
2021
2022     label_counter = (label_counter + 1) % max_label_counter;
2023     label_state = (label_counter >= 0 && label_counter <= 7 ?
2024                    MICROLABEL_LEVEL_NAME :
2025                    label_counter >= 9 && label_counter <= 12 ?
2026                    MICROLABEL_LEVEL_AUTHOR_HEAD :
2027                    label_counter >= 14 && label_counter <= 21 ?
2028                    MICROLABEL_LEVEL_AUTHOR :
2029                    label_counter >= 23 && label_counter <= 26 ?
2030                    MICROLABEL_IMPORTED_FROM_HEAD :
2031                    label_counter >= 28 && label_counter <= 35 ?
2032                    MICROLABEL_IMPORTED_FROM :
2033                    label_counter >= 37 && label_counter <= 40 ?
2034                    MICROLABEL_IMPORTED_BY_HEAD :
2035                    label_counter >= 42 && label_counter <= 49 ?
2036                    MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2037
2038     if (leveldir_current->imported_from == NULL &&
2039         (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2040          label_state == MICROLABEL_IMPORTED_FROM))
2041       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2042                      MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2043
2044     DrawPreviewLevelLabelExt(label_state);
2045   }
2046
2047   game_status = last_game_status;       /* restore current game status */
2048 }
2049
2050 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2051                                     int graphic, int sync_frame, int mask_mode)
2052 {
2053   int frame = getGraphicAnimationFrame(graphic, sync_frame);
2054
2055   if (mask_mode == USE_MASKING)
2056     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2057   else
2058     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2059 }
2060
2061 inline void DrawGraphicAnimation(int x, int y, int graphic)
2062 {
2063   int lx = LEVELX(x), ly = LEVELY(y);
2064
2065   if (!IN_SCR_FIELD(x, y))
2066     return;
2067
2068   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2069                           graphic, GfxFrame[lx][ly], NO_MASKING);
2070   MarkTileDirty(x, y);
2071 }
2072
2073 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2074 {
2075   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2076 }
2077
2078 void DrawLevelElementAnimation(int x, int y, int element)
2079 {
2080   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2081
2082   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2083 }
2084
2085 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2086 {
2087   int sx = SCREENX(x), sy = SCREENY(y);
2088
2089   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2090     return;
2091
2092   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2093     return;
2094
2095   DrawGraphicAnimation(sx, sy, graphic);
2096
2097 #if 1
2098   if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2099     DrawLevelFieldCrumbledSand(x, y);
2100 #else
2101   if (GFX_CRUMBLED(Feld[x][y]))
2102     DrawLevelFieldCrumbledSand(x, y);
2103 #endif
2104 }
2105
2106 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2107 {
2108   int sx = SCREENX(x), sy = SCREENY(y);
2109   int graphic;
2110
2111   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2112     return;
2113
2114   graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2115
2116   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2117     return;
2118
2119   DrawGraphicAnimation(sx, sy, graphic);
2120
2121   if (GFX_CRUMBLED(element))
2122     DrawLevelFieldCrumbledSand(x, y);
2123 }
2124
2125 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2126 {
2127   if (player->use_murphy)
2128   {
2129     /* this works only because currently only one player can be "murphy" ... */
2130     static int last_horizontal_dir = MV_LEFT;
2131     int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2132
2133     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2134       last_horizontal_dir = move_dir;
2135
2136     if (graphic == IMG_SP_MURPHY)       /* undefined => use special graphic */
2137     {
2138       int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2139
2140       graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2141     }
2142
2143     return graphic;
2144   }
2145   else
2146     return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2147 }
2148
2149 static boolean equalGraphics(int graphic1, int graphic2)
2150 {
2151   struct GraphicInfo *g1 = &graphic_info[graphic1];
2152   struct GraphicInfo *g2 = &graphic_info[graphic2];
2153
2154   return (g1->bitmap      == g2->bitmap &&
2155           g1->src_x       == g2->src_x &&
2156           g1->src_y       == g2->src_y &&
2157           g1->anim_frames == g2->anim_frames &&
2158           g1->anim_delay  == g2->anim_delay &&
2159           g1->anim_mode   == g2->anim_mode);
2160 }
2161
2162 void DrawAllPlayers()
2163 {
2164   int i;
2165
2166   for (i = 0; i < MAX_PLAYERS; i++)
2167     if (stored_player[i].active)
2168       DrawPlayer(&stored_player[i]);
2169 }
2170
2171 void DrawPlayerField(int x, int y)
2172 {
2173   if (!IS_PLAYER(x, y))
2174     return;
2175
2176   DrawPlayer(PLAYERINFO(x, y));
2177 }
2178
2179 void DrawPlayer(struct PlayerInfo *player)
2180 {
2181   int jx = player->jx;
2182   int jy = player->jy;
2183   int move_dir = player->MovDir;
2184   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2185   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
2186   int last_jx = (player->is_moving ? jx - dx : jx);
2187   int last_jy = (player->is_moving ? jy - dy : jy);
2188   int next_jx = jx + dx;
2189   int next_jy = jy + dy;
2190   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2191   boolean player_is_opaque = FALSE;
2192   int sx = SCREENX(jx), sy = SCREENY(jy);
2193   int sxx = 0, syy = 0;
2194   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2195   int graphic;
2196   int action = ACTION_DEFAULT;
2197   int last_player_graphic = getPlayerGraphic(player, move_dir);
2198   int last_player_frame = player->Frame;
2199   int frame = 0;
2200
2201   /* GfxElement[][] is set to the element the player is digging or collecting;
2202      remove also for off-screen player if the player is not moving anymore */
2203   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2204     GfxElement[jx][jy] = EL_UNDEFINED;
2205
2206   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2207     return;
2208
2209 #if DEBUG
2210   if (!IN_LEV_FIELD(jx, jy))
2211   {
2212     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2213     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2214     printf("DrawPlayerField(): This should never happen!\n");
2215     return;
2216   }
2217 #endif
2218
2219   if (element == EL_EXPLOSION)
2220     return;
2221
2222   action = (player->is_pushing    ? ACTION_PUSHING         :
2223             player->is_digging    ? ACTION_DIGGING         :
2224             player->is_collecting ? ACTION_COLLECTING      :
2225             player->is_moving     ? ACTION_MOVING          :
2226             player->is_snapping   ? ACTION_SNAPPING        :
2227             player->is_dropping   ? ACTION_DROPPING        :
2228             player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
2229
2230   if (player->is_waiting)
2231     move_dir = player->dir_waiting;
2232
2233   InitPlayerGfxAnimation(player, action, move_dir);
2234
2235   /* ----------------------------------------------------------------------- */
2236   /* draw things in the field the player is leaving, if needed               */
2237   /* ----------------------------------------------------------------------- */
2238
2239   if (player->is_moving)
2240   {
2241     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2242     {
2243       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2244
2245       if (last_element == EL_DYNAMITE_ACTIVE ||
2246           last_element == EL_EM_DYNAMITE_ACTIVE ||
2247           last_element == EL_SP_DISK_RED_ACTIVE)
2248         DrawDynamite(last_jx, last_jy);
2249       else
2250         DrawLevelFieldThruMask(last_jx, last_jy);
2251     }
2252     else if (last_element == EL_DYNAMITE_ACTIVE ||
2253              last_element == EL_EM_DYNAMITE_ACTIVE ||
2254              last_element == EL_SP_DISK_RED_ACTIVE)
2255       DrawDynamite(last_jx, last_jy);
2256 #if 0
2257     /* !!! this is not enough to prevent flickering of players which are
2258        moving next to each others without a free tile between them -- this
2259        can only be solved by drawing all players layer by layer (first the
2260        background, then the foreground etc.) !!! => TODO */
2261     else if (!IS_PLAYER(last_jx, last_jy))
2262       DrawLevelField(last_jx, last_jy);
2263 #else
2264     else
2265       DrawLevelField(last_jx, last_jy);
2266 #endif
2267
2268     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2269       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2270   }
2271
2272   if (!IN_SCR_FIELD(sx, sy))
2273     return;
2274
2275   if (setup.direct_draw)
2276     SetDrawtoField(DRAW_BUFFERED);
2277
2278   /* ----------------------------------------------------------------------- */
2279   /* draw things behind the player, if needed                                */
2280   /* ----------------------------------------------------------------------- */
2281
2282   if (Back[jx][jy])
2283     DrawLevelElement(jx, jy, Back[jx][jy]);
2284   else if (IS_ACTIVE_BOMB(element))
2285     DrawLevelElement(jx, jy, EL_EMPTY);
2286   else
2287   {
2288     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2289     {
2290       int old_element = GfxElement[jx][jy];
2291       int old_graphic = el_act_dir2img(old_element, action, move_dir);
2292       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2293
2294       if (GFX_CRUMBLED(old_element))
2295         DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2296       else
2297         DrawGraphic(sx, sy, old_graphic, frame);
2298
2299       if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2300         player_is_opaque = TRUE;
2301     }
2302     else
2303     {
2304       GfxElement[jx][jy] = EL_UNDEFINED;
2305
2306       /* make sure that pushed elements are drawn with correct frame rate */
2307 #if 1
2308       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2309
2310       if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2311         GfxFrame[jx][jy] = player->StepFrame;
2312 #else
2313       if (player->is_pushing && player->is_moving)
2314         GfxFrame[jx][jy] = player->StepFrame;
2315 #endif
2316
2317       DrawLevelField(jx, jy);
2318     }
2319   }
2320
2321   /* ----------------------------------------------------------------------- */
2322   /* draw player himself                                                     */
2323   /* ----------------------------------------------------------------------- */
2324
2325   graphic = getPlayerGraphic(player, move_dir);
2326
2327   /* in the case of changed player action or direction, prevent the current
2328      animation frame from being restarted for identical animations */
2329   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2330     player->Frame = last_player_frame;
2331
2332   frame = getGraphicAnimationFrame(graphic, player->Frame);
2333
2334   if (player->GfxPos)
2335   {
2336     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2337       sxx = player->GfxPos;
2338     else
2339       syy = player->GfxPos;
2340   }
2341
2342   if (!setup.soft_scrolling && ScreenMovPos)
2343     sxx = syy = 0;
2344
2345   if (player_is_opaque)
2346     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2347   else
2348     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2349
2350   if (SHIELD_ON(player))
2351   {
2352     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2353                    IMG_SHIELD_NORMAL_ACTIVE);
2354     int frame = getGraphicAnimationFrame(graphic, -1);
2355
2356     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2357   }
2358
2359   /* ----------------------------------------------------------------------- */
2360   /* draw things the player is pushing, if needed                            */
2361   /* ----------------------------------------------------------------------- */
2362
2363 #if 0
2364   printf("::: %d, %d [%d, %d] [%d]\n",
2365          player->is_pushing, player_is_moving, player->GfxAction,
2366          player->is_moving, player_is_moving);
2367 #endif
2368
2369 #if 1
2370   if (player->is_pushing && player->is_moving)
2371   {
2372     int px = SCREENX(jx), py = SCREENY(jy);
2373     int pxx = (TILEX - ABS(sxx)) * dx;
2374     int pyy = (TILEY - ABS(syy)) * dy;
2375     int gfx_frame = GfxFrame[jx][jy];
2376
2377     int graphic;
2378     int sync_frame;
2379     int frame;
2380
2381     if (!IS_MOVING(jx, jy))             /* push movement already finished */
2382     {
2383       element = Feld[next_jx][next_jy];
2384       gfx_frame = GfxFrame[next_jx][next_jy];
2385     }
2386
2387     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2388
2389 #if 1
2390     sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2391     frame = getGraphicAnimationFrame(graphic, sync_frame);
2392 #else
2393     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2394 #endif
2395
2396     /* draw background element under pushed element (like the Sokoban field) */
2397     if (Back[next_jx][next_jy])
2398       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2399
2400     /* masked drawing is needed for EMC style (double) movement graphics */
2401     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2402   }
2403 #endif
2404
2405   /* ----------------------------------------------------------------------- */
2406   /* draw things in front of player (active dynamite or dynabombs)           */
2407   /* ----------------------------------------------------------------------- */
2408
2409   if (IS_ACTIVE_BOMB(element))
2410   {
2411     graphic = el2img(element);
2412     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2413
2414     if (game.emulation == EMU_SUPAPLEX)
2415       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2416     else
2417       DrawGraphicThruMask(sx, sy, graphic, frame);
2418   }
2419
2420   if (player_is_moving && last_element == EL_EXPLOSION)
2421   {
2422     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2423                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
2424     int graphic = el_act2img(element, ACTION_EXPLODING);
2425     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2426     int phase = ExplodePhase[last_jx][last_jy] - 1;
2427     int frame = getGraphicAnimationFrame(graphic, phase - delay);
2428
2429     if (phase >= delay)
2430       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2431   }
2432
2433   /* ----------------------------------------------------------------------- */
2434   /* draw elements the player is just walking/passing through/under          */
2435   /* ----------------------------------------------------------------------- */
2436
2437   if (player_is_moving)
2438   {
2439     /* handle the field the player is leaving ... */
2440     if (IS_ACCESSIBLE_INSIDE(last_element))
2441       DrawLevelField(last_jx, last_jy);
2442     else if (IS_ACCESSIBLE_UNDER(last_element))
2443       DrawLevelFieldThruMask(last_jx, last_jy);
2444   }
2445
2446   /* do not redraw accessible elements if the player is just pushing them */
2447   if (!player_is_moving || !player->is_pushing)
2448   {
2449     /* ... and the field the player is entering */
2450     if (IS_ACCESSIBLE_INSIDE(element))
2451       DrawLevelField(jx, jy);
2452     else if (IS_ACCESSIBLE_UNDER(element))
2453       DrawLevelFieldThruMask(jx, jy);
2454   }
2455
2456   if (setup.direct_draw)
2457   {
2458     int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2459     int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2460     int x_size = TILEX * (1 + ABS(jx - last_jx));
2461     int y_size = TILEY * (1 + ABS(jy - last_jy));
2462
2463     BlitBitmap(drawto_field, window,
2464                dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2465     SetDrawtoField(DRAW_DIRECT);
2466   }
2467
2468   MarkTileDirty(sx, sy);
2469 }
2470
2471 /* ------------------------------------------------------------------------- */
2472
2473 void WaitForEventToContinue()
2474 {
2475   boolean still_wait = TRUE;
2476
2477   /* simulate releasing mouse button over last gadget, if still pressed */
2478   if (button_status)
2479     HandleGadgets(-1, -1, 0);
2480
2481   button_status = MB_RELEASED;
2482
2483 #if 1
2484   ClearEventQueue();
2485 #endif
2486
2487   while (still_wait)
2488   {
2489     if (PendingEvent())
2490     {
2491       Event event;
2492
2493       NextEvent(&event);
2494
2495       switch (event.type)
2496       {
2497         case EVENT_BUTTONPRESS:
2498         case EVENT_KEYPRESS:
2499           still_wait = FALSE;
2500           break;
2501
2502         case EVENT_KEYRELEASE:
2503           ClearPlayerAction();
2504           break;
2505
2506         default:
2507           HandleOtherEvents(&event);
2508           break;
2509       }
2510     }
2511     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2512     {
2513       still_wait = FALSE;
2514     }
2515
2516     DoAnimation();
2517
2518     /* don't eat all CPU time */
2519     Delay(10);
2520   }
2521 }
2522
2523 #define MAX_REQUEST_LINES               13
2524 #define MAX_REQUEST_LINE_FONT1_LEN      7
2525 #define MAX_REQUEST_LINE_FONT2_LEN      10
2526
2527 boolean Request(char *text, unsigned int req_state)
2528 {
2529   int mx, my, ty, result = -1;
2530   unsigned int old_door_state;
2531   int last_game_status = game_status;   /* save current game status */
2532   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2533   int font_nr = FONT_TEXT_2;
2534   int max_word_len = 0;
2535   char *text_ptr;
2536
2537   for (text_ptr = text; *text_ptr; text_ptr++)
2538   {
2539     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2540
2541     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2542     {
2543       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2544 #if 1
2545       font_nr = FONT_TEXT_1;
2546 #else
2547       font_nr = FONT_LEVEL_NUMBER;
2548 #endif
2549
2550       break;
2551     }
2552   }
2553
2554   if (game_status == GAME_MODE_PLAYING &&
2555       level.game_engine_type == GAME_ENGINE_TYPE_EM)
2556     BlitScreenToBitmap_EM(backbuffer);
2557
2558   /* disable deactivated drawing when quick-loading level tape recording */
2559   if (tape.playing && tape.deactivate_display)
2560     TapeDeactivateDisplayOff(TRUE);
2561
2562   SetMouseCursor(CURSOR_DEFAULT);
2563
2564 #if defined(NETWORK_AVALIABLE)
2565   /* pause network game while waiting for request to answer */
2566   if (options.network &&
2567       game_status == GAME_MODE_PLAYING &&
2568       req_state & REQUEST_WAIT_FOR_INPUT)
2569     SendToServer_PausePlaying();
2570 #endif
2571
2572   old_door_state = GetDoorState();
2573
2574   /* simulate releasing mouse button over last gadget, if still pressed */
2575   if (button_status)
2576     HandleGadgets(-1, -1, 0);
2577
2578   UnmapAllGadgets();
2579
2580   if (old_door_state & DOOR_OPEN_1)
2581   {
2582     CloseDoor(DOOR_CLOSE_1);
2583
2584     /* save old door content */
2585     BlitBitmap(bitmap_db_door, bitmap_db_door,
2586                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2587                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2588   }
2589
2590 #if 1
2591   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2592 #endif
2593
2594   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2595
2596   /* clear door drawing field */
2597   DrawBackground(DX, DY, DXSIZE, DYSIZE);
2598
2599   /* force DOOR font on preview level */
2600   game_status = GAME_MODE_PSEUDO_DOOR;
2601
2602   /* write text for request */
2603   for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2604   {
2605     char text_line[max_request_line_len + 1];
2606     int tx, tl, tc = 0;
2607
2608     if (!*text)
2609       break;
2610
2611     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2612     {
2613       tc = *(text + tx);
2614       if (!tc || tc == ' ')
2615         break;
2616     }
2617
2618     if (!tl)
2619     { 
2620       text++; 
2621       ty--; 
2622       continue; 
2623     }
2624
2625     strncpy(text_line, text, tl);
2626     text_line[tl] = 0;
2627
2628     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2629              DY + 8 + ty * (getFontHeight(font_nr) + 2),
2630              text_line, font_nr);
2631
2632     text += tl + (tc == ' ' ? 1 : 0);
2633   }
2634
2635   game_status = last_game_status;       /* restore current game status */
2636
2637   if (req_state & REQ_ASK)
2638   {
2639     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2640     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2641   }
2642   else if (req_state & REQ_CONFIRM)
2643   {
2644     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2645   }
2646   else if (req_state & REQ_PLAYER)
2647   {
2648     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2649     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2650     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2651     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2652   }
2653
2654   /* copy request gadgets to door backbuffer */
2655   BlitBitmap(drawto, bitmap_db_door,
2656              DX, DY, DXSIZE, DYSIZE,
2657              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2658
2659   OpenDoor(DOOR_OPEN_1);
2660
2661   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2662   {
2663     if (game_status == GAME_MODE_PLAYING)
2664     {
2665       SetPanelBackground();
2666       SetDrawBackgroundMask(REDRAW_DOOR_1);
2667     }
2668     else
2669     {
2670       SetDrawBackgroundMask(REDRAW_FIELD);
2671     }
2672
2673     return FALSE;
2674   }
2675
2676   if (game_status != GAME_MODE_MAIN)
2677     InitAnimation();
2678
2679   button_status = MB_RELEASED;
2680
2681   request_gadget_id = -1;
2682
2683   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2684
2685   while (result < 0)
2686   {
2687     if (PendingEvent())
2688     {
2689       Event event;
2690
2691       NextEvent(&event);
2692
2693       switch (event.type)
2694       {
2695         case EVENT_BUTTONPRESS:
2696         case EVENT_BUTTONRELEASE:
2697         case EVENT_MOTIONNOTIFY:
2698         {
2699           if (event.type == EVENT_MOTIONNOTIFY)
2700           {
2701             if (!PointerInWindow(window))
2702               continue; /* window and pointer are on different screens */
2703
2704             if (!button_status)
2705               continue;
2706
2707             motion_status = TRUE;
2708             mx = ((MotionEvent *) &event)->x;
2709             my = ((MotionEvent *) &event)->y;
2710           }
2711           else
2712           {
2713             motion_status = FALSE;
2714             mx = ((ButtonEvent *) &event)->x;
2715             my = ((ButtonEvent *) &event)->y;
2716             if (event.type == EVENT_BUTTONPRESS)
2717               button_status = ((ButtonEvent *) &event)->button;
2718             else
2719               button_status = MB_RELEASED;
2720           }
2721
2722           /* this sets 'request_gadget_id' */
2723           HandleGadgets(mx, my, button_status);
2724
2725           switch (request_gadget_id)
2726           {
2727             case TOOL_CTRL_ID_YES:
2728               result = TRUE;
2729               break;
2730             case TOOL_CTRL_ID_NO:
2731               result = FALSE;
2732               break;
2733             case TOOL_CTRL_ID_CONFIRM:
2734               result = TRUE | FALSE;
2735               break;
2736
2737             case TOOL_CTRL_ID_PLAYER_1:
2738               result = 1;
2739               break;
2740             case TOOL_CTRL_ID_PLAYER_2:
2741               result = 2;
2742               break;
2743             case TOOL_CTRL_ID_PLAYER_3:
2744               result = 3;
2745               break;
2746             case TOOL_CTRL_ID_PLAYER_4:
2747               result = 4;
2748               break;
2749
2750             default:
2751               break;
2752           }
2753
2754           break;
2755         }
2756
2757         case EVENT_KEYPRESS:
2758           switch (GetEventKey((KeyEvent *)&event, TRUE))
2759           {
2760             case KSYM_Return:
2761               result = 1;
2762               break;
2763
2764             case KSYM_Escape:
2765               result = 0;
2766               break;
2767
2768             default:
2769               break;
2770           }
2771           if (req_state & REQ_PLAYER)
2772             result = 0;
2773           break;
2774
2775         case EVENT_KEYRELEASE:
2776           ClearPlayerAction();
2777           break;
2778
2779         default:
2780           HandleOtherEvents(&event);
2781           break;
2782       }
2783     }
2784     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2785     {
2786       int joy = AnyJoystick();
2787
2788       if (joy & JOY_BUTTON_1)
2789         result = 1;
2790       else if (joy & JOY_BUTTON_2)
2791         result = 0;
2792     }
2793
2794 #if 1
2795
2796     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2797     {
2798       HandleGameActions();
2799       BackToFront();
2800     }
2801     else
2802     {
2803       DoAnimation();
2804
2805       if (!PendingEvent())      /* delay only if no pending events */
2806         Delay(10);
2807     }
2808
2809 #else
2810
2811     DoAnimation();
2812
2813 #if 1
2814     if (!PendingEvent())        /* delay only if no pending events */
2815       Delay(10);
2816 #else
2817     /* don't eat all CPU time */
2818     Delay(10);
2819 #endif
2820
2821 #endif
2822   }
2823
2824   if (game_status != GAME_MODE_MAIN)
2825     StopAnimation();
2826
2827   UnmapToolButtons();
2828
2829   if (!(req_state & REQ_STAY_OPEN))
2830   {
2831     CloseDoor(DOOR_CLOSE_1);
2832
2833     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2834         (req_state & REQ_REOPEN))
2835       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2836   }
2837
2838   RemapAllGadgets();
2839
2840   if (game_status == GAME_MODE_PLAYING)
2841   {
2842     SetPanelBackground();
2843     SetDrawBackgroundMask(REDRAW_DOOR_1);
2844   }
2845   else
2846   {
2847     SetDrawBackgroundMask(REDRAW_FIELD);
2848   }
2849
2850 #if defined(NETWORK_AVALIABLE)
2851   /* continue network game after request */
2852   if (options.network &&
2853       game_status == GAME_MODE_PLAYING &&
2854       req_state & REQUEST_WAIT_FOR_INPUT)
2855     SendToServer_ContinuePlaying();
2856 #endif
2857
2858   /* restore deactivated drawing when quick-loading level tape recording */
2859   if (tape.playing && tape.deactivate_display)
2860     TapeDeactivateDisplayOn();
2861
2862   return result;
2863 }
2864
2865 unsigned int OpenDoor(unsigned int door_state)
2866 {
2867   if (door_state & DOOR_COPY_BACK)
2868   {
2869     if (door_state & DOOR_OPEN_1)
2870       BlitBitmap(bitmap_db_door, bitmap_db_door,
2871                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2872                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2873
2874     if (door_state & DOOR_OPEN_2)
2875       BlitBitmap(bitmap_db_door, bitmap_db_door,
2876                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2877                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2878
2879     door_state &= ~DOOR_COPY_BACK;
2880   }
2881
2882   return MoveDoor(door_state);
2883 }
2884
2885 unsigned int CloseDoor(unsigned int door_state)
2886 {
2887   unsigned int old_door_state = GetDoorState();
2888
2889   if (!(door_state & DOOR_NO_COPY_BACK))
2890   {
2891     if (old_door_state & DOOR_OPEN_1)
2892       BlitBitmap(backbuffer, bitmap_db_door,
2893                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2894
2895     if (old_door_state & DOOR_OPEN_2)
2896       BlitBitmap(backbuffer, bitmap_db_door,
2897                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2898
2899     door_state &= ~DOOR_NO_COPY_BACK;
2900   }
2901
2902   return MoveDoor(door_state);
2903 }
2904
2905 unsigned int GetDoorState()
2906 {
2907   return MoveDoor(DOOR_GET_STATE);
2908 }
2909
2910 unsigned int SetDoorState(unsigned int door_state)
2911 {
2912   return MoveDoor(door_state | DOOR_SET_STATE);
2913 }
2914
2915 unsigned int MoveDoor(unsigned int door_state)
2916 {
2917   static int door1 = DOOR_OPEN_1;
2918   static int door2 = DOOR_CLOSE_2;
2919   unsigned long door_delay = 0;
2920   unsigned long door_delay_value;
2921   int stepsize = 1;
2922
2923   if (door_1.width < 0 || door_1.width > DXSIZE)
2924     door_1.width = DXSIZE;
2925   if (door_1.height < 0 || door_1.height > DYSIZE)
2926     door_1.height = DYSIZE;
2927   if (door_2.width < 0 || door_2.width > VXSIZE)
2928     door_2.width = VXSIZE;
2929   if (door_2.height < 0 || door_2.height > VYSIZE)
2930     door_2.height = VYSIZE;
2931
2932   if (door_state == DOOR_GET_STATE)
2933     return (door1 | door2);
2934
2935   if (door_state & DOOR_SET_STATE)
2936   {
2937     if (door_state & DOOR_ACTION_1)
2938       door1 = door_state & DOOR_ACTION_1;
2939     if (door_state & DOOR_ACTION_2)
2940       door2 = door_state & DOOR_ACTION_2;
2941
2942     return (door1 | door2);
2943   }
2944
2945   if (!(door_state & DOOR_FORCE_REDRAW))
2946   {
2947     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2948       door_state &= ~DOOR_OPEN_1;
2949     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2950       door_state &= ~DOOR_CLOSE_1;
2951     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2952       door_state &= ~DOOR_OPEN_2;
2953     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2954       door_state &= ~DOOR_CLOSE_2;
2955   }
2956
2957   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2958                       door_2.step_delay);
2959
2960   if (setup.quick_doors)
2961   {
2962     stepsize = 20;              /* must be choosen to always draw last frame */
2963     door_delay_value = 0;
2964   }
2965
2966   if (global.autoplay_leveldir)
2967   {
2968     door_state |= DOOR_NO_DELAY;
2969     door_state &= ~DOOR_CLOSE_ALL;
2970   }
2971
2972   if (door_state & DOOR_ACTION)
2973   {
2974     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
2975     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
2976     boolean door_1_done = (!handle_door_1);
2977     boolean door_2_done = (!handle_door_2);
2978     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
2979     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
2980     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
2981     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
2982     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
2983     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
2984     int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
2985     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
2986     int door_skip = max_door_size - door_size;
2987     int end = door_size;
2988     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
2989     int k;
2990
2991     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
2992     {
2993       /* opening door sound has priority over simultaneously closing door */
2994       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2995         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2996       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2997         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2998     }
2999
3000     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3001     {
3002       int x = k;
3003       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3004       GC gc = bitmap->stored_clip_gc;
3005
3006       if (door_state & DOOR_ACTION_1)
3007       {
3008         int a = MIN(x * door_1.step_offset, end);
3009         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3010         int i = p + door_skip;
3011
3012         if (door_1.anim_mode & ANIM_STATIC_PANEL)
3013         {
3014           BlitBitmap(bitmap_db_door, drawto,
3015                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3016                      DXSIZE, DYSIZE, DX, DY);
3017         }
3018         else if (x <= a)
3019         {
3020           BlitBitmap(bitmap_db_door, drawto,
3021                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3022                      DXSIZE, DYSIZE - p / 2, DX, DY);
3023
3024           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3025         }
3026
3027         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3028         {
3029           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
3030           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3031           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
3032           int dst2_x = DX,              dst2_y = DY;
3033           int width = i, height = DYSIZE;
3034
3035           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3036           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3037                            dst1_x, dst1_y);
3038
3039           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3040           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3041                            dst2_x, dst2_y);
3042         }
3043         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3044         {
3045           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
3046           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
3047           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3048           int dst2_x = DX,              dst2_y = DY;
3049           int width = DXSIZE, height = i;
3050
3051           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3052           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3053                            dst1_x, dst1_y);
3054
3055           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3056           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3057                            dst2_x, dst2_y);
3058         }
3059         else if (x <= DXSIZE)   /* ANIM_DEFAULT */
3060         {
3061           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3062
3063           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3064           BlitBitmapMasked(bitmap, drawto,
3065                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3066                            DX + DXSIZE - i, DY + j);
3067           BlitBitmapMasked(bitmap, drawto,
3068                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3069                            DX + DXSIZE - i, DY + 140 + j);
3070           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3071                         DY - (DOOR_GFX_PAGEY1 + j));
3072           BlitBitmapMasked(bitmap, drawto,
3073                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3074                            DX, DY);
3075           BlitBitmapMasked(bitmap, drawto,
3076                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3077                            DX, DY + 140 - j);
3078
3079           BlitBitmapMasked(bitmap, drawto,
3080                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3081                            DX, DY + 77 - j);
3082           BlitBitmapMasked(bitmap, drawto,
3083                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3084                            DX, DY + 203 - j);
3085           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3086           BlitBitmapMasked(bitmap, drawto,
3087                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3088                            DX + DXSIZE - i, DY + 77 + j);
3089           BlitBitmapMasked(bitmap, drawto,
3090                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3091                            DX + DXSIZE - i, DY + 203 + j);
3092         }
3093
3094         redraw_mask |= REDRAW_DOOR_1;
3095         door_1_done = (a == end);
3096       }
3097
3098       if (door_state & DOOR_ACTION_2)
3099       {
3100         int a = MIN(x * door_2.step_offset, door_size);
3101         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3102         int i = p + door_skip;
3103
3104         if (door_2.anim_mode & ANIM_STATIC_PANEL)
3105         {
3106           BlitBitmap(bitmap_db_door, drawto,
3107                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3108                      VXSIZE, VYSIZE, VX, VY);
3109         }
3110         else if (x <= VYSIZE)
3111         {
3112           BlitBitmap(bitmap_db_door, drawto,
3113                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3114                      VXSIZE, VYSIZE - p / 2, VX, VY);
3115
3116           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3117         }
3118
3119         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3120         {
3121           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
3122           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3123           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
3124           int dst2_x = VX,              dst2_y = VY;
3125           int width = i, height = VYSIZE;
3126
3127           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3128           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3129                            dst1_x, dst1_y);
3130
3131           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3132           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3133                            dst2_x, dst2_y);
3134         }
3135         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3136         {
3137           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
3138           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
3139           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3140           int dst2_x = VX,              dst2_y = VY;
3141           int width = VXSIZE, height = i;
3142
3143           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3144           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3145                            dst1_x, dst1_y);
3146
3147           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3148           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3149                            dst2_x, dst2_y);
3150         }
3151         else if (x <= VXSIZE)   /* ANIM_DEFAULT */
3152         {
3153           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3154
3155           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3156           BlitBitmapMasked(bitmap, drawto,
3157                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3158                            VX + VXSIZE - i, VY + j);
3159           SetClipOrigin(bitmap, gc,
3160                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3161           BlitBitmapMasked(bitmap, drawto,
3162                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3163                            VX, VY);
3164
3165           BlitBitmapMasked(bitmap, drawto,
3166                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3167                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3168           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3169           BlitBitmapMasked(bitmap, drawto,
3170                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3171                            i, VYSIZE / 2 - j,
3172                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3173         }
3174
3175         redraw_mask |= REDRAW_DOOR_2;
3176         door_2_done = (a == VXSIZE);
3177       }
3178
3179       if (!(door_state & DOOR_NO_DELAY))
3180       {
3181         BackToFront();
3182
3183         if (game_status == GAME_MODE_MAIN)
3184           DoAnimation();
3185
3186         WaitUntilDelayReached(&door_delay, door_delay_value);
3187       }
3188     }
3189   }
3190
3191   if (door_state & DOOR_ACTION_1)
3192     door1 = door_state & DOOR_ACTION_1;
3193   if (door_state & DOOR_ACTION_2)
3194     door2 = door_state & DOOR_ACTION_2;
3195
3196   return (door1 | door2);
3197 }
3198
3199 void DrawSpecialEditorDoor()
3200 {
3201   /* draw bigger toolbox window */
3202   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3203              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3204              EX - 4, EY - 12);
3205   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3206              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3207              EX - 6, EY - 4);
3208
3209   redraw_mask |= REDRAW_ALL;
3210 }
3211
3212 void UndrawSpecialEditorDoor()
3213 {
3214   /* draw normal tape recorder window */
3215   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3216              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3217              EX - 6, EY - 12);
3218
3219   redraw_mask |= REDRAW_ALL;
3220 }
3221
3222
3223 /* ---------- new tool button stuff ---------------------------------------- */
3224
3225 /* graphic position values for tool buttons */
3226 #define TOOL_BUTTON_YES_XPOS            2
3227 #define TOOL_BUTTON_YES_YPOS            250
3228 #define TOOL_BUTTON_YES_GFX_YPOS        0
3229 #define TOOL_BUTTON_YES_XSIZE           46
3230 #define TOOL_BUTTON_YES_YSIZE           28
3231 #define TOOL_BUTTON_NO_XPOS             52
3232 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
3233 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
3234 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
3235 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
3236 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
3237 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
3238 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
3239 #define TOOL_BUTTON_CONFIRM_XSIZE       96
3240 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
3241 #define TOOL_BUTTON_PLAYER_XSIZE        30
3242 #define TOOL_BUTTON_PLAYER_YSIZE        30
3243 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
3244 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
3245 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3246 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3247 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3248                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3249 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3250                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3251 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3252                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3253 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3254                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3255 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3256                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3257 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3258                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3259 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3260                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3261 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3262                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3263
3264 static struct
3265 {
3266   int xpos, ypos;
3267   int x, y;
3268   int width, height;
3269   int gadget_id;
3270   char *infotext;
3271 } toolbutton_info[NUM_TOOL_BUTTONS] =
3272 {
3273   {
3274     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
3275     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
3276     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
3277     TOOL_CTRL_ID_YES,
3278     "yes"
3279   },
3280   {
3281     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
3282     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
3283     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
3284     TOOL_CTRL_ID_NO,
3285     "no"
3286   },
3287   {
3288     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
3289     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
3290     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
3291     TOOL_CTRL_ID_CONFIRM,
3292     "confirm"
3293   },
3294   {
3295     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3296     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
3297     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3298     TOOL_CTRL_ID_PLAYER_1,
3299     "player 1"
3300   },
3301   {
3302     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3303     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
3304     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3305     TOOL_CTRL_ID_PLAYER_2,
3306     "player 2"
3307   },
3308   {
3309     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3310     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
3311     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3312     TOOL_CTRL_ID_PLAYER_3,
3313     "player 3"
3314   },
3315   {
3316     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3317     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
3318     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3319     TOOL_CTRL_ID_PLAYER_4,
3320     "player 4"
3321   }
3322 };
3323
3324 void CreateToolButtons()
3325 {
3326   int i;
3327
3328   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3329   {
3330     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3331     Bitmap *deco_bitmap = None;
3332     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3333     struct GadgetInfo *gi;
3334     unsigned long event_mask;
3335     int gd_xoffset, gd_yoffset;
3336     int gd_x1, gd_x2, gd_y;
3337     int id = i;
3338
3339     event_mask = GD_EVENT_RELEASED;
3340
3341     gd_xoffset = toolbutton_info[i].xpos;
3342     gd_yoffset = toolbutton_info[i].ypos;
3343     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3344     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3345     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3346
3347     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3348     {
3349       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3350
3351       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3352                            &deco_bitmap, &deco_x, &deco_y);
3353       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3354       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3355     }
3356
3357     gi = CreateGadget(GDI_CUSTOM_ID, id,
3358                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
3359                       GDI_X, DX + toolbutton_info[i].x,
3360                       GDI_Y, DY + toolbutton_info[i].y,
3361                       GDI_WIDTH, toolbutton_info[i].width,
3362                       GDI_HEIGHT, toolbutton_info[i].height,
3363                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3364                       GDI_STATE, GD_BUTTON_UNPRESSED,
3365                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3366                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3367                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3368                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3369                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3370                       GDI_DECORATION_SHIFTING, 1, 1,
3371                       GDI_DIRECT_DRAW, FALSE,
3372                       GDI_EVENT_MASK, event_mask,
3373                       GDI_CALLBACK_ACTION, HandleToolButtons,
3374                       GDI_END);
3375
3376     if (gi == NULL)
3377       Error(ERR_EXIT, "cannot create gadget");
3378
3379     tool_gadget[id] = gi;
3380   }
3381 }
3382
3383 void FreeToolButtons()
3384 {
3385   int i;
3386
3387   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3388     FreeGadget(tool_gadget[i]);
3389 }
3390
3391 static void UnmapToolButtons()
3392 {
3393   int i;
3394
3395   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3396     UnmapGadget(tool_gadget[i]);
3397 }
3398
3399 static void HandleToolButtons(struct GadgetInfo *gi)
3400 {
3401   request_gadget_id = gi->custom_id;
3402 }
3403
3404 static struct Mapping_EM_to_RND_object
3405 {
3406   int element_em;
3407   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
3408   boolean is_backside;                  /* backside of moving element */
3409
3410   int element_rnd;
3411   int action;
3412   int direction;
3413 }
3414 em_object_mapping_list[] =
3415 {
3416   {
3417     Xblank,                             TRUE,   FALSE,
3418     EL_EMPTY,                           -1, -1
3419   },
3420   {
3421     Yacid_splash_eB,                    FALSE,  FALSE,
3422     EL_ACID_SPLASH_RIGHT,               -1, -1
3423   },
3424   {
3425     Yacid_splash_wB,                    FALSE,  FALSE,
3426     EL_ACID_SPLASH_LEFT,                -1, -1
3427   },
3428
3429 #ifdef EM_ENGINE_BAD_ROLL
3430   {
3431     Xstone_force_e,                     FALSE,  FALSE,
3432     EL_ROCK,                            -1, MV_BIT_RIGHT
3433   },
3434   {
3435     Xstone_force_w,                     FALSE,  FALSE,
3436     EL_ROCK,                            -1, MV_BIT_LEFT
3437   },
3438   {
3439     Xnut_force_e,                       FALSE,  FALSE,
3440     EL_NUT,                             -1, MV_BIT_RIGHT
3441   },
3442   {
3443     Xnut_force_w,                       FALSE,  FALSE,
3444     EL_NUT,                             -1, MV_BIT_LEFT
3445   },
3446   {
3447     Xspring_force_e,                    FALSE,  FALSE,
3448     EL_SPRING,                          -1, MV_BIT_RIGHT
3449   },
3450   {
3451     Xspring_force_w,                    FALSE,  FALSE,
3452     EL_SPRING,                          -1, MV_BIT_LEFT
3453   },
3454   {
3455     Xemerald_force_e,                   FALSE,  FALSE,
3456     EL_EMERALD,                         -1, MV_BIT_RIGHT
3457   },
3458   {
3459     Xemerald_force_w,                   FALSE,  FALSE,
3460     EL_EMERALD,                         -1, MV_BIT_LEFT
3461   },
3462   {
3463     Xdiamond_force_e,                   FALSE,  FALSE,
3464     EL_DIAMOND,                         -1, MV_BIT_RIGHT
3465   },
3466   {
3467     Xdiamond_force_w,                   FALSE,  FALSE,
3468     EL_DIAMOND,                         -1, MV_BIT_LEFT
3469   },
3470   {
3471     Xbomb_force_e,                      FALSE,  FALSE,
3472     EL_BOMB,                            -1, MV_BIT_RIGHT
3473   },
3474   {
3475     Xbomb_force_w,                      FALSE,  FALSE,
3476     EL_BOMB,                            -1, MV_BIT_LEFT
3477   },
3478 #endif  /* EM_ENGINE_BAD_ROLL */
3479
3480   {
3481     Xstone,                             TRUE,   FALSE,
3482     EL_ROCK,                            -1, -1
3483   },
3484   {
3485     Xstone_pause,                       FALSE,  FALSE,
3486     EL_ROCK,                            -1, -1
3487   },
3488   {
3489     Xstone_fall,                        FALSE,  FALSE,
3490     EL_ROCK,                            -1, -1
3491   },
3492   {
3493     Ystone_s,                           FALSE,  FALSE,
3494     EL_ROCK,                            ACTION_FALLING, -1
3495   },
3496   {
3497     Ystone_sB,                          FALSE,  TRUE,
3498     EL_ROCK,                            ACTION_FALLING, -1
3499   },
3500   {
3501     Ystone_e,                           FALSE,  FALSE,
3502     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3503   },
3504   {
3505     Ystone_eB,                          FALSE,  TRUE,
3506     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3507   },
3508   {
3509     Ystone_w,                           FALSE,  FALSE,
3510     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3511   },
3512   {
3513     Ystone_wB,                          FALSE,  TRUE,
3514     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3515   },
3516   {
3517     Xnut,                               TRUE,   FALSE,
3518     EL_NUT,                             -1, -1
3519   },
3520   {
3521     Xnut_pause,                         FALSE,  FALSE,
3522     EL_NUT,                             -1, -1
3523   },
3524   {
3525     Xnut_fall,                          FALSE,  FALSE,
3526     EL_NUT,                             -1, -1
3527   },
3528   {
3529     Ynut_s,                             FALSE,  FALSE,
3530     EL_NUT,                             ACTION_FALLING, -1
3531   },
3532   {
3533     Ynut_sB,                            FALSE,  TRUE,
3534     EL_NUT,                             ACTION_FALLING, -1
3535   },
3536   {
3537     Ynut_e,                             FALSE,  FALSE,
3538     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3539   },
3540   {
3541     Ynut_eB,                            FALSE,  TRUE,
3542     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3543   },
3544   {
3545     Ynut_w,                             FALSE,  FALSE,
3546     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3547   },
3548   {
3549     Ynut_wB,                            FALSE,  TRUE,
3550     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3551   },
3552   {
3553     Xbug_n,                             TRUE,   FALSE,
3554     EL_BUG_UP,                          -1, -1
3555   },
3556   {
3557     Xbug_e,                             TRUE,   FALSE,
3558     EL_BUG_RIGHT,                       -1, -1
3559   },
3560   {
3561     Xbug_s,                             TRUE,   FALSE,
3562     EL_BUG_DOWN,                        -1, -1
3563   },
3564   {
3565     Xbug_w,                             TRUE,   FALSE,
3566     EL_BUG_LEFT,                        -1, -1
3567   },
3568   {
3569     Xbug_gon,                           FALSE,  FALSE,
3570     EL_BUG_UP,                          -1, -1
3571   },
3572   {
3573     Xbug_goe,                           FALSE,  FALSE,
3574     EL_BUG_RIGHT,                       -1, -1
3575   },
3576   {
3577     Xbug_gos,                           FALSE,  FALSE,
3578     EL_BUG_DOWN,                        -1, -1
3579   },
3580   {
3581     Xbug_gow,                           FALSE,  FALSE,
3582     EL_BUG_LEFT,                        -1, -1
3583   },
3584   {
3585     Ybug_n,                             FALSE,  FALSE,
3586     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3587   },
3588   {
3589     Ybug_nB,                            FALSE,  TRUE,
3590     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3591   },
3592   {
3593     Ybug_e,                             FALSE,  FALSE,
3594     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3595   },
3596   {
3597     Ybug_eB,                            FALSE,  TRUE,
3598     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3599   },
3600   {
3601     Ybug_s,                             FALSE,  FALSE,
3602     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3603   },
3604   {
3605     Ybug_sB,                            FALSE,  TRUE,
3606     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3607   },
3608   {
3609     Ybug_w,                             FALSE,  FALSE,
3610     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3611   },
3612   {
3613     Ybug_wB,                            FALSE,  TRUE,
3614     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3615   },
3616   {
3617     Ybug_w_n,                           FALSE,  FALSE,
3618     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3619   },
3620   {
3621     Ybug_n_e,                           FALSE,  FALSE,
3622     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3623   },
3624   {
3625     Ybug_e_s,                           FALSE,  FALSE,
3626     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3627   },
3628   {
3629     Ybug_s_w,                           FALSE,  FALSE,
3630     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3631   },
3632   {
3633     Ybug_e_n,                           FALSE,  FALSE,
3634     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3635   },
3636   {
3637     Ybug_s_e,                           FALSE,  FALSE,
3638     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3639   },
3640   {
3641     Ybug_w_s,                           FALSE,  FALSE,
3642     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3643   },
3644   {
3645     Ybug_n_w,                           FALSE,  FALSE,
3646     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3647   },
3648   {
3649     Ybug_stone,                         FALSE,  FALSE,
3650     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
3651   },
3652   {
3653     Ybug_spring,                        FALSE,  FALSE,
3654     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
3655   },
3656   {
3657     Xtank_n,                            TRUE,   FALSE,
3658     EL_SPACESHIP_UP,                    -1, -1
3659   },
3660   {
3661     Xtank_e,                            TRUE,   FALSE,
3662     EL_SPACESHIP_RIGHT,                 -1, -1
3663   },
3664   {
3665     Xtank_s,                            TRUE,   FALSE,
3666     EL_SPACESHIP_DOWN,                  -1, -1
3667   },
3668   {
3669     Xtank_w,                            TRUE,   FALSE,
3670     EL_SPACESHIP_LEFT,                  -1, -1
3671   },
3672   {
3673     Xtank_gon,                          FALSE,  FALSE,
3674     EL_SPACESHIP_UP,                    -1, -1
3675   },
3676   {
3677     Xtank_goe,                          FALSE,  FALSE,
3678     EL_SPACESHIP_RIGHT,                 -1, -1
3679   },
3680   {
3681     Xtank_gos,                          FALSE,  FALSE,
3682     EL_SPACESHIP_DOWN,                  -1, -1
3683   },
3684   {
3685     Xtank_gow,                          FALSE,  FALSE,
3686     EL_SPACESHIP_LEFT,                  -1, -1
3687   },
3688   {
3689     Ytank_n,                            FALSE,  FALSE,
3690     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3691   },
3692   {
3693     Ytank_nB,                           FALSE,  TRUE,
3694     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3695   },
3696   {
3697     Ytank_e,                            FALSE,  FALSE,
3698     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3699   },
3700   {
3701     Ytank_eB,                           FALSE,  TRUE,
3702     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3703   },
3704   {
3705     Ytank_s,                            FALSE,  FALSE,
3706     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3707   },
3708   {
3709     Ytank_sB,                           FALSE,  TRUE,
3710     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3711   },
3712   {
3713     Ytank_w,                            FALSE,  FALSE,
3714     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3715   },
3716   {
3717     Ytank_wB,                           FALSE,  TRUE,
3718     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3719   },
3720   {
3721     Ytank_w_n,                          FALSE,  FALSE,
3722     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3723   },
3724   {
3725     Ytank_n_e,                          FALSE,  FALSE,
3726     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3727   },
3728   {
3729     Ytank_e_s,                          FALSE,  FALSE,
3730     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3731   },
3732   {
3733     Ytank_s_w,                          FALSE,  FALSE,
3734     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3735   },
3736   {
3737     Ytank_e_n,                          FALSE,  FALSE,
3738     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3739   },
3740   {
3741     Ytank_s_e,                          FALSE,  FALSE,
3742     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3743   },
3744   {
3745     Ytank_w_s,                          FALSE,  FALSE,
3746     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3747   },
3748   {
3749     Ytank_n_w,                          FALSE,  FALSE,
3750     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3751   },
3752   {
3753     Ytank_stone,                        FALSE,  FALSE,
3754     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
3755   },
3756   {
3757     Ytank_spring,                       FALSE,  FALSE,
3758     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
3759   },
3760   {
3761     Xandroid,                           TRUE,   FALSE,
3762     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
3763   },
3764   {
3765     Xandroid_1_n,                       FALSE,  FALSE,
3766     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
3767   },
3768   {
3769     Xandroid_2_n,                       FALSE,  FALSE,
3770     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
3771   },
3772   {
3773     Xandroid_1_e,                       FALSE,  FALSE,
3774     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
3775   },
3776   {
3777     Xandroid_2_e,                       FALSE,  FALSE,
3778     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
3779   },
3780   {
3781     Xandroid_1_w,                       FALSE,  FALSE,
3782     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
3783   },
3784   {
3785     Xandroid_2_w,                       FALSE,  FALSE,
3786     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
3787   },
3788   {
3789     Xandroid_1_s,                       FALSE,  FALSE,
3790     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
3791   },
3792   {
3793     Xandroid_2_s,                       FALSE,  FALSE,
3794     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
3795   },
3796   {
3797     Yandroid_n,                         FALSE,  FALSE,
3798     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
3799   },
3800   {
3801     Yandroid_nB,                        FALSE,  TRUE,
3802     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
3803   },
3804   {
3805     Yandroid_ne,                        FALSE,  FALSE,
3806     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
3807   },
3808   {
3809     Yandroid_neB,                       FALSE,  TRUE,
3810     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
3811   },
3812   {
3813     Yandroid_e,                         FALSE,  FALSE,
3814     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
3815   },
3816   {
3817     Yandroid_eB,                        FALSE,  TRUE,
3818     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
3819   },
3820   {
3821     Yandroid_se,                        FALSE,  FALSE,
3822     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
3823   },
3824   {
3825     Yandroid_seB,                       FALSE,  TRUE,
3826     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3827   },
3828   {
3829     Yandroid_s,                         FALSE,  FALSE,
3830     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
3831   },
3832   {
3833     Yandroid_sB,                        FALSE,  TRUE,
3834     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
3835   },
3836   {
3837     Yandroid_sw,                        FALSE,  FALSE,
3838     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
3839   },
3840   {
3841     Yandroid_swB,                       FALSE,  TRUE,
3842     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
3843   },
3844   {
3845     Yandroid_w,                         FALSE,  FALSE,
3846     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
3847   },
3848   {
3849     Yandroid_wB,                        FALSE,  TRUE,
3850     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
3851   },
3852   {
3853     Yandroid_nw,                        FALSE,  FALSE,
3854     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
3855   },
3856   {
3857     Yandroid_nwB,                       FALSE,  TRUE,
3858     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
3859   },
3860   {
3861     Xspring,                            TRUE,   FALSE,
3862     EL_SPRING,                          -1, -1
3863   },
3864   {
3865     Xspring_pause,                      FALSE,  FALSE,
3866     EL_SPRING,                          -1, -1
3867   },
3868   {
3869     Xspring_e,                          FALSE,  FALSE,
3870     EL_SPRING,                          -1, -1
3871   },
3872   {
3873     Xspring_w,                          FALSE,  FALSE,
3874     EL_SPRING,                          -1, -1
3875   },
3876   {
3877     Xspring_fall,                       FALSE,  FALSE,
3878     EL_SPRING,                          -1, -1
3879   },
3880   {
3881     Yspring_s,                          FALSE,  FALSE,
3882     EL_SPRING,                          ACTION_FALLING, -1
3883   },
3884   {
3885     Yspring_sB,                         FALSE,  TRUE,
3886     EL_SPRING,                          ACTION_FALLING, -1
3887   },
3888   {
3889     Yspring_e,                          FALSE,  FALSE,
3890     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
3891   },
3892   {
3893     Yspring_eB,                         FALSE,  TRUE,
3894     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
3895   },
3896   {
3897     Yspring_w,                          FALSE,  FALSE,
3898     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
3899   },
3900   {
3901     Yspring_wB,                         FALSE,  TRUE,
3902     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
3903   },
3904   {
3905     Yspring_kill_e,                     FALSE,  FALSE,
3906     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
3907   },
3908   {
3909     Yspring_kill_eB,                    FALSE,  TRUE,
3910     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
3911   },
3912   {
3913     Yspring_kill_w,                     FALSE,  FALSE,
3914     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
3915   },
3916   {
3917     Yspring_kill_wB,                    FALSE,  TRUE,
3918     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
3919   },
3920   {
3921     Xeater_n,                           TRUE,   FALSE,
3922     EL_YAMYAM_UP,                       -1, -1
3923   },
3924   {
3925     Xeater_e,                           TRUE,   FALSE,
3926     EL_YAMYAM_RIGHT,                    -1, -1
3927   },
3928   {
3929     Xeater_w,                           TRUE,   FALSE,
3930     EL_YAMYAM_LEFT,                     -1, -1
3931   },
3932   {
3933     Xeater_s,                           TRUE,   FALSE,
3934     EL_YAMYAM_DOWN,                     -1, -1
3935   },
3936   {
3937     Yeater_n,                           FALSE,  FALSE,
3938     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
3939   },
3940   {
3941     Yeater_nB,                          FALSE,  TRUE,
3942     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
3943   },
3944   {
3945     Yeater_e,                           FALSE,  FALSE,
3946     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
3947   },
3948   {
3949     Yeater_eB,                          FALSE,  TRUE,
3950     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
3951   },
3952   {
3953     Yeater_s,                           FALSE,  FALSE,
3954     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
3955   },
3956   {
3957     Yeater_sB,                          FALSE,  TRUE,
3958     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
3959   },
3960   {
3961     Yeater_w,                           FALSE,  FALSE,
3962     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
3963   },
3964   {
3965     Yeater_wB,                          FALSE,  TRUE,
3966     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
3967   },
3968   {
3969     Yeater_stone,                       FALSE,  FALSE,
3970     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
3971   },
3972   {
3973     Yeater_spring,                      FALSE,  FALSE,
3974     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
3975   },
3976   {
3977     Xalien,                             TRUE,   FALSE,
3978     EL_ROBOT,                           -1, -1
3979   },
3980   {
3981     Xalien_pause,                       FALSE,  FALSE,
3982     EL_ROBOT,                           -1, -1
3983   },
3984   {
3985     Yalien_n,                           FALSE,  FALSE,
3986     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
3987   },
3988   {
3989     Yalien_nB,                          FALSE,  TRUE,
3990     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
3991   },
3992   {
3993     Yalien_e,                           FALSE,  FALSE,
3994     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
3995   },
3996   {
3997     Yalien_eB,                          FALSE,  TRUE,
3998     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
3999   },
4000   {
4001     Yalien_s,                           FALSE,  FALSE,
4002     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
4003   },
4004   {
4005     Yalien_sB,                          FALSE,  TRUE,
4006     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
4007   },
4008   {
4009     Yalien_w,                           FALSE,  FALSE,
4010     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
4011   },
4012   {
4013     Yalien_wB,                          FALSE,  TRUE,
4014     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
4015   },
4016   {
4017     Yalien_stone,                       FALSE,  FALSE,
4018     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
4019   },
4020   {
4021     Yalien_spring,                      FALSE,  FALSE,
4022     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
4023   },
4024   {
4025     Xemerald,                           TRUE,   FALSE,
4026     EL_EMERALD,                         -1, -1
4027   },
4028   {
4029     Xemerald_pause,                     FALSE,  FALSE,
4030     EL_EMERALD,                         -1, -1
4031   },
4032   {
4033     Xemerald_fall,                      FALSE,  FALSE,
4034     EL_EMERALD,                         -1, -1
4035   },
4036   {
4037     Xemerald_shine,                     FALSE,  FALSE,
4038     EL_EMERALD,                         ACTION_TWINKLING, -1
4039   },
4040   {
4041     Yemerald_s,                         FALSE,  FALSE,
4042     EL_EMERALD,                         ACTION_FALLING, -1
4043   },
4044   {
4045     Yemerald_sB,                        FALSE,  TRUE,
4046     EL_EMERALD,                         ACTION_FALLING, -1
4047   },
4048   {
4049     Yemerald_e,                         FALSE,  FALSE,
4050     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
4051   },
4052   {
4053     Yemerald_eB,                        FALSE,  TRUE,
4054     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
4055   },
4056   {
4057     Yemerald_w,                         FALSE,  FALSE,
4058     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
4059   },
4060   {
4061     Yemerald_wB,                        FALSE,  TRUE,
4062     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
4063   },
4064   {
4065     Yemerald_eat,                       FALSE,  FALSE,
4066     EL_EMERALD,                         ACTION_COLLECTING, -1
4067   },
4068   {
4069     Yemerald_stone,                     FALSE,  FALSE,
4070     EL_NUT,                             ACTION_BREAKING, -1
4071   },
4072   {
4073     Xdiamond,                           TRUE,   FALSE,
4074     EL_DIAMOND,                         -1, -1
4075   },
4076   {
4077     Xdiamond_pause,                     FALSE,  FALSE,
4078     EL_DIAMOND,                         -1, -1
4079   },
4080   {
4081     Xdiamond_fall,                      FALSE,  FALSE,
4082     EL_DIAMOND,                         -1, -1
4083   },
4084   {
4085     Xdiamond_shine,                     FALSE,  FALSE,
4086     EL_DIAMOND,                         ACTION_TWINKLING, -1
4087   },
4088   {
4089     Ydiamond_s,                         FALSE,  FALSE,
4090     EL_DIAMOND,                         ACTION_FALLING, -1
4091   },
4092   {
4093     Ydiamond_sB,                        FALSE,  TRUE,
4094     EL_DIAMOND,                         ACTION_FALLING, -1
4095   },
4096   {
4097     Ydiamond_e,                         FALSE,  FALSE,
4098     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
4099   },
4100   {
4101     Ydiamond_eB,                        FALSE,  TRUE,
4102     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
4103   },
4104   {
4105     Ydiamond_w,                         FALSE,  FALSE,
4106     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
4107   },
4108   {
4109     Ydiamond_wB,                        FALSE,  TRUE,
4110     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
4111   },
4112   {
4113     Ydiamond_eat,                       FALSE,  FALSE,
4114     EL_DIAMOND,                         ACTION_COLLECTING, -1
4115   },
4116   {
4117     Ydiamond_stone,                     FALSE,  FALSE,
4118     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
4119   },
4120   {
4121     Xdrip_fall,                         TRUE,   FALSE,
4122     EL_AMOEBA_DROP,                     -1, -1
4123   },
4124   {
4125     Xdrip_stretch,                      FALSE,  FALSE,
4126     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4127   },
4128   {
4129     Xdrip_stretchB,                     FALSE,  TRUE,
4130     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4131   },
4132   {
4133     Xdrip_eat,                          FALSE,  FALSE,
4134     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
4135   },
4136   {
4137     Ydrip_s1,                           FALSE,  FALSE,
4138     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4139   },
4140   {
4141     Ydrip_s1B,                          FALSE,  TRUE,
4142     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4143   },
4144   {
4145     Ydrip_s2,                           FALSE,  FALSE,
4146     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4147   },
4148   {
4149     Ydrip_s2B,                          FALSE,  TRUE,
4150     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4151   },
4152   {
4153     Xbomb,                              TRUE,   FALSE,
4154     EL_BOMB,                            -1, -1
4155   },
4156   {
4157     Xbomb_pause,                        FALSE,  FALSE,
4158     EL_BOMB,                            -1, -1
4159   },
4160   {
4161     Xbomb_fall,                         FALSE,  FALSE,
4162     EL_BOMB,                            -1, -1
4163   },
4164   {
4165     Ybomb_s,                            FALSE,  FALSE,
4166     EL_BOMB,                            ACTION_FALLING, -1
4167   },
4168   {
4169     Ybomb_sB,                           FALSE,  TRUE,
4170     EL_BOMB,                            ACTION_FALLING, -1
4171   },
4172   {
4173     Ybomb_e,                            FALSE,  FALSE,
4174     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
4175   },
4176   {
4177     Ybomb_eB,                           FALSE,  TRUE,
4178     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
4179   },
4180   {
4181     Ybomb_w,                            FALSE,  FALSE,
4182     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
4183   },
4184   {
4185     Ybomb_wB,                           FALSE,  TRUE,
4186     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
4187   },
4188   {
4189     Ybomb_eat,                          FALSE,  FALSE,
4190     EL_BOMB,                            ACTION_ACTIVATING, -1
4191   },
4192   {
4193     Xballoon,                           TRUE,   FALSE,
4194     EL_BALLOON,                         -1, -1
4195   },
4196   {
4197     Yballoon_n,                         FALSE,  FALSE,
4198     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
4199   },
4200   {
4201     Yballoon_nB,                        FALSE,  TRUE,
4202     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
4203   },
4204   {
4205     Yballoon_e,                         FALSE,  FALSE,
4206     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
4207   },
4208   {
4209     Yballoon_eB,                        FALSE,  TRUE,
4210     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
4211   },
4212   {
4213     Yballoon_s,                         FALSE,  FALSE,
4214     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
4215   },
4216   {
4217     Yballoon_sB,                        FALSE,  TRUE,
4218     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
4219   },
4220   {
4221     Yballoon_w,                         FALSE,  FALSE,
4222     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
4223   },
4224   {
4225     Yballoon_wB,                        FALSE,  TRUE,
4226     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
4227   },
4228   {
4229     Xgrass,                             TRUE,   FALSE,
4230     EL_EMC_GRASS,                       -1, -1
4231   },
4232   {
4233     Ygrass_nB,                          FALSE,  FALSE,
4234     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
4235   },
4236   {
4237     Ygrass_eB,                          FALSE,  FALSE,
4238     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
4239   },
4240   {
4241     Ygrass_sB,                          FALSE,  FALSE,
4242     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
4243   },
4244   {
4245     Ygrass_wB,                          FALSE,  FALSE,
4246     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
4247   },
4248   {
4249     Xdirt,                              TRUE,   FALSE,
4250     EL_SAND,                            -1, -1
4251   },
4252   {
4253     Ydirt_nB,                           FALSE,  FALSE,
4254     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
4255   },
4256   {
4257     Ydirt_eB,                           FALSE,  FALSE,
4258     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
4259   },
4260   {
4261     Ydirt_sB,                           FALSE,  FALSE,
4262     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
4263   },
4264   {
4265     Ydirt_wB,                           FALSE,  FALSE,
4266     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
4267   },
4268   {
4269     Xacid_ne,                           TRUE,   FALSE,
4270     EL_ACID_POOL_TOPRIGHT,              -1, -1
4271   },
4272   {
4273     Xacid_se,                           TRUE,   FALSE,
4274     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
4275   },
4276   {
4277     Xacid_s,                            TRUE,   FALSE,
4278     EL_ACID_POOL_BOTTOM,                -1, -1
4279   },
4280   {
4281     Xacid_sw,                           TRUE,   FALSE,
4282     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
4283   },
4284   {
4285     Xacid_nw,                           TRUE,   FALSE,
4286     EL_ACID_POOL_TOPLEFT,               -1, -1
4287   },
4288   {
4289     Xacid_1,                            TRUE,   FALSE,
4290     EL_ACID,                            -1, -1
4291   },
4292   {
4293     Xacid_2,                            FALSE,  FALSE,
4294     EL_ACID,                            -1, -1
4295   },
4296   {
4297     Xacid_3,                            FALSE,  FALSE,
4298     EL_ACID,                            -1, -1
4299   },
4300   {
4301     Xacid_4,                            FALSE,  FALSE,
4302     EL_ACID,                            -1, -1
4303   },
4304   {
4305     Xacid_5,                            FALSE,  FALSE,
4306     EL_ACID,                            -1, -1
4307   },
4308   {
4309     Xacid_6,                            FALSE,  FALSE,
4310     EL_ACID,                            -1, -1
4311   },
4312   {
4313     Xacid_7,                            FALSE,  FALSE,
4314     EL_ACID,                            -1, -1
4315   },
4316   {
4317     Xacid_8,                            FALSE,  FALSE,
4318     EL_ACID,                            -1, -1
4319   },
4320   {
4321     Xball_1,                            TRUE,   FALSE,
4322     EL_EMC_MAGIC_BALL,                  -1, -1
4323   },
4324   {
4325     Xball_1B,                           FALSE,  FALSE,
4326     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4327   },
4328   {
4329     Xball_2,                            FALSE,  FALSE,
4330     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4331   },
4332   {
4333     Xball_2B,                           FALSE,  FALSE,
4334     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4335   },
4336   {
4337     Yball_eat,                          FALSE,  FALSE,
4338     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
4339   },
4340   {
4341     Ykey_1_eat,                         FALSE,  FALSE,
4342     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
4343   },
4344   {
4345     Ykey_2_eat,                         FALSE,  FALSE,
4346     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
4347   },
4348   {
4349     Ykey_3_eat,                         FALSE,  FALSE,
4350     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
4351   },
4352   {
4353     Ykey_4_eat,                         FALSE,  FALSE,
4354     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
4355   },
4356   {
4357     Ykey_5_eat,                         FALSE,  FALSE,
4358     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
4359   },
4360   {
4361     Ykey_6_eat,                         FALSE,  FALSE,
4362     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
4363   },
4364   {
4365     Ykey_7_eat,                         FALSE,  FALSE,
4366     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
4367   },
4368   {
4369     Ykey_8_eat,                         FALSE,  FALSE,
4370     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
4371   },
4372   {
4373     Ylenses_eat,                        FALSE,  FALSE,
4374     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
4375   },
4376   {
4377     Ymagnify_eat,                       FALSE,  FALSE,
4378     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
4379   },
4380   {
4381     Ygrass_eat,                         FALSE,  FALSE,
4382     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
4383   },
4384   {
4385     Ydirt_eat,                          FALSE,  FALSE,
4386     EL_SAND,                            ACTION_SNAPPING, -1
4387   },
4388   {
4389     Xgrow_ns,                           TRUE,   FALSE,
4390     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
4391   },
4392   {
4393     Ygrow_ns_eat,                       FALSE,  FALSE,
4394     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
4395   },
4396   {
4397     Xgrow_ew,                           TRUE,   FALSE,
4398     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
4399   },
4400   {
4401     Ygrow_ew_eat,                       FALSE,  FALSE,
4402     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
4403   },
4404   {
4405     Xwonderwall,                        TRUE,   FALSE,
4406     EL_MAGIC_WALL,                      -1, -1
4407   },
4408   {
4409     XwonderwallB,                       FALSE,  FALSE,
4410     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
4411   },
4412   {
4413     Xamoeba_1,                          TRUE,   FALSE,
4414     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4415   },
4416   {
4417     Xamoeba_2,                          FALSE,  FALSE,
4418     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4419   },
4420   {
4421     Xamoeba_3,                          FALSE,  FALSE,
4422     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4423   },
4424   {
4425     Xamoeba_4,                          FALSE,  FALSE,
4426     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4427   },
4428   {
4429     Xamoeba_5,                          TRUE,   FALSE,
4430     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4431   },
4432   {
4433     Xamoeba_6,                          FALSE,  FALSE,
4434     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4435   },
4436   {
4437     Xamoeba_7,                          FALSE,  FALSE,
4438     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4439   },
4440   {
4441     Xamoeba_8,                          FALSE,  FALSE,
4442     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4443   },
4444   {
4445     Xdoor_1,                            TRUE,   FALSE,
4446     EL_EM_GATE_1,                       -1, -1
4447   },
4448   {
4449     Xdoor_2,                            TRUE,   FALSE,
4450     EL_EM_GATE_2,                       -1, -1
4451   },
4452   {
4453     Xdoor_3,                            TRUE,   FALSE,
4454     EL_EM_GATE_3,                       -1, -1
4455   },
4456   {
4457     Xdoor_4,                            TRUE,   FALSE,
4458     EL_EM_GATE_4,                       -1, -1
4459   },
4460   {
4461     Xdoor_5,                            TRUE,   FALSE,
4462     EL_EMC_GATE_5,                      -1, -1
4463   },
4464   {
4465     Xdoor_6,                            TRUE,   FALSE,
4466     EL_EMC_GATE_6,                      -1, -1
4467   },
4468   {
4469     Xdoor_7,                            TRUE,   FALSE,
4470     EL_EMC_GATE_7,                      -1, -1
4471   },
4472   {
4473     Xdoor_8,                            TRUE,   FALSE,
4474     EL_EMC_GATE_8,                      -1, -1
4475   },
4476   {
4477     Xkey_1,                             TRUE,   FALSE,
4478     EL_EM_KEY_1,                        -1, -1
4479   },
4480   {
4481     Xkey_2,                             TRUE,   FALSE,
4482     EL_EM_KEY_2,                        -1, -1
4483   },
4484   {
4485     Xkey_3,                             TRUE,   FALSE,
4486     EL_EM_KEY_3,                        -1, -1
4487   },
4488   {
4489     Xkey_4,                             TRUE,   FALSE,
4490     EL_EM_KEY_4,                        -1, -1
4491   },
4492   {
4493     Xkey_5,                             TRUE,   FALSE,
4494     EL_EMC_KEY_5,                       -1, -1
4495   },
4496   {
4497     Xkey_6,                             TRUE,   FALSE,
4498     EL_EMC_KEY_6,                       -1, -1
4499   },
4500   {
4501     Xkey_7,                             TRUE,   FALSE,
4502     EL_EMC_KEY_7,                       -1, -1
4503   },
4504   {
4505     Xkey_8,                             TRUE,   FALSE,
4506     EL_EMC_KEY_8,                       -1, -1
4507   },
4508   {
4509     Xwind_n,                            TRUE,   FALSE,
4510     EL_BALLOON_SWITCH_UP,               -1, -1
4511   },
4512   {
4513     Xwind_e,                            TRUE,   FALSE,
4514     EL_BALLOON_SWITCH_RIGHT,            -1, -1
4515   },
4516   {
4517     Xwind_s,                            TRUE,   FALSE,
4518     EL_BALLOON_SWITCH_DOWN,             -1, -1
4519   },
4520   {
4521     Xwind_w,                            TRUE,   FALSE,
4522     EL_BALLOON_SWITCH_LEFT,             -1, -1
4523   },
4524   {
4525     Xwind_nesw,                         TRUE,   FALSE,
4526     EL_BALLOON_SWITCH_ANY,              -1, -1
4527   },
4528   {
4529     Xwind_stop,                         TRUE,   FALSE,
4530     EL_BALLOON_SWITCH_NONE,             -1, -1
4531   },
4532   {
4533     Xexit,                              TRUE,   FALSE,
4534     EL_EM_EXIT_CLOSED,                  -1, -1
4535   },
4536   {
4537     Xexit_1,                            TRUE,   FALSE,
4538     EL_EM_EXIT_OPEN,                    -1, -1
4539   },
4540   {
4541     Xexit_2,                            FALSE,  FALSE,
4542     EL_EM_EXIT_OPEN,                    -1, -1
4543   },
4544   {
4545     Xexit_3,                            FALSE,  FALSE,
4546     EL_EM_EXIT_OPEN,                    -1, -1
4547   },
4548   {
4549     Xdynamite,                          TRUE,   FALSE,
4550     EL_EM_DYNAMITE,                     -1, -1
4551   },
4552   {
4553     Ydynamite_eat,                      FALSE,  FALSE,
4554     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
4555   },
4556   {
4557     Xdynamite_1,                        TRUE,   FALSE,
4558     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4559   },
4560   {
4561     Xdynamite_2,                        FALSE,  FALSE,
4562     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4563   },
4564   {
4565     Xdynamite_3,                        FALSE,  FALSE,
4566     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4567   },
4568   {
4569     Xdynamite_4,                        FALSE,  FALSE,
4570     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4571   },
4572   {
4573     Xbumper,                            TRUE,   FALSE,
4574     EL_EMC_SPRING_BUMPER,               -1, -1
4575   },
4576   {
4577     XbumperB,                           FALSE,  FALSE,
4578     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
4579   },
4580   {
4581     Xwheel,                             TRUE,   FALSE,
4582     EL_ROBOT_WHEEL,                     -1, -1
4583   },
4584   {
4585     XwheelB,                            FALSE,  FALSE,
4586     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
4587   },
4588   {
4589     Xswitch,                            TRUE,   FALSE,
4590     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
4591   },
4592   {
4593     XswitchB,                           FALSE,  FALSE,
4594     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
4595   },
4596   {
4597     Xsand,                              TRUE,   FALSE,
4598     EL_QUICKSAND_EMPTY,                 -1, -1
4599   },
4600   {
4601     Xsand_stone,                        TRUE,   FALSE,
4602     EL_QUICKSAND_FULL,                  -1, -1
4603   },
4604   {
4605     Xsand_stonein_1,                    FALSE,  TRUE,
4606     EL_ROCK,                            ACTION_FILLING, -1
4607   },
4608   {
4609     Xsand_stonein_2,                    FALSE,  TRUE,
4610     EL_ROCK,                            ACTION_FILLING, -1
4611   },
4612   {
4613     Xsand_stonein_3,                    FALSE,  TRUE,
4614     EL_ROCK,                            ACTION_FILLING, -1
4615   },
4616   {
4617     Xsand_stonein_4,                    FALSE,  TRUE,
4618     EL_ROCK,                            ACTION_FILLING, -1
4619   },
4620   {
4621     Xsand_stonesand_1,                  FALSE,  FALSE,
4622     EL_QUICKSAND_FULL,                  -1, -1
4623   },
4624   {
4625     Xsand_stonesand_2,                  FALSE,  FALSE,
4626     EL_QUICKSAND_FULL,                  -1, -1
4627   },
4628   {
4629     Xsand_stonesand_3,                  FALSE,  FALSE,
4630     EL_QUICKSAND_FULL,                  -1, -1
4631   },
4632   {
4633     Xsand_stonesand_4,                  FALSE,  FALSE,
4634     EL_QUICKSAND_FULL,                  -1, -1
4635   },
4636   {
4637     Xsand_stoneout_1,                   FALSE,  FALSE,
4638     EL_ROCK,                            ACTION_EMPTYING, -1
4639   },
4640   {
4641     Xsand_stoneout_2,                   FALSE,  FALSE,
4642     EL_ROCK,                            ACTION_EMPTYING, -1
4643   },
4644   {
4645     Xsand_sandstone_1,                  FALSE,  FALSE,
4646     EL_QUICKSAND_FULL,                  -1, -1
4647   },
4648   {
4649     Xsand_sandstone_2,                  FALSE,  FALSE,
4650     EL_QUICKSAND_FULL,                  -1, -1
4651   },
4652   {
4653     Xsand_sandstone_3,                  FALSE,  FALSE,
4654     EL_QUICKSAND_FULL,                  -1, -1
4655   },
4656   {
4657     Xsand_sandstone_4,                  FALSE,  FALSE,
4658     EL_QUICKSAND_FULL,                  -1, -1
4659   },
4660   {
4661     Xplant,                             TRUE,   FALSE,
4662     EL_EMC_PLANT,                       -1, -1
4663   },
4664   {
4665     Yplant,                             FALSE,  FALSE,
4666     EL_EMC_PLANT,                       -1, -1
4667   },
4668   {
4669     Xlenses,                            TRUE,   FALSE,
4670     EL_EMC_LENSES,                      -1, -1
4671   },
4672   {
4673     Xmagnify,                           TRUE,   FALSE,
4674     EL_EMC_MAGNIFIER,                   -1, -1
4675   },
4676   {
4677     Xdripper,                           TRUE,   FALSE,
4678     EL_EMC_DRIPPER,                     -1, -1
4679   },
4680   {
4681     XdripperB,                          FALSE,  FALSE,
4682     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
4683   },
4684   {
4685     Xfake_blank,                        TRUE,   FALSE,
4686     EL_INVISIBLE_WALL,                  -1, -1
4687   },
4688   {
4689     Xfake_blankB,                       FALSE,  FALSE,
4690     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
4691   },
4692   {
4693     Xfake_grass,                        TRUE,   FALSE,
4694     EL_EMC_FAKE_GRASS,                  -1, -1
4695   },
4696   {
4697     Xfake_grassB,                       FALSE,  FALSE,
4698     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
4699   },
4700   {
4701     Xfake_door_1,                       TRUE,   FALSE,
4702     EL_EM_GATE_1_GRAY,                  -1, -1
4703   },
4704   {
4705     Xfake_door_2,                       TRUE,   FALSE,
4706     EL_EM_GATE_2_GRAY,                  -1, -1
4707   },
4708   {
4709     Xfake_door_3,                       TRUE,   FALSE,
4710     EL_EM_GATE_3_GRAY,                  -1, -1
4711   },
4712   {
4713     Xfake_door_4,                       TRUE,   FALSE,
4714     EL_EM_GATE_4_GRAY,                  -1, -1
4715   },
4716   {
4717     Xfake_door_5,                       TRUE,   FALSE,
4718     EL_EMC_GATE_5_GRAY,                 -1, -1
4719   },
4720   {
4721     Xfake_door_6,                       TRUE,   FALSE,
4722     EL_EMC_GATE_6_GRAY,                 -1, -1
4723   },
4724   {
4725     Xfake_door_7,                       TRUE,   FALSE,
4726     EL_EMC_GATE_7_GRAY,                 -1, -1
4727   },
4728   {
4729     Xfake_door_8,                       TRUE,   FALSE,
4730     EL_EMC_GATE_8_GRAY,                 -1, -1
4731   },
4732   {
4733     Xfake_acid_1,                       TRUE,   FALSE,
4734     EL_EMC_FAKE_ACID,                   -1, -1
4735   },
4736   {
4737     Xfake_acid_2,                       FALSE,  FALSE,
4738     EL_EMC_FAKE_ACID,                   -1, -1
4739   },
4740   {
4741     Xfake_acid_3,                       FALSE,  FALSE,
4742     EL_EMC_FAKE_ACID,                   -1, -1
4743   },
4744   {
4745     Xfake_acid_4,                       FALSE,  FALSE,
4746     EL_EMC_FAKE_ACID,                   -1, -1
4747   },
4748   {
4749     Xfake_acid_5,                       FALSE,  FALSE,
4750     EL_EMC_FAKE_ACID,                   -1, -1
4751   },
4752   {
4753     Xfake_acid_6,                       FALSE,  FALSE,
4754     EL_EMC_FAKE_ACID,                   -1, -1
4755   },
4756   {
4757     Xfake_acid_7,                       FALSE,  FALSE,
4758     EL_EMC_FAKE_ACID,                   -1, -1
4759   },
4760   {
4761     Xfake_acid_8,                       FALSE,  FALSE,
4762     EL_EMC_FAKE_ACID,                   -1, -1
4763   },
4764   {
4765     Xsteel_1,                           TRUE,   FALSE,
4766     EL_STEELWALL,                       -1, -1
4767   },
4768   {
4769     Xsteel_2,                           TRUE,   FALSE,
4770     EL_EMC_STEELWALL_2,                 -1, -1
4771   },
4772   {
4773     Xsteel_3,                           TRUE,   FALSE,
4774     EL_EMC_STEELWALL_3,                 -1, -1
4775   },
4776   {
4777     Xsteel_4,                           TRUE,   FALSE,
4778     EL_EMC_STEELWALL_4,                 -1, -1
4779   },
4780   {
4781     Xwall_1,                            TRUE,   FALSE,
4782     EL_WALL,                            -1, -1
4783   },
4784   {
4785     Xwall_2,                            TRUE,   FALSE,
4786     EL_EMC_WALL_14,                     -1, -1
4787   },
4788   {
4789     Xwall_3,                            TRUE,   FALSE,
4790     EL_EMC_WALL_15,                     -1, -1
4791   },
4792   {
4793     Xwall_4,                            TRUE,   FALSE,
4794     EL_EMC_WALL_16,                     -1, -1
4795   },
4796   {
4797     Xround_wall_1,                      TRUE,   FALSE,
4798     EL_WALL_SLIPPERY,                   -1, -1
4799   },
4800   {
4801     Xround_wall_2,                      TRUE,   FALSE,
4802     EL_EMC_WALL_SLIPPERY_2,             -1, -1
4803   },
4804   {
4805     Xround_wall_3,                      TRUE,   FALSE,
4806     EL_EMC_WALL_SLIPPERY_3,             -1, -1
4807   },
4808   {
4809     Xround_wall_4,                      TRUE,   FALSE,
4810     EL_EMC_WALL_SLIPPERY_4,             -1, -1
4811   },
4812   {
4813     Xdecor_1,                           TRUE,   FALSE,
4814     EL_EMC_WALL_8,                      -1, -1
4815   },
4816   {
4817     Xdecor_2,                           TRUE,   FALSE,
4818     EL_EMC_WALL_6,                      -1, -1
4819   },
4820   {
4821     Xdecor_3,                           TRUE,   FALSE,
4822     EL_EMC_WALL_4,                      -1, -1
4823   },
4824   {
4825     Xdecor_4,                           TRUE,   FALSE,
4826     EL_EMC_WALL_7,                      -1, -1
4827   },
4828   {
4829     Xdecor_5,                           TRUE,   FALSE,
4830     EL_EMC_WALL_5,                      -1, -1
4831   },
4832   {
4833     Xdecor_6,                           TRUE,   FALSE,
4834     EL_EMC_WALL_9,                      -1, -1
4835   },
4836   {
4837     Xdecor_7,                           TRUE,   FALSE,
4838     EL_EMC_WALL_10,                     -1, -1
4839   },
4840   {
4841     Xdecor_8,                           TRUE,   FALSE,
4842     EL_EMC_WALL_1,                      -1, -1
4843   },
4844   {
4845     Xdecor_9,                           TRUE,   FALSE,
4846     EL_EMC_WALL_2,                      -1, -1
4847   },
4848   {
4849     Xdecor_10,                          TRUE,   FALSE,
4850     EL_EMC_WALL_3,                      -1, -1
4851   },
4852   {
4853     Xdecor_11,                          TRUE,   FALSE,
4854     EL_EMC_WALL_11,                     -1, -1
4855   },
4856   {
4857     Xdecor_12,                          TRUE,   FALSE,
4858     EL_EMC_WALL_12,                     -1, -1
4859   },
4860   {
4861     Xalpha_0,                           TRUE,   FALSE,
4862     EL_CHAR('0'),                       -1, -1
4863   },
4864   {
4865     Xalpha_1,                           TRUE,   FALSE,
4866     EL_CHAR('1'),                       -1, -1
4867   },
4868   {
4869     Xalpha_2,                           TRUE,   FALSE,
4870     EL_CHAR('2'),                       -1, -1
4871   },
4872   {
4873     Xalpha_3,                           TRUE,   FALSE,
4874     EL_CHAR('3'),                       -1, -1
4875   },
4876   {
4877     Xalpha_4,                           TRUE,   FALSE,
4878     EL_CHAR('4'),                       -1, -1
4879   },
4880   {
4881     Xalpha_5,                           TRUE,   FALSE,
4882     EL_CHAR('5'),                       -1, -1
4883   },
4884   {
4885     Xalpha_6,                           TRUE,   FALSE,
4886     EL_CHAR('6'),                       -1, -1
4887   },
4888   {
4889     Xalpha_7,                           TRUE,   FALSE,
4890     EL_CHAR('7'),                       -1, -1
4891   },
4892   {
4893     Xalpha_8,                           TRUE,   FALSE,
4894     EL_CHAR('8'),                       -1, -1
4895   },
4896   {
4897     Xalpha_9,                           TRUE,   FALSE,
4898     EL_CHAR('9'),                       -1, -1
4899   },
4900   {
4901     Xalpha_excla,                       TRUE,   FALSE,
4902     EL_CHAR('!'),                       -1, -1
4903   },
4904   {
4905     Xalpha_quote,                       TRUE,   FALSE,
4906     EL_CHAR('"'),                       -1, -1
4907   },
4908   {
4909     Xalpha_comma,                       TRUE,   FALSE,
4910     EL_CHAR(','),                       -1, -1
4911   },
4912   {
4913     Xalpha_minus,                       TRUE,   FALSE,
4914     EL_CHAR('-'),                       -1, -1
4915   },
4916   {
4917     Xalpha_perio,                       TRUE,   FALSE,
4918     EL_CHAR('.'),                       -1, -1
4919   },
4920   {
4921     Xalpha_colon,                       TRUE,   FALSE,
4922     EL_CHAR(':'),                       -1, -1
4923   },
4924   {
4925     Xalpha_quest,                       TRUE,   FALSE,
4926     EL_CHAR('?'),                       -1, -1
4927   },
4928   {
4929     Xalpha_a,                           TRUE,   FALSE,
4930     EL_CHAR('A'),                       -1, -1
4931   },
4932   {
4933     Xalpha_b,                           TRUE,   FALSE,
4934     EL_CHAR('B'),                       -1, -1
4935   },
4936   {
4937     Xalpha_c,                           TRUE,   FALSE,
4938     EL_CHAR('C'),                       -1, -1
4939   },
4940   {
4941     Xalpha_d,                           TRUE,   FALSE,
4942     EL_CHAR('D'),                       -1, -1
4943   },
4944   {
4945     Xalpha_e,                           TRUE,   FALSE,
4946     EL_CHAR('E'),                       -1, -1
4947   },
4948   {
4949     Xalpha_f,                           TRUE,   FALSE,
4950     EL_CHAR('F'),                       -1, -1
4951   },
4952   {
4953     Xalpha_g,                           TRUE,   FALSE,
4954     EL_CHAR('G'),                       -1, -1
4955   },
4956   {
4957     Xalpha_h,                           TRUE,   FALSE,
4958     EL_CHAR('H'),                       -1, -1
4959   },
4960   {
4961     Xalpha_i,                           TRUE,   FALSE,
4962     EL_CHAR('I'),                       -1, -1
4963   },
4964   {
4965     Xalpha_j,                           TRUE,   FALSE,
4966     EL_CHAR('J'),                       -1, -1
4967   },
4968   {
4969     Xalpha_k,                           TRUE,   FALSE,
4970     EL_CHAR('K'),                       -1, -1
4971   },
4972   {
4973     Xalpha_l,                           TRUE,   FALSE,
4974     EL_CHAR('L'),                       -1, -1
4975   },
4976   {
4977     Xalpha_m,                           TRUE,   FALSE,
4978     EL_CHAR('M'),                       -1, -1
4979   },
4980   {
4981     Xalpha_n,                           TRUE,   FALSE,
4982     EL_CHAR('N'),                       -1, -1
4983   },
4984   {
4985     Xalpha_o,                           TRUE,   FALSE,
4986     EL_CHAR('O'),                       -1, -1
4987   },
4988   {
4989     Xalpha_p,                           TRUE,   FALSE,
4990     EL_CHAR('P'),                       -1, -1
4991   },
4992   {
4993     Xalpha_q,                           TRUE,   FALSE,
4994     EL_CHAR('Q'),                       -1, -1
4995   },
4996   {
4997     Xalpha_r,                           TRUE,   FALSE,
4998     EL_CHAR('R'),                       -1, -1
4999   },
5000   {
5001     Xalpha_s,                           TRUE,   FALSE,
5002     EL_CHAR('S'),                       -1, -1
5003   },
5004   {
5005     Xalpha_t,                           TRUE,   FALSE,
5006     EL_CHAR('T'),                       -1, -1
5007   },
5008   {
5009     Xalpha_u,                           TRUE,   FALSE,
5010     EL_CHAR('U'),                       -1, -1
5011   },
5012   {
5013     Xalpha_v,                           TRUE,   FALSE,
5014     EL_CHAR('V'),                       -1, -1
5015   },
5016   {
5017     Xalpha_w,                           TRUE,   FALSE,
5018     EL_CHAR('W'),                       -1, -1
5019   },
5020   {
5021     Xalpha_x,                           TRUE,   FALSE,
5022     EL_CHAR('X'),                       -1, -1
5023   },
5024   {
5025     Xalpha_y,                           TRUE,   FALSE,
5026     EL_CHAR('Y'),                       -1, -1
5027   },
5028   {
5029     Xalpha_z,                           TRUE,   FALSE,
5030     EL_CHAR('Z'),                       -1, -1
5031   },
5032   {
5033     Xalpha_arrow_e,                     TRUE,   FALSE,
5034     EL_CHAR('>'),                       -1, -1
5035   },
5036   {
5037     Xalpha_arrow_w,                     TRUE,   FALSE,
5038     EL_CHAR('<'),                       -1, -1
5039   },
5040   {
5041     Xalpha_copyr,                       TRUE,   FALSE,
5042     EL_CHAR('©'),                       -1, -1
5043   },
5044
5045   {
5046     Xboom_bug,                          FALSE,  FALSE,
5047     EL_BUG,                             ACTION_EXPLODING, -1
5048   },
5049   {
5050     Xboom_bomb,                         FALSE,  FALSE,
5051     EL_BOMB,                            ACTION_EXPLODING, -1
5052   },
5053   {
5054     Xboom_android,                      FALSE,  FALSE,
5055     EL_EMC_ANDROID,                     ACTION_OTHER, -1
5056   },
5057   {
5058     Xboom_1,                            FALSE,  FALSE,
5059     EL_DEFAULT,                         ACTION_EXPLODING, -1
5060   },
5061   {
5062     Xboom_2,                            FALSE,  FALSE,
5063     EL_DEFAULT,                         ACTION_EXPLODING, -1
5064   },
5065   {
5066     Znormal,                            FALSE,  FALSE,
5067     EL_EMPTY,                           -1, -1
5068   },
5069   {
5070     Zdynamite,                          FALSE,  FALSE,
5071     EL_EMPTY,                           -1, -1
5072   },
5073   {
5074     Zplayer,                            FALSE,  FALSE,
5075     EL_EMPTY,                           -1, -1
5076   },
5077   {
5078     ZBORDER,                            FALSE,  FALSE,
5079     EL_EMPTY,                           -1, -1
5080   },
5081
5082   {
5083     -1,                                 FALSE,  FALSE,
5084     -1,                                 -1, -1
5085   }
5086 };
5087
5088 static struct Mapping_EM_to_RND_player
5089 {
5090   int action_em;
5091   int player_nr;
5092
5093   int element_rnd;
5094   int action;
5095   int direction;
5096 }
5097 em_player_mapping_list[] =
5098 {
5099   {
5100     SPR_walk + 0,                       0,
5101     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
5102   },
5103   {
5104     SPR_walk + 1,                       0,
5105     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
5106   },
5107   {
5108     SPR_walk + 2,                       0,
5109     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
5110   },
5111   {
5112     SPR_walk + 3,                       0,
5113     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
5114   },
5115   {
5116     SPR_push + 0,                       0,
5117     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
5118   },
5119   {
5120     SPR_push + 1,                       0,
5121     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
5122   },
5123   {
5124     SPR_push + 2,                       0,
5125     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
5126   },
5127   {
5128     SPR_push + 3,                       0,
5129     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
5130   },
5131   {
5132     SPR_spray + 0,                      0,
5133     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
5134   },
5135   {
5136     SPR_spray + 1,                      0,
5137     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5138   },
5139   {
5140     SPR_spray + 2,                      0,
5141     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
5142   },
5143   {
5144     SPR_spray + 3,                      0,
5145     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
5146   },
5147   {
5148     SPR_walk + 0,                       1,
5149     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
5150   },
5151   {
5152     SPR_walk + 1,                       1,
5153     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
5154   },
5155   {
5156     SPR_walk + 2,                       1,
5157     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
5158   },
5159   {
5160     SPR_walk + 3,                       1,
5161     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
5162   },
5163   {
5164     SPR_push + 0,                       1,
5165     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
5166   },
5167   {
5168     SPR_push + 1,                       1,
5169     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
5170   },
5171   {
5172     SPR_push + 2,                       1,
5173     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
5174   },
5175   {
5176     SPR_push + 3,                       1,
5177     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
5178   },
5179   {
5180     SPR_spray + 0,                      1,
5181     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
5182   },
5183   {
5184     SPR_spray + 1,                      1,
5185     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5186   },
5187   {
5188     SPR_spray + 2,                      1,
5189     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
5190   },
5191   {
5192     SPR_spray + 3,                      1,
5193     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
5194   },
5195   {
5196     SPR_still,                          0,
5197     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
5198   },
5199   {
5200     SPR_still,                          1,
5201     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
5202   },
5203   {
5204     SPR_walk + 0,                       2,
5205     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
5206   },
5207   {
5208     SPR_walk + 1,                       2,
5209     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
5210   },
5211   {
5212     SPR_walk + 2,                       2,
5213     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
5214   },
5215   {
5216     SPR_walk + 3,                       2,
5217     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
5218   },
5219   {
5220     SPR_push + 0,                       2,
5221     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
5222   },
5223   {
5224     SPR_push + 1,                       2,
5225     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
5226   },
5227   {
5228     SPR_push + 2,                       2,
5229     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
5230   },
5231   {
5232     SPR_push + 3,                       2,
5233     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
5234   },
5235   {
5236     SPR_spray + 0,                      2,
5237     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
5238   },
5239   {
5240     SPR_spray + 1,                      2,
5241     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5242   },
5243   {
5244     SPR_spray + 2,                      2,
5245     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
5246   },
5247   {
5248     SPR_spray + 3,                      2,
5249     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
5250   },
5251   {
5252     SPR_walk + 0,                       3,
5253     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
5254   },
5255   {
5256     SPR_walk + 1,                       3,
5257     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
5258   },
5259   {
5260     SPR_walk + 2,                       3,
5261     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
5262   },
5263   {
5264     SPR_walk + 3,                       3,
5265     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
5266   },
5267   {
5268     SPR_push + 0,                       3,
5269     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
5270   },
5271   {
5272     SPR_push + 1,                       3,
5273     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
5274   },
5275   {
5276     SPR_push + 2,                       3,
5277     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
5278   },
5279   {
5280     SPR_push + 3,                       3,
5281     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
5282   },
5283   {
5284     SPR_spray + 0,                      3,
5285     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
5286   },
5287   {
5288     SPR_spray + 1,                      3,
5289     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5290   },
5291   {
5292     SPR_spray + 2,                      3,
5293     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
5294   },
5295   {
5296     SPR_spray + 3,                      3,
5297     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
5298   },
5299   {
5300     SPR_still,                          2,
5301     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
5302   },
5303   {
5304     SPR_still,                          3,
5305     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
5306   },
5307
5308   {
5309     -1,                                 -1,
5310     -1,                                 -1, -1
5311   }
5312 };
5313
5314 int map_element_RND_to_EM(int element_rnd)
5315 {
5316   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5317   static boolean mapping_initialized = FALSE;
5318
5319   if (!mapping_initialized)
5320   {
5321     int i;
5322
5323     /* return "Xalpha_quest" for all undefined elements in mapping array */
5324     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5325       mapping_RND_to_EM[i] = Xalpha_quest;
5326
5327     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5328       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5329         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5330           em_object_mapping_list[i].element_em;
5331
5332     mapping_initialized = TRUE;
5333   }
5334
5335   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5336     return mapping_RND_to_EM[element_rnd];
5337
5338   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5339
5340   return EL_UNKNOWN;
5341 }
5342
5343 int map_element_EM_to_RND(int element_em)
5344 {
5345   static unsigned short mapping_EM_to_RND[TILE_MAX];
5346   static boolean mapping_initialized = FALSE;
5347
5348   if (!mapping_initialized)
5349   {
5350     int i;
5351
5352     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5353     for (i = 0; i < TILE_MAX; i++)
5354       mapping_EM_to_RND[i] = EL_UNKNOWN;
5355
5356     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5357       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5358         em_object_mapping_list[i].element_rnd;
5359
5360     mapping_initialized = TRUE;
5361   }
5362
5363   if (element_em >= 0 && element_em < TILE_MAX)
5364     return mapping_EM_to_RND[element_em];
5365
5366   Error(ERR_WARN, "invalid EM level element %d", element_em);
5367
5368   return EL_UNKNOWN;
5369 }
5370
5371 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5372 {
5373   struct LevelInfo_EM *level_em = level->native_em_level;
5374   struct LEVEL *lev = level_em->lev;
5375   int i, j;
5376
5377   for (i = 0; i < TILE_MAX; i++)
5378     lev->android_array[i] = Xblank;
5379
5380   for (i = 0; i < level->num_android_clone_elements; i++)
5381   {
5382     int element_rnd = level->android_clone_element[i];
5383     int element_em = map_element_RND_to_EM(element_rnd);
5384
5385     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5386       if (em_object_mapping_list[j].element_rnd == element_rnd)
5387         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5388   }
5389 }
5390
5391 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5392 {
5393   struct LevelInfo_EM *level_em = level->native_em_level;
5394   struct LEVEL *lev = level_em->lev;
5395   int i, j;
5396
5397   level->num_android_clone_elements = 0;
5398
5399   for (i = 0; i < TILE_MAX; i++)
5400   {
5401     int element_em = lev->android_array[i];
5402     int element_rnd;
5403     boolean element_found = FALSE;
5404
5405     if (element_em == Xblank)
5406       continue;
5407
5408     element_rnd = map_element_EM_to_RND(element_em);
5409
5410     for (j = 0; j < level->num_android_clone_elements; j++)
5411       if (level->android_clone_element[j] == element_rnd)
5412         element_found = TRUE;
5413
5414     if (!element_found)
5415     {
5416       level->android_clone_element[level->num_android_clone_elements++] =
5417         element_rnd;
5418
5419       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5420         break;
5421     }
5422   }
5423
5424   if (level->num_android_clone_elements == 0)
5425   {
5426     level->num_android_clone_elements = 1;
5427     level->android_clone_element[0] = EL_EMPTY;
5428   }
5429 }
5430
5431 int map_direction_RND_to_EM(int direction)
5432 {
5433   return (direction == MV_UP    ? 0 :
5434           direction == MV_RIGHT ? 1 :
5435           direction == MV_DOWN  ? 2 :
5436           direction == MV_LEFT  ? 3 :
5437           -1);
5438 }
5439
5440 int map_direction_EM_to_RND(int direction)
5441 {
5442   return (direction == 0 ? MV_UP    :
5443           direction == 1 ? MV_RIGHT :
5444           direction == 2 ? MV_DOWN  :
5445           direction == 3 ? MV_LEFT  :
5446           MV_NONE);
5447 }
5448
5449 int get_next_element(int element)
5450 {
5451   switch (element)
5452   {
5453     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
5454     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
5455     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
5456     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
5457     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
5458     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
5459     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
5460     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
5461     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
5462     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
5463     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
5464
5465     default:                            return element;
5466   }
5467 }
5468
5469 #if 0
5470 int el_act_dir2img(int element, int action, int direction)
5471 {
5472   element = GFX_ELEMENT(element);
5473
5474   if (direction == MV_NONE)
5475     return element_info[element].graphic[action];
5476
5477   direction = MV_DIR_TO_BIT(direction);
5478
5479   return element_info[element].direction_graphic[action][direction];
5480 }
5481 #else
5482 int el_act_dir2img(int element, int action, int direction)
5483 {
5484   element = GFX_ELEMENT(element);
5485   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5486
5487   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5488   return element_info[element].direction_graphic[action][direction];
5489 }
5490 #endif
5491
5492 #if 0
5493 static int el_act_dir2crm(int element, int action, int direction)
5494 {
5495   element = GFX_ELEMENT(element);
5496
5497   if (direction == MV_NONE)
5498     return element_info[element].crumbled[action];
5499
5500   direction = MV_DIR_TO_BIT(direction);
5501
5502   return element_info[element].direction_crumbled[action][direction];
5503 }
5504 #else
5505 static int el_act_dir2crm(int element, int action, int direction)
5506 {
5507   element = GFX_ELEMENT(element);
5508   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5509
5510   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5511   return element_info[element].direction_crumbled[action][direction];
5512 }
5513 #endif
5514
5515 int el_act2img(int element, int action)
5516 {
5517   element = GFX_ELEMENT(element);
5518
5519   return element_info[element].graphic[action];
5520 }
5521
5522 int el_act2crm(int element, int action)
5523 {
5524   element = GFX_ELEMENT(element);
5525
5526   return element_info[element].crumbled[action];
5527 }
5528
5529 int el_dir2img(int element, int direction)
5530 {
5531   element = GFX_ELEMENT(element);
5532
5533   return el_act_dir2img(element, ACTION_DEFAULT, direction);
5534 }
5535
5536 int el2baseimg(int element)
5537 {
5538   return element_info[element].graphic[ACTION_DEFAULT];
5539 }
5540
5541 int el2img(int element)
5542 {
5543   element = GFX_ELEMENT(element);
5544
5545   return element_info[element].graphic[ACTION_DEFAULT];
5546 }
5547
5548 int el2edimg(int element)
5549 {
5550   element = GFX_ELEMENT(element);
5551
5552   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5553 }
5554
5555 int el2preimg(int element)
5556 {
5557   element = GFX_ELEMENT(element);
5558
5559   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5560 }
5561
5562 int font2baseimg(int font_nr)
5563 {
5564   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5565 }
5566
5567 int getNumActivePlayers_EM()
5568 {
5569   int num_players = 0;
5570   int i;
5571
5572   if (!tape.playing)
5573     return -1;
5574
5575   for (i = 0; i < MAX_PLAYERS; i++)
5576     if (tape.player_participates[i])
5577       num_players++;
5578
5579   return num_players;
5580 }
5581
5582 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5583 {
5584   int game_frame_delay_value;
5585
5586   game_frame_delay_value =
5587     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5588      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5589      GameFrameDelay);
5590
5591   if (tape.playing && tape.warp_forward && !tape.pausing)
5592     game_frame_delay_value = 0;
5593
5594   return game_frame_delay_value;
5595 }
5596
5597 unsigned int InitRND(long seed)
5598 {
5599   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5600     return InitEngineRandom_EM(seed);
5601   else
5602     return InitEngineRandom_RND(seed);
5603 }
5604
5605 void InitGraphicInfo_EM(void)
5606 {
5607   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5608   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5609   int i, j, p;
5610
5611 #if DEBUG_EM_GFX
5612   int num_em_gfx_errors = 0;
5613
5614   if (graphic_info_em_object[0][0].bitmap == NULL)
5615   {
5616     /* EM graphics not yet initialized in em_open_all() */
5617
5618     return;
5619   }
5620
5621   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5622 #endif
5623
5624   /* always start with reliable default values */
5625   for (i = 0; i < TILE_MAX; i++)
5626   {
5627     object_mapping[i].element_rnd = EL_UNKNOWN;
5628     object_mapping[i].is_backside = FALSE;
5629     object_mapping[i].action = ACTION_DEFAULT;
5630     object_mapping[i].direction = MV_NONE;
5631   }
5632
5633   /* always start with reliable default values */
5634   for (p = 0; p < MAX_PLAYERS; p++)
5635   {
5636     for (i = 0; i < SPR_MAX; i++)
5637     {
5638       player_mapping[p][i].element_rnd = EL_UNKNOWN;
5639       player_mapping[p][i].action = ACTION_DEFAULT;
5640       player_mapping[p][i].direction = MV_NONE;
5641     }
5642   }
5643
5644   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5645   {
5646     int e = em_object_mapping_list[i].element_em;
5647
5648     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5649     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5650
5651     if (em_object_mapping_list[i].action != -1)
5652       object_mapping[e].action = em_object_mapping_list[i].action;
5653
5654     if (em_object_mapping_list[i].direction != -1)
5655       object_mapping[e].direction =
5656         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5657   }
5658
5659   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5660   {
5661     int a = em_player_mapping_list[i].action_em;
5662     int p = em_player_mapping_list[i].player_nr;
5663
5664     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5665
5666     if (em_player_mapping_list[i].action != -1)
5667       player_mapping[p][a].action = em_player_mapping_list[i].action;
5668
5669     if (em_player_mapping_list[i].direction != -1)
5670       player_mapping[p][a].direction =
5671         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5672   }
5673
5674   for (i = 0; i < TILE_MAX; i++)
5675   {
5676     int element = object_mapping[i].element_rnd;
5677     int action = object_mapping[i].action;
5678     int direction = object_mapping[i].direction;
5679     boolean is_backside = object_mapping[i].is_backside;
5680     boolean action_removing = (action == ACTION_DIGGING ||
5681                                action == ACTION_SNAPPING ||
5682                                action == ACTION_COLLECTING);
5683     boolean action_exploding = ((action == ACTION_EXPLODING ||
5684                                  action == ACTION_SMASHED_BY_ROCK ||
5685                                  action == ACTION_SMASHED_BY_SPRING) &&
5686                                 element != EL_DIAMOND);
5687     boolean action_active = (action == ACTION_ACTIVE);
5688     boolean action_other = (action == ACTION_OTHER);
5689
5690     for (j = 0; j < 8; j++)
5691     {
5692       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5693                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5694                                j < 7 ? element :
5695                                i == Xdrip_stretch ? element :
5696                                i == Xdrip_stretchB ? element :
5697                                i == Ydrip_s1 ? element :
5698                                i == Ydrip_s1B ? element :
5699                                i == Xball_1B ? element :
5700                                i == Xball_2 ? element :
5701                                i == Xball_2B ? element :
5702                                i == Yball_eat ? element :
5703                                i == Ykey_1_eat ? element :
5704                                i == Ykey_2_eat ? element :
5705                                i == Ykey_3_eat ? element :
5706                                i == Ykey_4_eat ? element :
5707                                i == Ykey_5_eat ? element :
5708                                i == Ykey_6_eat ? element :
5709                                i == Ykey_7_eat ? element :
5710                                i == Ykey_8_eat ? element :
5711                                i == Ylenses_eat ? element :
5712                                i == Ymagnify_eat ? element :
5713                                i == Ygrass_eat ? element :
5714                                i == Ydirt_eat ? element :
5715                                i == Yemerald_stone ? EL_EMERALD :
5716                                i == Ydiamond_stone ? EL_ROCK :
5717                                i == Xsand_stonein_1 ? element :
5718                                i == Xsand_stonein_2 ? element :
5719                                i == Xsand_stonein_3 ? element :
5720                                i == Xsand_stonein_4 ? element :
5721                                is_backside ? EL_EMPTY :
5722                                action_removing ? EL_EMPTY :
5723                                element);
5724       int effective_action = (j < 7 ? action :
5725                               i == Xdrip_stretch ? action :
5726                               i == Xdrip_stretchB ? action :
5727                               i == Ydrip_s1 ? action :
5728                               i == Ydrip_s1B ? action :
5729                               i == Xball_1B ? action :
5730                               i == Xball_2 ? action :
5731                               i == Xball_2B ? action :
5732                               i == Yball_eat ? action :
5733                               i == Ykey_1_eat ? action :
5734                               i == Ykey_2_eat ? action :
5735                               i == Ykey_3_eat ? action :
5736                               i == Ykey_4_eat ? action :
5737                               i == Ykey_5_eat ? action :
5738                               i == Ykey_6_eat ? action :
5739                               i == Ykey_7_eat ? action :
5740                               i == Ykey_8_eat ? action :
5741                               i == Ylenses_eat ? action :
5742                               i == Ymagnify_eat ? action :
5743                               i == Ygrass_eat ? action :
5744                               i == Ydirt_eat ? action :
5745                               i == Xsand_stonein_1 ? action :
5746                               i == Xsand_stonein_2 ? action :
5747                               i == Xsand_stonein_3 ? action :
5748                               i == Xsand_stonein_4 ? action :
5749                               i == Xsand_stoneout_1 ? action :
5750                               i == Xsand_stoneout_2 ? action :
5751                               i == Xboom_android ? ACTION_EXPLODING :
5752                               action_exploding ? ACTION_EXPLODING :
5753                               action_active ? action :
5754                               action_other ? action :
5755                               ACTION_DEFAULT);
5756       int graphic = (el_act_dir2img(effective_element, effective_action,
5757                                     direction));
5758       int crumbled = (el_act_dir2crm(effective_element, effective_action,
5759                                      direction));
5760       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5761       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5762       boolean has_action_graphics = (graphic != base_graphic);
5763       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5764       struct GraphicInfo *g = &graphic_info[graphic];
5765       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5766       Bitmap *src_bitmap;
5767       int src_x, src_y;
5768       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
5769       boolean special_animation = (action != ACTION_DEFAULT &&
5770                                    g->anim_frames == 3 &&
5771                                    g->anim_delay == 2 &&
5772                                    g->anim_mode & ANIM_LINEAR);
5773       int sync_frame = (i == Xdrip_stretch ? 7 :
5774                         i == Xdrip_stretchB ? 7 :
5775                         i == Ydrip_s2 ? j + 8 :
5776                         i == Ydrip_s2B ? j + 8 :
5777                         i == Xacid_1 ? 0 :
5778                         i == Xacid_2 ? 10 :
5779                         i == Xacid_3 ? 20 :
5780                         i == Xacid_4 ? 30 :
5781                         i == Xacid_5 ? 40 :
5782                         i == Xacid_6 ? 50 :
5783                         i == Xacid_7 ? 60 :
5784                         i == Xacid_8 ? 70 :
5785                         i == Xfake_acid_1 ? 0 :
5786                         i == Xfake_acid_2 ? 10 :
5787                         i == Xfake_acid_3 ? 20 :
5788                         i == Xfake_acid_4 ? 30 :
5789                         i == Xfake_acid_5 ? 40 :
5790                         i == Xfake_acid_6 ? 50 :
5791                         i == Xfake_acid_7 ? 60 :
5792                         i == Xfake_acid_8 ? 70 :
5793                         i == Xball_2 ? 7 :
5794                         i == Xball_2B ? j + 8 :
5795                         i == Yball_eat ? j + 1 :
5796                         i == Ykey_1_eat ? j + 1 :
5797                         i == Ykey_2_eat ? j + 1 :
5798                         i == Ykey_3_eat ? j + 1 :
5799                         i == Ykey_4_eat ? j + 1 :
5800                         i == Ykey_5_eat ? j + 1 :
5801                         i == Ykey_6_eat ? j + 1 :
5802                         i == Ykey_7_eat ? j + 1 :
5803                         i == Ykey_8_eat ? j + 1 :
5804                         i == Ylenses_eat ? j + 1 :
5805                         i == Ymagnify_eat ? j + 1 :
5806                         i == Ygrass_eat ? j + 1 :
5807                         i == Ydirt_eat ? j + 1 :
5808                         i == Xamoeba_1 ? 0 :
5809                         i == Xamoeba_2 ? 1 :
5810                         i == Xamoeba_3 ? 2 :
5811                         i == Xamoeba_4 ? 3 :
5812                         i == Xamoeba_5 ? 0 :
5813                         i == Xamoeba_6 ? 1 :
5814                         i == Xamoeba_7 ? 2 :
5815                         i == Xamoeba_8 ? 3 :
5816                         i == Xexit_2 ? j + 8 :
5817                         i == Xexit_3 ? j + 16 :
5818                         i == Xdynamite_1 ? 0 :
5819                         i == Xdynamite_2 ? 8 :
5820                         i == Xdynamite_3 ? 16 :
5821                         i == Xdynamite_4 ? 24 :
5822                         i == Xsand_stonein_1 ? j + 1 :
5823                         i == Xsand_stonein_2 ? j + 9 :
5824                         i == Xsand_stonein_3 ? j + 17 :
5825                         i == Xsand_stonein_4 ? j + 25 :
5826                         i == Xsand_stoneout_1 && j == 0 ? 0 :
5827                         i == Xsand_stoneout_1 && j == 1 ? 0 :
5828                         i == Xsand_stoneout_1 && j == 2 ? 1 :
5829                         i == Xsand_stoneout_1 && j == 3 ? 2 :
5830                         i == Xsand_stoneout_1 && j == 4 ? 2 :
5831                         i == Xsand_stoneout_1 && j == 5 ? 3 :
5832                         i == Xsand_stoneout_1 && j == 6 ? 4 :
5833                         i == Xsand_stoneout_1 && j == 7 ? 4 :
5834                         i == Xsand_stoneout_2 && j == 0 ? 5 :
5835                         i == Xsand_stoneout_2 && j == 1 ? 6 :
5836                         i == Xsand_stoneout_2 && j == 2 ? 7 :
5837                         i == Xsand_stoneout_2 && j == 3 ? 8 :
5838                         i == Xsand_stoneout_2 && j == 4 ? 9 :
5839                         i == Xsand_stoneout_2 && j == 5 ? 11 :
5840                         i == Xsand_stoneout_2 && j == 6 ? 13 :
5841                         i == Xsand_stoneout_2 && j == 7 ? 15 :
5842                         i == Xboom_bug && j == 1 ? 2 :
5843                         i == Xboom_bug && j == 2 ? 2 :
5844                         i == Xboom_bug && j == 3 ? 4 :
5845                         i == Xboom_bug && j == 4 ? 4 :
5846                         i == Xboom_bug && j == 5 ? 2 :
5847                         i == Xboom_bug && j == 6 ? 2 :
5848                         i == Xboom_bug && j == 7 ? 0 :
5849                         i == Xboom_bomb && j == 1 ? 2 :
5850                         i == Xboom_bomb && j == 2 ? 2 :
5851                         i == Xboom_bomb && j == 3 ? 4 :
5852                         i == Xboom_bomb && j == 4 ? 4 :
5853                         i == Xboom_bomb && j == 5 ? 2 :
5854                         i == Xboom_bomb && j == 6 ? 2 :
5855                         i == Xboom_bomb && j == 7 ? 0 :
5856                         i == Xboom_android && j == 7 ? 6 :
5857                         i == Xboom_1 && j == 1 ? 2 :
5858                         i == Xboom_1 && j == 2 ? 2 :
5859                         i == Xboom_1 && j == 3 ? 4 :
5860                         i == Xboom_1 && j == 4 ? 4 :
5861                         i == Xboom_1 && j == 5 ? 6 :
5862                         i == Xboom_1 && j == 6 ? 6 :
5863                         i == Xboom_1 && j == 7 ? 8 :
5864                         i == Xboom_2 && j == 0 ? 8 :
5865                         i == Xboom_2 && j == 1 ? 8 :
5866                         i == Xboom_2 && j == 2 ? 10 :
5867                         i == Xboom_2 && j == 3 ? 10 :
5868                         i == Xboom_2 && j == 4 ? 10 :
5869                         i == Xboom_2 && j == 5 ? 12 :
5870                         i == Xboom_2 && j == 6 ? 12 :
5871                         i == Xboom_2 && j == 7 ? 12 :
5872                         special_animation && j == 4 ? 3 :
5873                         effective_action != action ? 0 :
5874                         j);
5875
5876 #if DEBUG_EM_GFX
5877       Bitmap *debug_bitmap = g_em->bitmap;
5878       int debug_src_x = g_em->src_x;
5879       int debug_src_y = g_em->src_y;
5880 #endif
5881
5882       int frame = getAnimationFrame(g->anim_frames,
5883                                     g->anim_delay,
5884                                     g->anim_mode,
5885                                     g->anim_start_frame,
5886                                     sync_frame);
5887
5888       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
5889                           g->double_movement && is_backside);
5890
5891       g_em->bitmap = src_bitmap;
5892       g_em->src_x = src_x;
5893       g_em->src_y = src_y;
5894       g_em->src_offset_x = 0;
5895       g_em->src_offset_y = 0;
5896       g_em->dst_offset_x = 0;
5897       g_em->dst_offset_y = 0;
5898       g_em->width  = TILEX;
5899       g_em->height = TILEY;
5900
5901       g_em->crumbled_bitmap = NULL;
5902       g_em->crumbled_src_x = 0;
5903       g_em->crumbled_src_y = 0;
5904       g_em->crumbled_border_size = 0;
5905
5906       g_em->has_crumbled_graphics = FALSE;
5907       g_em->preserve_background = FALSE;
5908
5909 #if 0
5910       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
5911         printf("::: empty crumbled: %d [%s], %d, %d\n",
5912                effective_element, element_info[effective_element].token_name,
5913                effective_action, direction);
5914 #endif
5915
5916       /* if element can be crumbled, but certain action graphics are just empty
5917          space (like snapping sand with the original R'n'D graphics), do not
5918          treat these empty space graphics as crumbled graphics in EMC engine */
5919       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
5920       {
5921         getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
5922
5923         g_em->has_crumbled_graphics = TRUE;
5924         g_em->crumbled_bitmap = src_bitmap;
5925         g_em->crumbled_src_x = src_x;
5926         g_em->crumbled_src_y = src_y;
5927         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
5928       }
5929
5930 #if 0
5931       if (element == EL_ROCK &&
5932           effective_action == ACTION_FILLING)
5933         printf("::: has_action_graphics == %d\n", has_action_graphics);
5934 #endif
5935
5936       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
5937                                    effective_action == ACTION_MOVING  ||
5938                                    effective_action == ACTION_PUSHING ||
5939                                    effective_action == ACTION_EATING)) ||
5940           (!has_action_graphics && (effective_action == ACTION_FILLING ||
5941                                     effective_action == ACTION_EMPTYING)))
5942       {
5943         int move_dir =
5944           (effective_action == ACTION_FALLING ||
5945            effective_action == ACTION_FILLING ||
5946            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
5947         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
5948         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
5949         int num_steps = (i == Ydrip_s1  ? 16 :
5950                          i == Ydrip_s1B ? 16 :
5951                          i == Ydrip_s2  ? 16 :
5952                          i == Ydrip_s2B ? 16 :
5953                          i == Xsand_stonein_1 ? 32 :
5954                          i == Xsand_stonein_2 ? 32 :
5955                          i == Xsand_stonein_3 ? 32 :
5956                          i == Xsand_stonein_4 ? 32 :
5957                          i == Xsand_stoneout_1 ? 16 :
5958                          i == Xsand_stoneout_2 ? 16 : 8);
5959         int cx = ABS(dx) * (TILEX / num_steps);
5960         int cy = ABS(dy) * (TILEY / num_steps);
5961         int step_frame = (i == Ydrip_s2         ? j + 8 :
5962                           i == Ydrip_s2B        ? j + 8 :
5963                           i == Xsand_stonein_2  ? j + 8 :
5964                           i == Xsand_stonein_3  ? j + 16 :
5965                           i == Xsand_stonein_4  ? j + 24 :
5966                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
5967         int step = (is_backside ? step_frame : num_steps - step_frame);
5968
5969         if (is_backside)        /* tile where movement starts */
5970         {
5971           if (dx < 0 || dy < 0)
5972           {
5973             g_em->src_offset_x = cx * step;
5974             g_em->src_offset_y = cy * step;
5975           }
5976           else
5977           {
5978             g_em->dst_offset_x = cx * step;
5979             g_em->dst_offset_y = cy * step;
5980           }
5981         }
5982         else                    /* tile where movement ends */
5983         {
5984           if (dx < 0 || dy < 0)
5985           {
5986             g_em->dst_offset_x = cx * step;
5987             g_em->dst_offset_y = cy * step;
5988           }
5989           else
5990           {
5991             g_em->src_offset_x = cx * step;
5992             g_em->src_offset_y = cy * step;
5993           }
5994         }
5995
5996         g_em->width  = TILEX - cx * step;
5997         g_em->height = TILEY - cy * step;
5998       }
5999
6000       /* create unique graphic identifier to decide if tile must be redrawn */
6001       /* bit 31 - 16 (16 bit): EM style graphic
6002          bit 15 - 12 ( 4 bit): EM style frame
6003          bit 11 -  6 ( 6 bit): graphic width
6004          bit  5 -  0 ( 6 bit): graphic height */
6005       g_em->unique_identifier =
6006         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6007
6008 #if DEBUG_EM_GFX
6009
6010       /* skip check for EMC elements not contained in original EMC artwork */
6011       if (element == EL_EMC_FAKE_ACID)
6012         continue;
6013
6014       if (g_em->bitmap != debug_bitmap ||
6015           g_em->src_x != debug_src_x ||
6016           g_em->src_y != debug_src_y ||
6017           g_em->src_offset_x != 0 ||
6018           g_em->src_offset_y != 0 ||
6019           g_em->dst_offset_x != 0 ||
6020           g_em->dst_offset_y != 0 ||
6021           g_em->width != TILEX ||
6022           g_em->height != TILEY)
6023       {
6024         static int last_i = -1;
6025
6026         if (i != last_i)
6027         {
6028           printf("\n");
6029           last_i = i;
6030         }
6031
6032         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6033                i, element, element_info[element].token_name,
6034                element_action_info[effective_action].suffix, direction);
6035
6036         if (element != effective_element)
6037           printf(" [%d ('%s')]",
6038                  effective_element,
6039                  element_info[effective_element].token_name);
6040
6041         printf("\n");
6042
6043         if (g_em->bitmap != debug_bitmap)
6044           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6045                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6046
6047         if (g_em->src_x != debug_src_x ||
6048             g_em->src_y != debug_src_y)
6049           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6050                  j, (is_backside ? 'B' : 'F'),
6051                  g_em->src_x, g_em->src_y,
6052                  g_em->src_x / 32, g_em->src_y / 32,
6053                  debug_src_x, debug_src_y,
6054                  debug_src_x / 32, debug_src_y / 32);
6055
6056         if (g_em->src_offset_x != 0 ||
6057             g_em->src_offset_y != 0 ||
6058             g_em->dst_offset_x != 0 ||
6059             g_em->dst_offset_y != 0)
6060           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6061                  j, is_backside,
6062                  g_em->src_offset_x, g_em->src_offset_y,
6063                  g_em->dst_offset_x, g_em->dst_offset_y);
6064
6065         if (g_em->width != TILEX ||
6066             g_em->height != TILEY)
6067           printf("    %d (%d): size %d,%d should be %d,%d\n",
6068                  j, is_backside,
6069                  g_em->width, g_em->height, TILEX, TILEY);
6070
6071         num_em_gfx_errors++;
6072       }
6073 #endif
6074
6075     }
6076   }
6077
6078   for (i = 0; i < TILE_MAX; i++)
6079   {
6080     for (j = 0; j < 8; j++)
6081     {
6082       int element = object_mapping[i].element_rnd;
6083       int action = object_mapping[i].action;
6084       int direction = object_mapping[i].direction;
6085       boolean is_backside = object_mapping[i].is_backside;
6086       int graphic_action  = el_act_dir2img(element, action, direction);
6087       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6088
6089       if ((action == ACTION_SMASHED_BY_ROCK ||
6090            action == ACTION_SMASHED_BY_SPRING ||
6091            action == ACTION_EATING) &&
6092           graphic_action == graphic_default)
6093       {
6094         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
6095                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6096                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
6097                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6098                  Xspring);
6099
6100         /* no separate animation for "smashed by rock" -- use rock instead */
6101         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6102         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6103
6104         g_em->bitmap            = g_xx->bitmap;
6105         g_em->src_x             = g_xx->src_x;
6106         g_em->src_y             = g_xx->src_y;
6107         g_em->src_offset_x      = g_xx->src_offset_x;
6108         g_em->src_offset_y      = g_xx->src_offset_y;
6109         g_em->dst_offset_x      = g_xx->dst_offset_x;
6110         g_em->dst_offset_y      = g_xx->dst_offset_y;
6111         g_em->width             = g_xx->width;
6112         g_em->height            = g_xx->height;
6113         g_em->unique_identifier = g_xx->unique_identifier;
6114
6115         if (!is_backside)
6116           g_em->preserve_background = TRUE;
6117       }
6118     }
6119   }
6120
6121   for (p = 0; p < MAX_PLAYERS; p++)
6122   {
6123     for (i = 0; i < SPR_MAX; i++)
6124     {
6125       int element = player_mapping[p][i].element_rnd;
6126       int action = player_mapping[p][i].action;
6127       int direction = player_mapping[p][i].direction;
6128
6129       for (j = 0; j < 8; j++)
6130       {
6131         int effective_element = element;
6132         int effective_action = action;
6133         int graphic = (direction == MV_NONE ?
6134                        el_act2img(effective_element, effective_action) :
6135                        el_act_dir2img(effective_element, effective_action,
6136                                       direction));
6137         struct GraphicInfo *g = &graphic_info[graphic];
6138         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6139         Bitmap *src_bitmap;
6140         int src_x, src_y;
6141         int sync_frame = j;
6142
6143 #if DEBUG_EM_GFX
6144         Bitmap *debug_bitmap = g_em->bitmap;
6145         int debug_src_x = g_em->src_x;
6146         int debug_src_y = g_em->src_y;
6147 #endif
6148
6149         int frame = getAnimationFrame(g->anim_frames,
6150                                       g->anim_delay,
6151                                       g->anim_mode,
6152                                       g->anim_start_frame,
6153                                       sync_frame);
6154
6155         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
6156
6157         g_em->bitmap = src_bitmap;
6158         g_em->src_x = src_x;
6159         g_em->src_y = src_y;
6160         g_em->src_offset_x = 0;
6161         g_em->src_offset_y = 0;
6162         g_em->dst_offset_x = 0;
6163         g_em->dst_offset_y = 0;
6164         g_em->width  = TILEX;
6165         g_em->height = TILEY;
6166
6167 #if DEBUG_EM_GFX
6168
6169         /* skip check for EMC elements not contained in original EMC artwork */
6170         if (element == EL_PLAYER_3 ||
6171             element == EL_PLAYER_4)
6172           continue;
6173
6174         if (g_em->bitmap != debug_bitmap ||
6175             g_em->src_x != debug_src_x ||
6176             g_em->src_y != debug_src_y)
6177         {
6178           static int last_i = -1;
6179
6180           if (i != last_i)
6181           {
6182             printf("\n");
6183             last_i = i;
6184           }
6185
6186           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6187                  p, i, element, element_info[element].token_name,
6188                  element_action_info[effective_action].suffix, direction);
6189
6190           if (element != effective_element)
6191             printf(" [%d ('%s')]",
6192                    effective_element,
6193                    element_info[effective_element].token_name);
6194
6195           printf("\n");
6196
6197           if (g_em->bitmap != debug_bitmap)
6198             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
6199                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
6200
6201           if (g_em->src_x != debug_src_x ||
6202               g_em->src_y != debug_src_y)
6203             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6204                    j,
6205                    g_em->src_x, g_em->src_y,
6206                    g_em->src_x / 32, g_em->src_y / 32,
6207                    debug_src_x, debug_src_y,
6208                    debug_src_x / 32, debug_src_y / 32);
6209
6210           num_em_gfx_errors++;
6211         }
6212 #endif
6213
6214       }
6215     }
6216   }
6217
6218 #if DEBUG_EM_GFX
6219   printf("\n");
6220   printf("::: [%d errors found]\n", num_em_gfx_errors);
6221
6222   exit(0);
6223 #endif
6224 }
6225
6226 void PlayMenuSound()
6227 {
6228   int sound = menu.sound[game_status];
6229
6230   if (sound == SND_UNDEFINED)
6231     return;
6232
6233   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6234       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6235     return;
6236
6237   if (IS_LOOP_SOUND(sound))
6238     PlaySoundLoop(sound);
6239   else
6240     PlaySound(sound);
6241 }
6242
6243 void PlayMenuSoundStereo(int sound, int stereo_position)
6244 {
6245   if (sound == SND_UNDEFINED)
6246     return;
6247
6248   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6249       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6250     return;
6251
6252   if (IS_LOOP_SOUND(sound))
6253     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6254   else
6255     PlaySoundStereo(sound, stereo_position);
6256 }
6257
6258 void PlayMenuSoundIfLoop()
6259 {
6260   int sound = menu.sound[game_status];
6261
6262   if (sound == SND_UNDEFINED)
6263     return;
6264
6265   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6266       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6267     return;
6268
6269   if (IS_LOOP_SOUND(sound))
6270     PlaySoundLoop(sound);
6271 }
6272
6273 void PlayMenuMusic()
6274 {
6275   int music = menu.music[game_status];
6276
6277   if (music == MUS_UNDEFINED)
6278     return;
6279
6280   if (!setup.sound_music)
6281     return;
6282
6283   PlayMusic(music);
6284 }
6285
6286 void PlaySoundActivating()
6287 {
6288 #if 0
6289   PlaySound(SND_MENU_ITEM_ACTIVATING);
6290 #endif
6291 }
6292
6293 void PlaySoundSelecting()
6294 {
6295 #if 0
6296   PlaySound(SND_MENU_ITEM_SELECTING);
6297 #endif
6298 }
6299
6300 void ToggleFullscreenIfNeeded()
6301 {
6302   boolean change_fullscreen = (setup.fullscreen !=
6303                                video.fullscreen_enabled);
6304   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6305                                     !strEqual(setup.fullscreen_mode,
6306                                               video.fullscreen_mode_current));
6307
6308   if (!video.fullscreen_available)
6309     return;
6310
6311 #if 1
6312   if (change_fullscreen || change_fullscreen_mode)
6313 #else
6314   if (setup.fullscreen != video.fullscreen_enabled ||
6315       setup.fullscreen_mode != video.fullscreen_mode_current)
6316 #endif
6317   {
6318     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6319
6320     /* save backbuffer content which gets lost when toggling fullscreen mode */
6321     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6322
6323 #if 1
6324     if (change_fullscreen_mode)
6325 #else
6326     if (setup.fullscreen && video.fullscreen_enabled)
6327 #endif
6328     {
6329       /* keep fullscreen, but change fullscreen mode (screen resolution) */
6330 #if 1
6331       /* (this is now set in sdl.c) */
6332 #else
6333       video.fullscreen_mode_current = setup.fullscreen_mode;
6334 #endif
6335       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
6336     }
6337
6338     /* toggle fullscreen */
6339     ChangeVideoModeIfNeeded(setup.fullscreen);
6340
6341     setup.fullscreen = video.fullscreen_enabled;
6342
6343     /* restore backbuffer content from temporary backbuffer backup bitmap */
6344     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6345
6346     FreeBitmap(tmp_backbuffer);
6347
6348 #if 1
6349     /* update visible window/screen */
6350     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6351 #else
6352     redraw_mask = REDRAW_ALL;
6353 #endif
6354   }
6355 }