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