rnd-20100719-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 "init.h"
18 #include "game.h"
19 #include "events.h"
20 #include "cartoons.h"
21 #include "network.h"
22 #include "tape.h"
23 #include "screens.h"
24
25
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX    0
28
29 /* tool button identifiers */
30 #define TOOL_CTRL_ID_YES        0
31 #define TOOL_CTRL_ID_NO         1
32 #define TOOL_CTRL_ID_CONFIRM    2
33 #define TOOL_CTRL_ID_PLAYER_1   3
34 #define TOOL_CTRL_ID_PLAYER_2   4
35 #define TOOL_CTRL_ID_PLAYER_3   5
36 #define TOOL_CTRL_ID_PLAYER_4   6
37
38 #define NUM_TOOL_BUTTONS        7
39
40 /* forward declaration for internal use */
41 static void UnmapToolButtons();
42 static void HandleToolButtons(struct GadgetInfo *);
43 static int el_act_dir2crm(int, int, int);
44 static int el_act2crm(int, int);
45
46 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
47 static int request_gadget_id = -1;
48
49 static char *print_if_not_empty(int element)
50 {
51   static char *s = NULL;
52   char *token_name = element_info[element].token_name;
53
54   if (s != NULL)
55     free(s);
56
57   s = checked_malloc(strlen(token_name) + 10 + 1);
58
59   if (element != EL_EMPTY)
60     sprintf(s, "%d\t['%s']", element, token_name);
61   else
62     sprintf(s, "%d", element);
63
64   return s;
65 }
66
67 void DumpTile(int x, int y)
68 {
69   int sx = SCREENX(x);
70   int sy = SCREENY(y);
71
72   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
73   {
74     x--;
75     y--;
76   }
77
78   printf_line("-", 79);
79   printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80   printf_line("-", 79);
81
82   if (!IN_LEV_FIELD(x, y))
83   {
84     printf("(not in level field)\n");
85     printf("\n");
86
87     return;
88   }
89
90   printf("  Feld:        %d\t['%s']\n", Feld[x][y],
91          element_info[Feld[x][y]].token_name);
92   printf("  Back:        %s\n", print_if_not_empty(Back[x][y]));
93   printf("  Store:       %s\n", print_if_not_empty(Store[x][y]));
94   printf("  Store2:      %s\n", print_if_not_empty(Store2[x][y]));
95   printf("  StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
96   printf("  MovPos:      %d\n", MovPos[x][y]);
97   printf("  MovDir:      %d\n", MovDir[x][y]);
98   printf("  MovDelay:    %d\n", MovDelay[x][y]);
99   printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
100   printf("  CustomValue: %d\n", CustomValue[x][y]);
101   printf("  GfxElement:  %d\n", GfxElement[x][y]);
102   printf("  GfxAction:   %d\n", GfxAction[x][y]);
103   printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
104   printf("\n");
105 }
106
107 void SetDrawtoField(int mode)
108 {
109   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
110   {
111 #if NEW_TILESIZE
112 #if NEW_SCROLL
113     FX = 2 * TILEX_VAR;
114     FY = 2 * TILEY_VAR;
115     BX1 = -2;
116     BY1 = -2;
117     BX2 = SCR_FIELDX + 1;
118     BY2 = SCR_FIELDY + 1;
119     redraw_x1 = 2;
120     redraw_y1 = 2;
121 #else
122     FX = TILEX_VAR;
123     FY = TILEY_VAR;
124     BX1 = -1;
125     BY1 = -1;
126     BX2 = SCR_FIELDX;
127     BY2 = SCR_FIELDY;
128     redraw_x1 = 1;
129     redraw_y1 = 1;
130 #endif
131 #else
132 #if NEW_SCROLL
133     FX = 2 * TILEX;
134     FY = 2 * TILEY;
135     BX1 = -2;
136     BY1 = -2;
137     BX2 = SCR_FIELDX + 1;
138     BY2 = SCR_FIELDY + 1;
139     redraw_x1 = 2;
140     redraw_y1 = 2;
141 #else
142     FX = TILEX;
143     FY = TILEY;
144     BX1 = -1;
145     BY1 = -1;
146     BX2 = SCR_FIELDX;
147     BY2 = SCR_FIELDY;
148     redraw_x1 = 1;
149     redraw_y1 = 1;
150 #endif
151 #endif
152
153     drawto_field = fieldbuffer;
154   }
155   else  /* DRAW_BACKBUFFER */
156   {
157     FX = SX;
158     FY = SY;
159     BX1 = 0;
160     BY1 = 0;
161     BX2 = SCR_FIELDX - 1;
162     BY2 = SCR_FIELDY - 1;
163     redraw_x1 = 0;
164     redraw_y1 = 0;
165
166     drawto_field = backbuffer;
167   }
168 }
169
170 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
171 {
172   if (game_status == GAME_MODE_PLAYING &&
173       level.game_engine_type == GAME_ENGINE_TYPE_EM)
174   {
175     /* currently there is no partial redraw -- always redraw whole playfield */
176     RedrawPlayfield_EM(TRUE);
177
178     /* blit playfield from scroll buffer to normal back buffer for fading in */
179     BlitScreenToBitmap_EM(backbuffer);
180   }
181   else if (game_status == GAME_MODE_PLAYING &&
182            level.game_engine_type == GAME_ENGINE_TYPE_SP)
183   {
184     /* currently there is no partial redraw -- always redraw whole playfield */
185     RedrawPlayfield_SP(TRUE);
186
187     /* blit playfield from scroll buffer to normal back buffer for fading in */
188     BlitScreenToBitmap_SP(backbuffer);
189   }
190   else if (game_status == GAME_MODE_PLAYING &&
191            !game.envelope_active)
192   {
193     if (force_redraw)
194     {
195       x = gfx.sx - TILEX;
196       y = gfx.sy - TILEY;
197       width = gfx.sxsize + 2 * TILEX;
198       height = gfx.sysize + 2 * TILEY;
199     }
200
201     if (force_redraw)
202     {
203       int xx, yy;
204       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
205       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
206
207       for (xx = BX1; xx <= BX2; xx++)
208         for (yy = BY1; yy <= BY2; yy++)
209           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
210             DrawScreenField(xx, yy);
211       DrawAllPlayers();
212     }
213
214     if (setup.soft_scrolling)
215     {
216       int fx = FX, fy = FY;
217
218       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
219       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
220
221       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
222     }
223   }
224
225   if (force_redraw)
226   {
227     x = gfx.sx;
228     y = gfx.sy;
229     width = gfx.sxsize;
230     height = gfx.sysize;
231   }
232
233   BlitBitmap(drawto, window, x, y, width, height, x, y);
234 }
235
236 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
237 {
238   Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
239
240   SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
241   BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
242 }
243
244 void DrawMaskedBorder_FIELD()
245 {
246   if (global.border_status >= GAME_MODE_TITLE &&
247       global.border_status <= GAME_MODE_PLAYING &&
248       border.draw_masked[global.border_status])
249     DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
250 }
251
252 void DrawMaskedBorder_DOOR_1()
253 {
254   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
255       (global.border_status != GAME_MODE_EDITOR ||
256        border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
257     DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
258 }
259
260 void DrawMaskedBorder_DOOR_2()
261 {
262   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
263       global.border_status != GAME_MODE_EDITOR)
264     DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
265 }
266
267 void DrawMaskedBorder_DOOR_3()
268 {
269   /* currently not available */
270 }
271
272 void DrawMaskedBorder_ALL()
273 {
274   DrawMaskedBorder_FIELD();
275   DrawMaskedBorder_DOOR_1();
276   DrawMaskedBorder_DOOR_2();
277   DrawMaskedBorder_DOOR_3();
278 }
279
280 void DrawMaskedBorder(int redraw_mask)
281 {
282   /* never draw masked screen borders on borderless screens */
283   if (effectiveGameStatus() == GAME_MODE_LOADING ||
284       effectiveGameStatus() == GAME_MODE_TITLE)
285     return;
286
287   /* never draw masked screen borders when displaying request outside door */
288   if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
289       global.use_envelope_request)
290     return;
291
292   if (redraw_mask & REDRAW_ALL)
293     DrawMaskedBorder_ALL();
294   else
295   {
296     if (redraw_mask & REDRAW_FIELD)
297       DrawMaskedBorder_FIELD();
298     if (redraw_mask & REDRAW_DOOR_1)
299       DrawMaskedBorder_DOOR_1();
300     if (redraw_mask & REDRAW_DOOR_2)
301       DrawMaskedBorder_DOOR_2();
302     if (redraw_mask & REDRAW_DOOR_3)
303       DrawMaskedBorder_DOOR_3();
304   }
305 }
306
307 void BlitScreenToBitmap(Bitmap *target_bitmap)
308 {
309   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
310   int fx = FX, fy = FY;
311
312 #if NEW_TILESIZE
313   int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
314   int dy = (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
315   int dx_var = dx * TILESIZE_VAR / TILESIZE;
316   int dy_var = dy * TILESIZE_VAR / TILESIZE;
317   int ffx, ffy;
318
319   // fx += dx * TILESIZE_VAR / TILESIZE;
320   // fy += dy * TILESIZE_VAR / TILESIZE;
321 #else
322   fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
323   fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
324 #endif
325
326   ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
327   ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
328
329   if (EVEN(SCR_FIELDX))
330   {
331     if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
332       fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
333     else
334       fx += (dx_var > 0 ? TILEX_VAR : 0);
335   }
336   else
337   {
338     fx += dx_var;
339   }
340
341   if (EVEN(SCR_FIELDY))
342   {
343     if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
344       fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
345     else
346       fy += (dy_var > 0 ? TILEY_VAR : 0);
347   }
348   else
349   {
350     fy += dy_var;
351   }
352
353 #if 0
354   printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
355          scroll_x, scroll_y,
356          SBX_Left, SBX_Right,
357          SBY_Upper, SBY_Lower,
358          fx, fy);
359 #endif
360
361   if (border.draw_masked[GAME_MODE_PLAYING])
362   {
363     if (buffer != backbuffer)
364     {
365       /* copy playfield buffer to backbuffer to add masked border */
366       BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
367       DrawMaskedBorder(REDRAW_FIELD);
368     }
369
370     BlitBitmap(backbuffer, target_bitmap,
371                REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
372                REAL_SX, REAL_SY);
373   }
374   else
375   {
376     BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
377   }
378 }
379
380 void BackToFront()
381 {
382   int x, y;
383   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
384
385 #if 0
386   printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
387   for (x = 0; x < SCR_FIELDX; x++)
388     for (y = 0 ; y < SCR_FIELDY; y++)
389       if (redraw[redraw_x1 + x][redraw_y1 + y])
390         printf("::: - %d, %d [%s]\n",
391                LEVELX(x), LEVELY(y),
392                EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
393 #endif
394
395   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
396     redraw_mask |= REDRAW_FIELD;
397
398 #if 0
399   /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 */
400   /* (force full redraw) */
401   if (game_status == GAME_MODE_PLAYING)
402     redraw_mask |= REDRAW_FIELD;
403 #endif
404
405   if (redraw_mask & REDRAW_FIELD)
406     redraw_mask &= ~REDRAW_TILES;
407
408   if (redraw_mask == REDRAW_NONE)
409     return;
410
411   if (redraw_mask & REDRAW_TILES &&
412       game_status == GAME_MODE_PLAYING &&
413       border.draw_masked[GAME_MODE_PLAYING])
414     redraw_mask |= REDRAW_FIELD;
415
416   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
417   {
418     static boolean last_frame_skipped = FALSE;
419     boolean skip_even_when_not_scrolling = TRUE;
420     boolean just_scrolling = (ScreenMovDir != 0);
421     boolean verbose = FALSE;
422
423     if (global.fps_slowdown_factor > 1 &&
424         (FrameCounter % global.fps_slowdown_factor) &&
425         (just_scrolling || skip_even_when_not_scrolling))
426     {
427       redraw_mask &= ~REDRAW_MAIN;
428
429       last_frame_skipped = TRUE;
430
431       if (verbose)
432         printf("FRAME SKIPPED\n");
433     }
434     else
435     {
436       if (last_frame_skipped)
437         redraw_mask |= REDRAW_FIELD;
438
439       last_frame_skipped = FALSE;
440
441       if (verbose)
442         printf("frame not skipped\n");
443     }
444   }
445
446   /* synchronize X11 graphics at this point; if we would synchronize the
447      display immediately after the buffer switching (after the XFlush),
448      this could mean that we have to wait for the graphics to complete,
449      although we could go on doing calculations for the next frame */
450
451   SyncDisplay();
452
453   /* never draw masked border to backbuffer when using playfield buffer */
454   if (game_status != GAME_MODE_PLAYING ||
455       redraw_mask & REDRAW_FROM_BACKBUFFER ||
456       buffer == backbuffer)
457     DrawMaskedBorder(redraw_mask);
458   else
459     DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
460
461   if (redraw_mask & REDRAW_ALL)
462   {
463     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
464
465     redraw_mask = REDRAW_NONE;
466   }
467
468   if (redraw_mask & REDRAW_FIELD)
469   {
470 #if 0
471     printf("::: REDRAW_FIELD\n");
472 #endif
473
474     if (game_status != GAME_MODE_PLAYING ||
475         redraw_mask & REDRAW_FROM_BACKBUFFER)
476     {
477       BlitBitmap(backbuffer, window,
478                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
479     }
480     else
481     {
482 #if 1
483       BlitScreenToBitmap(window);
484 #else
485       int fx = FX, fy = FY;
486
487 #if NEW_TILESIZE
488       int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
489       int dy = (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
490       int dx_var = dx * TILESIZE_VAR / TILESIZE;
491       int dy_var = dy * TILESIZE_VAR / TILESIZE;
492       int ffx, ffy;
493
494       // fx += dx * TILESIZE_VAR / TILESIZE;
495       // fy += dy * TILESIZE_VAR / TILESIZE;
496 #else
497       fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
498       fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
499 #endif
500
501       /* !!! THIS WORKS !!! */
502
503       printf("::: %d, %d\n", scroll_x, scroll_y);
504
505       ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
506       ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
507
508       if (EVEN(SCR_FIELDX))
509       {
510         if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
511           fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
512         else
513           fx += (dx > 0 ? TILEX_VAR : 0);
514       }
515       else
516       {
517         fx += dx;
518       }
519
520       if (EVEN(SCR_FIELDY))
521       {
522         if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
523           fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
524         else
525           fy += (dy > 0 ? TILEY_VAR : 0);
526       }
527       else
528       {
529         fy += dy;
530       }
531
532       if (border.draw_masked[GAME_MODE_PLAYING])
533       {
534         if (buffer != backbuffer)
535         {
536           /* copy playfield buffer to backbuffer to add masked border */
537           BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
538           DrawMaskedBorder(REDRAW_FIELD);
539         }
540
541         BlitBitmap(backbuffer, window,
542                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
543                    REAL_SX, REAL_SY);
544       }
545       else
546       {
547         BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
548       }
549 #endif
550
551 #if 0
552 #ifdef DEBUG
553       printf("redrawing all (ScreenGfxPos == %d) because %s\n",
554              ScreenGfxPos,
555              (setup.soft_scrolling ?
556               "setup.soft_scrolling" :
557               ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
558               "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
559               ABS(ScreenGfxPos) == ScrollStepSize ?
560               "ABS(ScreenGfxPos) == ScrollStepSize" :
561               "redraw_tiles > REDRAWTILES_THRESHOLD"));
562 #endif
563 #endif
564     }
565
566     redraw_mask &= ~REDRAW_MAIN;
567   }
568
569   if (redraw_mask & REDRAW_DOORS)
570   {
571     if (redraw_mask & REDRAW_DOOR_1)
572       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
573
574     if (redraw_mask & REDRAW_DOOR_2)
575       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
576
577     if (redraw_mask & REDRAW_DOOR_3)
578       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
579
580     redraw_mask &= ~REDRAW_DOORS;
581   }
582
583   if (redraw_mask & REDRAW_MICROLEVEL)
584   {
585     BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
586                SX, SY + 10 * TILEY);
587
588     redraw_mask &= ~REDRAW_MICROLEVEL;
589   }
590
591   if (redraw_mask & REDRAW_TILES)
592   {
593 #if 0
594     printf("::: REDRAW_TILES\n");
595 #endif
596
597 #if NEW_TILESIZE
598
599 #if 1
600     InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
601
602     {
603       int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
604       int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
605
606       int dx = 0, dy = 0;
607       int dx_var = dx * TILESIZE_VAR / TILESIZE;
608       int dy_var = dy * TILESIZE_VAR / TILESIZE;
609       int ffx, ffy;
610       int fx = FX, fy = FY;
611
612       int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
613       int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
614
615       ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
616       ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
617
618       if (EVEN(SCR_FIELDX))
619       {
620         if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
621         {
622           fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
623
624           if (fx % TILEX_VAR)
625             sx -= TILEX_VAR / 2;
626           else
627             sx -= TILEX_VAR;
628         }
629         else
630         {
631           fx += (dx_var > 0 ? TILEX_VAR : 0);
632         }
633       }
634
635       if (EVEN(SCR_FIELDY))
636       {
637         if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
638         {
639           fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
640
641           if (fy % TILEY_VAR)
642             sy -= TILEY_VAR / 2;
643           else
644             sy -= TILEY_VAR;
645         }
646         else
647         {
648           fy += (dy_var > 0 ? TILEY_VAR : 0);
649         }
650       }
651
652 #if 0
653       printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
654 #endif
655
656       for (x = 0; x < scr_fieldx; x++)
657         for (y = 0 ; y < scr_fieldy; y++)
658           if (redraw[redraw_x1 + x][redraw_y1 + y])
659             BlitBitmap(buffer, window,
660                        FX + x * TILEX_VAR, FY + y * TILEY_VAR,
661                        TILEX_VAR, TILEY_VAR,
662                        sx + x * TILEX_VAR, sy + y * TILEY_VAR);
663     }
664
665     InitGfxClipRegion(FALSE, -1, -1, -1, -1);
666 #else
667     for (x = 0; x < SCR_FIELDX; x++)
668       for (y = 0 ; y < SCR_FIELDY; y++)
669         if (redraw[redraw_x1 + x][redraw_y1 + y])
670           BlitBitmap(buffer, window,
671                      FX + x * TILEX_VAR, FY + y * TILEY_VAR,
672                      TILEX_VAR, TILEY_VAR,
673                      SX + x * TILEX_VAR, SY + y * TILEY_VAR);
674 #endif
675
676 #else
677     for (x = 0; x < SCR_FIELDX; x++)
678       for (y = 0 ; y < SCR_FIELDY; y++)
679         if (redraw[redraw_x1 + x][redraw_y1 + y])
680           BlitBitmap(buffer, window,
681                      FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
682                      SX + x * TILEX, SY + y * TILEY);
683 #endif
684   }
685
686   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
687   {
688     char text[100];
689     char info1[100];
690
691     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
692     if (!global.fps_slowdown)
693       info1[0] = '\0';
694
695     sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
696 #if 1
697     DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
698 #else
699     DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
700 #endif
701   }
702
703   FlushDisplay();
704
705   for (x = 0; x < MAX_BUF_XSIZE; x++)
706     for (y = 0; y < MAX_BUF_YSIZE; y++)
707       redraw[x][y] = 0;
708   redraw_tiles = 0;
709   redraw_mask = REDRAW_NONE;
710 }
711
712 static void FadeCrossSaveBackbuffer()
713 {
714   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
715 }
716
717 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
718 {
719   static int fade_type_skip = FADE_TYPE_NONE;
720   void (*draw_border_function)(void) = NULL;
721   Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
722   int x, y, width, height;
723   int fade_delay, post_delay;
724
725   if (fade_type == FADE_TYPE_FADE_OUT)
726   {
727     if (fade_type_skip != FADE_TYPE_NONE)
728     {
729 #if 0
730       printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
731 #endif
732
733       /* skip all fade operations until specified fade operation */
734       if (fade_type & fade_type_skip)
735         fade_type_skip = FADE_TYPE_NONE;
736
737       return;
738     }
739
740     if (fading.fade_mode & FADE_TYPE_TRANSFORM)
741     {
742       FadeCrossSaveBackbuffer();
743
744       return;
745     }
746   }
747
748   redraw_mask |= fade_mask;
749
750   if (fade_type == FADE_TYPE_SKIP)
751   {
752 #if 0
753     printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
754 #endif
755
756     fade_type_skip = fade_mode;
757
758     return;
759   }
760
761 #if 0
762   printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
763          fade_type_skip);
764 #endif
765
766 #if 1
767   fade_delay = fading.fade_delay;
768   post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
769 #endif
770
771   if (fade_type_skip != FADE_TYPE_NONE)
772   {
773 #if 0
774     printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
775 #endif
776
777     /* skip all fade operations until specified fade operation */
778     if (fade_type & fade_type_skip)
779       fade_type_skip = FADE_TYPE_NONE;
780
781 #if 1
782     fade_delay = 0;
783 #else
784     return;
785 #endif
786   }
787
788 #if 1
789   if (global.autoplay_leveldir)
790   {
791     // fading.fade_mode = FADE_MODE_NONE;
792
793     return;
794   }
795 #endif
796
797 #if 0
798   if (fading.fade_mode == FADE_MODE_NONE)
799   {
800     BackToFront();
801
802     return;
803   }
804 #endif
805
806   /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
807
808 #if 0
809   printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
810 #endif
811
812 #if 0
813   if (fade_mask == REDRAW_NONE)
814     fade_mask = REDRAW_FIELD;
815 #endif
816
817   // if (fade_mask & REDRAW_FIELD)
818   if (fade_mask == REDRAW_FIELD)
819   {
820     x = REAL_SX;
821     y = REAL_SY;
822     width  = FULL_SXSIZE;
823     height = FULL_SYSIZE;
824
825 #if 0
826     fade_delay = fading.fade_delay;
827     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
828 #endif
829
830     if (border.draw_masked_when_fading)
831       draw_border_function = DrawMaskedBorder_FIELD;    /* update when fading */
832     else
833       DrawMaskedBorder_FIELD();                         /* draw once */
834   }
835   else          /* REDRAW_ALL */
836   {
837     x = 0;
838     y = 0;
839     width  = WIN_XSIZE;
840     height = WIN_YSIZE;
841
842 #if 0
843     fade_delay = fading.fade_delay;
844     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
845 #endif
846   }
847
848 #if 1
849   if (!setup.fade_screens ||
850       fade_delay == 0 ||
851       fading.fade_mode == FADE_MODE_NONE)
852 #else
853   if (!setup.fade_screens || fade_delay == 0)
854 #endif
855   {
856     if (fade_mode == FADE_MODE_FADE_OUT)
857       return;
858
859 #if 0
860     if (fade_mode == FADE_MODE_FADE_OUT &&
861         fading.fade_mode != FADE_MODE_NONE)
862       ClearRectangle(backbuffer, x, y, width, height);
863 #endif
864
865 #if 1
866     BlitBitmap(backbuffer, window, x, y, width, height, x, y);
867     redraw_mask = REDRAW_NONE;
868 #else
869     BackToFront();
870 #endif
871
872     return;
873   }
874
875   FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
876                 draw_border_function);
877
878   redraw_mask &= ~fade_mask;
879 }
880
881 void FadeIn(int fade_mask)
882 {
883   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
884     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
885   else
886     FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
887 }
888
889 void FadeOut(int fade_mask)
890 {
891   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
892     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
893   else
894     FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
895
896   global.border_status = game_status;
897 }
898
899 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
900 {
901   static struct TitleFadingInfo fading_leave_stored;
902
903   if (set)
904     fading_leave_stored = fading_leave;
905   else
906     fading = fading_leave_stored;
907 }
908
909 void FadeSetEnterMenu()
910 {
911   fading = menu.enter_menu;
912
913 #if 0
914   printf("::: storing enter_menu\n");
915 #endif
916
917   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
918 }
919
920 void FadeSetLeaveMenu()
921 {
922   fading = menu.leave_menu;
923
924 #if 0
925   printf("::: storing leave_menu\n");
926 #endif
927
928   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
929 }
930
931 void FadeSetEnterScreen()
932 {
933   fading = menu.enter_screen[game_status];
934
935 #if 0
936   printf("::: storing leave_screen[%d]\n", game_status);
937 #endif
938
939   FadeSetLeaveNext(menu.leave_screen[game_status], TRUE);       /* store */
940 }
941
942 void FadeSetNextScreen()
943 {
944   fading = menu.next_screen;
945
946 #if 0
947   printf("::: storing next_screen\n");
948 #endif
949
950   // (do not overwrite fade mode set by FadeSetEnterScreen)
951   // FadeSetLeaveNext(fading, TRUE);    /* (keep same fade mode) */
952 }
953
954 void FadeSetLeaveScreen()
955 {
956 #if 0
957   printf("::: recalling last stored value\n");
958 #endif
959
960   FadeSetLeaveNext(menu.leave_screen[game_status], FALSE);      /* recall */
961 }
962
963 void FadeSetFromType(int type)
964 {
965   if (type & TYPE_ENTER_SCREEN)
966     FadeSetEnterScreen();
967   else if (type & TYPE_ENTER)
968     FadeSetEnterMenu();
969   else if (type & TYPE_LEAVE)
970     FadeSetLeaveMenu();
971 }
972
973 void FadeSetDisabled()
974 {
975   static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
976
977   fading = fading_none;
978 }
979
980 void FadeSkipNextFadeIn()
981 {
982   FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
983 }
984
985 void FadeSkipNextFadeOut()
986 {
987   FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
988 }
989
990 void SetWindowBackgroundImageIfDefined(int graphic)
991 {
992   if (graphic_info[graphic].bitmap)
993     SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
994 }
995
996 void SetMainBackgroundImageIfDefined(int graphic)
997 {
998   if (graphic_info[graphic].bitmap)
999     SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1000 }
1001
1002 void SetDoorBackgroundImageIfDefined(int graphic)
1003 {
1004   if (graphic_info[graphic].bitmap)
1005     SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1006 }
1007
1008 void SetWindowBackgroundImage(int graphic)
1009 {
1010   SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1011                             graphic_info[graphic].bitmap ?
1012                             graphic_info[graphic].bitmap :
1013                             graphic_info[IMG_BACKGROUND].bitmap);
1014 }
1015
1016 void SetMainBackgroundImage(int graphic)
1017 {
1018   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1019                           graphic_info[graphic].bitmap ?
1020                           graphic_info[graphic].bitmap :
1021                           graphic_info[IMG_BACKGROUND].bitmap);
1022 }
1023
1024 void SetDoorBackgroundImage(int graphic)
1025 {
1026   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1027                           graphic_info[graphic].bitmap ?
1028                           graphic_info[graphic].bitmap :
1029                           graphic_info[IMG_BACKGROUND].bitmap);
1030 }
1031
1032 void SetPanelBackground()
1033 {
1034 #if 1
1035   struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1036
1037 #if 1
1038   BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1039                   gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1040 #else
1041   /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1042   ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1043   BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1044              MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1045 #endif
1046 #else
1047   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1048              DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1049 #endif
1050
1051   SetDoorBackgroundBitmap(bitmap_db_panel);
1052 }
1053
1054 void DrawBackground(int x, int y, int width, int height)
1055 {
1056   /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1057   /* (when entering hall of fame after playing) */
1058 #if 0
1059   ClearRectangleOnBackground(drawto, x, y, width, height);
1060 #else
1061   ClearRectangleOnBackground(backbuffer, x, y, width, height);
1062 #endif
1063
1064   redraw_mask |= REDRAW_FIELD;
1065 }
1066
1067 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1068 {
1069   struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1070
1071   if (font->bitmap == NULL)
1072     return;
1073
1074   DrawBackground(x, y, width, height);
1075 }
1076
1077 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1078 {
1079   struct GraphicInfo *g = &graphic_info[graphic];
1080
1081   if (g->bitmap == NULL)
1082     return;
1083
1084   DrawBackground(x, y, width, height);
1085 }
1086
1087 void ClearField()
1088 {
1089   /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1090   /* (when entering hall of fame after playing) */
1091   DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1092
1093   /* !!! maybe this should be done before clearing the background !!! */
1094   if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1095   {
1096     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1097     SetDrawtoField(DRAW_BUFFERED);
1098   }
1099   else
1100     SetDrawtoField(DRAW_BACKBUFFER);
1101 }
1102
1103 void MarkTileDirty(int x, int y)
1104 {
1105   int xx = redraw_x1 + x;
1106   int yy = redraw_y1 + y;
1107
1108   if (!redraw[xx][yy])
1109     redraw_tiles++;
1110
1111   redraw[xx][yy] = TRUE;
1112   redraw_mask |= REDRAW_TILES;
1113 }
1114
1115 void SetBorderElement()
1116 {
1117   int x, y;
1118
1119   BorderElement = EL_EMPTY;
1120
1121   for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1122   {
1123     for (x = 0; x < lev_fieldx; x++)
1124     {
1125       if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1126         BorderElement = EL_STEELWALL;
1127
1128       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1129         x = lev_fieldx - 2;
1130     }
1131   }
1132 }
1133
1134 void FloodFillLevel(int from_x, int from_y, int fill_element,
1135                     short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1136                     int max_fieldx, int max_fieldy)
1137 {
1138   int i,x,y;
1139   int old_element;
1140   static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1141   static int safety = 0;
1142
1143   /* check if starting field still has the desired content */
1144   if (field[from_x][from_y] == fill_element)
1145     return;
1146
1147   safety++;
1148
1149   if (safety > max_fieldx * max_fieldy)
1150     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1151
1152   old_element = field[from_x][from_y];
1153   field[from_x][from_y] = fill_element;
1154
1155   for (i = 0; i < 4; i++)
1156   {
1157     x = from_x + check[i][0];
1158     y = from_y + check[i][1];
1159
1160     if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1161       FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1162   }
1163
1164   safety--;
1165 }
1166
1167 void SetRandomAnimationValue(int x, int y)
1168 {
1169   gfx.anim_random_frame = GfxRandom[x][y];
1170 }
1171
1172 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1173 {
1174   /* animation synchronized with global frame counter, not move position */
1175   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1176     sync_frame = FrameCounter;
1177
1178   return getAnimationFrame(graphic_info[graphic].anim_frames,
1179                            graphic_info[graphic].anim_delay,
1180                            graphic_info[graphic].anim_mode,
1181                            graphic_info[graphic].anim_start_frame,
1182                            sync_frame);
1183 }
1184
1185 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1186                               Bitmap **bitmap, int *x, int *y,
1187                               boolean get_backside)
1188 {
1189   struct
1190   {
1191     int width_mult, width_div;
1192     int height_mult, height_div;
1193   }
1194   offset_calc[6] =
1195   {
1196     { 15, 16,   2, 3    },      /* 1 x 1 */
1197     { 7, 8,     2, 3    },      /* 2 x 2 */
1198     { 3, 4,     2, 3    },      /* 4 x 4 */
1199     { 1, 2,     2, 3    },      /* 8 x 8 */
1200     { 0, 1,     2, 3    },      /* 16 x 16 */
1201     { 0, 1,     0, 1    },      /* 32 x 32 */
1202   };
1203   struct GraphicInfo *g = &graphic_info[graphic];
1204   Bitmap *src_bitmap = g->bitmap;
1205   int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1206   int offset_calc_pos = log_2(tilesize);
1207   int width_mult  = offset_calc[offset_calc_pos].width_mult;
1208   int width_div   = offset_calc[offset_calc_pos].width_div;
1209   int height_mult = offset_calc[offset_calc_pos].height_mult;
1210   int height_div  = offset_calc[offset_calc_pos].height_div;
1211   int startx = src_bitmap->width * width_mult / width_div;
1212   int starty = src_bitmap->height * height_mult / height_div;
1213 #if NEW_TILESIZE
1214   int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1215     tilesize / TILESIZE;
1216   int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1217     tilesize / TILESIZE;
1218 #else
1219   int src_x = g->src_x * tilesize / TILESIZE;
1220   int src_y = g->src_y * tilesize / TILESIZE;
1221 #endif
1222   int width = g->width * tilesize / TILESIZE;
1223   int height = g->height * tilesize / TILESIZE;
1224   int offset_x = g->offset_x * tilesize / TILESIZE;
1225   int offset_y = g->offset_y * tilesize / TILESIZE;
1226
1227   if (g->offset_y == 0)         /* frames are ordered horizontally */
1228   {
1229     int max_width = g->anim_frames_per_line * width;
1230     int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1231
1232     src_x = pos % max_width;
1233     src_y = src_y % height + pos / max_width * height;
1234   }
1235   else if (g->offset_x == 0)    /* frames are ordered vertically */
1236   {
1237     int max_height = g->anim_frames_per_line * height;
1238     int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1239
1240     src_x = src_x % width + pos / max_height * width;
1241     src_y = pos % max_height;
1242   }
1243   else                          /* frames are ordered diagonally */
1244   {
1245     src_x = src_x + frame * offset_x;
1246     src_y = src_y + frame * offset_y;
1247   }
1248
1249   *bitmap = src_bitmap;
1250   *x = startx + src_x;
1251   *y = starty + src_y;
1252 }
1253
1254 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1255                               int *x, int *y, boolean get_backside)
1256 {
1257   getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1258                            get_backside);
1259 }
1260
1261 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1262                            Bitmap **bitmap, int *x, int *y)
1263 {
1264   getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1265 }
1266
1267 void getFixedGraphicSource(int graphic, int frame,
1268                            Bitmap **bitmap, int *x, int *y)
1269 {
1270   getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1271 }
1272
1273 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1274 {
1275 #if 1
1276   getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1277 #else
1278   struct GraphicInfo *g = &graphic_info[graphic];
1279   int mini_startx = 0;
1280   int mini_starty = g->bitmap->height * 2 / 3;
1281
1282   *bitmap = g->bitmap;
1283   *x = mini_startx + g->src_x / 2;
1284   *y = mini_starty + g->src_y / 2;
1285 #endif
1286 }
1287
1288 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1289                                 int *x, int *y, boolean get_backside)
1290 {
1291   struct GraphicInfo *g = &graphic_info[graphic];
1292   int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1293   int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1294
1295 #if NEW_TILESIZE
1296   if (TILESIZE_VAR != TILESIZE)
1297     return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1298                                     get_backside);
1299 #endif
1300
1301   *bitmap = g->bitmap;
1302
1303   if (g->offset_y == 0)         /* frames are ordered horizontally */
1304   {
1305     int max_width = g->anim_frames_per_line * g->width;
1306     int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1307
1308     *x = pos % max_width;
1309     *y = src_y % g->height + pos / max_width * g->height;
1310   }
1311   else if (g->offset_x == 0)    /* frames are ordered vertically */
1312   {
1313     int max_height = g->anim_frames_per_line * g->height;
1314     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1315
1316     *x = src_x % g->width + pos / max_height * g->width;
1317     *y = pos % max_height;
1318   }
1319   else                          /* frames are ordered diagonally */
1320   {
1321     *x = src_x + frame * g->offset_x;
1322     *y = src_y + frame * g->offset_y;
1323   }
1324 }
1325
1326 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1327 {
1328   getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1329 }
1330
1331 void DrawGraphic(int x, int y, int graphic, int frame)
1332 {
1333 #if DEBUG
1334   if (!IN_SCR_FIELD(x, y))
1335   {
1336     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1337     printf("DrawGraphic(): This should never happen!\n");
1338     return;
1339   }
1340 #endif
1341
1342 #if NEW_TILESIZE
1343   DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1344                  frame);
1345 #else
1346   DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1347 #endif
1348   MarkTileDirty(x, y);
1349 }
1350
1351 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1352 {
1353 #if DEBUG
1354   if (!IN_SCR_FIELD(x, y))
1355   {
1356     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1357     printf("DrawGraphic(): This should never happen!\n");
1358     return;
1359   }
1360 #endif
1361
1362   DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1363                       frame);
1364   MarkTileDirty(x, y);
1365 }
1366
1367 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1368                     int frame)
1369 {
1370   Bitmap *src_bitmap;
1371   int src_x, src_y;
1372
1373   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1374 #if NEW_TILESIZE
1375   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1376 #else
1377   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1378 #endif
1379 }
1380
1381 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1382                          int frame)
1383 {
1384   Bitmap *src_bitmap;
1385   int src_x, src_y;
1386
1387   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1388   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1389 }
1390
1391 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1392 {
1393 #if DEBUG
1394   if (!IN_SCR_FIELD(x, y))
1395   {
1396     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1397     printf("DrawGraphicThruMask(): This should never happen!\n");
1398     return;
1399   }
1400 #endif
1401
1402 #if NEW_TILESIZE
1403   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1404                          graphic, frame);
1405 #else
1406   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1407                          frame);
1408 #endif
1409   MarkTileDirty(x, y);
1410 }
1411
1412 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1413 {
1414 #if DEBUG
1415   if (!IN_SCR_FIELD(x, y))
1416   {
1417     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1418     printf("DrawGraphicThruMask(): This should never happen!\n");
1419     return;
1420   }
1421 #endif
1422
1423   DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1424                               graphic, frame);
1425   MarkTileDirty(x, y);
1426 }
1427
1428 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1429                             int frame)
1430 {
1431   Bitmap *src_bitmap;
1432   int src_x, src_y;
1433
1434   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1435
1436   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1437                 dst_x - src_x, dst_y - src_y);
1438 #if NEW_TILESIZE
1439   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1440                    dst_x, dst_y);
1441 #else
1442   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1443 #endif
1444 }
1445
1446 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1447                                  int graphic, int frame)
1448 {
1449   Bitmap *src_bitmap;
1450   int src_x, src_y;
1451
1452   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1453
1454   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1455                 dst_x - src_x, dst_y - src_y);
1456   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1457 }
1458
1459 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1460 {
1461   DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1462                       frame, tilesize);
1463   MarkTileDirty(x / tilesize, y / tilesize);
1464 }
1465
1466 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1467                          int tilesize)
1468 {
1469   Bitmap *src_bitmap;
1470   int src_x, src_y;
1471
1472   getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1473   BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1474 }
1475
1476 void DrawMiniGraphic(int x, int y, int graphic)
1477 {
1478   DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1479   MarkTileDirty(x / 2, y / 2);
1480 }
1481
1482 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1483 {
1484   Bitmap *src_bitmap;
1485   int src_x, src_y;
1486
1487   getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1488   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1489 }
1490
1491 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1492                                             int graphic, int frame,
1493                                             int cut_mode, int mask_mode)
1494 {
1495   Bitmap *src_bitmap;
1496   int src_x, src_y;
1497   int dst_x, dst_y;
1498   int width = TILEX, height = TILEY;
1499   int cx = 0, cy = 0;
1500
1501   if (dx || dy)                 /* shifted graphic */
1502   {
1503     if (x < BX1)                /* object enters playfield from the left */
1504     {
1505       x = BX1;
1506       width = dx;
1507       cx = TILEX - dx;
1508       dx = 0;
1509     }
1510     else if (x > BX2)           /* object enters playfield from the right */
1511     {
1512       x = BX2;
1513       width = -dx;
1514       dx = TILEX + dx;
1515     }
1516     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
1517     {
1518       width += dx;
1519       cx = -dx;
1520       dx = 0;
1521     }
1522     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
1523       width -= dx;
1524     else if (dx)                /* general horizontal movement */
1525       MarkTileDirty(x + SIGN(dx), y);
1526
1527     if (y < BY1)                /* object enters playfield from the top */
1528     {
1529       if (cut_mode==CUT_BELOW)  /* object completely above top border */
1530         return;
1531
1532       y = BY1;
1533       height = dy;
1534       cy = TILEY - dy;
1535       dy = 0;
1536     }
1537     else if (y > BY2)           /* object enters playfield from the bottom */
1538     {
1539       y = BY2;
1540       height = -dy;
1541       dy = TILEY + dy;
1542     }
1543     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
1544     {
1545       height += dy;
1546       cy = -dy;
1547       dy = 0;
1548     }
1549     else if (dy > 0 && cut_mode == CUT_ABOVE)
1550     {
1551       if (y == BY2)             /* object completely above bottom border */
1552         return;
1553
1554       height = dy;
1555       cy = TILEY - dy;
1556       dy = TILEY;
1557       MarkTileDirty(x, y + 1);
1558     }                           /* object leaves playfield to the bottom */
1559     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1560       height -= dy;
1561     else if (dy)                /* general vertical movement */
1562       MarkTileDirty(x, y + SIGN(dy));
1563   }
1564
1565 #if DEBUG
1566   if (!IN_SCR_FIELD(x, y))
1567   {
1568     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1569     printf("DrawGraphicShifted(): This should never happen!\n");
1570     return;
1571   }
1572 #endif
1573
1574 #if NEW_TILESIZE
1575   width = width * TILESIZE_VAR / TILESIZE;
1576   height = height * TILESIZE_VAR / TILESIZE;
1577   cx = cx * TILESIZE_VAR / TILESIZE;
1578   cy = cy * TILESIZE_VAR / TILESIZE;
1579   dx = dx * TILESIZE_VAR / TILESIZE;
1580   dy = dy * TILESIZE_VAR / TILESIZE;
1581 #endif
1582
1583   if (width > 0 && height > 0)
1584   {
1585     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1586
1587     src_x += cx;
1588     src_y += cy;
1589
1590 #if NEW_TILESIZE
1591     dst_x = FX + x * TILEX_VAR + dx;
1592     dst_y = FY + y * TILEY_VAR + dy;
1593 #else
1594     dst_x = FX + x * TILEX + dx;
1595     dst_y = FY + y * TILEY + dy;
1596 #endif
1597
1598     if (mask_mode == USE_MASKING)
1599     {
1600       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1601                     dst_x - src_x, dst_y - src_y);
1602       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1603                        dst_x, dst_y);
1604     }
1605     else
1606       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1607                  dst_x, dst_y);
1608
1609     MarkTileDirty(x, y);
1610   }
1611 }
1612
1613 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1614                                             int graphic, int frame,
1615                                             int cut_mode, int mask_mode)
1616 {
1617   Bitmap *src_bitmap;
1618   int src_x, src_y;
1619   int dst_x, dst_y;
1620 #if NEW_TILESIZE
1621   int width = TILEX_VAR, height = TILEY_VAR;
1622 #else
1623   int width = TILEX, height = TILEY;
1624 #endif
1625   int x1 = x;
1626   int y1 = y;
1627   int x2 = x + SIGN(dx);
1628   int y2 = y + SIGN(dy);
1629 #if 0
1630   /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1631   int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1632 #else
1633   /* movement with two-tile animations must be sync'ed with movement position,
1634      not with current GfxFrame (which can be higher when using slow movement) */
1635   int anim_pos = (dx ? ABS(dx) : ABS(dy));
1636   int anim_frames = graphic_info[graphic].anim_frames;
1637 #if 1
1638   /* (we also need anim_delay here for movement animations with less frames) */
1639   int anim_delay = graphic_info[graphic].anim_delay;
1640   int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1641 #else
1642   int sync_frame = anim_pos * anim_frames / TILESIZE;
1643 #endif
1644 #endif
1645   boolean draw_start_tile = (cut_mode != CUT_ABOVE);    /* only for falling! */
1646   boolean draw_end_tile   = (cut_mode != CUT_BELOW);    /* only for falling! */
1647
1648   /* re-calculate animation frame for two-tile movement animation */
1649   frame = getGraphicAnimationFrame(graphic, sync_frame);
1650
1651 #if 0
1652 #if 0
1653   printf("::: %d, %d, %d => %d [%d]\n",
1654          anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1655 #else
1656   printf("::: %d, %d => %d\n",
1657          anim_pos, anim_frames, sync_frame);
1658 #endif
1659 #endif
1660
1661 #if 0
1662   printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1663          GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1664 #endif
1665
1666   /* check if movement start graphic inside screen area and should be drawn */
1667   if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1668   {
1669     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1670
1671 #if NEW_TILESIZE
1672     dst_x = FX + x1 * TILEX_VAR;
1673     dst_y = FY + y1 * TILEY_VAR;
1674 #else
1675     dst_x = FX + x1 * TILEX;
1676     dst_y = FY + y1 * TILEY;
1677 #endif
1678
1679     if (mask_mode == USE_MASKING)
1680     {
1681       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1682                     dst_x - src_x, dst_y - src_y);
1683       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1684                        dst_x, dst_y);
1685     }
1686     else
1687       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1688                  dst_x, dst_y);
1689
1690     MarkTileDirty(x1, y1);
1691   }
1692
1693   /* check if movement end graphic inside screen area and should be drawn */
1694   if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1695   {
1696     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1697
1698 #if NEW_TILESIZE
1699     dst_x = FX + x2 * TILEX_VAR;
1700     dst_y = FY + y2 * TILEY_VAR;
1701 #else
1702     dst_x = FX + x2 * TILEX;
1703     dst_y = FY + y2 * TILEY;
1704 #endif
1705
1706     if (mask_mode == USE_MASKING)
1707     {
1708       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1709                     dst_x - src_x, dst_y - src_y);
1710       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1711                        dst_x, dst_y);
1712     }
1713     else
1714       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1715                  dst_x, dst_y);
1716
1717     MarkTileDirty(x2, y2);
1718   }
1719 }
1720
1721 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1722                                int graphic, int frame,
1723                                int cut_mode, int mask_mode)
1724 {
1725   if (graphic < 0)
1726   {
1727     DrawGraphic(x, y, graphic, frame);
1728
1729     return;
1730   }
1731
1732   if (graphic_info[graphic].double_movement)    /* EM style movement images */
1733     DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1734   else
1735     DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1736 }
1737
1738 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1739                                 int frame, int cut_mode)
1740 {
1741   DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1742 }
1743
1744 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1745                           int cut_mode, int mask_mode)
1746 {
1747   int lx = LEVELX(x), ly = LEVELY(y);
1748   int graphic;
1749   int frame;
1750
1751   if (IN_LEV_FIELD(lx, ly))
1752   {
1753     SetRandomAnimationValue(lx, ly);
1754
1755     graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1756     frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1757
1758     /* do not use double (EM style) movement graphic when not moving */
1759     if (graphic_info[graphic].double_movement && !dx && !dy)
1760     {
1761       graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1762       frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1763     }
1764   }
1765   else  /* border element */
1766   {
1767     graphic = el2img(element);
1768     frame = getGraphicAnimationFrame(graphic, -1);
1769   }
1770
1771   if (element == EL_EXPANDABLE_WALL)
1772   {
1773     boolean left_stopped = FALSE, right_stopped = FALSE;
1774
1775     if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1776       left_stopped = TRUE;
1777     if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1778       right_stopped = TRUE;
1779
1780     if (left_stopped && right_stopped)
1781       graphic = IMG_WALL;
1782     else if (left_stopped)
1783     {
1784       graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1785       frame = graphic_info[graphic].anim_frames - 1;
1786     }
1787     else if (right_stopped)
1788     {
1789       graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1790       frame = graphic_info[graphic].anim_frames - 1;
1791     }
1792   }
1793
1794   if (dx || dy)
1795     DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1796   else if (mask_mode == USE_MASKING)
1797     DrawGraphicThruMask(x, y, graphic, frame);
1798   else
1799     DrawGraphic(x, y, graphic, frame);
1800 }
1801
1802 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1803                          int cut_mode, int mask_mode)
1804 {
1805   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1806     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1807                          cut_mode, mask_mode);
1808 }
1809
1810 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1811                               int cut_mode)
1812 {
1813   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1814 }
1815
1816 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1817                              int cut_mode)
1818 {
1819   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1820 }
1821
1822 void DrawLevelElementThruMask(int x, int y, int element)
1823 {
1824   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1825 }
1826
1827 void DrawLevelFieldThruMask(int x, int y)
1828 {
1829   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1830 }
1831
1832 /* !!! implementation of quicksand is totally broken !!! */
1833 #define IS_CRUMBLED_TILE(x, y, e)                                       \
1834         (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) ||                     \
1835                              !IS_MOVING(x, y) ||                        \
1836                              (e) == EL_QUICKSAND_EMPTYING ||            \
1837                              (e) == EL_QUICKSAND_FAST_EMPTYING))
1838
1839 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1840                                                int graphic)
1841 {
1842   Bitmap *src_bitmap;
1843   int src_x, src_y;
1844   int width, height, cx, cy;
1845   int sx = SCREENX(x), sy = SCREENY(y);
1846   int crumbled_border_size = graphic_info[graphic].border_size;
1847   int i;
1848
1849   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1850
1851   for (i = 1; i < 4; i++)
1852   {
1853     int dxx = (i & 1 ? dx : 0);
1854     int dyy = (i & 2 ? dy : 0);
1855     int xx = x + dxx;
1856     int yy = y + dyy;
1857     int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1858                    BorderElement);
1859
1860     /* check if neighbour field is of same crumble type */
1861     boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1862                     graphic_info[graphic].class ==
1863                     graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1864
1865     /* return if check prevents inner corner */
1866     if (same == (dxx == dx && dyy == dy))
1867       return;
1868   }
1869
1870   /* if we reach this point, we have an inner corner */
1871
1872   getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1873
1874 #if NEW_TILESIZE
1875   width  = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1876   height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1877   cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1878   cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1879
1880   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1881              width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1882 #else
1883   width  = crumbled_border_size;
1884   height = crumbled_border_size;
1885   cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1886   cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1887
1888   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1889              width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1890 #endif
1891 }
1892
1893 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1894                                           int dir)
1895 {
1896   Bitmap *src_bitmap;
1897   int src_x, src_y;
1898   int width, height, bx, by, cx, cy;
1899   int sx = SCREENX(x), sy = SCREENY(y);
1900   int crumbled_border_size = graphic_info[graphic].border_size;
1901   int i;
1902
1903   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1904
1905   /* draw simple, sloppy, non-corner-accurate crumbled border */
1906
1907 #if 1
1908   width  = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1909   height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1910   cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1911   cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1912 #else
1913   if (dir == 1 || dir == 2)             /* left or right crumbled border */
1914   {
1915     width = crumbled_border_size;
1916     height = TILEY;
1917     cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1918     cy = 0;
1919   }
1920   else                                  /* top or bottom crumbled border */
1921   {
1922     width = TILEX;
1923     height = crumbled_border_size;
1924     cx = 0;
1925     cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1926   }
1927 #endif
1928
1929 #if NEW_TILESIZE
1930   BlitBitmap(src_bitmap, drawto_field,
1931              src_x + cx * TILESIZE_VAR / TILESIZE,
1932              src_y + cy * TILESIZE_VAR / TILESIZE,
1933              width * TILESIZE_VAR / TILESIZE,
1934              height * TILESIZE_VAR / TILESIZE,
1935              FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
1936              FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
1937 #else
1938   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1939              width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1940 #endif
1941
1942   /* (remaining middle border part must be at least as big as corner part) */
1943   if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1944       crumbled_border_size >= TILESIZE / 3)
1945     return;
1946
1947   /* correct corners of crumbled border, if needed */
1948
1949 #if 1
1950   for (i = -1; i <= 1; i+=2)
1951   {
1952     int xx = x + (dir == 0 || dir == 3 ? i : 0);
1953     int yy = y + (dir == 1 || dir == 2 ? i : 0);
1954     int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1955                    BorderElement);
1956
1957     /* check if neighbour field is of same crumble type */
1958     if (IS_CRUMBLED_TILE(xx, yy, element) &&
1959         graphic_info[graphic].class ==
1960         graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1961     {
1962       /* no crumbled corner, but continued crumbled border */
1963
1964       int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
1965       int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
1966       int b1 = (i == 1 ? crumbled_border_size :
1967                 TILESIZE - 2 * crumbled_border_size);
1968
1969       width  = crumbled_border_size;
1970       height = crumbled_border_size;
1971
1972       if (dir == 1 || dir == 2)
1973       {
1974         cx = c1;
1975         cy = c2;
1976         bx = cx;
1977         by = b1;
1978       }
1979       else
1980       {
1981         cx = c2;
1982         cy = c1;
1983         bx = b1;
1984         by = cy;
1985       }
1986
1987 #if NEW_TILESIZE
1988       BlitBitmap(src_bitmap, drawto_field,
1989                  src_x + bx * TILESIZE_VAR / TILESIZE,
1990                  src_y + by * TILESIZE_VAR / TILESIZE,
1991                  width * TILESIZE_VAR / TILESIZE,
1992                  height * TILESIZE_VAR / TILESIZE,
1993                  FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
1994                  FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
1995 #else
1996       BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1997                  width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1998 #endif
1999     }
2000   }
2001 #else
2002   if (dir == 1 || dir == 2)             /* left or right crumbled border */
2003   {
2004     for (i = -1; i <= 1; i+=2)
2005     {
2006       int xx = x;
2007       int yy = y + i;
2008       int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2009                      BorderElement);
2010
2011       /* check if neighbour field is of same crumble type */
2012       if (IS_CRUMBLED_TILE(xx, yy, element) &&
2013           graphic_info[graphic].class ==
2014           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2015       {
2016         /* no crumbled corner, but continued crumbled border */
2017
2018         width  = crumbled_border_size;
2019         height = crumbled_border_size;
2020         cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2021         cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2022         bx = cx;
2023         by = (i == 1 ? crumbled_border_size :
2024               TILEY - 2 * crumbled_border_size);
2025
2026         BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2027                    width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2028       }
2029     }
2030   }
2031   else                          /* top or bottom crumbled border */
2032   {
2033     for (i = -1; i <= 1; i+=2)
2034     {
2035       int xx = x + i;
2036       int yy = y;
2037       int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2038                      BorderElement);
2039
2040       /* check if neighbour field is of same crumble type */
2041       if (IS_CRUMBLED_TILE(xx, yy, element) &&
2042           graphic_info[graphic].class ==
2043           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2044       {
2045         /* no crumbled corner, but continued crumbled border */
2046
2047         width  = crumbled_border_size;
2048         height = crumbled_border_size;
2049         cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2050         cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2051         bx = (i == 1 ? crumbled_border_size :
2052               TILEX - 2 * crumbled_border_size);
2053         by = cy;
2054
2055         BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2056                    width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2057       }
2058     }
2059   }
2060 #endif
2061 }
2062
2063 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2064 {
2065   int sx = SCREENX(x), sy = SCREENY(y);
2066   int element;
2067   int i;
2068   static int xy[4][2] =
2069   {
2070     { 0, -1 },
2071     { -1, 0 },
2072     { +1, 0 },
2073     { 0, +1 }
2074   };
2075
2076   if (!IN_LEV_FIELD(x, y))
2077     return;
2078
2079   element = TILE_GFX_ELEMENT(x, y);
2080
2081   /* crumble field itself */
2082   if (IS_CRUMBLED_TILE(x, y, element))
2083   {
2084     if (!IN_SCR_FIELD(sx, sy))
2085       return;
2086
2087     for (i = 0; i < 4; i++)
2088     {
2089       int xx = x + xy[i][0];
2090       int yy = y + xy[i][1];
2091
2092       element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2093                  BorderElement);
2094
2095       /* check if neighbour field is of same crumble type */
2096 #if 1
2097       if (IS_CRUMBLED_TILE(xx, yy, element) &&
2098           graphic_info[graphic].class ==
2099           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2100         continue;
2101 #else
2102       if (IS_CRUMBLED_TILE(xx, yy, element))
2103         continue;
2104 #endif
2105
2106       DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2107     }
2108
2109     if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2110         graphic_info[graphic].anim_frames == 2)
2111     {
2112       for (i = 0; i < 4; i++)
2113       {
2114         int dx = (i & 1 ? +1 : -1);
2115         int dy = (i & 2 ? +1 : -1);
2116
2117         DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2118       }
2119     }
2120
2121     MarkTileDirty(sx, sy);
2122   }
2123   else          /* center field not crumbled -- crumble neighbour fields */
2124   {
2125     for (i = 0; i < 4; i++)
2126     {
2127       int xx = x + xy[i][0];
2128       int yy = y + xy[i][1];
2129       int sxx = sx + xy[i][0];
2130       int syy = sy + xy[i][1];
2131
2132       if (!IN_LEV_FIELD(xx, yy) ||
2133           !IN_SCR_FIELD(sxx, syy))
2134         continue;
2135
2136       if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2137         continue;
2138
2139       element = TILE_GFX_ELEMENT(xx, yy);
2140
2141       if (!IS_CRUMBLED_TILE(xx, yy, element))
2142         continue;
2143
2144       graphic = el_act2crm(element, ACTION_DEFAULT);
2145
2146       DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2147
2148       MarkTileDirty(sxx, syy);
2149     }
2150   }
2151 }
2152
2153 void DrawLevelFieldCrumbled(int x, int y)
2154 {
2155   int graphic;
2156
2157   if (!IN_LEV_FIELD(x, y))
2158     return;
2159
2160 #if 1
2161   /* !!! CHECK THIS !!! */
2162
2163   /*
2164   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2165       GFX_CRUMBLED(GfxElement[x][y]))
2166   */
2167
2168   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2169       GfxElement[x][y] != EL_UNDEFINED &&
2170       GFX_CRUMBLED(GfxElement[x][y]))
2171   {
2172     DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2173
2174     return;
2175   }
2176 #endif
2177
2178 #if 1
2179   graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2180 #else
2181   graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2182 #endif
2183
2184   DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2185 }
2186
2187 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2188                                    int step_frame)
2189 {
2190   int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2191   int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2192   int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2193   int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2194   int sx = SCREENX(x), sy = SCREENY(y);
2195
2196   DrawGraphic(sx, sy, graphic1, frame1);
2197   DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2198 }
2199
2200 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2201 {
2202   int sx = SCREENX(x), sy = SCREENY(y);
2203   static int xy[4][2] =
2204   {
2205     { 0, -1 },
2206     { -1, 0 },
2207     { +1, 0 },
2208     { 0, +1 }
2209   };
2210   int i;
2211
2212   for (i = 0; i < 4; i++)
2213   {
2214     int xx = x + xy[i][0];
2215     int yy = y + xy[i][1];
2216     int sxx = sx + xy[i][0];
2217     int syy = sy + xy[i][1];
2218
2219     if (!IN_LEV_FIELD(xx, yy) ||
2220         !IN_SCR_FIELD(sxx, syy) ||
2221         !GFX_CRUMBLED(Feld[xx][yy]) ||
2222         IS_MOVING(xx, yy))
2223       continue;
2224
2225     DrawLevelField(xx, yy);
2226   }
2227 }
2228
2229 static int getBorderElement(int x, int y)
2230 {
2231   int border[7][2] =
2232   {
2233     { EL_STEELWALL_TOPLEFT,             EL_INVISIBLE_STEELWALL_TOPLEFT     },
2234     { EL_STEELWALL_TOPRIGHT,            EL_INVISIBLE_STEELWALL_TOPRIGHT    },
2235     { EL_STEELWALL_BOTTOMLEFT,          EL_INVISIBLE_STEELWALL_BOTTOMLEFT  },
2236     { EL_STEELWALL_BOTTOMRIGHT,         EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2237     { EL_STEELWALL_VERTICAL,            EL_INVISIBLE_STEELWALL_VERTICAL    },
2238     { EL_STEELWALL_HORIZONTAL,          EL_INVISIBLE_STEELWALL_HORIZONTAL  },
2239     { EL_STEELWALL,                     EL_INVISIBLE_STEELWALL             }
2240   };
2241   int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2242   int steel_position = (x == -1         && y == -1              ? 0 :
2243                         x == lev_fieldx && y == -1              ? 1 :
2244                         x == -1         && y == lev_fieldy      ? 2 :
2245                         x == lev_fieldx && y == lev_fieldy      ? 3 :
2246                         x == -1         || x == lev_fieldx      ? 4 :
2247                         y == -1         || y == lev_fieldy      ? 5 : 6);
2248
2249   return border[steel_position][steel_type];
2250 }
2251
2252 void DrawScreenElement(int x, int y, int element)
2253 {
2254   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2255   DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2256 }
2257
2258 void DrawLevelElement(int x, int y, int element)
2259 {
2260   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2261     DrawScreenElement(SCREENX(x), SCREENY(y), element);
2262 }
2263
2264 void DrawScreenField(int x, int y)
2265 {
2266   int lx = LEVELX(x), ly = LEVELY(y);
2267   int element, content;
2268
2269   if (!IN_LEV_FIELD(lx, ly))
2270   {
2271     if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2272       element = EL_EMPTY;
2273     else
2274       element = getBorderElement(lx, ly);
2275
2276     DrawScreenElement(x, y, element);
2277
2278     return;
2279   }
2280
2281   element = Feld[lx][ly];
2282   content = Store[lx][ly];
2283
2284   if (IS_MOVING(lx, ly))
2285   {
2286     int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2287     boolean cut_mode = NO_CUTTING;
2288
2289     if (element == EL_QUICKSAND_EMPTYING ||
2290         element == EL_QUICKSAND_FAST_EMPTYING ||
2291         element == EL_MAGIC_WALL_EMPTYING ||
2292         element == EL_BD_MAGIC_WALL_EMPTYING ||
2293         element == EL_DC_MAGIC_WALL_EMPTYING ||
2294         element == EL_AMOEBA_DROPPING)
2295       cut_mode = CUT_ABOVE;
2296     else if (element == EL_QUICKSAND_FILLING ||
2297              element == EL_QUICKSAND_FAST_FILLING ||
2298              element == EL_MAGIC_WALL_FILLING ||
2299              element == EL_BD_MAGIC_WALL_FILLING ||
2300              element == EL_DC_MAGIC_WALL_FILLING)
2301       cut_mode = CUT_BELOW;
2302
2303 #if 0
2304     if (lx == 9 && ly == 1)
2305       printf("::: %s [%d] [%d, %d] [%d]\n",
2306              EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2307              el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2308              element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2309              element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2310              GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2311 #endif
2312
2313     if (cut_mode == CUT_ABOVE)
2314 #if 1
2315       DrawScreenElement(x, y, element);
2316 #else
2317       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2318 #endif
2319     else
2320       DrawScreenElement(x, y, EL_EMPTY);
2321
2322     if (horiz_move)
2323       DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2324     else if (cut_mode == NO_CUTTING)
2325       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2326     else
2327     {
2328       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2329
2330 #if 1
2331       if (cut_mode == CUT_BELOW &&
2332           IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2333         DrawLevelElement(lx, ly + 1, element);
2334 #endif
2335     }
2336
2337     if (content == EL_ACID)
2338     {
2339       int dir = MovDir[lx][ly];
2340       int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2341       int newly = ly + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
2342
2343       DrawLevelElementThruMask(newlx, newly, EL_ACID);
2344     }
2345   }
2346   else if (IS_BLOCKED(lx, ly))
2347   {
2348     int oldx, oldy;
2349     int sx, sy;
2350     int horiz_move;
2351     boolean cut_mode = NO_CUTTING;
2352     int element_old, content_old;
2353
2354     Blocked2Moving(lx, ly, &oldx, &oldy);
2355     sx = SCREENX(oldx);
2356     sy = SCREENY(oldy);
2357     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2358                   MovDir[oldx][oldy] == MV_RIGHT);
2359
2360     element_old = Feld[oldx][oldy];
2361     content_old = Store[oldx][oldy];
2362
2363     if (element_old == EL_QUICKSAND_EMPTYING ||
2364         element_old == EL_QUICKSAND_FAST_EMPTYING ||
2365         element_old == EL_MAGIC_WALL_EMPTYING ||
2366         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2367         element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2368         element_old == EL_AMOEBA_DROPPING)
2369       cut_mode = CUT_ABOVE;
2370
2371     DrawScreenElement(x, y, EL_EMPTY);
2372
2373     if (horiz_move)
2374       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2375                                NO_CUTTING);
2376     else if (cut_mode == NO_CUTTING)
2377       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2378                                cut_mode);
2379     else
2380       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2381                                cut_mode);
2382   }
2383   else if (IS_DRAWABLE(element))
2384     DrawScreenElement(x, y, element);
2385   else
2386     DrawScreenElement(x, y, EL_EMPTY);
2387 }
2388
2389 void DrawLevelField(int x, int y)
2390 {
2391   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2392     DrawScreenField(SCREENX(x), SCREENY(y));
2393   else if (IS_MOVING(x, y))
2394   {
2395     int newx,newy;
2396
2397     Moving2Blocked(x, y, &newx, &newy);
2398     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2399       DrawScreenField(SCREENX(newx), SCREENY(newy));
2400   }
2401   else if (IS_BLOCKED(x, y))
2402   {
2403     int oldx, oldy;
2404
2405     Blocked2Moving(x, y, &oldx, &oldy);
2406     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2407       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2408   }
2409 }
2410
2411 void DrawMiniElement(int x, int y, int element)
2412 {
2413   int graphic;
2414
2415   graphic = el2edimg(element);
2416   DrawMiniGraphic(x, y, graphic);
2417 }
2418
2419 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2420 {
2421   int x = sx + scroll_x, y = sy + scroll_y;
2422
2423   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2424     DrawMiniElement(sx, sy, EL_EMPTY);
2425   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2426     DrawMiniElement(sx, sy, Feld[x][y]);
2427   else
2428     DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2429 }
2430
2431 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2432                             int x, int y, int xsize, int ysize, int font_nr)
2433 {
2434   int font_width  = getFontWidth(font_nr);
2435   int font_height = getFontHeight(font_nr);
2436   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2437   Bitmap *src_bitmap;
2438   int src_x, src_y;
2439   int dst_x = SX + startx + x * font_width;
2440   int dst_y = SY + starty + y * font_height;
2441   int width  = graphic_info[graphic].width;
2442   int height = graphic_info[graphic].height;
2443   int inner_width  = MAX(width  - 2 * font_width,  font_width);
2444   int inner_height = MAX(height - 2 * font_height, font_height);
2445   int inner_sx = (width >= 3 * font_width ? font_width : 0);
2446   int inner_sy = (height >= 3 * font_height ? font_height : 0);
2447   boolean draw_masked = graphic_info[graphic].draw_masked;
2448
2449   getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2450
2451   if (src_bitmap == NULL || width < font_width || height < font_height)
2452   {
2453     ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2454     return;
2455   }
2456
2457   src_x += (x == 0 ? 0 : x == xsize - 1 ? width  - font_width  :
2458             inner_sx + (x - 1) * font_width  % inner_width);
2459   src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2460             inner_sy + (y - 1) * font_height % inner_height);
2461
2462   if (draw_masked)
2463   {
2464     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2465                   dst_x - src_x, dst_y - src_y);
2466     BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2467                      dst_x, dst_y);
2468   }
2469   else
2470     BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2471                dst_x, dst_y);
2472 }
2473
2474 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2475 {
2476   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2477   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2478   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2479   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2480   boolean no_delay = (tape.warp_forward);
2481   unsigned long anim_delay = 0;
2482   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2483   int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2484   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2485   int font_width = getFontWidth(font_nr);
2486   int font_height = getFontHeight(font_nr);
2487   int max_xsize = level.envelope[envelope_nr].xsize;
2488   int max_ysize = level.envelope[envelope_nr].ysize;
2489   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2490   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2491   int xend = max_xsize;
2492   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2493   int xstep = (xstart < xend ? 1 : 0);
2494   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2495   int x, y;
2496
2497   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2498   {
2499     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2500     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2501     int sx = (SXSIZE - xsize * font_width)  / 2;
2502     int sy = (SYSIZE - ysize * font_height) / 2;
2503     int xx, yy;
2504
2505     SetDrawtoField(DRAW_BUFFERED);
2506
2507     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2508
2509     SetDrawtoField(DRAW_BACKBUFFER);
2510
2511     for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2512       DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2513
2514 #if 1
2515     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2516                    level.envelope[envelope_nr].text, font_nr, max_xsize,
2517                    xsize - 2, ysize - 2, 0, mask_mode,
2518                    level.envelope[envelope_nr].autowrap,
2519                    level.envelope[envelope_nr].centered, FALSE);
2520 #else
2521     DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2522                        level.envelope[envelope_nr].text, font_nr, max_xsize,
2523                        xsize - 2, ysize - 2, mask_mode);
2524 #endif
2525
2526     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2527     BackToFront();
2528
2529     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2530   }
2531 }
2532
2533 void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2534 {
2535 #if 1
2536   int envelope_nr = 0;
2537 #endif
2538   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2539   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2540   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2541   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2542   boolean no_delay = (tape.warp_forward);
2543   unsigned long anim_delay = 0;
2544   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2545   int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2546 #if 1
2547   int max_word_len = maxWordLengthInString(text);
2548   int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2549 #else
2550   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2551 #endif
2552   int font_width = getFontWidth(font_nr);
2553   int font_height = getFontHeight(font_nr);
2554 #if 1
2555
2556 #if 1
2557   int max_xsize = DXSIZE / font_width;
2558   int max_ysize = DYSIZE / font_height;
2559 #else
2560   int max_xsize = 7;    /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2561   int max_ysize = 13;   /* tools.c: MAX_REQUEST_LINES == 13 */
2562 #endif
2563
2564 #else
2565   int max_xsize = level.envelope[envelope_nr].xsize;
2566   int max_ysize = level.envelope[envelope_nr].ysize;
2567 #endif
2568   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2569   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2570   int xend = max_xsize;
2571   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2572   int xstep = (xstart < xend ? 1 : 0);
2573   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2574   int x, y;
2575
2576 #if 1
2577   char *text_ptr;
2578   char *text_copy = getStringCopy(text);
2579 #else
2580 #if 1
2581   font_nr = FONT_TEXT_2;
2582
2583   if (maxWordLengthInString(text) > 7)  /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2584   {
2585     max_xsize = 10;     /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2586     font_nr = FONT_TEXT_1;
2587   }
2588 #else
2589   int max_word_len = 0;
2590   char *text_ptr;
2591   char *text_copy = getStringCopy(text);
2592
2593   font_nr = FONT_TEXT_2;
2594
2595   for (text_ptr = text; *text_ptr; text_ptr++)
2596   {
2597     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2598
2599     if (max_word_len > 7)       /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2600     {
2601       max_xsize = 10;   /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2602       font_nr = FONT_TEXT_1;
2603
2604       break;
2605     }
2606   }
2607 #endif
2608 #endif
2609
2610 #if 1
2611   for (text_ptr = text_copy; *text_ptr; text_ptr++)
2612     if (*text_ptr == ' ')
2613       *text_ptr = '\n';
2614 #endif
2615
2616 #if 1
2617   dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2618   dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2619 #else
2620   dDX = SX + SXSIZE / 2 - max_xsize * font_width  / 2 - DX;
2621   dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2622 #endif
2623
2624   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2625   {
2626     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2627     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2628     int sx = (SXSIZE - xsize * font_width)  / 2;
2629     int sy = (SYSIZE - ysize * font_height) / 2;
2630     int xx, yy;
2631
2632 #if 1
2633     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2634 #else
2635     SetDrawtoField(DRAW_BUFFERED);
2636
2637     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2638
2639     SetDrawtoField(DRAW_BACKBUFFER);
2640 #endif
2641
2642     for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2643       DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2644
2645 #if 1
2646
2647 #if 1
2648     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
2649                    text_copy, font_nr, max_xsize,
2650                    xsize - 2, ysize - 2, 2, mask_mode,
2651                    FALSE, TRUE, FALSE);
2652 #else
2653     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2654                    level.envelope[envelope_nr].text, font_nr, max_xsize,
2655                    xsize - 2, ysize - 2, 0, mask_mode,
2656                    level.envelope[envelope_nr].autowrap,
2657                    level.envelope[envelope_nr].centered, FALSE);
2658 #endif
2659
2660 #else
2661     DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2662                        level.envelope[envelope_nr].text, font_nr, max_xsize,
2663                        xsize - 2, ysize - 2, mask_mode);
2664 #endif
2665
2666     /* copy request gadgets to door backbuffer */
2667 #if 1
2668     if ((ysize - 2) > 13)
2669       BlitBitmap(bitmap_db_door, drawto,
2670                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2671                  DOOR_GFX_PAGEY1 + 13 * font_height,
2672                  (xsize - 2) * font_width,
2673                  (ysize - 2 - 13) * font_height,
2674                  SX + sx + font_width,
2675                  SY + sy + font_height * (1 + 13));
2676 #else
2677     if ((ysize - 2) > 13)
2678       BlitBitmap(bitmap_db_door, drawto,
2679                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2680                  DOOR_GFX_PAGEY1 + 13 * font_height,
2681                  (xsize - 2) * font_width,
2682                  (ysize - 2 - 13) * font_height,
2683                  SX + sx + font_width,
2684                  SY + sy + font_height * (1 + 13));
2685 #endif
2686
2687 #if 1
2688     redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2689     // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2690 #else
2691     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2692 #endif
2693
2694 #if 1
2695     DoAnimation();
2696     BackToFront();
2697 #else
2698     BackToFront();
2699 #endif
2700
2701     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2702   }
2703
2704 #if 1
2705   free(text_copy);
2706 #endif
2707 }
2708
2709 void ShowEnvelope(int envelope_nr)
2710 {
2711   int element = EL_ENVELOPE_1 + envelope_nr;
2712   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2713   int sound_opening = element_info[element].sound[ACTION_OPENING];
2714   int sound_closing = element_info[element].sound[ACTION_CLOSING];
2715   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2716   boolean no_delay = (tape.warp_forward);
2717   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2718   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2719   int anim_mode = graphic_info[graphic].anim_mode;
2720   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2721                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2722
2723   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
2724
2725   PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2726
2727   if (anim_mode == ANIM_DEFAULT)
2728     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2729
2730   AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2731
2732   if (tape.playing)
2733     Delay(wait_delay_value);
2734   else
2735     WaitForEventToContinue();
2736
2737   PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2738
2739   if (anim_mode != ANIM_NONE)
2740     AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2741
2742   if (anim_mode == ANIM_DEFAULT)
2743     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2744
2745   game.envelope_active = FALSE;
2746
2747   SetDrawtoField(DRAW_BUFFERED);
2748
2749   redraw_mask |= REDRAW_FIELD;
2750   BackToFront();
2751 }
2752
2753 void ShowEnvelopeDoor(char *text, int action)
2754 {
2755 #if 1
2756   int last_game_status = game_status;   /* save current game status */
2757   // int last_draw_background_mask = gfx.draw_background_mask;
2758   int envelope_nr = 0;
2759 #endif
2760   int element = EL_ENVELOPE_1 + envelope_nr;
2761   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2762   int sound_opening = element_info[element].sound[ACTION_OPENING];
2763   int sound_closing = element_info[element].sound[ACTION_CLOSING];
2764 #if 0
2765   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2766   boolean no_delay = (tape.warp_forward);
2767   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2768   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2769 #endif
2770   int anim_mode = graphic_info[graphic].anim_mode;
2771   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2772                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2773
2774 #if 1
2775   if (game_status == GAME_MODE_PLAYING)
2776   {
2777     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2778       BlitScreenToBitmap_EM(backbuffer);
2779     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2780       BlitScreenToBitmap_SP(backbuffer);
2781     else
2782     {
2783       BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2784     }
2785   }
2786
2787   SetDrawtoField(DRAW_BACKBUFFER);
2788
2789   // SetDrawBackgroundMask(REDRAW_NONE);
2790
2791   if (action == ACTION_OPENING)
2792   {
2793     BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2794
2795     if (game_status != GAME_MODE_MAIN)
2796       InitAnimation();
2797   }
2798
2799   /* force DOOR font inside door area */
2800   game_status = GAME_MODE_PSEUDO_DOOR;
2801 #endif
2802
2803   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
2804
2805   if (action == ACTION_OPENING)
2806   {
2807     PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2808
2809     if (anim_mode == ANIM_DEFAULT)
2810       AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2811
2812     AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2813
2814 #if 0
2815     if (tape.playing)
2816       Delay(wait_delay_value);
2817     else
2818       WaitForEventToContinue();
2819 #endif
2820   }
2821   else
2822   {
2823     PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2824
2825     if (anim_mode != ANIM_NONE)
2826       AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2827
2828     if (anim_mode == ANIM_DEFAULT)
2829       AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2830   }
2831
2832   game.envelope_active = FALSE;
2833
2834 #if 1
2835   // game_status = last_game_status;    /* restore current game status */
2836
2837   if (action == ACTION_CLOSING)
2838   {
2839     if (game_status != GAME_MODE_MAIN)
2840       StopAnimation();
2841
2842     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2843   }
2844 #else
2845   SetDrawtoField(DRAW_BUFFERED);
2846 #endif
2847
2848   // SetDrawBackgroundMask(last_draw_background_mask);
2849
2850 #if 1
2851   redraw_mask = REDRAW_FIELD;
2852   // redraw_mask |= REDRAW_ALL;
2853 #else
2854   redraw_mask |= REDRAW_FIELD;
2855 #endif
2856
2857 #if 1
2858   if (game_status == GAME_MODE_MAIN)
2859     DoAnimation();
2860
2861   BackToFront();
2862
2863   /* (important: after "BackToFront()", but before "SetDrawtoField()") */
2864   game_status = last_game_status;       /* restore current game status */
2865
2866   if (game_status == GAME_MODE_PLAYING &&
2867       level.game_engine_type == GAME_ENGINE_TYPE_RND)
2868     SetDrawtoField(DRAW_BUFFERED);
2869 #else
2870   BackToFront();
2871 #endif
2872 }
2873
2874 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2875 {
2876   Bitmap *src_bitmap;
2877   int src_x, src_y;
2878   int graphic = el2preimg(element);
2879
2880   getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2881   BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2882 }
2883
2884 void DrawLevel()
2885 {
2886   int x,y;
2887
2888 #if 1
2889   SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2890   SetDrawBackgroundMask(REDRAW_FIELD);
2891 #else
2892   SetDrawBackgroundMask(REDRAW_NONE);
2893 #endif
2894
2895   ClearField();
2896
2897   for (x = BX1; x <= BX2; x++)
2898     for (y = BY1; y <= BY2; y++)
2899       DrawScreenField(x, y);
2900
2901   redraw_mask |= REDRAW_FIELD;
2902 }
2903
2904 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2905 {
2906   int x,y;
2907
2908   for (x = 0; x < size_x; x++)
2909     for (y = 0; y < size_y; y++)
2910       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2911
2912   redraw_mask |= REDRAW_FIELD;
2913 }
2914
2915 static void DrawPreviewLevelExt(int from_x, int from_y)
2916 {
2917   boolean show_level_border = (BorderElement != EL_EMPTY);
2918   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2919   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2920   int tile_size = preview.tile_size;
2921   int preview_width  = preview.xsize * tile_size;
2922   int preview_height = preview.ysize * tile_size;
2923   int real_preview_xsize = MIN(level_xsize, preview.xsize);
2924   int real_preview_ysize = MIN(level_ysize, preview.ysize);
2925   int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2926   int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2927   int x, y;
2928
2929   DrawBackground(dst_x, dst_y, preview_width, preview_height);
2930
2931   dst_x += (preview_width  - real_preview_xsize * tile_size) / 2;
2932   dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2933
2934   for (x = 0; x < real_preview_xsize; x++)
2935   {
2936     for (y = 0; y < real_preview_ysize; y++)
2937     {
2938       int lx = from_x + x + (show_level_border ? -1 : 0);
2939       int ly = from_y + y + (show_level_border ? -1 : 0);
2940       int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2941                      getBorderElement(lx, ly));
2942
2943       DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2944                          element, tile_size);
2945     }
2946   }
2947
2948   redraw_mask |= REDRAW_MICROLEVEL;
2949 }
2950
2951 #define MICROLABEL_EMPTY                0
2952 #define MICROLABEL_LEVEL_NAME           1
2953 #define MICROLABEL_LEVEL_AUTHOR_HEAD    2
2954 #define MICROLABEL_LEVEL_AUTHOR         3
2955 #define MICROLABEL_IMPORTED_FROM_HEAD   4
2956 #define MICROLABEL_IMPORTED_FROM        5
2957 #define MICROLABEL_IMPORTED_BY_HEAD     6
2958 #define MICROLABEL_IMPORTED_BY          7
2959
2960 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2961 {
2962   int max_text_width = SXSIZE;
2963   int font_width = getFontWidth(font_nr);
2964
2965   if (pos->align == ALIGN_CENTER)
2966     max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2967   else if (pos->align == ALIGN_RIGHT)
2968     max_text_width = pos->x;
2969   else
2970     max_text_width = SXSIZE - pos->x;
2971
2972   return max_text_width / font_width;
2973 }
2974
2975 static void DrawPreviewLevelLabelExt(int mode)
2976 {
2977   struct TextPosInfo *pos = &menu.main.text.level_info_2;
2978   char label_text[MAX_OUTPUT_LINESIZE + 1];
2979   int max_len_label_text;
2980 #if 1
2981   int font_nr = pos->font;
2982   int i;
2983
2984   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2985       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2986       mode == MICROLABEL_IMPORTED_BY_HEAD)
2987     font_nr = pos->font_alt;
2988 #else
2989   int font_nr = FONT_TEXT_2;
2990   int i;
2991
2992   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2993       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2994       mode == MICROLABEL_IMPORTED_BY_HEAD)
2995     font_nr = FONT_TEXT_3;
2996 #endif
2997
2998 #if 1
2999   max_len_label_text = getMaxTextLength(pos, font_nr);
3000 #else
3001   max_len_label_text = SXSIZE / getFontWidth(font_nr);
3002 #endif
3003
3004 #if 1
3005   if (pos->size != -1)
3006     max_len_label_text = pos->size;
3007 #endif
3008
3009   for (i = 0; i < max_len_label_text; i++)
3010     label_text[i] = ' ';
3011   label_text[max_len_label_text] = '\0';
3012
3013   if (strlen(label_text) > 0)
3014   {
3015 #if 1
3016     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3017 #else
3018     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3019     int lypos = MICROLABEL2_YPOS;
3020
3021     DrawText(lxpos, lypos, label_text, font_nr);
3022 #endif
3023   }
3024
3025   strncpy(label_text,
3026           (mode == MICROLABEL_LEVEL_NAME ? level.name :
3027            mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3028            mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3029            mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3030            mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3031            mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3032            mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3033           max_len_label_text);
3034   label_text[max_len_label_text] = '\0';
3035
3036   if (strlen(label_text) > 0)
3037   {
3038 #if 1
3039     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3040 #else
3041     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3042     int lypos = MICROLABEL2_YPOS;
3043
3044     DrawText(lxpos, lypos, label_text, font_nr);
3045 #endif
3046   }
3047
3048   redraw_mask |= REDRAW_MICROLEVEL;
3049 }
3050
3051 void DrawPreviewLevel(boolean restart)
3052 {
3053   static unsigned long scroll_delay = 0;
3054   static unsigned long label_delay = 0;
3055   static int from_x, from_y, scroll_direction;
3056   static int label_state, label_counter;
3057   unsigned long scroll_delay_value = preview.step_delay;
3058   boolean show_level_border = (BorderElement != EL_EMPTY);
3059   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3060   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3061   int last_game_status = game_status;           /* save current game status */
3062
3063 #if 0
3064   /* force PREVIEW font on preview level */
3065   game_status = GAME_MODE_PSEUDO_PREVIEW;
3066 #endif
3067
3068   if (restart)
3069   {
3070     from_x = 0;
3071     from_y = 0;
3072
3073     if (preview.anim_mode == ANIM_CENTERED)
3074     {
3075       if (level_xsize > preview.xsize)
3076         from_x = (level_xsize - preview.xsize) / 2;
3077       if (level_ysize > preview.ysize)
3078         from_y = (level_ysize - preview.ysize) / 2;
3079     }
3080
3081     from_x += preview.xoffset;
3082     from_y += preview.yoffset;
3083
3084     scroll_direction = MV_RIGHT;
3085     label_state = 1;
3086     label_counter = 0;
3087
3088     DrawPreviewLevelExt(from_x, from_y);
3089     DrawPreviewLevelLabelExt(label_state);
3090
3091     /* initialize delay counters */
3092     DelayReached(&scroll_delay, 0);
3093     DelayReached(&label_delay, 0);
3094
3095     if (leveldir_current->name)
3096     {
3097       struct TextPosInfo *pos = &menu.main.text.level_info_1;
3098       char label_text[MAX_OUTPUT_LINESIZE + 1];
3099 #if 1
3100       int font_nr = pos->font;
3101 #else
3102       int font_nr = FONT_TEXT_1;
3103 #endif
3104 #if 1
3105       int max_len_label_text = getMaxTextLength(pos, font_nr);
3106 #else
3107       int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3108 #endif
3109 #if 0
3110       int text_width;
3111       int lxpos, lypos;
3112 #endif
3113
3114 #if 1
3115       if (pos->size != -1)
3116         max_len_label_text = pos->size;
3117 #endif
3118
3119       strncpy(label_text, leveldir_current->name, max_len_label_text);
3120       label_text[max_len_label_text] = '\0';
3121
3122 #if 1
3123       DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3124 #else
3125       lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3126       lypos = SY + MICROLABEL1_YPOS;
3127
3128       DrawText(lxpos, lypos, label_text, font_nr);
3129 #endif
3130     }
3131
3132     game_status = last_game_status;     /* restore current game status */
3133
3134     return;
3135   }
3136
3137   /* scroll preview level, if needed */
3138   if (preview.anim_mode != ANIM_NONE &&
3139       (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3140       DelayReached(&scroll_delay, scroll_delay_value))
3141   {
3142     switch (scroll_direction)
3143     {
3144       case MV_LEFT:
3145         if (from_x > 0)
3146         {
3147           from_x -= preview.step_offset;
3148           from_x = (from_x < 0 ? 0 : from_x);
3149         }
3150         else
3151           scroll_direction = MV_UP;
3152         break;
3153
3154       case MV_RIGHT:
3155         if (from_x < level_xsize - preview.xsize)
3156         {
3157           from_x += preview.step_offset;
3158           from_x = (from_x > level_xsize - preview.xsize ?
3159                     level_xsize - preview.xsize : from_x);
3160         }
3161         else
3162           scroll_direction = MV_DOWN;
3163         break;
3164
3165       case MV_UP:
3166         if (from_y > 0)
3167         {
3168           from_y -= preview.step_offset;
3169           from_y = (from_y < 0 ? 0 : from_y);
3170         }
3171         else
3172           scroll_direction = MV_RIGHT;
3173         break;
3174
3175       case MV_DOWN:
3176         if (from_y < level_ysize - preview.ysize)
3177         {
3178           from_y += preview.step_offset;
3179           from_y = (from_y > level_ysize - preview.ysize ?
3180                     level_ysize - preview.ysize : from_y);
3181         }
3182         else
3183           scroll_direction = MV_LEFT;
3184         break;
3185
3186       default:
3187         break;
3188     }
3189
3190     DrawPreviewLevelExt(from_x, from_y);
3191   }
3192
3193   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3194   /* redraw micro level label, if needed */
3195   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3196       !strEqual(level.author, ANONYMOUS_NAME) &&
3197       !strEqual(level.author, leveldir_current->name) &&
3198       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3199   {
3200     int max_label_counter = 23;
3201
3202     if (leveldir_current->imported_from != NULL &&
3203         strlen(leveldir_current->imported_from) > 0)
3204       max_label_counter += 14;
3205     if (leveldir_current->imported_by != NULL &&
3206         strlen(leveldir_current->imported_by) > 0)
3207       max_label_counter += 14;
3208
3209     label_counter = (label_counter + 1) % max_label_counter;
3210     label_state = (label_counter >= 0 && label_counter <= 7 ?
3211                    MICROLABEL_LEVEL_NAME :
3212                    label_counter >= 9 && label_counter <= 12 ?
3213                    MICROLABEL_LEVEL_AUTHOR_HEAD :
3214                    label_counter >= 14 && label_counter <= 21 ?
3215                    MICROLABEL_LEVEL_AUTHOR :
3216                    label_counter >= 23 && label_counter <= 26 ?
3217                    MICROLABEL_IMPORTED_FROM_HEAD :
3218                    label_counter >= 28 && label_counter <= 35 ?
3219                    MICROLABEL_IMPORTED_FROM :
3220                    label_counter >= 37 && label_counter <= 40 ?
3221                    MICROLABEL_IMPORTED_BY_HEAD :
3222                    label_counter >= 42 && label_counter <= 49 ?
3223                    MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3224
3225     if (leveldir_current->imported_from == NULL &&
3226         (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3227          label_state == MICROLABEL_IMPORTED_FROM))
3228       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3229                      MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3230
3231     DrawPreviewLevelLabelExt(label_state);
3232   }
3233
3234   game_status = last_game_status;       /* restore current game status */
3235 }
3236
3237 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3238                                     int graphic, int sync_frame, int mask_mode)
3239 {
3240   int frame = getGraphicAnimationFrame(graphic, sync_frame);
3241
3242   if (mask_mode == USE_MASKING)
3243     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3244   else
3245     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3246 }
3247
3248 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3249                                          int graphic, int sync_frame,
3250                                          int mask_mode)
3251 {
3252   int frame = getGraphicAnimationFrame(graphic, sync_frame);
3253
3254   if (mask_mode == USE_MASKING)
3255     DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3256   else
3257     DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3258 }
3259
3260 inline void DrawGraphicAnimation(int x, int y, int graphic)
3261 {
3262   int lx = LEVELX(x), ly = LEVELY(y);
3263
3264   if (!IN_SCR_FIELD(x, y))
3265     return;
3266
3267 #if NEW_TILESIZE
3268   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3269                           graphic, GfxFrame[lx][ly], NO_MASKING);
3270 #else
3271   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3272                           graphic, GfxFrame[lx][ly], NO_MASKING);
3273 #endif
3274   MarkTileDirty(x, y);
3275 }
3276
3277 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3278 {
3279   int lx = LEVELX(x), ly = LEVELY(y);
3280
3281   if (!IN_SCR_FIELD(x, y))
3282     return;
3283
3284   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3285                           graphic, GfxFrame[lx][ly], NO_MASKING);
3286   MarkTileDirty(x, y);
3287 }
3288
3289 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3290 {
3291   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3292 }
3293
3294 void DrawLevelElementAnimation(int x, int y, int element)
3295 {
3296   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3297
3298   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3299 }
3300
3301 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3302 {
3303   int sx = SCREENX(x), sy = SCREENY(y);
3304
3305   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3306     return;
3307
3308   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3309     return;
3310
3311   DrawGraphicAnimation(sx, sy, graphic);
3312
3313 #if 1
3314   if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3315     DrawLevelFieldCrumbled(x, y);
3316 #else
3317   if (GFX_CRUMBLED(Feld[x][y]))
3318     DrawLevelFieldCrumbled(x, y);
3319 #endif
3320 }
3321
3322 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3323 {
3324   int sx = SCREENX(x), sy = SCREENY(y);
3325   int graphic;
3326
3327   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3328     return;
3329
3330   graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3331
3332   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3333     return;
3334
3335   DrawGraphicAnimation(sx, sy, graphic);
3336
3337   if (GFX_CRUMBLED(element))
3338     DrawLevelFieldCrumbled(x, y);
3339 }
3340
3341 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3342 {
3343   if (player->use_murphy)
3344   {
3345     /* this works only because currently only one player can be "murphy" ... */
3346     static int last_horizontal_dir = MV_LEFT;
3347     int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3348
3349     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3350       last_horizontal_dir = move_dir;
3351
3352     if (graphic == IMG_SP_MURPHY)       /* undefined => use special graphic */
3353     {
3354       int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3355
3356       graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3357     }
3358
3359     return graphic;
3360   }
3361   else
3362     return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3363 }
3364
3365 static boolean equalGraphics(int graphic1, int graphic2)
3366 {
3367   struct GraphicInfo *g1 = &graphic_info[graphic1];
3368   struct GraphicInfo *g2 = &graphic_info[graphic2];
3369
3370   return (g1->bitmap      == g2->bitmap &&
3371           g1->src_x       == g2->src_x &&
3372           g1->src_y       == g2->src_y &&
3373           g1->anim_frames == g2->anim_frames &&
3374           g1->anim_delay  == g2->anim_delay &&
3375           g1->anim_mode   == g2->anim_mode);
3376 }
3377
3378 void DrawAllPlayers()
3379 {
3380   int i;
3381
3382   for (i = 0; i < MAX_PLAYERS; i++)
3383     if (stored_player[i].active)
3384       DrawPlayer(&stored_player[i]);
3385 }
3386
3387 void DrawPlayerField(int x, int y)
3388 {
3389   if (!IS_PLAYER(x, y))
3390     return;
3391
3392   DrawPlayer(PLAYERINFO(x, y));
3393 }
3394
3395 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3396
3397 void DrawPlayer(struct PlayerInfo *player)
3398 {
3399   int jx = player->jx;
3400   int jy = player->jy;
3401   int move_dir = player->MovDir;
3402   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3403   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
3404   int last_jx = (player->is_moving ? jx - dx : jx);
3405   int last_jy = (player->is_moving ? jy - dy : jy);
3406   int next_jx = jx + dx;
3407   int next_jy = jy + dy;
3408   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3409   boolean player_is_opaque = FALSE;
3410   int sx = SCREENX(jx), sy = SCREENY(jy);
3411   int sxx = 0, syy = 0;
3412   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3413   int graphic;
3414   int action = ACTION_DEFAULT;
3415   int last_player_graphic = getPlayerGraphic(player, move_dir);
3416   int last_player_frame = player->Frame;
3417   int frame = 0;
3418
3419   /* GfxElement[][] is set to the element the player is digging or collecting;
3420      remove also for off-screen player if the player is not moving anymore */
3421   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3422     GfxElement[jx][jy] = EL_UNDEFINED;
3423
3424   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3425     return;
3426
3427 #if DEBUG
3428   if (!IN_LEV_FIELD(jx, jy))
3429   {
3430     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3431     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3432     printf("DrawPlayerField(): This should never happen!\n");
3433     return;
3434   }
3435 #endif
3436
3437   if (element == EL_EXPLOSION)
3438     return;
3439
3440   action = (player->is_pushing    ? ACTION_PUSHING         :
3441             player->is_digging    ? ACTION_DIGGING         :
3442             player->is_collecting ? ACTION_COLLECTING      :
3443             player->is_moving     ? ACTION_MOVING          :
3444             player->is_snapping   ? ACTION_SNAPPING        :
3445             player->is_dropping   ? ACTION_DROPPING        :
3446             player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
3447
3448   if (player->is_waiting)
3449     move_dir = player->dir_waiting;
3450
3451   InitPlayerGfxAnimation(player, action, move_dir);
3452
3453   /* ----------------------------------------------------------------------- */
3454   /* draw things in the field the player is leaving, if needed               */
3455   /* ----------------------------------------------------------------------- */
3456
3457   if (player->is_moving)
3458   {
3459     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3460     {
3461       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3462
3463       if (last_element == EL_DYNAMITE_ACTIVE ||
3464           last_element == EL_EM_DYNAMITE_ACTIVE ||
3465           last_element == EL_SP_DISK_RED_ACTIVE)
3466         DrawDynamite(last_jx, last_jy);
3467       else
3468         DrawLevelFieldThruMask(last_jx, last_jy);
3469     }
3470     else if (last_element == EL_DYNAMITE_ACTIVE ||
3471              last_element == EL_EM_DYNAMITE_ACTIVE ||
3472              last_element == EL_SP_DISK_RED_ACTIVE)
3473       DrawDynamite(last_jx, last_jy);
3474 #if 0
3475     /* !!! this is not enough to prevent flickering of players which are
3476        moving next to each others without a free tile between them -- this
3477        can only be solved by drawing all players layer by layer (first the
3478        background, then the foreground etc.) !!! => TODO */
3479     else if (!IS_PLAYER(last_jx, last_jy))
3480       DrawLevelField(last_jx, last_jy);
3481 #else
3482     else
3483       DrawLevelField(last_jx, last_jy);
3484 #endif
3485
3486     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3487       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3488   }
3489
3490   if (!IN_SCR_FIELD(sx, sy))
3491     return;
3492
3493   /* ----------------------------------------------------------------------- */
3494   /* draw things behind the player, if needed                                */
3495   /* ----------------------------------------------------------------------- */
3496
3497   if (Back[jx][jy])
3498     DrawLevelElement(jx, jy, Back[jx][jy]);
3499   else if (IS_ACTIVE_BOMB(element))
3500     DrawLevelElement(jx, jy, EL_EMPTY);
3501   else
3502   {
3503     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3504     {
3505       int old_element = GfxElement[jx][jy];
3506       int old_graphic = el_act_dir2img(old_element, action, move_dir);
3507       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3508
3509       if (GFX_CRUMBLED(old_element))
3510         DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3511       else
3512         DrawGraphic(sx, sy, old_graphic, frame);
3513
3514       if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3515         player_is_opaque = TRUE;
3516     }
3517     else
3518     {
3519       GfxElement[jx][jy] = EL_UNDEFINED;
3520
3521       /* make sure that pushed elements are drawn with correct frame rate */
3522 #if 1
3523       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3524
3525       if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3526         GfxFrame[jx][jy] = player->StepFrame;
3527 #else
3528       if (player->is_pushing && player->is_moving)
3529         GfxFrame[jx][jy] = player->StepFrame;
3530 #endif
3531
3532       DrawLevelField(jx, jy);
3533     }
3534   }
3535
3536 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3537   /* ----------------------------------------------------------------------- */
3538   /* draw player himself                                                     */
3539   /* ----------------------------------------------------------------------- */
3540
3541   graphic = getPlayerGraphic(player, move_dir);
3542
3543   /* in the case of changed player action or direction, prevent the current
3544      animation frame from being restarted for identical animations */
3545   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3546     player->Frame = last_player_frame;
3547
3548   frame = getGraphicAnimationFrame(graphic, player->Frame);
3549
3550   if (player->GfxPos)
3551   {
3552     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3553       sxx = player->GfxPos;
3554     else
3555       syy = player->GfxPos;
3556   }
3557
3558   if (!setup.soft_scrolling && ScreenMovPos)
3559     sxx = syy = 0;
3560
3561   if (player_is_opaque)
3562     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3563   else
3564     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3565
3566   if (SHIELD_ON(player))
3567   {
3568     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3569                    IMG_SHIELD_NORMAL_ACTIVE);
3570     int frame = getGraphicAnimationFrame(graphic, -1);
3571
3572     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3573   }
3574 #endif
3575
3576 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3577   if (player->GfxPos)
3578   {
3579     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3580       sxx = player->GfxPos;
3581     else
3582       syy = player->GfxPos;
3583   }
3584 #endif
3585
3586   /* ----------------------------------------------------------------------- */
3587   /* draw things the player is pushing, if needed                            */
3588   /* ----------------------------------------------------------------------- */
3589
3590 #if 0
3591   printf("::: %d, %d [%d, %d] [%d]\n",
3592          player->is_pushing, player_is_moving, player->GfxAction,
3593          player->is_moving, player_is_moving);
3594 #endif
3595
3596 #if 1
3597   if (player->is_pushing && player->is_moving)
3598   {
3599     int px = SCREENX(jx), py = SCREENY(jy);
3600     int pxx = (TILEX - ABS(sxx)) * dx;
3601     int pyy = (TILEY - ABS(syy)) * dy;
3602     int gfx_frame = GfxFrame[jx][jy];
3603
3604     int graphic;
3605     int sync_frame;
3606     int frame;
3607
3608     if (!IS_MOVING(jx, jy))             /* push movement already finished */
3609     {
3610       element = Feld[next_jx][next_jy];
3611       gfx_frame = GfxFrame[next_jx][next_jy];
3612     }
3613
3614     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3615
3616 #if 1
3617     sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3618     frame = getGraphicAnimationFrame(graphic, sync_frame);
3619 #else
3620     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3621 #endif
3622
3623     /* draw background element under pushed element (like the Sokoban field) */
3624 #if 1
3625     if (game.use_masked_pushing && IS_MOVING(jx, jy))
3626     {
3627       /* this allows transparent pushing animation over non-black background */
3628
3629       if (Back[jx][jy])
3630         DrawLevelElement(jx, jy, Back[jx][jy]);
3631       else
3632         DrawLevelElement(jx, jy, EL_EMPTY);
3633
3634       if (Back[next_jx][next_jy])
3635         DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3636       else
3637         DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3638     }
3639     else if (Back[next_jx][next_jy])
3640       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3641 #else
3642     if (Back[next_jx][next_jy])
3643       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3644 #endif
3645
3646 #if 0
3647     printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3648            jx, px, player->GfxPos, player->StepFrame,
3649            player->is_pushing,
3650            dx, sxx, pxx,
3651            IS_MOVING(jx, jy),
3652            graphic, frame,
3653            GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3654 #endif
3655
3656 #if 1
3657     /* do not draw (EM style) pushing animation when pushing is finished */
3658     /* (two-tile animations usually do not contain start and end frame) */
3659     if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3660       DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3661     else
3662       DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3663 #else
3664     /* masked drawing is needed for EMC style (double) movement graphics */
3665     /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3666     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3667 #endif
3668   }
3669 #endif
3670
3671 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3672   /* ----------------------------------------------------------------------- */
3673   /* draw player himself                                                     */
3674   /* ----------------------------------------------------------------------- */
3675
3676   graphic = getPlayerGraphic(player, move_dir);
3677
3678   /* in the case of changed player action or direction, prevent the current
3679      animation frame from being restarted for identical animations */
3680   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3681     player->Frame = last_player_frame;
3682
3683   frame = getGraphicAnimationFrame(graphic, player->Frame);
3684
3685   if (player->GfxPos)
3686   {
3687     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3688       sxx = player->GfxPos;
3689     else
3690       syy = player->GfxPos;
3691   }
3692
3693   if (!setup.soft_scrolling && ScreenMovPos)
3694     sxx = syy = 0;
3695
3696   if (player_is_opaque)
3697     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3698   else
3699     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3700
3701   if (SHIELD_ON(player))
3702   {
3703     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3704                    IMG_SHIELD_NORMAL_ACTIVE);
3705     int frame = getGraphicAnimationFrame(graphic, -1);
3706
3707     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3708   }
3709 #endif
3710
3711   /* ----------------------------------------------------------------------- */
3712   /* draw things in front of player (active dynamite or dynabombs)           */
3713   /* ----------------------------------------------------------------------- */
3714
3715   if (IS_ACTIVE_BOMB(element))
3716   {
3717     graphic = el2img(element);
3718     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3719
3720     if (game.emulation == EMU_SUPAPLEX)
3721       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3722     else
3723       DrawGraphicThruMask(sx, sy, graphic, frame);
3724   }
3725
3726   if (player_is_moving && last_element == EL_EXPLOSION)
3727   {
3728     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3729                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
3730     int graphic = el_act2img(element, ACTION_EXPLODING);
3731     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3732     int phase = ExplodePhase[last_jx][last_jy] - 1;
3733     int frame = getGraphicAnimationFrame(graphic, phase - delay);
3734
3735     if (phase >= delay)
3736       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3737   }
3738
3739   /* ----------------------------------------------------------------------- */
3740   /* draw elements the player is just walking/passing through/under          */
3741   /* ----------------------------------------------------------------------- */
3742
3743   if (player_is_moving)
3744   {
3745     /* handle the field the player is leaving ... */
3746     if (IS_ACCESSIBLE_INSIDE(last_element))
3747       DrawLevelField(last_jx, last_jy);
3748     else if (IS_ACCESSIBLE_UNDER(last_element))
3749       DrawLevelFieldThruMask(last_jx, last_jy);
3750   }
3751
3752   /* do not redraw accessible elements if the player is just pushing them */
3753   if (!player_is_moving || !player->is_pushing)
3754   {
3755     /* ... and the field the player is entering */
3756     if (IS_ACCESSIBLE_INSIDE(element))
3757       DrawLevelField(jx, jy);
3758     else if (IS_ACCESSIBLE_UNDER(element))
3759       DrawLevelFieldThruMask(jx, jy);
3760   }
3761
3762   MarkTileDirty(sx, sy);
3763 }
3764
3765 /* ------------------------------------------------------------------------- */
3766
3767 void WaitForEventToContinue()
3768 {
3769   boolean still_wait = TRUE;
3770
3771   /* simulate releasing mouse button over last gadget, if still pressed */
3772   if (button_status)
3773     HandleGadgets(-1, -1, 0);
3774
3775   button_status = MB_RELEASED;
3776
3777 #if 1
3778   ClearEventQueue();
3779 #endif
3780
3781   while (still_wait)
3782   {
3783     if (PendingEvent())
3784     {
3785       Event event;
3786
3787       NextEvent(&event);
3788
3789       switch (event.type)
3790       {
3791         case EVENT_BUTTONPRESS:
3792         case EVENT_KEYPRESS:
3793           still_wait = FALSE;
3794           break;
3795
3796         case EVENT_KEYRELEASE:
3797           ClearPlayerAction();
3798           break;
3799
3800         default:
3801           HandleOtherEvents(&event);
3802           break;
3803       }
3804     }
3805     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3806     {
3807       still_wait = FALSE;
3808     }
3809
3810     DoAnimation();
3811
3812     /* don't eat all CPU time */
3813     Delay(10);
3814   }
3815 }
3816
3817 #define MAX_REQUEST_LINES               13
3818 #define MAX_REQUEST_LINE_FONT1_LEN      7
3819 #define MAX_REQUEST_LINE_FONT2_LEN      10
3820
3821 boolean Request(char *text, unsigned int req_state)
3822 {
3823   int mx, my, ty, result = -1;
3824   unsigned int old_door_state;
3825   int last_game_status = game_status;   /* save current game status */
3826   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3827   int font_nr = FONT_TEXT_2;
3828 #if 0
3829   int max_word_len = 0;
3830 #endif
3831   char *text_ptr;
3832   int i;
3833
3834 #if 1
3835   global.use_envelope_request = 0;
3836 #endif
3837
3838 #if 1
3839   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3840   {
3841     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3842     font_nr = FONT_TEXT_1;
3843   }
3844 #else
3845   for (text_ptr = text; *text_ptr; text_ptr++)
3846   {
3847     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3848
3849     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3850     {
3851       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3852 #if 1
3853       font_nr = FONT_TEXT_1;
3854 #else
3855       font_nr = FONT_LEVEL_NUMBER;
3856 #endif
3857
3858       break;
3859     }
3860   }
3861 #endif
3862
3863   if (game_status == GAME_MODE_PLAYING)
3864   {
3865     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3866       BlitScreenToBitmap_EM(backbuffer);
3867     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3868       BlitScreenToBitmap_SP(backbuffer);
3869   }
3870
3871   /* disable deactivated drawing when quick-loading level tape recording */
3872   if (tape.playing && tape.deactivate_display)
3873     TapeDeactivateDisplayOff(TRUE);
3874
3875   SetMouseCursor(CURSOR_DEFAULT);
3876
3877 #if defined(NETWORK_AVALIABLE)
3878   /* pause network game while waiting for request to answer */
3879   if (options.network &&
3880       game_status == GAME_MODE_PLAYING &&
3881       req_state & REQUEST_WAIT_FOR_INPUT)
3882     SendToServer_PausePlaying();
3883 #endif
3884
3885   old_door_state = GetDoorState();
3886
3887   /* simulate releasing mouse button over last gadget, if still pressed */
3888   if (button_status)
3889     HandleGadgets(-1, -1, 0);
3890
3891   UnmapAllGadgets();
3892
3893   /* draw released gadget before proceeding */
3894   // BackToFront();
3895
3896 #if 0
3897   if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3898 #else
3899   if (old_door_state & DOOR_OPEN_1)
3900 #endif
3901   {
3902 #if 1
3903     if (!global.use_envelope_request)
3904       CloseDoor(DOOR_CLOSE_1);
3905 #else
3906     CloseDoor(DOOR_CLOSE_1);
3907 #endif
3908
3909     /* save old door content */
3910     BlitBitmap(bitmap_db_door, bitmap_db_door,
3911                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3912                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3913   }
3914
3915 #if 1
3916   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3917 #endif
3918
3919   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3920
3921   /* clear door drawing field */
3922   DrawBackground(DX, DY, DXSIZE, DYSIZE);
3923
3924   /* force DOOR font inside door area */
3925   game_status = GAME_MODE_PSEUDO_DOOR;
3926
3927   /* write text for request */
3928   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3929   {
3930     char text_line[max_request_line_len + 1];
3931     int tx, tl, tc = 0;
3932
3933     if (!*text_ptr)
3934       break;
3935
3936     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3937     {
3938       tc = *(text_ptr + tx);
3939       if (!tc || tc == ' ')
3940         break;
3941     }
3942
3943     if (!tl)
3944     { 
3945       text_ptr++; 
3946       ty--; 
3947       continue; 
3948     }
3949
3950     strncpy(text_line, text_ptr, tl);
3951     text_line[tl] = 0;
3952
3953     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3954              DY + 8 + ty * (getFontHeight(font_nr) + 2),
3955              text_line, font_nr);
3956
3957     text_ptr += tl + (tc == ' ' ? 1 : 0);
3958   }
3959
3960   game_status = last_game_status;       /* restore current game status */
3961
3962 #if 1
3963   if (global.use_envelope_request)
3964   {
3965     /* !!! TMP !!! */
3966     FreeToolButtons();
3967     CreateToolButtons();
3968   }
3969 #endif
3970
3971   if (req_state & REQ_ASK)
3972   {
3973     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3974     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3975   }
3976   else if (req_state & REQ_CONFIRM)
3977   {
3978     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3979   }
3980   else if (req_state & REQ_PLAYER)
3981   {
3982     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3983     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3984     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3985     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3986   }
3987
3988   /* copy request gadgets to door backbuffer */
3989   BlitBitmap(drawto, bitmap_db_door,
3990              DX, DY, DXSIZE, DYSIZE,
3991              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3992
3993 #if 1
3994   if (global.use_envelope_request)
3995   {
3996     ShowEnvelopeDoor(text, ACTION_OPENING);
3997
3998     for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3999     {
4000       if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4001                                    i == TOOL_CTRL_ID_NO)) ||
4002           (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4003           (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4004                                       i == TOOL_CTRL_ID_PLAYER_2 &&
4005                                       i == TOOL_CTRL_ID_PLAYER_3 &&
4006                                       i == TOOL_CTRL_ID_PLAYER_4)))
4007       {
4008         int x = tool_gadget[i]->x + dDX;
4009         int y = tool_gadget[i]->y + dDY;
4010
4011         ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4012       }
4013     }
4014   }
4015 #endif
4016
4017 #if 1
4018   if (!global.use_envelope_request)
4019     OpenDoor(DOOR_OPEN_1);
4020 #else
4021   OpenDoor(DOOR_OPEN_1);
4022 #endif
4023
4024   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4025   {
4026     if (game_status == GAME_MODE_PLAYING)
4027     {
4028       SetPanelBackground();
4029       SetDrawBackgroundMask(REDRAW_DOOR_1);
4030     }
4031     else
4032     {
4033       SetDrawBackgroundMask(REDRAW_FIELD);
4034     }
4035
4036     return FALSE;
4037   }
4038
4039 #if 1
4040   if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
4041     InitAnimation();
4042 #else
4043   if (game_status != GAME_MODE_MAIN)
4044     InitAnimation();
4045 #endif
4046
4047   button_status = MB_RELEASED;
4048
4049   request_gadget_id = -1;
4050
4051   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4052
4053   while (result < 0)
4054   {
4055     if (PendingEvent())
4056     {
4057       Event event;
4058
4059       NextEvent(&event);
4060
4061       switch (event.type)
4062       {
4063         case EVENT_BUTTONPRESS:
4064         case EVENT_BUTTONRELEASE:
4065         case EVENT_MOTIONNOTIFY:
4066         {
4067           if (event.type == EVENT_MOTIONNOTIFY)
4068           {
4069             if (!PointerInWindow(window))
4070               continue; /* window and pointer are on different screens */
4071
4072             if (!button_status)
4073               continue;
4074
4075             motion_status = TRUE;
4076             mx = ((MotionEvent *) &event)->x;
4077             my = ((MotionEvent *) &event)->y;
4078           }
4079           else
4080           {
4081             motion_status = FALSE;
4082             mx = ((ButtonEvent *) &event)->x;
4083             my = ((ButtonEvent *) &event)->y;
4084             if (event.type == EVENT_BUTTONPRESS)
4085               button_status = ((ButtonEvent *) &event)->button;
4086             else
4087               button_status = MB_RELEASED;
4088           }
4089
4090           /* this sets 'request_gadget_id' */
4091           HandleGadgets(mx, my, button_status);
4092
4093           switch (request_gadget_id)
4094           {
4095             case TOOL_CTRL_ID_YES:
4096               result = TRUE;
4097               break;
4098             case TOOL_CTRL_ID_NO:
4099               result = FALSE;
4100               break;
4101             case TOOL_CTRL_ID_CONFIRM:
4102               result = TRUE | FALSE;
4103               break;
4104
4105             case TOOL_CTRL_ID_PLAYER_1:
4106               result = 1;
4107               break;
4108             case TOOL_CTRL_ID_PLAYER_2:
4109               result = 2;
4110               break;
4111             case TOOL_CTRL_ID_PLAYER_3:
4112               result = 3;
4113               break;
4114             case TOOL_CTRL_ID_PLAYER_4:
4115               result = 4;
4116               break;
4117
4118             default:
4119               break;
4120           }
4121
4122           break;
4123         }
4124
4125         case EVENT_KEYPRESS:
4126           switch (GetEventKey((KeyEvent *)&event, TRUE))
4127           {
4128             case KSYM_space:
4129               if (req_state & REQ_CONFIRM)
4130                 result = 1;
4131               break;
4132
4133             case KSYM_Return:
4134               result = 1;
4135               break;
4136
4137             case KSYM_Escape:
4138               result = 0;
4139               break;
4140
4141             default:
4142               break;
4143           }
4144
4145           if (req_state & REQ_PLAYER)
4146             result = 0;
4147           break;
4148
4149         case EVENT_KEYRELEASE:
4150           ClearPlayerAction();
4151           break;
4152
4153         default:
4154           HandleOtherEvents(&event);
4155           break;
4156       }
4157     }
4158     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4159     {
4160       int joy = AnyJoystick();
4161
4162       if (joy & JOY_BUTTON_1)
4163         result = 1;
4164       else if (joy & JOY_BUTTON_2)
4165         result = 0;
4166     }
4167
4168 #if 1
4169
4170     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4171     {
4172       HandleGameActions();
4173     }
4174     else
4175     {
4176       DoAnimation();
4177
4178       if (!PendingEvent())      /* delay only if no pending events */
4179         Delay(10);
4180     }
4181
4182 #if 1
4183     game_status = GAME_MODE_PSEUDO_DOOR;
4184 #endif
4185
4186     BackToFront();
4187
4188 #if 1
4189     game_status = last_game_status;     /* restore current game status */
4190 #endif
4191
4192 #else
4193
4194     DoAnimation();
4195
4196 #if 1
4197     if (!PendingEvent())        /* delay only if no pending events */
4198       Delay(10);
4199 #else
4200     /* don't eat all CPU time */
4201     Delay(10);
4202 #endif
4203
4204 #endif
4205   }
4206
4207   if (game_status != GAME_MODE_MAIN)
4208     StopAnimation();
4209
4210   UnmapToolButtons();
4211
4212 #if 1
4213   if (global.use_envelope_request)
4214     ShowEnvelopeDoor(text, ACTION_CLOSING);
4215 #endif
4216
4217 #if 1
4218   if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
4219 #else
4220   if (!(req_state & REQ_STAY_OPEN))
4221 #endif
4222   {
4223     CloseDoor(DOOR_CLOSE_1);
4224
4225     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4226         (req_state & REQ_REOPEN))
4227       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4228   }
4229
4230   RemapAllGadgets();
4231
4232   if (game_status == GAME_MODE_PLAYING)
4233   {
4234     SetPanelBackground();
4235     SetDrawBackgroundMask(REDRAW_DOOR_1);
4236   }
4237   else
4238   {
4239     SetDrawBackgroundMask(REDRAW_FIELD);
4240   }
4241
4242 #if defined(NETWORK_AVALIABLE)
4243   /* continue network game after request */
4244   if (options.network &&
4245       game_status == GAME_MODE_PLAYING &&
4246       req_state & REQUEST_WAIT_FOR_INPUT)
4247     SendToServer_ContinuePlaying();
4248 #endif
4249
4250   /* restore deactivated drawing when quick-loading level tape recording */
4251   if (tape.playing && tape.deactivate_display)
4252     TapeDeactivateDisplayOn();
4253
4254   return result;
4255 }
4256
4257 unsigned int OpenDoor(unsigned int door_state)
4258 {
4259   if (door_state & DOOR_COPY_BACK)
4260   {
4261     if (door_state & DOOR_OPEN_1)
4262       BlitBitmap(bitmap_db_door, bitmap_db_door,
4263                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4264                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4265
4266     if (door_state & DOOR_OPEN_2)
4267       BlitBitmap(bitmap_db_door, bitmap_db_door,
4268                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
4269                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4270
4271     door_state &= ~DOOR_COPY_BACK;
4272   }
4273
4274   return MoveDoor(door_state);
4275 }
4276
4277 unsigned int CloseDoor(unsigned int door_state)
4278 {
4279   unsigned int old_door_state = GetDoorState();
4280
4281   if (!(door_state & DOOR_NO_COPY_BACK))
4282   {
4283     if (old_door_state & DOOR_OPEN_1)
4284       BlitBitmap(backbuffer, bitmap_db_door,
4285                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4286
4287     if (old_door_state & DOOR_OPEN_2)
4288       BlitBitmap(backbuffer, bitmap_db_door,
4289                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4290
4291     door_state &= ~DOOR_NO_COPY_BACK;
4292   }
4293
4294   return MoveDoor(door_state);
4295 }
4296
4297 unsigned int GetDoorState()
4298 {
4299   return MoveDoor(DOOR_GET_STATE);
4300 }
4301
4302 unsigned int SetDoorState(unsigned int door_state)
4303 {
4304   return MoveDoor(door_state | DOOR_SET_STATE);
4305 }
4306
4307 unsigned int MoveDoor(unsigned int door_state)
4308 {
4309   static int door1 = DOOR_OPEN_1;
4310   static int door2 = DOOR_CLOSE_2;
4311   unsigned long door_delay = 0;
4312   unsigned long door_delay_value;
4313   int stepsize = 1;
4314
4315   if (door_1.width < 0 || door_1.width > DXSIZE)
4316     door_1.width = DXSIZE;
4317   if (door_1.height < 0 || door_1.height > DYSIZE)
4318     door_1.height = DYSIZE;
4319   if (door_2.width < 0 || door_2.width > VXSIZE)
4320     door_2.width = VXSIZE;
4321   if (door_2.height < 0 || door_2.height > VYSIZE)
4322     door_2.height = VYSIZE;
4323
4324   if (door_state == DOOR_GET_STATE)
4325     return (door1 | door2);
4326
4327   if (door_state & DOOR_SET_STATE)
4328   {
4329     if (door_state & DOOR_ACTION_1)
4330       door1 = door_state & DOOR_ACTION_1;
4331     if (door_state & DOOR_ACTION_2)
4332       door2 = door_state & DOOR_ACTION_2;
4333
4334     return (door1 | door2);
4335   }
4336
4337   if (!(door_state & DOOR_FORCE_REDRAW))
4338   {
4339     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4340       door_state &= ~DOOR_OPEN_1;
4341     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4342       door_state &= ~DOOR_CLOSE_1;
4343     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4344       door_state &= ~DOOR_OPEN_2;
4345     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4346       door_state &= ~DOOR_CLOSE_2;
4347   }
4348
4349   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
4350                       door_2.step_delay);
4351
4352   if (setup.quick_doors)
4353   {
4354     stepsize = 20;              /* must be chosen to always draw last frame */
4355     door_delay_value = 0;
4356   }
4357
4358   if (global.autoplay_leveldir)
4359   {
4360     door_state |= DOOR_NO_DELAY;
4361     door_state &= ~DOOR_CLOSE_ALL;
4362   }
4363
4364 #if 1
4365   if (game_status == GAME_MODE_EDITOR)
4366     door_state |= DOOR_NO_DELAY;
4367 #endif
4368
4369   if (door_state & DOOR_ACTION)
4370   {
4371     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
4372     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
4373     boolean door_1_done = (!handle_door_1);
4374     boolean door_2_done = (!handle_door_2);
4375     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
4376     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
4377     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
4378     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
4379     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
4380     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
4381     int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
4382     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
4383     int door_skip = max_door_size - door_size;
4384     int end = door_size;
4385     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
4386     int k;
4387
4388     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
4389     {
4390       /* opening door sound has priority over simultaneously closing door */
4391       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4392         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4393       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4394         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4395     }
4396
4397     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
4398     {
4399       int x = k;
4400       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4401       GC gc = bitmap->stored_clip_gc;
4402
4403       if (door_state & DOOR_ACTION_1)
4404       {
4405         int a = MIN(x * door_1.step_offset, end);
4406         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
4407         int i = p + door_skip;
4408
4409         if (door_1.anim_mode & ANIM_STATIC_PANEL)
4410         {
4411           BlitBitmap(bitmap_db_door, drawto,
4412                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
4413                      DXSIZE, DYSIZE, DX, DY);
4414         }
4415         else if (x <= a)
4416         {
4417           BlitBitmap(bitmap_db_door, drawto,
4418                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
4419                      DXSIZE, DYSIZE - p / 2, DX, DY);
4420
4421           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
4422         }
4423
4424         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
4425         {
4426           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
4427           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4428           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
4429           int dst2_x = DX,              dst2_y = DY;
4430           int width = i, height = DYSIZE;
4431
4432           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4433           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4434                            dst1_x, dst1_y);
4435
4436           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4437           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4438                            dst2_x, dst2_y);
4439         }
4440         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4441         {
4442           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
4443           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
4444           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4445           int dst2_x = DX,              dst2_y = DY;
4446           int width = DXSIZE, height = i;
4447
4448           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4449           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4450                            dst1_x, dst1_y);
4451
4452           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4453           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4454                            dst2_x, dst2_y);
4455         }
4456         else if (x <= DXSIZE)   /* ANIM_DEFAULT */
4457         {
4458           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4459
4460           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4461           BlitBitmapMasked(bitmap, drawto,
4462                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4463                            DX + DXSIZE - i, DY + j);
4464           BlitBitmapMasked(bitmap, drawto,
4465                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4466                            DX + DXSIZE - i, DY + 140 + j);
4467           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4468                         DY - (DOOR_GFX_PAGEY1 + j));
4469           BlitBitmapMasked(bitmap, drawto,
4470                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4471                            DX, DY);
4472           BlitBitmapMasked(bitmap, drawto,
4473                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4474                            DX, DY + 140 - j);
4475
4476           BlitBitmapMasked(bitmap, drawto,
4477                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4478                            DX, DY + 77 - j);
4479           BlitBitmapMasked(bitmap, drawto,
4480                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4481                            DX, DY + 203 - j);
4482           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4483           BlitBitmapMasked(bitmap, drawto,
4484                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4485                            DX + DXSIZE - i, DY + 77 + j);
4486           BlitBitmapMasked(bitmap, drawto,
4487                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4488                            DX + DXSIZE - i, DY + 203 + j);
4489         }
4490
4491         redraw_mask |= REDRAW_DOOR_1;
4492         door_1_done = (a == end);
4493       }
4494
4495       if (door_state & DOOR_ACTION_2)
4496       {
4497         int a = MIN(x * door_2.step_offset, door_size);
4498         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4499         int i = p + door_skip;
4500
4501         if (door_2.anim_mode & ANIM_STATIC_PANEL)
4502         {
4503           BlitBitmap(bitmap_db_door, drawto,
4504                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4505                      VXSIZE, VYSIZE, VX, VY);
4506         }
4507         else if (x <= VYSIZE)
4508         {
4509           BlitBitmap(bitmap_db_door, drawto,
4510                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4511                      VXSIZE, VYSIZE - p / 2, VX, VY);
4512
4513           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4514         }
4515
4516         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4517         {
4518           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
4519           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4520           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
4521           int dst2_x = VX,              dst2_y = VY;
4522           int width = i, height = VYSIZE;
4523
4524           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4525           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4526                            dst1_x, dst1_y);
4527
4528           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4529           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4530                            dst2_x, dst2_y);
4531         }
4532         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4533         {
4534           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
4535           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
4536           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4537           int dst2_x = VX,              dst2_y = VY;
4538           int width = VXSIZE, height = i;
4539
4540           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4541           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4542                            dst1_x, dst1_y);
4543
4544           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4545           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4546                            dst2_x, dst2_y);
4547         }
4548         else if (x <= VXSIZE)   /* ANIM_DEFAULT */
4549         {
4550           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4551
4552           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4553           BlitBitmapMasked(bitmap, drawto,
4554                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4555                            VX + VXSIZE - i, VY + j);
4556           SetClipOrigin(bitmap, gc,
4557                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4558           BlitBitmapMasked(bitmap, drawto,
4559                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4560                            VX, VY);
4561
4562           BlitBitmapMasked(bitmap, drawto,
4563                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4564                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4565           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4566           BlitBitmapMasked(bitmap, drawto,
4567                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4568                            i, VYSIZE / 2 - j,
4569                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4570         }
4571
4572         redraw_mask |= REDRAW_DOOR_2;
4573         door_2_done = (a == VXSIZE);
4574       }
4575
4576       if (!(door_state & DOOR_NO_DELAY))
4577       {
4578         BackToFront();
4579
4580         if (game_status == GAME_MODE_MAIN)
4581           DoAnimation();
4582
4583         WaitUntilDelayReached(&door_delay, door_delay_value);
4584       }
4585     }
4586   }
4587
4588   if (door_state & DOOR_ACTION_1)
4589     door1 = door_state & DOOR_ACTION_1;
4590   if (door_state & DOOR_ACTION_2)
4591     door2 = door_state & DOOR_ACTION_2;
4592
4593   return (door1 | door2);
4594 }
4595
4596 void DrawSpecialEditorDoor()
4597 {
4598   /* draw bigger toolbox window */
4599   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4600              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4601              EX - 4, EY - 12);
4602   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4603              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4604              EX - 6, EY - 4);
4605
4606   redraw_mask |= REDRAW_ALL;
4607 }
4608
4609 void UndrawSpecialEditorDoor()
4610 {
4611   /* draw normal tape recorder window */
4612   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4613              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4614              EX - 6, EY - 12);
4615
4616   redraw_mask |= REDRAW_ALL;
4617 }
4618
4619
4620 /* ---------- new tool button stuff ---------------------------------------- */
4621
4622 /* graphic position values for tool buttons */
4623 #define TOOL_BUTTON_YES_XPOS            2
4624 #define TOOL_BUTTON_YES_YPOS            250
4625 #define TOOL_BUTTON_YES_GFX_YPOS        0
4626 #define TOOL_BUTTON_YES_XSIZE           46
4627 #define TOOL_BUTTON_YES_YSIZE           28
4628 #define TOOL_BUTTON_NO_XPOS             52
4629 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
4630 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
4631 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
4632 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
4633 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
4634 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
4635 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
4636 #define TOOL_BUTTON_CONFIRM_XSIZE       96
4637 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
4638 #define TOOL_BUTTON_PLAYER_XSIZE        30
4639 #define TOOL_BUTTON_PLAYER_YSIZE        30
4640 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
4641 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
4642 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4643 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4644 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4645                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4646 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4647                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4648 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4649                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4650 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4651                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4652 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4653                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4654 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4655                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4656 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4657                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4658 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4659                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4660
4661 static struct
4662 {
4663   int xpos, ypos;
4664   int x, y;
4665   int width, height;
4666   int gadget_id;
4667   char *infotext;
4668 } toolbutton_info[NUM_TOOL_BUTTONS] =
4669 {
4670   {
4671     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
4672     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
4673     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
4674     TOOL_CTRL_ID_YES,
4675     "yes"
4676   },
4677   {
4678     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
4679     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
4680     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
4681     TOOL_CTRL_ID_NO,
4682     "no"
4683   },
4684   {
4685     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
4686     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
4687     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
4688     TOOL_CTRL_ID_CONFIRM,
4689     "confirm"
4690   },
4691   {
4692     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4693     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
4694     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4695     TOOL_CTRL_ID_PLAYER_1,
4696     "player 1"
4697   },
4698   {
4699     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4700     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
4701     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4702     TOOL_CTRL_ID_PLAYER_2,
4703     "player 2"
4704   },
4705   {
4706     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4707     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
4708     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4709     TOOL_CTRL_ID_PLAYER_3,
4710     "player 3"
4711   },
4712   {
4713     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4714     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
4715     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4716     TOOL_CTRL_ID_PLAYER_4,
4717     "player 4"
4718   }
4719 };
4720
4721 void CreateToolButtons()
4722 {
4723   int i;
4724
4725   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4726   {
4727     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4728     Bitmap *deco_bitmap = None;
4729     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4730     struct GadgetInfo *gi;
4731     unsigned long event_mask;
4732     int gd_xoffset, gd_yoffset;
4733     int gd_x1, gd_x2, gd_y;
4734     int id = i;
4735
4736     event_mask = GD_EVENT_RELEASED;
4737
4738     gd_xoffset = toolbutton_info[i].xpos;
4739     gd_yoffset = toolbutton_info[i].ypos;
4740     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4741     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4742     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4743
4744     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4745     {
4746       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4747
4748       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4749                            &deco_bitmap, &deco_x, &deco_y);
4750       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4751       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4752     }
4753
4754     gi = CreateGadget(GDI_CUSTOM_ID, id,
4755                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
4756                       GDI_X, DX + toolbutton_info[i].x,
4757                       GDI_Y, DY + toolbutton_info[i].y,
4758                       GDI_WIDTH, toolbutton_info[i].width,
4759                       GDI_HEIGHT, toolbutton_info[i].height,
4760                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4761                       GDI_STATE, GD_BUTTON_UNPRESSED,
4762                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4763                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4764                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4765                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4766                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4767                       GDI_DECORATION_SHIFTING, 1, 1,
4768                       GDI_DIRECT_DRAW, FALSE,
4769                       GDI_EVENT_MASK, event_mask,
4770                       GDI_CALLBACK_ACTION, HandleToolButtons,
4771                       GDI_END);
4772
4773     if (gi == NULL)
4774       Error(ERR_EXIT, "cannot create gadget");
4775
4776     tool_gadget[id] = gi;
4777   }
4778 }
4779
4780 void FreeToolButtons()
4781 {
4782   int i;
4783
4784   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4785     FreeGadget(tool_gadget[i]);
4786 }
4787
4788 static void UnmapToolButtons()
4789 {
4790   int i;
4791
4792   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4793     UnmapGadget(tool_gadget[i]);
4794 }
4795
4796 static void HandleToolButtons(struct GadgetInfo *gi)
4797 {
4798   request_gadget_id = gi->custom_id;
4799 }
4800
4801 static struct Mapping_EM_to_RND_object
4802 {
4803   int element_em;
4804   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
4805   boolean is_backside;                  /* backside of moving element */
4806
4807   int element_rnd;
4808   int action;
4809   int direction;
4810 }
4811 em_object_mapping_list[] =
4812 {
4813   {
4814     Xblank,                             TRUE,   FALSE,
4815     EL_EMPTY,                           -1, -1
4816   },
4817   {
4818     Yacid_splash_eB,                    FALSE,  FALSE,
4819     EL_ACID_SPLASH_RIGHT,               -1, -1
4820   },
4821   {
4822     Yacid_splash_wB,                    FALSE,  FALSE,
4823     EL_ACID_SPLASH_LEFT,                -1, -1
4824   },
4825
4826 #ifdef EM_ENGINE_BAD_ROLL
4827   {
4828     Xstone_force_e,                     FALSE,  FALSE,
4829     EL_ROCK,                            -1, MV_BIT_RIGHT
4830   },
4831   {
4832     Xstone_force_w,                     FALSE,  FALSE,
4833     EL_ROCK,                            -1, MV_BIT_LEFT
4834   },
4835   {
4836     Xnut_force_e,                       FALSE,  FALSE,
4837     EL_NUT,                             -1, MV_BIT_RIGHT
4838   },
4839   {
4840     Xnut_force_w,                       FALSE,  FALSE,
4841     EL_NUT,                             -1, MV_BIT_LEFT
4842   },
4843   {
4844     Xspring_force_e,                    FALSE,  FALSE,
4845     EL_SPRING,                          -1, MV_BIT_RIGHT
4846   },
4847   {
4848     Xspring_force_w,                    FALSE,  FALSE,
4849     EL_SPRING,                          -1, MV_BIT_LEFT
4850   },
4851   {
4852     Xemerald_force_e,                   FALSE,  FALSE,
4853     EL_EMERALD,                         -1, MV_BIT_RIGHT
4854   },
4855   {
4856     Xemerald_force_w,                   FALSE,  FALSE,
4857     EL_EMERALD,                         -1, MV_BIT_LEFT
4858   },
4859   {
4860     Xdiamond_force_e,                   FALSE,  FALSE,
4861     EL_DIAMOND,                         -1, MV_BIT_RIGHT
4862   },
4863   {
4864     Xdiamond_force_w,                   FALSE,  FALSE,
4865     EL_DIAMOND,                         -1, MV_BIT_LEFT
4866   },
4867   {
4868     Xbomb_force_e,                      FALSE,  FALSE,
4869     EL_BOMB,                            -1, MV_BIT_RIGHT
4870   },
4871   {
4872     Xbomb_force_w,                      FALSE,  FALSE,
4873     EL_BOMB,                            -1, MV_BIT_LEFT
4874   },
4875 #endif  /* EM_ENGINE_BAD_ROLL */
4876
4877   {
4878     Xstone,                             TRUE,   FALSE,
4879     EL_ROCK,                            -1, -1
4880   },
4881   {
4882     Xstone_pause,                       FALSE,  FALSE,
4883     EL_ROCK,                            -1, -1
4884   },
4885   {
4886     Xstone_fall,                        FALSE,  FALSE,
4887     EL_ROCK,                            -1, -1
4888   },
4889   {
4890     Ystone_s,                           FALSE,  FALSE,
4891     EL_ROCK,                            ACTION_FALLING, -1
4892   },
4893   {
4894     Ystone_sB,                          FALSE,  TRUE,
4895     EL_ROCK,                            ACTION_FALLING, -1
4896   },
4897   {
4898     Ystone_e,                           FALSE,  FALSE,
4899     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
4900   },
4901   {
4902     Ystone_eB,                          FALSE,  TRUE,
4903     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
4904   },
4905   {
4906     Ystone_w,                           FALSE,  FALSE,
4907     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
4908   },
4909   {
4910     Ystone_wB,                          FALSE,  TRUE,
4911     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
4912   },
4913   {
4914     Xnut,                               TRUE,   FALSE,
4915     EL_NUT,                             -1, -1
4916   },
4917   {
4918     Xnut_pause,                         FALSE,  FALSE,
4919     EL_NUT,                             -1, -1
4920   },
4921   {
4922     Xnut_fall,                          FALSE,  FALSE,
4923     EL_NUT,                             -1, -1
4924   },
4925   {
4926     Ynut_s,                             FALSE,  FALSE,
4927     EL_NUT,                             ACTION_FALLING, -1
4928   },
4929   {
4930     Ynut_sB,                            FALSE,  TRUE,
4931     EL_NUT,                             ACTION_FALLING, -1
4932   },
4933   {
4934     Ynut_e,                             FALSE,  FALSE,
4935     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
4936   },
4937   {
4938     Ynut_eB,                            FALSE,  TRUE,
4939     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
4940   },
4941   {
4942     Ynut_w,                             FALSE,  FALSE,
4943     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
4944   },
4945   {
4946     Ynut_wB,                            FALSE,  TRUE,
4947     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
4948   },
4949   {
4950     Xbug_n,                             TRUE,   FALSE,
4951     EL_BUG_UP,                          -1, -1
4952   },
4953   {
4954     Xbug_e,                             TRUE,   FALSE,
4955     EL_BUG_RIGHT,                       -1, -1
4956   },
4957   {
4958     Xbug_s,                             TRUE,   FALSE,
4959     EL_BUG_DOWN,                        -1, -1
4960   },
4961   {
4962     Xbug_w,                             TRUE,   FALSE,
4963     EL_BUG_LEFT,                        -1, -1
4964   },
4965   {
4966     Xbug_gon,                           FALSE,  FALSE,
4967     EL_BUG_UP,                          -1, -1
4968   },
4969   {
4970     Xbug_goe,                           FALSE,  FALSE,
4971     EL_BUG_RIGHT,                       -1, -1
4972   },
4973   {
4974     Xbug_gos,                           FALSE,  FALSE,
4975     EL_BUG_DOWN,                        -1, -1
4976   },
4977   {
4978     Xbug_gow,                           FALSE,  FALSE,
4979     EL_BUG_LEFT,                        -1, -1
4980   },
4981   {
4982     Ybug_n,                             FALSE,  FALSE,
4983     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
4984   },
4985   {
4986     Ybug_nB,                            FALSE,  TRUE,
4987     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
4988   },
4989   {
4990     Ybug_e,                             FALSE,  FALSE,
4991     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
4992   },
4993   {
4994     Ybug_eB,                            FALSE,  TRUE,
4995     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
4996   },
4997   {
4998     Ybug_s,                             FALSE,  FALSE,
4999     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
5000   },
5001   {
5002     Ybug_sB,                            FALSE,  TRUE,
5003     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
5004   },
5005   {
5006     Ybug_w,                             FALSE,  FALSE,
5007     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
5008   },
5009   {
5010     Ybug_wB,                            FALSE,  TRUE,
5011     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
5012   },
5013   {
5014     Ybug_w_n,                           FALSE,  FALSE,
5015     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5016   },
5017   {
5018     Ybug_n_e,                           FALSE,  FALSE,
5019     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5020   },
5021   {
5022     Ybug_e_s,                           FALSE,  FALSE,
5023     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5024   },
5025   {
5026     Ybug_s_w,                           FALSE,  FALSE,
5027     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5028   },
5029   {
5030     Ybug_e_n,                           FALSE,  FALSE,
5031     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5032   },
5033   {
5034     Ybug_s_e,                           FALSE,  FALSE,
5035     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5036   },
5037   {
5038     Ybug_w_s,                           FALSE,  FALSE,
5039     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5040   },
5041   {
5042     Ybug_n_w,                           FALSE,  FALSE,
5043     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5044   },
5045   {
5046     Ybug_stone,                         FALSE,  FALSE,
5047     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
5048   },
5049   {
5050     Ybug_spring,                        FALSE,  FALSE,
5051     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
5052   },
5053   {
5054     Xtank_n,                            TRUE,   FALSE,
5055     EL_SPACESHIP_UP,                    -1, -1
5056   },
5057   {
5058     Xtank_e,                            TRUE,   FALSE,
5059     EL_SPACESHIP_RIGHT,                 -1, -1
5060   },
5061   {
5062     Xtank_s,                            TRUE,   FALSE,
5063     EL_SPACESHIP_DOWN,                  -1, -1
5064   },
5065   {
5066     Xtank_w,                            TRUE,   FALSE,
5067     EL_SPACESHIP_LEFT,                  -1, -1
5068   },
5069   {
5070     Xtank_gon,                          FALSE,  FALSE,
5071     EL_SPACESHIP_UP,                    -1, -1
5072   },
5073   {
5074     Xtank_goe,                          FALSE,  FALSE,
5075     EL_SPACESHIP_RIGHT,                 -1, -1
5076   },
5077   {
5078     Xtank_gos,                          FALSE,  FALSE,
5079     EL_SPACESHIP_DOWN,                  -1, -1
5080   },
5081   {
5082     Xtank_gow,                          FALSE,  FALSE,
5083     EL_SPACESHIP_LEFT,                  -1, -1
5084   },
5085   {
5086     Ytank_n,                            FALSE,  FALSE,
5087     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
5088   },
5089   {
5090     Ytank_nB,                           FALSE,  TRUE,
5091     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
5092   },
5093   {
5094     Ytank_e,                            FALSE,  FALSE,
5095     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
5096   },
5097   {
5098     Ytank_eB,                           FALSE,  TRUE,
5099     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
5100   },
5101   {
5102     Ytank_s,                            FALSE,  FALSE,
5103     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
5104   },
5105   {
5106     Ytank_sB,                           FALSE,  TRUE,
5107     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
5108   },
5109   {
5110     Ytank_w,                            FALSE,  FALSE,
5111     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
5112   },
5113   {
5114     Ytank_wB,                           FALSE,  TRUE,
5115     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
5116   },
5117   {
5118     Ytank_w_n,                          FALSE,  FALSE,
5119     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5120   },
5121   {
5122     Ytank_n_e,                          FALSE,  FALSE,
5123     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5124   },
5125   {
5126     Ytank_e_s,                          FALSE,  FALSE,
5127     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5128   },
5129   {
5130     Ytank_s_w,                          FALSE,  FALSE,
5131     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5132   },
5133   {
5134     Ytank_e_n,                          FALSE,  FALSE,
5135     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5136   },
5137   {
5138     Ytank_s_e,                          FALSE,  FALSE,
5139     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5140   },
5141   {
5142     Ytank_w_s,                          FALSE,  FALSE,
5143     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5144   },
5145   {
5146     Ytank_n_w,                          FALSE,  FALSE,
5147     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5148   },
5149   {
5150     Ytank_stone,                        FALSE,  FALSE,
5151     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
5152   },
5153   {
5154     Ytank_spring,                       FALSE,  FALSE,
5155     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
5156   },
5157   {
5158     Xandroid,                           TRUE,   FALSE,
5159     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
5160   },
5161   {
5162     Xandroid_1_n,                       FALSE,  FALSE,
5163     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
5164   },
5165   {
5166     Xandroid_2_n,                       FALSE,  FALSE,
5167     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
5168   },
5169   {
5170     Xandroid_1_e,                       FALSE,  FALSE,
5171     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
5172   },
5173   {
5174     Xandroid_2_e,                       FALSE,  FALSE,
5175     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
5176   },
5177   {
5178     Xandroid_1_w,                       FALSE,  FALSE,
5179     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
5180   },
5181   {
5182     Xandroid_2_w,                       FALSE,  FALSE,
5183     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
5184   },
5185   {
5186     Xandroid_1_s,                       FALSE,  FALSE,
5187     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
5188   },
5189   {
5190     Xandroid_2_s,                       FALSE,  FALSE,
5191     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
5192   },
5193   {
5194     Yandroid_n,                         FALSE,  FALSE,
5195     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
5196   },
5197   {
5198     Yandroid_nB,                        FALSE,  TRUE,
5199     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
5200   },
5201   {
5202     Yandroid_ne,                        FALSE,  FALSE,
5203     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
5204   },
5205   {
5206     Yandroid_neB,                       FALSE,  TRUE,
5207     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
5208   },
5209   {
5210     Yandroid_e,                         FALSE,  FALSE,
5211     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
5212   },
5213   {
5214     Yandroid_eB,                        FALSE,  TRUE,
5215     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
5216   },
5217   {
5218     Yandroid_se,                        FALSE,  FALSE,
5219     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
5220   },
5221   {
5222     Yandroid_seB,                       FALSE,  TRUE,
5223     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5224   },
5225   {
5226     Yandroid_s,                         FALSE,  FALSE,
5227     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
5228   },
5229   {
5230     Yandroid_sB,                        FALSE,  TRUE,
5231     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
5232   },
5233   {
5234     Yandroid_sw,                        FALSE,  FALSE,
5235     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
5236   },
5237   {
5238     Yandroid_swB,                       FALSE,  TRUE,
5239     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
5240   },
5241   {
5242     Yandroid_w,                         FALSE,  FALSE,
5243     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
5244   },
5245   {
5246     Yandroid_wB,                        FALSE,  TRUE,
5247     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
5248   },
5249   {
5250     Yandroid_nw,                        FALSE,  FALSE,
5251     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
5252   },
5253   {
5254     Yandroid_nwB,                       FALSE,  TRUE,
5255     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
5256   },
5257   {
5258     Xspring,                            TRUE,   FALSE,
5259     EL_SPRING,                          -1, -1
5260   },
5261   {
5262     Xspring_pause,                      FALSE,  FALSE,
5263     EL_SPRING,                          -1, -1
5264   },
5265   {
5266     Xspring_e,                          FALSE,  FALSE,
5267     EL_SPRING,                          -1, -1
5268   },
5269   {
5270     Xspring_w,                          FALSE,  FALSE,
5271     EL_SPRING,                          -1, -1
5272   },
5273   {
5274     Xspring_fall,                       FALSE,  FALSE,
5275     EL_SPRING,                          -1, -1
5276   },
5277   {
5278     Yspring_s,                          FALSE,  FALSE,
5279     EL_SPRING,                          ACTION_FALLING, -1
5280   },
5281   {
5282     Yspring_sB,                         FALSE,  TRUE,
5283     EL_SPRING,                          ACTION_FALLING, -1
5284   },
5285   {
5286     Yspring_e,                          FALSE,  FALSE,
5287     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
5288   },
5289   {
5290     Yspring_eB,                         FALSE,  TRUE,
5291     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
5292   },
5293   {
5294     Yspring_w,                          FALSE,  FALSE,
5295     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
5296   },
5297   {
5298     Yspring_wB,                         FALSE,  TRUE,
5299     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
5300   },
5301   {
5302     Yspring_kill_e,                     FALSE,  FALSE,
5303     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
5304   },
5305   {
5306     Yspring_kill_eB,                    FALSE,  TRUE,
5307     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
5308   },
5309   {
5310     Yspring_kill_w,                     FALSE,  FALSE,
5311     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
5312   },
5313   {
5314     Yspring_kill_wB,                    FALSE,  TRUE,
5315     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
5316   },
5317   {
5318     Xeater_n,                           TRUE,   FALSE,
5319     EL_YAMYAM_UP,                       -1, -1
5320   },
5321   {
5322     Xeater_e,                           TRUE,   FALSE,
5323     EL_YAMYAM_RIGHT,                    -1, -1
5324   },
5325   {
5326     Xeater_w,                           TRUE,   FALSE,
5327     EL_YAMYAM_LEFT,                     -1, -1
5328   },
5329   {
5330     Xeater_s,                           TRUE,   FALSE,
5331     EL_YAMYAM_DOWN,                     -1, -1
5332   },
5333   {
5334     Yeater_n,                           FALSE,  FALSE,
5335     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
5336   },
5337   {
5338     Yeater_nB,                          FALSE,  TRUE,
5339     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
5340   },
5341   {
5342     Yeater_e,                           FALSE,  FALSE,
5343     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
5344   },
5345   {
5346     Yeater_eB,                          FALSE,  TRUE,
5347     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
5348   },
5349   {
5350     Yeater_s,                           FALSE,  FALSE,
5351     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
5352   },
5353   {
5354     Yeater_sB,                          FALSE,  TRUE,
5355     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
5356   },
5357   {
5358     Yeater_w,                           FALSE,  FALSE,
5359     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
5360   },
5361   {
5362     Yeater_wB,                          FALSE,  TRUE,
5363     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
5364   },
5365   {
5366     Yeater_stone,                       FALSE,  FALSE,
5367     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
5368   },
5369   {
5370     Yeater_spring,                      FALSE,  FALSE,
5371     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
5372   },
5373   {
5374     Xalien,                             TRUE,   FALSE,
5375     EL_ROBOT,                           -1, -1
5376   },
5377   {
5378     Xalien_pause,                       FALSE,  FALSE,
5379     EL_ROBOT,                           -1, -1
5380   },
5381   {
5382     Yalien_n,                           FALSE,  FALSE,
5383     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
5384   },
5385   {
5386     Yalien_nB,                          FALSE,  TRUE,
5387     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
5388   },
5389   {
5390     Yalien_e,                           FALSE,  FALSE,
5391     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
5392   },
5393   {
5394     Yalien_eB,                          FALSE,  TRUE,
5395     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
5396   },
5397   {
5398     Yalien_s,                           FALSE,  FALSE,
5399     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
5400   },
5401   {
5402     Yalien_sB,                          FALSE,  TRUE,
5403     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
5404   },
5405   {
5406     Yalien_w,                           FALSE,  FALSE,
5407     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
5408   },
5409   {
5410     Yalien_wB,                          FALSE,  TRUE,
5411     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
5412   },
5413   {
5414     Yalien_stone,                       FALSE,  FALSE,
5415     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
5416   },
5417   {
5418     Yalien_spring,                      FALSE,  FALSE,
5419     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
5420   },
5421   {
5422     Xemerald,                           TRUE,   FALSE,
5423     EL_EMERALD,                         -1, -1
5424   },
5425   {
5426     Xemerald_pause,                     FALSE,  FALSE,
5427     EL_EMERALD,                         -1, -1
5428   },
5429   {
5430     Xemerald_fall,                      FALSE,  FALSE,
5431     EL_EMERALD,                         -1, -1
5432   },
5433   {
5434     Xemerald_shine,                     FALSE,  FALSE,
5435     EL_EMERALD,                         ACTION_TWINKLING, -1
5436   },
5437   {
5438     Yemerald_s,                         FALSE,  FALSE,
5439     EL_EMERALD,                         ACTION_FALLING, -1
5440   },
5441   {
5442     Yemerald_sB,                        FALSE,  TRUE,
5443     EL_EMERALD,                         ACTION_FALLING, -1
5444   },
5445   {
5446     Yemerald_e,                         FALSE,  FALSE,
5447     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
5448   },
5449   {
5450     Yemerald_eB,                        FALSE,  TRUE,
5451     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
5452   },
5453   {
5454     Yemerald_w,                         FALSE,  FALSE,
5455     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
5456   },
5457   {
5458     Yemerald_wB,                        FALSE,  TRUE,
5459     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
5460   },
5461   {
5462     Yemerald_eat,                       FALSE,  FALSE,
5463     EL_EMERALD,                         ACTION_COLLECTING, -1
5464   },
5465   {
5466     Yemerald_stone,                     FALSE,  FALSE,
5467     EL_NUT,                             ACTION_BREAKING, -1
5468   },
5469   {
5470     Xdiamond,                           TRUE,   FALSE,
5471     EL_DIAMOND,                         -1, -1
5472   },
5473   {
5474     Xdiamond_pause,                     FALSE,  FALSE,
5475     EL_DIAMOND,                         -1, -1
5476   },
5477   {
5478     Xdiamond_fall,                      FALSE,  FALSE,
5479     EL_DIAMOND,                         -1, -1
5480   },
5481   {
5482     Xdiamond_shine,                     FALSE,  FALSE,
5483     EL_DIAMOND,                         ACTION_TWINKLING, -1
5484   },
5485   {
5486     Ydiamond_s,                         FALSE,  FALSE,
5487     EL_DIAMOND,                         ACTION_FALLING, -1
5488   },
5489   {
5490     Ydiamond_sB,                        FALSE,  TRUE,
5491     EL_DIAMOND,                         ACTION_FALLING, -1
5492   },
5493   {
5494     Ydiamond_e,                         FALSE,  FALSE,
5495     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
5496   },
5497   {
5498     Ydiamond_eB,                        FALSE,  TRUE,
5499     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
5500   },
5501   {
5502     Ydiamond_w,                         FALSE,  FALSE,
5503     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
5504   },
5505   {
5506     Ydiamond_wB,                        FALSE,  TRUE,
5507     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
5508   },
5509   {
5510     Ydiamond_eat,                       FALSE,  FALSE,
5511     EL_DIAMOND,                         ACTION_COLLECTING, -1
5512   },
5513   {
5514     Ydiamond_stone,                     FALSE,  FALSE,
5515     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
5516   },
5517   {
5518     Xdrip_fall,                         TRUE,   FALSE,
5519     EL_AMOEBA_DROP,                     -1, -1
5520   },
5521   {
5522     Xdrip_stretch,                      FALSE,  FALSE,
5523     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5524   },
5525   {
5526     Xdrip_stretchB,                     FALSE,  TRUE,
5527     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5528   },
5529   {
5530     Xdrip_eat,                          FALSE,  FALSE,
5531     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
5532   },
5533   {
5534     Ydrip_s1,                           FALSE,  FALSE,
5535     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5536   },
5537   {
5538     Ydrip_s1B,                          FALSE,  TRUE,
5539     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5540   },
5541   {
5542     Ydrip_s2,                           FALSE,  FALSE,
5543     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5544   },
5545   {
5546     Ydrip_s2B,                          FALSE,  TRUE,
5547     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5548   },
5549   {
5550     Xbomb,                              TRUE,   FALSE,
5551     EL_BOMB,                            -1, -1
5552   },
5553   {
5554     Xbomb_pause,                        FALSE,  FALSE,
5555     EL_BOMB,                            -1, -1
5556   },
5557   {
5558     Xbomb_fall,                         FALSE,  FALSE,
5559     EL_BOMB,                            -1, -1
5560   },
5561   {
5562     Ybomb_s,                            FALSE,  FALSE,
5563     EL_BOMB,                            ACTION_FALLING, -1
5564   },
5565   {
5566     Ybomb_sB,                           FALSE,  TRUE,
5567     EL_BOMB,                            ACTION_FALLING, -1
5568   },
5569   {
5570     Ybomb_e,                            FALSE,  FALSE,
5571     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
5572   },
5573   {
5574     Ybomb_eB,                           FALSE,  TRUE,
5575     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
5576   },
5577   {
5578     Ybomb_w,                            FALSE,  FALSE,
5579     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
5580   },
5581   {
5582     Ybomb_wB,                           FALSE,  TRUE,
5583     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
5584   },
5585   {
5586     Ybomb_eat,                          FALSE,  FALSE,
5587     EL_BOMB,                            ACTION_ACTIVATING, -1
5588   },
5589   {
5590     Xballoon,                           TRUE,   FALSE,
5591     EL_BALLOON,                         -1, -1
5592   },
5593   {
5594     Yballoon_n,                         FALSE,  FALSE,
5595     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
5596   },
5597   {
5598     Yballoon_nB,                        FALSE,  TRUE,
5599     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
5600   },
5601   {
5602     Yballoon_e,                         FALSE,  FALSE,
5603     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
5604   },
5605   {
5606     Yballoon_eB,                        FALSE,  TRUE,
5607     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
5608   },
5609   {
5610     Yballoon_s,                         FALSE,  FALSE,
5611     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
5612   },
5613   {
5614     Yballoon_sB,                        FALSE,  TRUE,
5615     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
5616   },
5617   {
5618     Yballoon_w,                         FALSE,  FALSE,
5619     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
5620   },
5621   {
5622     Yballoon_wB,                        FALSE,  TRUE,
5623     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
5624   },
5625   {
5626     Xgrass,                             TRUE,   FALSE,
5627     EL_EMC_GRASS,                       -1, -1
5628   },
5629   {
5630     Ygrass_nB,                          FALSE,  FALSE,
5631     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
5632   },
5633   {
5634     Ygrass_eB,                          FALSE,  FALSE,
5635     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
5636   },
5637   {
5638     Ygrass_sB,                          FALSE,  FALSE,
5639     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
5640   },
5641   {
5642     Ygrass_wB,                          FALSE,  FALSE,
5643     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
5644   },
5645   {
5646     Xdirt,                              TRUE,   FALSE,
5647     EL_SAND,                            -1, -1
5648   },
5649   {
5650     Ydirt_nB,                           FALSE,  FALSE,
5651     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
5652   },
5653   {
5654     Ydirt_eB,                           FALSE,  FALSE,
5655     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
5656   },
5657   {
5658     Ydirt_sB,                           FALSE,  FALSE,
5659     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
5660   },
5661   {
5662     Ydirt_wB,                           FALSE,  FALSE,
5663     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
5664   },
5665   {
5666     Xacid_ne,                           TRUE,   FALSE,
5667     EL_ACID_POOL_TOPRIGHT,              -1, -1
5668   },
5669   {
5670     Xacid_se,                           TRUE,   FALSE,
5671     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
5672   },
5673   {
5674     Xacid_s,                            TRUE,   FALSE,
5675     EL_ACID_POOL_BOTTOM,                -1, -1
5676   },
5677   {
5678     Xacid_sw,                           TRUE,   FALSE,
5679     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
5680   },
5681   {
5682     Xacid_nw,                           TRUE,   FALSE,
5683     EL_ACID_POOL_TOPLEFT,               -1, -1
5684   },
5685   {
5686     Xacid_1,                            TRUE,   FALSE,
5687     EL_ACID,                            -1, -1
5688   },
5689   {
5690     Xacid_2,                            FALSE,  FALSE,
5691     EL_ACID,                            -1, -1
5692   },
5693   {
5694     Xacid_3,                            FALSE,  FALSE,
5695     EL_ACID,                            -1, -1
5696   },
5697   {
5698     Xacid_4,                            FALSE,  FALSE,
5699     EL_ACID,                            -1, -1
5700   },
5701   {
5702     Xacid_5,                            FALSE,  FALSE,
5703     EL_ACID,                            -1, -1
5704   },
5705   {
5706     Xacid_6,                            FALSE,  FALSE,
5707     EL_ACID,                            -1, -1
5708   },
5709   {
5710     Xacid_7,                            FALSE,  FALSE,
5711     EL_ACID,                            -1, -1
5712   },
5713   {
5714     Xacid_8,                            FALSE,  FALSE,
5715     EL_ACID,                            -1, -1
5716   },
5717   {
5718     Xball_1,                            TRUE,   FALSE,
5719     EL_EMC_MAGIC_BALL,                  -1, -1
5720   },
5721   {
5722     Xball_1B,                           FALSE,  FALSE,
5723     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5724   },
5725   {
5726     Xball_2,                            FALSE,  FALSE,
5727     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5728   },
5729   {
5730     Xball_2B,                           FALSE,  FALSE,
5731     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5732   },
5733   {
5734     Yball_eat,                          FALSE,  FALSE,
5735     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
5736   },
5737   {
5738     Ykey_1_eat,                         FALSE,  FALSE,
5739     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
5740   },
5741   {
5742     Ykey_2_eat,                         FALSE,  FALSE,
5743     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
5744   },
5745   {
5746     Ykey_3_eat,                         FALSE,  FALSE,
5747     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
5748   },
5749   {
5750     Ykey_4_eat,                         FALSE,  FALSE,
5751     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
5752   },
5753   {
5754     Ykey_5_eat,                         FALSE,  FALSE,
5755     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
5756   },
5757   {
5758     Ykey_6_eat,                         FALSE,  FALSE,
5759     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
5760   },
5761   {
5762     Ykey_7_eat,                         FALSE,  FALSE,
5763     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
5764   },
5765   {
5766     Ykey_8_eat,                         FALSE,  FALSE,
5767     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
5768   },
5769   {
5770     Ylenses_eat,                        FALSE,  FALSE,
5771     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
5772   },
5773   {
5774     Ymagnify_eat,                       FALSE,  FALSE,
5775     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
5776   },
5777   {
5778     Ygrass_eat,                         FALSE,  FALSE,
5779     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
5780   },
5781   {
5782     Ydirt_eat,                          FALSE,  FALSE,
5783     EL_SAND,                            ACTION_SNAPPING, -1
5784   },
5785   {
5786     Xgrow_ns,                           TRUE,   FALSE,
5787     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
5788   },
5789   {
5790     Ygrow_ns_eat,                       FALSE,  FALSE,
5791     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
5792   },
5793   {
5794     Xgrow_ew,                           TRUE,   FALSE,
5795     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
5796   },
5797   {
5798     Ygrow_ew_eat,                       FALSE,  FALSE,
5799     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
5800   },
5801   {
5802     Xwonderwall,                        TRUE,   FALSE,
5803     EL_MAGIC_WALL,                      -1, -1
5804   },
5805   {
5806     XwonderwallB,                       FALSE,  FALSE,
5807     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
5808   },
5809   {
5810     Xamoeba_1,                          TRUE,   FALSE,
5811     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5812   },
5813   {
5814     Xamoeba_2,                          FALSE,  FALSE,
5815     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5816   },
5817   {
5818     Xamoeba_3,                          FALSE,  FALSE,
5819     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5820   },
5821   {
5822     Xamoeba_4,                          FALSE,  FALSE,
5823     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5824   },
5825   {
5826     Xamoeba_5,                          TRUE,   FALSE,
5827     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5828   },
5829   {
5830     Xamoeba_6,                          FALSE,  FALSE,
5831     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5832   },
5833   {
5834     Xamoeba_7,                          FALSE,  FALSE,
5835     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5836   },
5837   {
5838     Xamoeba_8,                          FALSE,  FALSE,
5839     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5840   },
5841   {
5842     Xdoor_1,                            TRUE,   FALSE,
5843     EL_EM_GATE_1,                       -1, -1
5844   },
5845   {
5846     Xdoor_2,                            TRUE,   FALSE,
5847     EL_EM_GATE_2,                       -1, -1
5848   },
5849   {
5850     Xdoor_3,                            TRUE,   FALSE,
5851     EL_EM_GATE_3,                       -1, -1
5852   },
5853   {
5854     Xdoor_4,                            TRUE,   FALSE,
5855     EL_EM_GATE_4,                       -1, -1
5856   },
5857   {
5858     Xdoor_5,                            TRUE,   FALSE,
5859     EL_EMC_GATE_5,                      -1, -1
5860   },
5861   {
5862     Xdoor_6,                            TRUE,   FALSE,
5863     EL_EMC_GATE_6,                      -1, -1
5864   },
5865   {
5866     Xdoor_7,                            TRUE,   FALSE,
5867     EL_EMC_GATE_7,                      -1, -1
5868   },
5869   {
5870     Xdoor_8,                            TRUE,   FALSE,
5871     EL_EMC_GATE_8,                      -1, -1
5872   },
5873   {
5874     Xkey_1,                             TRUE,   FALSE,
5875     EL_EM_KEY_1,                        -1, -1
5876   },
5877   {
5878     Xkey_2,                             TRUE,   FALSE,
5879     EL_EM_KEY_2,                        -1, -1
5880   },
5881   {
5882     Xkey_3,                             TRUE,   FALSE,
5883     EL_EM_KEY_3,                        -1, -1
5884   },
5885   {
5886     Xkey_4,                             TRUE,   FALSE,
5887     EL_EM_KEY_4,                        -1, -1
5888   },
5889   {
5890     Xkey_5,                             TRUE,   FALSE,
5891     EL_EMC_KEY_5,                       -1, -1
5892   },
5893   {
5894     Xkey_6,                             TRUE,   FALSE,
5895     EL_EMC_KEY_6,                       -1, -1
5896   },
5897   {
5898     Xkey_7,                             TRUE,   FALSE,
5899     EL_EMC_KEY_7,                       -1, -1
5900   },
5901   {
5902     Xkey_8,                             TRUE,   FALSE,
5903     EL_EMC_KEY_8,                       -1, -1
5904   },
5905   {
5906     Xwind_n,                            TRUE,   FALSE,
5907     EL_BALLOON_SWITCH_UP,               -1, -1
5908   },
5909   {
5910     Xwind_e,                            TRUE,   FALSE,
5911     EL_BALLOON_SWITCH_RIGHT,            -1, -1
5912   },
5913   {
5914     Xwind_s,                            TRUE,   FALSE,
5915     EL_BALLOON_SWITCH_DOWN,             -1, -1
5916   },
5917   {
5918     Xwind_w,                            TRUE,   FALSE,
5919     EL_BALLOON_SWITCH_LEFT,             -1, -1
5920   },
5921   {
5922     Xwind_nesw,                         TRUE,   FALSE,
5923     EL_BALLOON_SWITCH_ANY,              -1, -1
5924   },
5925   {
5926     Xwind_stop,                         TRUE,   FALSE,
5927     EL_BALLOON_SWITCH_NONE,             -1, -1
5928   },
5929   {
5930     Xexit,                              TRUE,   FALSE,
5931     EL_EM_EXIT_CLOSED,                  -1, -1
5932   },
5933   {
5934     Xexit_1,                            TRUE,   FALSE,
5935     EL_EM_EXIT_OPEN,                    -1, -1
5936   },
5937   {
5938     Xexit_2,                            FALSE,  FALSE,
5939     EL_EM_EXIT_OPEN,                    -1, -1
5940   },
5941   {
5942     Xexit_3,                            FALSE,  FALSE,
5943     EL_EM_EXIT_OPEN,                    -1, -1
5944   },
5945   {
5946     Xdynamite,                          TRUE,   FALSE,
5947     EL_EM_DYNAMITE,                     -1, -1
5948   },
5949   {
5950     Ydynamite_eat,                      FALSE,  FALSE,
5951     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
5952   },
5953   {
5954     Xdynamite_1,                        TRUE,   FALSE,
5955     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5956   },
5957   {
5958     Xdynamite_2,                        FALSE,  FALSE,
5959     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5960   },
5961   {
5962     Xdynamite_3,                        FALSE,  FALSE,
5963     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5964   },
5965   {
5966     Xdynamite_4,                        FALSE,  FALSE,
5967     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5968   },
5969   {
5970     Xbumper,                            TRUE,   FALSE,
5971     EL_EMC_SPRING_BUMPER,               -1, -1
5972   },
5973   {
5974     XbumperB,                           FALSE,  FALSE,
5975     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
5976   },
5977   {
5978     Xwheel,                             TRUE,   FALSE,
5979     EL_ROBOT_WHEEL,                     -1, -1
5980   },
5981   {
5982     XwheelB,                            FALSE,  FALSE,
5983     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
5984   },
5985   {
5986     Xswitch,                            TRUE,   FALSE,
5987     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
5988   },
5989   {
5990     XswitchB,                           FALSE,  FALSE,
5991     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
5992   },
5993   {
5994     Xsand,                              TRUE,   FALSE,
5995     EL_QUICKSAND_EMPTY,                 -1, -1
5996   },
5997   {
5998     Xsand_stone,                        TRUE,   FALSE,
5999     EL_QUICKSAND_FULL,                  -1, -1
6000   },
6001   {
6002     Xsand_stonein_1,                    FALSE,  TRUE,
6003     EL_ROCK,                            ACTION_FILLING, -1
6004   },
6005   {
6006     Xsand_stonein_2,                    FALSE,  TRUE,
6007     EL_ROCK,                            ACTION_FILLING, -1
6008   },
6009   {
6010     Xsand_stonein_3,                    FALSE,  TRUE,
6011     EL_ROCK,                            ACTION_FILLING, -1
6012   },
6013   {
6014     Xsand_stonein_4,                    FALSE,  TRUE,
6015     EL_ROCK,                            ACTION_FILLING, -1
6016   },
6017 #if 1
6018   {
6019     Xsand_stonesand_1,                  FALSE,  FALSE,
6020     EL_QUICKSAND_EMPTYING,              -1, -1
6021   },
6022   {
6023     Xsand_stonesand_2,                  FALSE,  FALSE,
6024     EL_QUICKSAND_EMPTYING,              -1, -1
6025   },
6026   {
6027     Xsand_stonesand_3,                  FALSE,  FALSE,
6028     EL_QUICKSAND_EMPTYING,              -1, -1
6029   },
6030   {
6031     Xsand_stonesand_4,                  FALSE,  FALSE,
6032     EL_QUICKSAND_EMPTYING,              -1, -1
6033   },
6034   {
6035     Xsand_stonesand_quickout_1,         FALSE,  FALSE,
6036     EL_QUICKSAND_EMPTYING,              -1, -1
6037   },
6038   {
6039     Xsand_stonesand_quickout_2,         FALSE,  FALSE,
6040     EL_QUICKSAND_EMPTYING,              -1, -1
6041   },
6042 #else
6043   {
6044     Xsand_stonesand_1,                  FALSE,  FALSE,
6045     EL_QUICKSAND_FULL,                  -1, -1
6046   },
6047   {
6048     Xsand_stonesand_2,                  FALSE,  FALSE,
6049     EL_QUICKSAND_FULL,                  -1, -1
6050   },
6051   {
6052     Xsand_stonesand_3,                  FALSE,  FALSE,
6053     EL_QUICKSAND_FULL,                  -1, -1
6054   },
6055   {
6056     Xsand_stonesand_4,                  FALSE,  FALSE,
6057     EL_QUICKSAND_FULL,                  -1, -1
6058   },
6059 #endif
6060   {
6061     Xsand_stoneout_1,                   FALSE,  FALSE,
6062     EL_ROCK,                            ACTION_EMPTYING, -1
6063   },
6064   {
6065     Xsand_stoneout_2,                   FALSE,  FALSE,
6066     EL_ROCK,                            ACTION_EMPTYING, -1
6067   },
6068 #if 1
6069   {
6070     Xsand_sandstone_1,                  FALSE,  FALSE,
6071     EL_QUICKSAND_FILLING,               -1, -1
6072   },
6073   {
6074     Xsand_sandstone_2,                  FALSE,  FALSE,
6075     EL_QUICKSAND_FILLING,               -1, -1
6076   },
6077   {
6078     Xsand_sandstone_3,                  FALSE,  FALSE,
6079     EL_QUICKSAND_FILLING,               -1, -1
6080   },
6081   {
6082     Xsand_sandstone_4,                  FALSE,  FALSE,
6083     EL_QUICKSAND_FILLING,               -1, -1
6084   },
6085 #else
6086   {
6087     Xsand_sandstone_1,                  FALSE,  FALSE,
6088     EL_QUICKSAND_FULL,                  -1, -1
6089   },
6090   {
6091     Xsand_sandstone_2,                  FALSE,  FALSE,
6092     EL_QUICKSAND_FULL,                  -1, -1
6093   },
6094   {
6095     Xsand_sandstone_3,                  FALSE,  FALSE,
6096     EL_QUICKSAND_FULL,                  -1, -1
6097   },
6098   {
6099     Xsand_sandstone_4,                  FALSE,  FALSE,
6100     EL_QUICKSAND_FULL,                  -1, -1
6101   },
6102 #endif
6103   {
6104     Xplant,                             TRUE,   FALSE,
6105     EL_EMC_PLANT,                       -1, -1
6106   },
6107   {
6108     Yplant,                             FALSE,  FALSE,
6109     EL_EMC_PLANT,                       -1, -1
6110   },
6111   {
6112     Xlenses,                            TRUE,   FALSE,
6113     EL_EMC_LENSES,                      -1, -1
6114   },
6115   {
6116     Xmagnify,                           TRUE,   FALSE,
6117     EL_EMC_MAGNIFIER,                   -1, -1
6118   },
6119   {
6120     Xdripper,                           TRUE,   FALSE,
6121     EL_EMC_DRIPPER,                     -1, -1
6122   },
6123   {
6124     XdripperB,                          FALSE,  FALSE,
6125     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
6126   },
6127   {
6128     Xfake_blank,                        TRUE,   FALSE,
6129     EL_INVISIBLE_WALL,                  -1, -1
6130   },
6131   {
6132     Xfake_blankB,                       FALSE,  FALSE,
6133     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
6134   },
6135   {
6136     Xfake_grass,                        TRUE,   FALSE,
6137     EL_EMC_FAKE_GRASS,                  -1, -1
6138   },
6139   {
6140     Xfake_grassB,                       FALSE,  FALSE,
6141     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
6142   },
6143   {
6144     Xfake_door_1,                       TRUE,   FALSE,
6145     EL_EM_GATE_1_GRAY,                  -1, -1
6146   },
6147   {
6148     Xfake_door_2,                       TRUE,   FALSE,
6149     EL_EM_GATE_2_GRAY,                  -1, -1
6150   },
6151   {
6152     Xfake_door_3,                       TRUE,   FALSE,
6153     EL_EM_GATE_3_GRAY,                  -1, -1
6154   },
6155   {
6156     Xfake_door_4,                       TRUE,   FALSE,
6157     EL_EM_GATE_4_GRAY,                  -1, -1
6158   },
6159   {
6160     Xfake_door_5,                       TRUE,   FALSE,
6161     EL_EMC_GATE_5_GRAY,                 -1, -1
6162   },
6163   {
6164     Xfake_door_6,                       TRUE,   FALSE,
6165     EL_EMC_GATE_6_GRAY,                 -1, -1
6166   },
6167   {
6168     Xfake_door_7,                       TRUE,   FALSE,
6169     EL_EMC_GATE_7_GRAY,                 -1, -1
6170   },
6171   {
6172     Xfake_door_8,                       TRUE,   FALSE,
6173     EL_EMC_GATE_8_GRAY,                 -1, -1
6174   },
6175   {
6176     Xfake_acid_1,                       TRUE,   FALSE,
6177     EL_EMC_FAKE_ACID,                   -1, -1
6178   },
6179   {
6180     Xfake_acid_2,                       FALSE,  FALSE,
6181     EL_EMC_FAKE_ACID,                   -1, -1
6182   },
6183   {
6184     Xfake_acid_3,                       FALSE,  FALSE,
6185     EL_EMC_FAKE_ACID,                   -1, -1
6186   },
6187   {
6188     Xfake_acid_4,                       FALSE,  FALSE,
6189     EL_EMC_FAKE_ACID,                   -1, -1
6190   },
6191   {
6192     Xfake_acid_5,                       FALSE,  FALSE,
6193     EL_EMC_FAKE_ACID,                   -1, -1
6194   },
6195   {
6196     Xfake_acid_6,                       FALSE,  FALSE,
6197     EL_EMC_FAKE_ACID,                   -1, -1
6198   },
6199   {
6200     Xfake_acid_7,                       FALSE,  FALSE,
6201     EL_EMC_FAKE_ACID,                   -1, -1
6202   },
6203   {
6204     Xfake_acid_8,                       FALSE,  FALSE,
6205     EL_EMC_FAKE_ACID,                   -1, -1
6206   },
6207   {
6208     Xsteel_1,                           TRUE,   FALSE,
6209     EL_STEELWALL,                       -1, -1
6210   },
6211   {
6212     Xsteel_2,                           TRUE,   FALSE,
6213     EL_EMC_STEELWALL_2,                 -1, -1
6214   },
6215   {
6216     Xsteel_3,                           TRUE,   FALSE,
6217     EL_EMC_STEELWALL_3,                 -1, -1
6218   },
6219   {
6220     Xsteel_4,                           TRUE,   FALSE,
6221     EL_EMC_STEELWALL_4,                 -1, -1
6222   },
6223   {
6224     Xwall_1,                            TRUE,   FALSE,
6225     EL_WALL,                            -1, -1
6226   },
6227   {
6228     Xwall_2,                            TRUE,   FALSE,
6229     EL_EMC_WALL_14,                     -1, -1
6230   },
6231   {
6232     Xwall_3,                            TRUE,   FALSE,
6233     EL_EMC_WALL_15,                     -1, -1
6234   },
6235   {
6236     Xwall_4,                            TRUE,   FALSE,
6237     EL_EMC_WALL_16,                     -1, -1
6238   },
6239   {
6240     Xround_wall_1,                      TRUE,   FALSE,
6241     EL_WALL_SLIPPERY,                   -1, -1
6242   },
6243   {
6244     Xround_wall_2,                      TRUE,   FALSE,
6245     EL_EMC_WALL_SLIPPERY_2,             -1, -1
6246   },
6247   {
6248     Xround_wall_3,                      TRUE,   FALSE,
6249     EL_EMC_WALL_SLIPPERY_3,             -1, -1
6250   },
6251   {
6252     Xround_wall_4,                      TRUE,   FALSE,
6253     EL_EMC_WALL_SLIPPERY_4,             -1, -1
6254   },
6255   {
6256     Xdecor_1,                           TRUE,   FALSE,
6257     EL_EMC_WALL_8,                      -1, -1
6258   },
6259   {
6260     Xdecor_2,                           TRUE,   FALSE,
6261     EL_EMC_WALL_6,                      -1, -1
6262   },
6263   {
6264     Xdecor_3,                           TRUE,   FALSE,
6265     EL_EMC_WALL_4,                      -1, -1
6266   },
6267   {
6268     Xdecor_4,                           TRUE,   FALSE,
6269     EL_EMC_WALL_7,                      -1, -1
6270   },
6271   {
6272     Xdecor_5,                           TRUE,   FALSE,
6273     EL_EMC_WALL_5,                      -1, -1
6274   },
6275   {
6276     Xdecor_6,                           TRUE,   FALSE,
6277     EL_EMC_WALL_9,                      -1, -1
6278   },
6279   {
6280     Xdecor_7,                           TRUE,   FALSE,
6281     EL_EMC_WALL_10,                     -1, -1
6282   },
6283   {
6284     Xdecor_8,                           TRUE,   FALSE,
6285     EL_EMC_WALL_1,                      -1, -1
6286   },
6287   {
6288     Xdecor_9,                           TRUE,   FALSE,
6289     EL_EMC_WALL_2,                      -1, -1
6290   },
6291   {
6292     Xdecor_10,                          TRUE,   FALSE,
6293     EL_EMC_WALL_3,                      -1, -1
6294   },
6295   {
6296     Xdecor_11,                          TRUE,   FALSE,
6297     EL_EMC_WALL_11,                     -1, -1
6298   },
6299   {
6300     Xdecor_12,                          TRUE,   FALSE,
6301     EL_EMC_WALL_12,                     -1, -1
6302   },
6303   {
6304     Xalpha_0,                           TRUE,   FALSE,
6305     EL_CHAR('0'),                       -1, -1
6306   },
6307   {
6308     Xalpha_1,                           TRUE,   FALSE,
6309     EL_CHAR('1'),                       -1, -1
6310   },
6311   {
6312     Xalpha_2,                           TRUE,   FALSE,
6313     EL_CHAR('2'),                       -1, -1
6314   },
6315   {
6316     Xalpha_3,                           TRUE,   FALSE,
6317     EL_CHAR('3'),                       -1, -1
6318   },
6319   {
6320     Xalpha_4,                           TRUE,   FALSE,
6321     EL_CHAR('4'),                       -1, -1
6322   },
6323   {
6324     Xalpha_5,                           TRUE,   FALSE,
6325     EL_CHAR('5'),                       -1, -1
6326   },
6327   {
6328     Xalpha_6,                           TRUE,   FALSE,
6329     EL_CHAR('6'),                       -1, -1
6330   },
6331   {
6332     Xalpha_7,                           TRUE,   FALSE,
6333     EL_CHAR('7'),                       -1, -1
6334   },
6335   {
6336     Xalpha_8,                           TRUE,   FALSE,
6337     EL_CHAR('8'),                       -1, -1
6338   },
6339   {
6340     Xalpha_9,                           TRUE,   FALSE,
6341     EL_CHAR('9'),                       -1, -1
6342   },
6343   {
6344     Xalpha_excla,                       TRUE,   FALSE,
6345     EL_CHAR('!'),                       -1, -1
6346   },
6347   {
6348     Xalpha_quote,                       TRUE,   FALSE,
6349     EL_CHAR('"'),                       -1, -1
6350   },
6351   {
6352     Xalpha_comma,                       TRUE,   FALSE,
6353     EL_CHAR(','),                       -1, -1
6354   },
6355   {
6356     Xalpha_minus,                       TRUE,   FALSE,
6357     EL_CHAR('-'),                       -1, -1
6358   },
6359   {
6360     Xalpha_perio,                       TRUE,   FALSE,
6361     EL_CHAR('.'),                       -1, -1
6362   },
6363   {
6364     Xalpha_colon,                       TRUE,   FALSE,
6365     EL_CHAR(':'),                       -1, -1
6366   },
6367   {
6368     Xalpha_quest,                       TRUE,   FALSE,
6369     EL_CHAR('?'),                       -1, -1
6370   },
6371   {
6372     Xalpha_a,                           TRUE,   FALSE,
6373     EL_CHAR('A'),                       -1, -1
6374   },
6375   {
6376     Xalpha_b,                           TRUE,   FALSE,
6377     EL_CHAR('B'),                       -1, -1
6378   },
6379   {
6380     Xalpha_c,                           TRUE,   FALSE,
6381     EL_CHAR('C'),                       -1, -1
6382   },
6383   {
6384     Xalpha_d,                           TRUE,   FALSE,
6385     EL_CHAR('D'),                       -1, -1
6386   },
6387   {
6388     Xalpha_e,                           TRUE,   FALSE,
6389     EL_CHAR('E'),                       -1, -1
6390   },
6391   {
6392     Xalpha_f,                           TRUE,   FALSE,
6393     EL_CHAR('F'),                       -1, -1
6394   },
6395   {
6396     Xalpha_g,                           TRUE,   FALSE,
6397     EL_CHAR('G'),                       -1, -1
6398   },
6399   {
6400     Xalpha_h,                           TRUE,   FALSE,
6401     EL_CHAR('H'),                       -1, -1
6402   },
6403   {
6404     Xalpha_i,                           TRUE,   FALSE,
6405     EL_CHAR('I'),                       -1, -1
6406   },
6407   {
6408     Xalpha_j,                           TRUE,   FALSE,
6409     EL_CHAR('J'),                       -1, -1
6410   },
6411   {
6412     Xalpha_k,                           TRUE,   FALSE,
6413     EL_CHAR('K'),                       -1, -1
6414   },
6415   {
6416     Xalpha_l,                           TRUE,   FALSE,
6417     EL_CHAR('L'),                       -1, -1
6418   },
6419   {
6420     Xalpha_m,                           TRUE,   FALSE,
6421     EL_CHAR('M'),                       -1, -1
6422   },
6423   {
6424     Xalpha_n,                           TRUE,   FALSE,
6425     EL_CHAR('N'),                       -1, -1
6426   },
6427   {
6428     Xalpha_o,                           TRUE,   FALSE,
6429     EL_CHAR('O'),                       -1, -1
6430   },
6431   {
6432     Xalpha_p,                           TRUE,   FALSE,
6433     EL_CHAR('P'),                       -1, -1
6434   },
6435   {
6436     Xalpha_q,                           TRUE,   FALSE,
6437     EL_CHAR('Q'),                       -1, -1
6438   },
6439   {
6440     Xalpha_r,                           TRUE,   FALSE,
6441     EL_CHAR('R'),                       -1, -1
6442   },
6443   {
6444     Xalpha_s,                           TRUE,   FALSE,
6445     EL_CHAR('S'),                       -1, -1
6446   },
6447   {
6448     Xalpha_t,                           TRUE,   FALSE,
6449     EL_CHAR('T'),                       -1, -1
6450   },
6451   {
6452     Xalpha_u,                           TRUE,   FALSE,
6453     EL_CHAR('U'),                       -1, -1
6454   },
6455   {
6456     Xalpha_v,                           TRUE,   FALSE,
6457     EL_CHAR('V'),                       -1, -1
6458   },
6459   {
6460     Xalpha_w,                           TRUE,   FALSE,
6461     EL_CHAR('W'),                       -1, -1
6462   },
6463   {
6464     Xalpha_x,                           TRUE,   FALSE,
6465     EL_CHAR('X'),                       -1, -1
6466   },
6467   {
6468     Xalpha_y,                           TRUE,   FALSE,
6469     EL_CHAR('Y'),                       -1, -1
6470   },
6471   {
6472     Xalpha_z,                           TRUE,   FALSE,
6473     EL_CHAR('Z'),                       -1, -1
6474   },
6475   {
6476     Xalpha_arrow_e,                     TRUE,   FALSE,
6477     EL_CHAR('>'),                       -1, -1
6478   },
6479   {
6480     Xalpha_arrow_w,                     TRUE,   FALSE,
6481     EL_CHAR('<'),                       -1, -1
6482   },
6483   {
6484     Xalpha_copyr,                       TRUE,   FALSE,
6485     EL_CHAR('©'),                       -1, -1
6486   },
6487
6488   {
6489     Xboom_bug,                          FALSE,  FALSE,
6490     EL_BUG,                             ACTION_EXPLODING, -1
6491   },
6492   {
6493     Xboom_bomb,                         FALSE,  FALSE,
6494     EL_BOMB,                            ACTION_EXPLODING, -1
6495   },
6496   {
6497     Xboom_android,                      FALSE,  FALSE,
6498     EL_EMC_ANDROID,                     ACTION_OTHER, -1
6499   },
6500   {
6501     Xboom_1,                            FALSE,  FALSE,
6502     EL_DEFAULT,                         ACTION_EXPLODING, -1
6503   },
6504   {
6505     Xboom_2,                            FALSE,  FALSE,
6506     EL_DEFAULT,                         ACTION_EXPLODING, -1
6507   },
6508   {
6509     Znormal,                            FALSE,  FALSE,
6510     EL_EMPTY,                           -1, -1
6511   },
6512   {
6513     Zdynamite,                          FALSE,  FALSE,
6514     EL_EMPTY,                           -1, -1
6515   },
6516   {
6517     Zplayer,                            FALSE,  FALSE,
6518     EL_EMPTY,                           -1, -1
6519   },
6520   {
6521     ZBORDER,                            FALSE,  FALSE,
6522     EL_EMPTY,                           -1, -1
6523   },
6524
6525   {
6526     -1,                                 FALSE,  FALSE,
6527     -1,                                 -1, -1
6528   }
6529 };
6530
6531 static struct Mapping_EM_to_RND_player
6532 {
6533   int action_em;
6534   int player_nr;
6535
6536   int element_rnd;
6537   int action;
6538   int direction;
6539 }
6540 em_player_mapping_list[] =
6541 {
6542   {
6543     SPR_walk + 0,                       0,
6544     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
6545   },
6546   {
6547     SPR_walk + 1,                       0,
6548     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
6549   },
6550   {
6551     SPR_walk + 2,                       0,
6552     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
6553   },
6554   {
6555     SPR_walk + 3,                       0,
6556     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
6557   },
6558   {
6559     SPR_push + 0,                       0,
6560     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
6561   },
6562   {
6563     SPR_push + 1,                       0,
6564     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
6565   },
6566   {
6567     SPR_push + 2,                       0,
6568     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
6569   },
6570   {
6571     SPR_push + 3,                       0,
6572     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
6573   },
6574   {
6575     SPR_spray + 0,                      0,
6576     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
6577   },
6578   {
6579     SPR_spray + 1,                      0,
6580     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6581   },
6582   {
6583     SPR_spray + 2,                      0,
6584     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
6585   },
6586   {
6587     SPR_spray + 3,                      0,
6588     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
6589   },
6590   {
6591     SPR_walk + 0,                       1,
6592     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
6593   },
6594   {
6595     SPR_walk + 1,                       1,
6596     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
6597   },
6598   {
6599     SPR_walk + 2,                       1,
6600     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
6601   },
6602   {
6603     SPR_walk + 3,                       1,
6604     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
6605   },
6606   {
6607     SPR_push + 0,                       1,
6608     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
6609   },
6610   {
6611     SPR_push + 1,                       1,
6612     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
6613   },
6614   {
6615     SPR_push + 2,                       1,
6616     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
6617   },
6618   {
6619     SPR_push + 3,                       1,
6620     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
6621   },
6622   {
6623     SPR_spray + 0,                      1,
6624     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
6625   },
6626   {
6627     SPR_spray + 1,                      1,
6628     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6629   },
6630   {
6631     SPR_spray + 2,                      1,
6632     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
6633   },
6634   {
6635     SPR_spray + 3,                      1,
6636     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
6637   },
6638   {
6639     SPR_still,                          0,
6640     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
6641   },
6642   {
6643     SPR_still,                          1,
6644     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
6645   },
6646   {
6647     SPR_walk + 0,                       2,
6648     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
6649   },
6650   {
6651     SPR_walk + 1,                       2,
6652     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
6653   },
6654   {
6655     SPR_walk + 2,                       2,
6656     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
6657   },
6658   {
6659     SPR_walk + 3,                       2,
6660     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
6661   },
6662   {
6663     SPR_push + 0,                       2,
6664     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
6665   },
6666   {
6667     SPR_push + 1,                       2,
6668     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
6669   },
6670   {
6671     SPR_push + 2,                       2,
6672     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
6673   },
6674   {
6675     SPR_push + 3,                       2,
6676     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
6677   },
6678   {
6679     SPR_spray + 0,                      2,
6680     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
6681   },
6682   {
6683     SPR_spray + 1,                      2,
6684     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6685   },
6686   {
6687     SPR_spray + 2,                      2,
6688     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
6689   },
6690   {
6691     SPR_spray + 3,                      2,
6692     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
6693   },
6694   {
6695     SPR_walk + 0,                       3,
6696     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
6697   },
6698   {
6699     SPR_walk + 1,                       3,
6700     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
6701   },
6702   {
6703     SPR_walk + 2,                       3,
6704     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
6705   },
6706   {
6707     SPR_walk + 3,                       3,
6708     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
6709   },
6710   {
6711     SPR_push + 0,                       3,
6712     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
6713   },
6714   {
6715     SPR_push + 1,                       3,
6716     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
6717   },
6718   {
6719     SPR_push + 2,                       3,
6720     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
6721   },
6722   {
6723     SPR_push + 3,                       3,
6724     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
6725   },
6726   {
6727     SPR_spray + 0,                      3,
6728     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
6729   },
6730   {
6731     SPR_spray + 1,                      3,
6732     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6733   },
6734   {
6735     SPR_spray + 2,                      3,
6736     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
6737   },
6738   {
6739     SPR_spray + 3,                      3,
6740     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
6741   },
6742   {
6743     SPR_still,                          2,
6744     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
6745   },
6746   {
6747     SPR_still,                          3,
6748     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
6749   },
6750
6751   {
6752     -1,                                 -1,
6753     -1,                                 -1, -1
6754   }
6755 };
6756
6757 int map_element_RND_to_EM(int element_rnd)
6758 {
6759   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6760   static boolean mapping_initialized = FALSE;
6761
6762   if (!mapping_initialized)
6763   {
6764     int i;
6765
6766     /* return "Xalpha_quest" for all undefined elements in mapping array */
6767     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6768       mapping_RND_to_EM[i] = Xalpha_quest;
6769
6770     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6771       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6772         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6773           em_object_mapping_list[i].element_em;
6774
6775     mapping_initialized = TRUE;
6776   }
6777
6778   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6779     return mapping_RND_to_EM[element_rnd];
6780
6781   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6782
6783   return EL_UNKNOWN;
6784 }
6785
6786 int map_element_EM_to_RND(int element_em)
6787 {
6788   static unsigned short mapping_EM_to_RND[TILE_MAX];
6789   static boolean mapping_initialized = FALSE;
6790
6791   if (!mapping_initialized)
6792   {
6793     int i;
6794
6795     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6796     for (i = 0; i < TILE_MAX; i++)
6797       mapping_EM_to_RND[i] = EL_UNKNOWN;
6798
6799     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6800       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6801         em_object_mapping_list[i].element_rnd;
6802
6803     mapping_initialized = TRUE;
6804   }
6805
6806   if (element_em >= 0 && element_em < TILE_MAX)
6807     return mapping_EM_to_RND[element_em];
6808
6809   Error(ERR_WARN, "invalid EM level element %d", element_em);
6810
6811   return EL_UNKNOWN;
6812 }
6813
6814 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6815 {
6816   struct LevelInfo_EM *level_em = level->native_em_level;
6817   struct LEVEL *lev = level_em->lev;
6818   int i, j;
6819
6820   for (i = 0; i < TILE_MAX; i++)
6821     lev->android_array[i] = Xblank;
6822
6823   for (i = 0; i < level->num_android_clone_elements; i++)
6824   {
6825     int element_rnd = level->android_clone_element[i];
6826     int element_em = map_element_RND_to_EM(element_rnd);
6827
6828     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6829       if (em_object_mapping_list[j].element_rnd == element_rnd)
6830         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6831   }
6832 }
6833
6834 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6835 {
6836   struct LevelInfo_EM *level_em = level->native_em_level;
6837   struct LEVEL *lev = level_em->lev;
6838   int i, j;
6839
6840   level->num_android_clone_elements = 0;
6841
6842   for (i = 0; i < TILE_MAX; i++)
6843   {
6844     int element_em = lev->android_array[i];
6845     int element_rnd;
6846     boolean element_found = FALSE;
6847
6848     if (element_em == Xblank)
6849       continue;
6850
6851     element_rnd = map_element_EM_to_RND(element_em);
6852
6853     for (j = 0; j < level->num_android_clone_elements; j++)
6854       if (level->android_clone_element[j] == element_rnd)
6855         element_found = TRUE;
6856
6857     if (!element_found)
6858     {
6859       level->android_clone_element[level->num_android_clone_elements++] =
6860         element_rnd;
6861
6862       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6863         break;
6864     }
6865   }
6866
6867   if (level->num_android_clone_elements == 0)
6868   {
6869     level->num_android_clone_elements = 1;
6870     level->android_clone_element[0] = EL_EMPTY;
6871   }
6872 }
6873
6874 int map_direction_RND_to_EM(int direction)
6875 {
6876   return (direction == MV_UP    ? 0 :
6877           direction == MV_RIGHT ? 1 :
6878           direction == MV_DOWN  ? 2 :
6879           direction == MV_LEFT  ? 3 :
6880           -1);
6881 }
6882
6883 int map_direction_EM_to_RND(int direction)
6884 {
6885   return (direction == 0 ? MV_UP    :
6886           direction == 1 ? MV_RIGHT :
6887           direction == 2 ? MV_DOWN  :
6888           direction == 3 ? MV_LEFT  :
6889           MV_NONE);
6890 }
6891
6892 int map_element_RND_to_SP(int element_rnd)
6893 {
6894   int element_sp = 0x20;        /* map unknown elements to yellow "hardware" */
6895
6896   if (element_rnd >= EL_SP_START &&
6897       element_rnd <= EL_SP_END)
6898     element_sp = element_rnd - EL_SP_START;
6899   else if (element_rnd == EL_EMPTY_SPACE)
6900     element_sp = 0x00;
6901   else if (element_rnd == EL_INVISIBLE_WALL)
6902     element_sp = 0x28;
6903
6904   return element_sp;
6905 }
6906
6907 int map_element_SP_to_RND(int element_sp)
6908 {
6909   int element_rnd = EL_UNKNOWN;
6910
6911   if (element_sp >= 0x00 &&
6912       element_sp <= 0x27)
6913     element_rnd = EL_SP_START + element_sp;
6914   else if (element_sp == 0x28)
6915     element_rnd = EL_INVISIBLE_WALL;
6916
6917   return element_rnd;
6918 }
6919
6920 int map_action_SP_to_RND(int action_sp)
6921 {
6922   switch (action_sp)
6923   {
6924     case actActive:             return ACTION_ACTIVE;
6925     case actImpact:             return ACTION_IMPACT;
6926     case actExploding:          return ACTION_EXPLODING;
6927     case actDigging:            return ACTION_DIGGING;
6928     case actSnapping:           return ACTION_SNAPPING;
6929     case actCollecting:         return ACTION_COLLECTING;
6930     case actPassing:            return ACTION_PASSING;
6931     case actPushing:            return ACTION_PUSHING;
6932     case actDropping:           return ACTION_DROPPING;
6933
6934     default:                    return ACTION_DEFAULT;
6935   }
6936 }
6937
6938 int get_next_element(int element)
6939 {
6940   switch (element)
6941   {
6942     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
6943     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
6944     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
6945     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
6946     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
6947     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
6948     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
6949     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
6950     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
6951     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
6952     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
6953
6954     default:                            return element;
6955   }
6956 }
6957
6958 #if 0
6959 int el_act_dir2img(int element, int action, int direction)
6960 {
6961   element = GFX_ELEMENT(element);
6962
6963   if (direction == MV_NONE)
6964     return element_info[element].graphic[action];
6965
6966   direction = MV_DIR_TO_BIT(direction);
6967
6968   return element_info[element].direction_graphic[action][direction];
6969 }
6970 #else
6971 int el_act_dir2img(int element, int action, int direction)
6972 {
6973   element = GFX_ELEMENT(element);
6974   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6975
6976   /* direction_graphic[][] == graphic[] for undefined direction graphics */
6977   return element_info[element].direction_graphic[action][direction];
6978 }
6979 #endif
6980
6981 #if 0
6982 static int el_act_dir2crm(int element, int action, int direction)
6983 {
6984   element = GFX_ELEMENT(element);
6985
6986   if (direction == MV_NONE)
6987     return element_info[element].crumbled[action];
6988
6989   direction = MV_DIR_TO_BIT(direction);
6990
6991   return element_info[element].direction_crumbled[action][direction];
6992 }
6993 #else
6994 static int el_act_dir2crm(int element, int action, int direction)
6995 {
6996   element = GFX_ELEMENT(element);
6997   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6998
6999   /* direction_graphic[][] == graphic[] for undefined direction graphics */
7000   return element_info[element].direction_crumbled[action][direction];
7001 }
7002 #endif
7003
7004 int el_act2img(int element, int action)
7005 {
7006   element = GFX_ELEMENT(element);
7007
7008   return element_info[element].graphic[action];
7009 }
7010
7011 int el_act2crm(int element, int action)
7012 {
7013   element = GFX_ELEMENT(element);
7014
7015   return element_info[element].crumbled[action];
7016 }
7017
7018 int el_dir2img(int element, int direction)
7019 {
7020   element = GFX_ELEMENT(element);
7021
7022   return el_act_dir2img(element, ACTION_DEFAULT, direction);
7023 }
7024
7025 int el2baseimg(int element)
7026 {
7027   return element_info[element].graphic[ACTION_DEFAULT];
7028 }
7029
7030 int el2img(int element)
7031 {
7032   element = GFX_ELEMENT(element);
7033
7034   return element_info[element].graphic[ACTION_DEFAULT];
7035 }
7036
7037 int el2edimg(int element)
7038 {
7039   element = GFX_ELEMENT(element);
7040
7041   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7042 }
7043
7044 int el2preimg(int element)
7045 {
7046   element = GFX_ELEMENT(element);
7047
7048   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7049 }
7050
7051 int el2panelimg(int element)
7052 {
7053   element = GFX_ELEMENT(element);
7054
7055   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7056 }
7057
7058 int font2baseimg(int font_nr)
7059 {
7060   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7061 }
7062
7063 int getBeltNrFromBeltElement(int element)
7064 {
7065   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7066           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7067           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7068 }
7069
7070 int getBeltNrFromBeltActiveElement(int element)
7071 {
7072   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7073           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7074           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7075 }
7076
7077 int getBeltNrFromBeltSwitchElement(int element)
7078 {
7079   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7080           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7081           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7082 }
7083
7084 int getBeltDirNrFromBeltElement(int element)
7085 {
7086   static int belt_base_element[4] =
7087   {
7088     EL_CONVEYOR_BELT_1_LEFT,
7089     EL_CONVEYOR_BELT_2_LEFT,
7090     EL_CONVEYOR_BELT_3_LEFT,
7091     EL_CONVEYOR_BELT_4_LEFT
7092   };
7093
7094   int belt_nr = getBeltNrFromBeltElement(element);
7095   int belt_dir_nr = element - belt_base_element[belt_nr];
7096
7097   return (belt_dir_nr % 3);
7098 }
7099
7100 int getBeltDirNrFromBeltSwitchElement(int element)
7101 {
7102   static int belt_base_element[4] =
7103   {
7104     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7105     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7106     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7107     EL_CONVEYOR_BELT_4_SWITCH_LEFT
7108   };
7109
7110   int belt_nr = getBeltNrFromBeltSwitchElement(element);
7111   int belt_dir_nr = element - belt_base_element[belt_nr];
7112
7113   return (belt_dir_nr % 3);
7114 }
7115
7116 int getBeltDirFromBeltElement(int element)
7117 {
7118   static int belt_move_dir[3] =
7119   {
7120     MV_LEFT,
7121     MV_NONE,
7122     MV_RIGHT
7123   };
7124
7125   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7126
7127   return belt_move_dir[belt_dir_nr];
7128 }
7129
7130 int getBeltDirFromBeltSwitchElement(int element)
7131 {
7132   static int belt_move_dir[3] =
7133   {
7134     MV_LEFT,
7135     MV_NONE,
7136     MV_RIGHT
7137   };
7138
7139   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7140
7141   return belt_move_dir[belt_dir_nr];
7142 }
7143
7144 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7145 {
7146   static int belt_base_element[4] =
7147   {
7148     EL_CONVEYOR_BELT_1_LEFT,
7149     EL_CONVEYOR_BELT_2_LEFT,
7150     EL_CONVEYOR_BELT_3_LEFT,
7151     EL_CONVEYOR_BELT_4_LEFT
7152   };
7153
7154   return belt_base_element[belt_nr] + belt_dir_nr;
7155 }
7156
7157 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7158 {
7159   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7160
7161   return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7162 }
7163
7164 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7165 {
7166   static int belt_base_element[4] =
7167   {
7168     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7169     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7170     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7171     EL_CONVEYOR_BELT_4_SWITCH_LEFT
7172   };
7173
7174   return belt_base_element[belt_nr] + belt_dir_nr;
7175 }
7176
7177 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7178 {
7179   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7180
7181   return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7182 }
7183
7184 int getNumActivePlayers_EM()
7185 {
7186   int num_players = 0;
7187   int i;
7188
7189   if (!tape.playing)
7190     return -1;
7191
7192   for (i = 0; i < MAX_PLAYERS; i++)
7193     if (tape.player_participates[i])
7194       num_players++;
7195
7196   return num_players;
7197 }
7198
7199 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7200 {
7201   int game_frame_delay_value;
7202
7203   game_frame_delay_value =
7204     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7205      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7206      GameFrameDelay);
7207
7208   if (tape.playing && tape.warp_forward && !tape.pausing)
7209     game_frame_delay_value = 0;
7210
7211   return game_frame_delay_value;
7212 }
7213
7214 unsigned int InitRND(long seed)
7215 {
7216   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7217     return InitEngineRandom_EM(seed);
7218   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7219     return InitEngineRandom_SP(seed);
7220   else
7221     return InitEngineRandom_RND(seed);
7222 }
7223
7224 #if 1
7225 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7226 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7227 #endif
7228
7229 inline static int get_effective_element_EM(int tile, int frame_em)
7230 {
7231   int element             = object_mapping[tile].element_rnd;
7232   int action              = object_mapping[tile].action;
7233   boolean is_backside     = object_mapping[tile].is_backside;
7234   boolean action_removing = (action == ACTION_DIGGING ||
7235                              action == ACTION_SNAPPING ||
7236                              action == ACTION_COLLECTING);
7237
7238   if (frame_em < 7)
7239   {
7240     switch (tile)
7241     {
7242       case Yacid_splash_eB:
7243       case Yacid_splash_wB:
7244         return (frame_em > 5 ? EL_EMPTY : element);
7245
7246 #if 0
7247         /* !!! FIX !!! */
7248       case Ydiamond_stone:
7249         //  if (!game.use_native_emc_graphics_engine)
7250         return EL_ROCK;
7251 #endif
7252
7253       default:
7254         return element;
7255     }
7256   }
7257   else  /* frame_em == 7 */
7258   {
7259     switch (tile)
7260     {
7261       case Yacid_splash_eB:
7262       case Yacid_splash_wB:
7263         return EL_EMPTY;
7264
7265       case Yemerald_stone:
7266         return EL_EMERALD;
7267
7268       case Ydiamond_stone:
7269         return EL_ROCK;
7270
7271       case Xdrip_stretch:
7272       case Xdrip_stretchB:
7273       case Ydrip_s1:
7274       case Ydrip_s1B:
7275       case Xball_1B:
7276       case Xball_2:
7277       case Xball_2B:
7278       case Yball_eat:
7279       case Ykey_1_eat:
7280       case Ykey_2_eat:
7281       case Ykey_3_eat:
7282       case Ykey_4_eat:
7283       case Ykey_5_eat:
7284       case Ykey_6_eat:
7285       case Ykey_7_eat:
7286       case Ykey_8_eat:
7287       case Ylenses_eat:
7288       case Ymagnify_eat:
7289       case Ygrass_eat:
7290       case Ydirt_eat:
7291       case Xsand_stonein_1:
7292       case Xsand_stonein_2:
7293       case Xsand_stonein_3:
7294       case Xsand_stonein_4:
7295         return element;
7296
7297       default:
7298         return (is_backside || action_removing ? EL_EMPTY : element);
7299     }
7300   }
7301 }
7302
7303 inline static boolean check_linear_animation_EM(int tile)
7304 {
7305   switch (tile)
7306   {
7307     case Xsand_stonesand_1:
7308     case Xsand_stonesand_quickout_1:
7309     case Xsand_sandstone_1:
7310     case Xsand_stonein_1:
7311     case Xsand_stoneout_1:
7312     case Xboom_1:
7313     case Xdynamite_1:
7314     case Ybug_w_n:
7315     case Ybug_n_e:
7316     case Ybug_e_s:
7317     case Ybug_s_w:
7318     case Ybug_e_n:
7319     case Ybug_s_e:
7320     case Ybug_w_s:
7321     case Ybug_n_w:
7322     case Ytank_w_n:
7323     case Ytank_n_e:
7324     case Ytank_e_s:
7325     case Ytank_s_w:
7326     case Ytank_e_n:
7327     case Ytank_s_e:
7328     case Ytank_w_s:
7329     case Ytank_n_w:
7330 #if 1
7331     case Yacid_splash_eB:
7332     case Yacid_splash_wB:
7333     case Yemerald_stone:
7334 #endif
7335       return TRUE;
7336   }
7337
7338   return FALSE;
7339 }
7340
7341 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7342                                             boolean has_crumbled_graphics,
7343                                             int crumbled, int sync_frame)
7344 {
7345   /* if element can be crumbled, but certain action graphics are just empty
7346      space (like instantly snapping sand to empty space in 1 frame), do not
7347      treat these empty space graphics as crumbled graphics in EMC engine */
7348   if (crumbled == IMG_EMPTY_SPACE)
7349     has_crumbled_graphics = FALSE;
7350
7351   if (has_crumbled_graphics)
7352   {
7353     struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7354     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7355                                            g_crumbled->anim_delay,
7356                                            g_crumbled->anim_mode,
7357                                            g_crumbled->anim_start_frame,
7358                                            sync_frame);
7359
7360     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7361                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7362
7363     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7364
7365     g_em->has_crumbled_graphics = TRUE;
7366   }
7367   else
7368   {
7369     g_em->crumbled_bitmap = NULL;
7370     g_em->crumbled_src_x = 0;
7371     g_em->crumbled_src_y = 0;
7372     g_em->crumbled_border_size = 0;
7373
7374     g_em->has_crumbled_graphics = FALSE;
7375   }
7376 }
7377
7378 void ResetGfxAnimation_EM(int x, int y, int tile)
7379 {
7380   GfxFrame[x][y] = 0;
7381 }
7382
7383 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7384                         int tile, int frame_em, int x, int y)
7385 {
7386   int action = object_mapping[tile].action;
7387 #if 1
7388   int direction = object_mapping[tile].direction;
7389   int effective_element = get_effective_element_EM(tile, frame_em);
7390   int graphic = (direction == MV_NONE ?
7391                  el_act2img(effective_element, action) :
7392                  el_act_dir2img(effective_element, action, direction));
7393   struct GraphicInfo *g = &graphic_info[graphic];
7394   int sync_frame;
7395 #endif
7396   boolean action_removing = (action == ACTION_DIGGING ||
7397                              action == ACTION_SNAPPING ||
7398                              action == ACTION_COLLECTING);
7399   boolean action_moving   = (action == ACTION_FALLING ||
7400                              action == ACTION_MOVING ||
7401                              action == ACTION_PUSHING ||
7402                              action == ACTION_EATING ||
7403                              action == ACTION_FILLING ||
7404                              action == ACTION_EMPTYING);
7405   boolean action_falling  = (action == ACTION_FALLING ||
7406                              action == ACTION_FILLING ||
7407                              action == ACTION_EMPTYING);
7408
7409   /* special case: graphic uses "2nd movement tile" and has defined
7410      7 frames for movement animation (or less) => use default graphic
7411      for last (8th) frame which ends the movement animation */
7412   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7413   {
7414     action = ACTION_DEFAULT;    /* (keep action_* unchanged for now) */
7415     graphic = (direction == MV_NONE ?
7416                el_act2img(effective_element, action) :
7417                el_act_dir2img(effective_element, action, direction));
7418
7419     g = &graphic_info[graphic];
7420   }
7421
7422 #if 0
7423   if (tile == Xsand_stonesand_1 ||
7424       tile == Xsand_stonesand_2 ||
7425       tile == Xsand_stonesand_3 ||
7426       tile == Xsand_stonesand_4)
7427     printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7428 #endif
7429
7430 #if 1
7431   if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7432   {
7433     GfxFrame[x][y] = 0;
7434
7435     // printf("::: resetting... [%d]\n", tile);
7436   }
7437 #else
7438   if (action_removing || check_linear_animation_EM(tile))
7439   {
7440     GfxFrame[x][y] = frame_em;
7441
7442     // printf("::: resetting... [%d]\n", tile);
7443   }
7444 #endif
7445   else if (action_moving)
7446   {
7447     boolean is_backside = object_mapping[tile].is_backside;
7448
7449     if (is_backside)
7450     {
7451       int direction = object_mapping[tile].direction;
7452       int move_dir = (action_falling ? MV_DOWN : direction);
7453
7454       GfxFrame[x][y]++;
7455
7456 #if 1
7457       /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7458       if (g->double_movement && frame_em == 0)
7459       {
7460         GfxFrame[x][y] = 0;
7461
7462         // printf("::: resetting... [%d]\n", tile);
7463       }
7464 #endif
7465
7466       if (move_dir == MV_LEFT)
7467         GfxFrame[x - 1][y] = GfxFrame[x][y];
7468       else if (move_dir == MV_RIGHT)
7469         GfxFrame[x + 1][y] = GfxFrame[x][y];
7470       else if (move_dir == MV_UP)
7471         GfxFrame[x][y - 1] = GfxFrame[x][y];
7472       else if (move_dir == MV_DOWN)
7473         GfxFrame[x][y + 1] = GfxFrame[x][y];
7474     }
7475   }
7476   else
7477   {
7478     GfxFrame[x][y]++;
7479
7480     /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7481     if (tile == Xsand_stonesand_quickout_1 ||
7482         tile == Xsand_stonesand_quickout_2)
7483       GfxFrame[x][y]++;
7484   }
7485
7486 #if 0
7487   if (tile == Xsand_stonesand_1 ||
7488       tile == Xsand_stonesand_2 ||
7489       tile == Xsand_stonesand_3 ||
7490       tile == Xsand_stonesand_4)
7491     printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7492 #endif
7493
7494 #if 1
7495   if (graphic_info[graphic].anim_global_sync)
7496     sync_frame = FrameCounter;
7497   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7498     sync_frame = GfxFrame[x][y];
7499   else
7500     sync_frame = 0;     /* playfield border (pseudo steel) */
7501
7502   SetRandomAnimationValue(x, y);
7503
7504   int frame = getAnimationFrame(g->anim_frames,
7505                                 g->anim_delay,
7506                                 g->anim_mode,
7507                                 g->anim_start_frame,
7508                                 sync_frame);
7509
7510   g_em->unique_identifier =
7511     (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7512 #endif
7513 }
7514
7515 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7516                                   int tile, int frame_em, int x, int y)
7517 {
7518   int action = object_mapping[tile].action;
7519   int direction = object_mapping[tile].direction;
7520   boolean is_backside = object_mapping[tile].is_backside;
7521   int effective_element = get_effective_element_EM(tile, frame_em);
7522 #if 1
7523   int effective_action = action;
7524 #else
7525   int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7526 #endif
7527   int graphic = (direction == MV_NONE ?
7528                  el_act2img(effective_element, effective_action) :
7529                  el_act_dir2img(effective_element, effective_action,
7530                                 direction));
7531   int crumbled = (direction == MV_NONE ?
7532                   el_act2crm(effective_element, effective_action) :
7533                   el_act_dir2crm(effective_element, effective_action,
7534                                  direction));
7535   int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7536   int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7537   boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7538   struct GraphicInfo *g = &graphic_info[graphic];
7539 #if 0
7540   struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7541 #endif
7542   int sync_frame;
7543
7544   /* special case: graphic uses "2nd movement tile" and has defined
7545      7 frames for movement animation (or less) => use default graphic
7546      for last (8th) frame which ends the movement animation */
7547   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7548   {
7549     effective_action = ACTION_DEFAULT;
7550     graphic = (direction == MV_NONE ?
7551                el_act2img(effective_element, effective_action) :
7552                el_act_dir2img(effective_element, effective_action,
7553                               direction));
7554     crumbled = (direction == MV_NONE ?
7555                 el_act2crm(effective_element, effective_action) :
7556                 el_act_dir2crm(effective_element, effective_action,
7557                                direction));
7558
7559     g = &graphic_info[graphic];
7560   }
7561
7562 #if 0
7563   if (frame_em == 7)
7564     return;
7565 #endif
7566
7567
7568 #if 0
7569   if (frame_em == 0)    /* reset animation frame for certain elements */
7570   {
7571     if (check_linear_animation_EM(tile))
7572       GfxFrame[x][y] = 0;
7573   }
7574 #endif
7575
7576   if (graphic_info[graphic].anim_global_sync)
7577     sync_frame = FrameCounter;
7578   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7579     sync_frame = GfxFrame[x][y];
7580   else
7581     sync_frame = 0;     /* playfield border (pseudo steel) */
7582
7583   SetRandomAnimationValue(x, y);
7584
7585 #if 0
7586   int i = tile;
7587   int j = frame_em;
7588   int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7589                         i == Xdrip_stretchB ? 7 :
7590                         i == Ydrip_s2 ? j + 8 :
7591                         i == Ydrip_s2B ? j + 8 :
7592                         i == Xacid_1 ? 0 :
7593                         i == Xacid_2 ? 10 :
7594                         i == Xacid_3 ? 20 :
7595                         i == Xacid_4 ? 30 :
7596                         i == Xacid_5 ? 40 :
7597                         i == Xacid_6 ? 50 :
7598                         i == Xacid_7 ? 60 :
7599                         i == Xacid_8 ? 70 :
7600                         i == Xfake_acid_1 ? 0 :
7601                         i == Xfake_acid_2 ? 10 :
7602                         i == Xfake_acid_3 ? 20 :
7603                         i == Xfake_acid_4 ? 30 :
7604                         i == Xfake_acid_5 ? 40 :
7605                         i == Xfake_acid_6 ? 50 :
7606                         i == Xfake_acid_7 ? 60 :
7607                         i == Xfake_acid_8 ? 70 :
7608                         i == Xball_2 ? 7 :
7609                         i == Xball_2B ? j + 8 :
7610                         i == Yball_eat ? j + 1 :
7611                         i == Ykey_1_eat ? j + 1 :
7612                         i == Ykey_2_eat ? j + 1 :
7613                         i == Ykey_3_eat ? j + 1 :
7614                         i == Ykey_4_eat ? j + 1 :
7615                         i == Ykey_5_eat ? j + 1 :
7616                         i == Ykey_6_eat ? j + 1 :
7617                         i == Ykey_7_eat ? j + 1 :
7618                         i == Ykey_8_eat ? j + 1 :
7619                         i == Ylenses_eat ? j + 1 :
7620                         i == Ymagnify_eat ? j + 1 :
7621                         i == Ygrass_eat ? j + 1 :
7622                         i == Ydirt_eat ? j + 1 :
7623                         i == Xamoeba_1 ? 0 :
7624                         i == Xamoeba_2 ? 1 :
7625                         i == Xamoeba_3 ? 2 :
7626                         i == Xamoeba_4 ? 3 :
7627                         i == Xamoeba_5 ? 0 :
7628                         i == Xamoeba_6 ? 1 :
7629                         i == Xamoeba_7 ? 2 :
7630                         i == Xamoeba_8 ? 3 :
7631                         i == Xexit_2 ? j + 8 :
7632                         i == Xexit_3 ? j + 16 :
7633                         i == Xdynamite_1 ? 0 :
7634                         i == Xdynamite_2 ? 8 :
7635                         i == Xdynamite_3 ? 16 :
7636                         i == Xdynamite_4 ? 24 :
7637                         i == Xsand_stonein_1 ? j + 1 :
7638                         i == Xsand_stonein_2 ? j + 9 :
7639                         i == Xsand_stonein_3 ? j + 17 :
7640                         i == Xsand_stonein_4 ? j + 25 :
7641                         i == Xsand_stoneout_1 && j == 0 ? 0 :
7642                         i == Xsand_stoneout_1 && j == 1 ? 0 :
7643                         i == Xsand_stoneout_1 && j == 2 ? 1 :
7644                         i == Xsand_stoneout_1 && j == 3 ? 2 :
7645                         i == Xsand_stoneout_1 && j == 4 ? 2 :
7646                         i == Xsand_stoneout_1 && j == 5 ? 3 :
7647                         i == Xsand_stoneout_1 && j == 6 ? 4 :
7648                         i == Xsand_stoneout_1 && j == 7 ? 4 :
7649                         i == Xsand_stoneout_2 && j == 0 ? 5 :
7650                         i == Xsand_stoneout_2 && j == 1 ? 6 :
7651                         i == Xsand_stoneout_2 && j == 2 ? 7 :
7652                         i == Xsand_stoneout_2 && j == 3 ? 8 :
7653                         i == Xsand_stoneout_2 && j == 4 ? 9 :
7654                         i == Xsand_stoneout_2 && j == 5 ? 11 :
7655                         i == Xsand_stoneout_2 && j == 6 ? 13 :
7656                         i == Xsand_stoneout_2 && j == 7 ? 15 :
7657                         i == Xboom_bug && j == 1 ? 2 :
7658                         i == Xboom_bug && j == 2 ? 2 :
7659                         i == Xboom_bug && j == 3 ? 4 :
7660                         i == Xboom_bug && j == 4 ? 4 :
7661                         i == Xboom_bug && j == 5 ? 2 :
7662                         i == Xboom_bug && j == 6 ? 2 :
7663                         i == Xboom_bug && j == 7 ? 0 :
7664                         i == Xboom_bomb && j == 1 ? 2 :
7665                         i == Xboom_bomb && j == 2 ? 2 :
7666                         i == Xboom_bomb && j == 3 ? 4 :
7667                         i == Xboom_bomb && j == 4 ? 4 :
7668                         i == Xboom_bomb && j == 5 ? 2 :
7669                         i == Xboom_bomb && j == 6 ? 2 :
7670                         i == Xboom_bomb && j == 7 ? 0 :
7671                         i == Xboom_android && j == 7 ? 6 :
7672                         i == Xboom_1 && j == 1 ? 2 :
7673                         i == Xboom_1 && j == 2 ? 2 :
7674                         i == Xboom_1 && j == 3 ? 4 :
7675                         i == Xboom_1 && j == 4 ? 4 :
7676                         i == Xboom_1 && j == 5 ? 6 :
7677                         i == Xboom_1 && j == 6 ? 6 :
7678                         i == Xboom_1 && j == 7 ? 8 :
7679                         i == Xboom_2 && j == 0 ? 8 :
7680                         i == Xboom_2 && j == 1 ? 8 :
7681                         i == Xboom_2 && j == 2 ? 10 :
7682                         i == Xboom_2 && j == 3 ? 10 :
7683                         i == Xboom_2 && j == 4 ? 10 :
7684                         i == Xboom_2 && j == 5 ? 12 :
7685                         i == Xboom_2 && j == 6 ? 12 :
7686                         i == Xboom_2 && j == 7 ? 12 :
7687 #if 0
7688                         special_animation && j == 4 ? 3 :
7689                         effective_action != action ? 0 :
7690 #endif
7691                         j);
7692 #endif
7693
7694 #if 0
7695   int xxx_effective_action;
7696   int xxx_has_action_graphics;
7697
7698   {
7699     int element = object_mapping[i].element_rnd;
7700     int action = object_mapping[i].action;
7701     int direction = object_mapping[i].direction;
7702     boolean is_backside = object_mapping[i].is_backside;
7703 #if 0
7704     boolean action_removing = (action == ACTION_DIGGING ||
7705                                action == ACTION_SNAPPING ||
7706                                action == ACTION_COLLECTING);
7707 #endif
7708     boolean action_exploding = ((action == ACTION_EXPLODING ||
7709                                  action == ACTION_SMASHED_BY_ROCK ||
7710                                  action == ACTION_SMASHED_BY_SPRING) &&
7711                                 element != EL_DIAMOND);
7712     boolean action_active = (action == ACTION_ACTIVE);
7713     boolean action_other = (action == ACTION_OTHER);
7714
7715     {
7716 #if 1
7717       int effective_element = get_effective_element_EM(i, j);
7718 #else
7719       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7720                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7721                                j < 7 ? element :
7722                                i == Xdrip_stretch ? element :
7723                                i == Xdrip_stretchB ? element :
7724                                i == Ydrip_s1 ? element :
7725                                i == Ydrip_s1B ? element :
7726                                i == Xball_1B ? element :
7727                                i == Xball_2 ? element :
7728                                i == Xball_2B ? element :
7729                                i == Yball_eat ? element :
7730                                i == Ykey_1_eat ? element :
7731                                i == Ykey_2_eat ? element :
7732                                i == Ykey_3_eat ? element :
7733                                i == Ykey_4_eat ? element :
7734                                i == Ykey_5_eat ? element :
7735                                i == Ykey_6_eat ? element :
7736                                i == Ykey_7_eat ? element :
7737                                i == Ykey_8_eat ? element :
7738                                i == Ylenses_eat ? element :
7739                                i == Ymagnify_eat ? element :
7740                                i == Ygrass_eat ? element :
7741                                i == Ydirt_eat ? element :
7742                                i == Yemerald_stone ? EL_EMERALD :
7743                                i == Ydiamond_stone ? EL_ROCK :
7744                                i == Xsand_stonein_1 ? element :
7745                                i == Xsand_stonein_2 ? element :
7746                                i == Xsand_stonein_3 ? element :
7747                                i == Xsand_stonein_4 ? element :
7748                                is_backside ? EL_EMPTY :
7749                                action_removing ? EL_EMPTY :
7750                                element);
7751 #endif
7752       int effective_action = (j < 7 ? action :
7753                               i == Xdrip_stretch ? action :
7754                               i == Xdrip_stretchB ? action :
7755                               i == Ydrip_s1 ? action :
7756                               i == Ydrip_s1B ? action :
7757                               i == Xball_1B ? action :
7758                               i == Xball_2 ? action :
7759                               i == Xball_2B ? action :
7760                               i == Yball_eat ? action :
7761                               i == Ykey_1_eat ? action :
7762                               i == Ykey_2_eat ? action :
7763                               i == Ykey_3_eat ? action :
7764                               i == Ykey_4_eat ? action :
7765                               i == Ykey_5_eat ? action :
7766                               i == Ykey_6_eat ? action :
7767                               i == Ykey_7_eat ? action :
7768                               i == Ykey_8_eat ? action :
7769                               i == Ylenses_eat ? action :
7770                               i == Ymagnify_eat ? action :
7771                               i == Ygrass_eat ? action :
7772                               i == Ydirt_eat ? action :
7773                               i == Xsand_stonein_1 ? action :
7774                               i == Xsand_stonein_2 ? action :
7775                               i == Xsand_stonein_3 ? action :
7776                               i == Xsand_stonein_4 ? action :
7777                               i == Xsand_stoneout_1 ? action :
7778                               i == Xsand_stoneout_2 ? action :
7779                               i == Xboom_android ? ACTION_EXPLODING :
7780                               action_exploding ? ACTION_EXPLODING :
7781                               action_active ? action :
7782                               action_other ? action :
7783                               ACTION_DEFAULT);
7784       int graphic = (el_act_dir2img(effective_element, effective_action,
7785                                     direction));
7786       int crumbled = (el_act_dir2crm(effective_element, effective_action,
7787                                      direction));
7788       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7789       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7790       boolean has_action_graphics = (graphic != base_graphic);
7791       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7792       struct GraphicInfo *g = &graphic_info[graphic];
7793 #if 0
7794       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7795 #endif
7796       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7797       Bitmap *src_bitmap;
7798       int src_x, src_y;
7799       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7800       boolean special_animation = (action != ACTION_DEFAULT &&
7801                                    g->anim_frames == 3 &&
7802                                    g->anim_delay == 2 &&
7803                                    g->anim_mode & ANIM_LINEAR);
7804       xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7805                         i == Xdrip_stretchB ? 7 :
7806                         i == Ydrip_s2 ? j + 8 :
7807                         i == Ydrip_s2B ? j + 8 :
7808                         i == Xacid_1 ? 0 :
7809                         i == Xacid_2 ? 10 :
7810                         i == Xacid_3 ? 20 :
7811                         i == Xacid_4 ? 30 :
7812                         i == Xacid_5 ? 40 :
7813                         i == Xacid_6 ? 50 :
7814                         i == Xacid_7 ? 60 :
7815                         i == Xacid_8 ? 70 :
7816                         i == Xfake_acid_1 ? 0 :
7817                         i == Xfake_acid_2 ? 10 :
7818                         i == Xfake_acid_3 ? 20 :
7819                         i == Xfake_acid_4 ? 30 :
7820                         i == Xfake_acid_5 ? 40 :
7821                         i == Xfake_acid_6 ? 50 :
7822                         i == Xfake_acid_7 ? 60 :
7823                         i == Xfake_acid_8 ? 70 :
7824                         i == Xball_2 ? 7 :
7825                         i == Xball_2B ? j + 8 :
7826                         i == Yball_eat ? j + 1 :
7827                         i == Ykey_1_eat ? j + 1 :
7828                         i == Ykey_2_eat ? j + 1 :
7829                         i == Ykey_3_eat ? j + 1 :
7830                         i == Ykey_4_eat ? j + 1 :
7831                         i == Ykey_5_eat ? j + 1 :
7832                         i == Ykey_6_eat ? j + 1 :
7833                         i == Ykey_7_eat ? j + 1 :
7834                         i == Ykey_8_eat ? j + 1 :
7835                         i == Ylenses_eat ? j + 1 :
7836                         i == Ymagnify_eat ? j + 1 :
7837                         i == Ygrass_eat ? j + 1 :
7838                         i == Ydirt_eat ? j + 1 :
7839                         i == Xamoeba_1 ? 0 :
7840                         i == Xamoeba_2 ? 1 :
7841                         i == Xamoeba_3 ? 2 :
7842                         i == Xamoeba_4 ? 3 :
7843                         i == Xamoeba_5 ? 0 :
7844                         i == Xamoeba_6 ? 1 :
7845                         i == Xamoeba_7 ? 2 :
7846                         i == Xamoeba_8 ? 3 :
7847                         i == Xexit_2 ? j + 8 :
7848                         i == Xexit_3 ? j + 16 :
7849                         i == Xdynamite_1 ? 0 :
7850                         i == Xdynamite_2 ? 8 :
7851                         i == Xdynamite_3 ? 16 :
7852                         i == Xdynamite_4 ? 24 :
7853                         i == Xsand_stonein_1 ? j + 1 :
7854                         i == Xsand_stonein_2 ? j + 9 :
7855                         i == Xsand_stonein_3 ? j + 17 :
7856                         i == Xsand_stonein_4 ? j + 25 :
7857                         i == Xsand_stoneout_1 && j == 0 ? 0 :
7858                         i == Xsand_stoneout_1 && j == 1 ? 0 :
7859                         i == Xsand_stoneout_1 && j == 2 ? 1 :
7860                         i == Xsand_stoneout_1 && j == 3 ? 2 :
7861                         i == Xsand_stoneout_1 && j == 4 ? 2 :
7862                         i == Xsand_stoneout_1 && j == 5 ? 3 :
7863                         i == Xsand_stoneout_1 && j == 6 ? 4 :
7864                         i == Xsand_stoneout_1 && j == 7 ? 4 :
7865                         i == Xsand_stoneout_2 && j == 0 ? 5 :
7866                         i == Xsand_stoneout_2 && j == 1 ? 6 :
7867                         i == Xsand_stoneout_2 && j == 2 ? 7 :
7868                         i == Xsand_stoneout_2 && j == 3 ? 8 :
7869                         i == Xsand_stoneout_2 && j == 4 ? 9 :
7870                         i == Xsand_stoneout_2 && j == 5 ? 11 :
7871                         i == Xsand_stoneout_2 && j == 6 ? 13 :
7872                         i == Xsand_stoneout_2 && j == 7 ? 15 :
7873                         i == Xboom_bug && j == 1 ? 2 :
7874                         i == Xboom_bug && j == 2 ? 2 :
7875                         i == Xboom_bug && j == 3 ? 4 :
7876                         i == Xboom_bug && j == 4 ? 4 :
7877                         i == Xboom_bug && j == 5 ? 2 :
7878                         i == Xboom_bug && j == 6 ? 2 :
7879                         i == Xboom_bug && j == 7 ? 0 :
7880                         i == Xboom_bomb && j == 1 ? 2 :
7881                         i == Xboom_bomb && j == 2 ? 2 :
7882                         i == Xboom_bomb && j == 3 ? 4 :
7883                         i == Xboom_bomb && j == 4 ? 4 :
7884                         i == Xboom_bomb && j == 5 ? 2 :
7885                         i == Xboom_bomb && j == 6 ? 2 :
7886                         i == Xboom_bomb && j == 7 ? 0 :
7887                         i == Xboom_android && j == 7 ? 6 :
7888                         i == Xboom_1 && j == 1 ? 2 :
7889                         i == Xboom_1 && j == 2 ? 2 :
7890                         i == Xboom_1 && j == 3 ? 4 :
7891                         i == Xboom_1 && j == 4 ? 4 :
7892                         i == Xboom_1 && j == 5 ? 6 :
7893                         i == Xboom_1 && j == 6 ? 6 :
7894                         i == Xboom_1 && j == 7 ? 8 :
7895                         i == Xboom_2 && j == 0 ? 8 :
7896                         i == Xboom_2 && j == 1 ? 8 :
7897                         i == Xboom_2 && j == 2 ? 10 :
7898                         i == Xboom_2 && j == 3 ? 10 :
7899                         i == Xboom_2 && j == 4 ? 10 :
7900                         i == Xboom_2 && j == 5 ? 12 :
7901                         i == Xboom_2 && j == 6 ? 12 :
7902                         i == Xboom_2 && j == 7 ? 12 :
7903                         special_animation && j == 4 ? 3 :
7904                         effective_action != action ? 0 :
7905                         j);
7906
7907       xxx_effective_action = effective_action;
7908       xxx_has_action_graphics = has_action_graphics;
7909     }
7910   }
7911 #endif
7912
7913   int frame = getAnimationFrame(g->anim_frames,
7914                                 g->anim_delay,
7915                                 g->anim_mode,
7916                                 g->anim_start_frame,
7917                                 sync_frame);
7918
7919
7920 #if 0
7921   return;
7922 #endif
7923
7924 #if 0
7925   if (frame_em == 7)
7926     return;
7927 #endif
7928
7929 #if 0
7930   int old_src_x = g_em->src_x;
7931   int old_src_y = g_em->src_y;
7932 #endif
7933
7934 #if 1
7935   getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7936                       g->double_movement && is_backside);
7937 #else
7938   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7939                       &g_em->src_x, &g_em->src_y, FALSE);
7940 #endif
7941
7942
7943 #if 0
7944   if (tile == Ydiamond_stone)
7945     printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
7946            frame_em,
7947            g->anim_frames,
7948            g->anim_delay,
7949            g->anim_mode,
7950            g->anim_start_frame,
7951            sync_frame,
7952            frame,
7953            g_em->src_x, g_em->src_y,
7954            g_em->src_offset_x, g_em->src_offset_y,
7955            g_em->dst_offset_x, g_em->dst_offset_y,
7956            graphic);
7957 #endif
7958
7959
7960 #if 0
7961   return;
7962 #endif
7963
7964 #if 0
7965   if (frame_em == 7)
7966   {
7967     if (graphic == IMG_BUG_MOVING_RIGHT)
7968       printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7969              g->double_movement, is_backside,
7970              old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7971
7972     return;
7973   }
7974 #endif
7975
7976
7977 #if 0
7978   g_em->src_offset_x = 0;
7979   g_em->src_offset_y = 0;
7980   g_em->dst_offset_x = 0;
7981   g_em->dst_offset_y = 0;
7982   g_em->width  = TILEX;
7983   g_em->height = TILEY;
7984
7985   g_em->preserve_background = FALSE;
7986 #endif
7987
7988   /* (updating the "crumbled" graphic definitions is probably not really needed,
7989      as animations for crumbled graphics can't be longer than one EMC cycle) */
7990 #if 1
7991   set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7992                            sync_frame);
7993
7994 #else
7995
7996   g_em->crumbled_bitmap = NULL;
7997   g_em->crumbled_src_x = 0;
7998   g_em->crumbled_src_y = 0;
7999
8000   g_em->has_crumbled_graphics = FALSE;
8001
8002   if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8003   {
8004     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8005                                            g_crumbled->anim_delay,
8006                                            g_crumbled->anim_mode,
8007                                            g_crumbled->anim_start_frame,
8008                                            sync_frame);
8009
8010     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8011                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8012
8013     g_em->has_crumbled_graphics = TRUE;
8014   }
8015 #endif
8016
8017 #if 0
8018  {
8019    int effective_action = xxx_effective_action;
8020    int has_action_graphics = xxx_has_action_graphics;
8021
8022       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8023                                    effective_action == ACTION_MOVING  ||
8024                                    effective_action == ACTION_PUSHING ||
8025                                    effective_action == ACTION_EATING)) ||
8026           (!has_action_graphics && (effective_action == ACTION_FILLING ||
8027                                     effective_action == ACTION_EMPTYING)))
8028       {
8029         int move_dir =
8030           (effective_action == ACTION_FALLING ||
8031            effective_action == ACTION_FILLING ||
8032            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8033         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8034         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
8035         int num_steps = (i == Ydrip_s1  ? 16 :
8036                          i == Ydrip_s1B ? 16 :
8037                          i == Ydrip_s2  ? 16 :
8038                          i == Ydrip_s2B ? 16 :
8039                          i == Xsand_stonein_1 ? 32 :
8040                          i == Xsand_stonein_2 ? 32 :
8041                          i == Xsand_stonein_3 ? 32 :
8042                          i == Xsand_stonein_4 ? 32 :
8043                          i == Xsand_stoneout_1 ? 16 :
8044                          i == Xsand_stoneout_2 ? 16 : 8);
8045         int cx = ABS(dx) * (TILEX / num_steps);
8046         int cy = ABS(dy) * (TILEY / num_steps);
8047         int step_frame = (i == Ydrip_s2         ? j + 8 :
8048                           i == Ydrip_s2B        ? j + 8 :
8049                           i == Xsand_stonein_2  ? j + 8 :
8050                           i == Xsand_stonein_3  ? j + 16 :
8051                           i == Xsand_stonein_4  ? j + 24 :
8052                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8053         int step = (is_backside ? step_frame : num_steps - step_frame);
8054
8055         if (is_backside)        /* tile where movement starts */
8056         {
8057           if (dx < 0 || dy < 0)
8058           {
8059             g_em->src_offset_x = cx * step;
8060             g_em->src_offset_y = cy * step;
8061           }
8062           else
8063           {
8064             g_em->dst_offset_x = cx * step;
8065             g_em->dst_offset_y = cy * step;
8066           }
8067         }
8068         else                    /* tile where movement ends */
8069         {
8070           if (dx < 0 || dy < 0)
8071           {
8072             g_em->dst_offset_x = cx * step;
8073             g_em->dst_offset_y = cy * step;
8074           }
8075           else
8076           {
8077             g_em->src_offset_x = cx * step;
8078             g_em->src_offset_y = cy * step;
8079           }
8080         }
8081
8082         g_em->width  = TILEX - cx * step;
8083         g_em->height = TILEY - cy * step;
8084       }
8085
8086       /* create unique graphic identifier to decide if tile must be redrawn */
8087       /* bit 31 - 16 (16 bit): EM style graphic
8088          bit 15 - 12 ( 4 bit): EM style frame
8089          bit 11 -  6 ( 6 bit): graphic width
8090          bit  5 -  0 ( 6 bit): graphic height */
8091       g_em->unique_identifier =
8092         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8093  }
8094 #endif
8095
8096 }
8097
8098 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8099                                   int player_nr, int anim, int frame_em)
8100 {
8101   int element   = player_mapping[player_nr][anim].element_rnd;
8102   int action    = player_mapping[player_nr][anim].action;
8103   int direction = player_mapping[player_nr][anim].direction;
8104   int graphic = (direction == MV_NONE ?
8105                  el_act2img(element, action) :
8106                  el_act_dir2img(element, action, direction));
8107   struct GraphicInfo *g = &graphic_info[graphic];
8108   int sync_frame;
8109
8110   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8111
8112   stored_player[player_nr].StepFrame = frame_em;
8113
8114   sync_frame = stored_player[player_nr].Frame;
8115
8116   int frame = getAnimationFrame(g->anim_frames,
8117                                 g->anim_delay,
8118                                 g->anim_mode,
8119                                 g->anim_start_frame,
8120                                 sync_frame);
8121
8122   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8123                       &g_em->src_x, &g_em->src_y, FALSE);
8124
8125 #if 0
8126   printf("::: %d: %d, %d [%d]\n",
8127          player_nr,
8128          stored_player[player_nr].Frame,
8129          stored_player[player_nr].StepFrame,
8130          FrameCounter);
8131 #endif
8132 }
8133
8134 void InitGraphicInfo_EM(void)
8135 {
8136 #if 0
8137   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
8138   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
8139 #endif
8140   int i, j, p;
8141
8142 #if DEBUG_EM_GFX
8143   int num_em_gfx_errors = 0;
8144
8145   if (graphic_info_em_object[0][0].bitmap == NULL)
8146   {
8147     /* EM graphics not yet initialized in em_open_all() */
8148
8149     return;
8150   }
8151
8152   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8153 #endif
8154
8155   /* always start with reliable default values */
8156   for (i = 0; i < TILE_MAX; i++)
8157   {
8158     object_mapping[i].element_rnd = EL_UNKNOWN;
8159     object_mapping[i].is_backside = FALSE;
8160     object_mapping[i].action = ACTION_DEFAULT;
8161     object_mapping[i].direction = MV_NONE;
8162   }
8163
8164   /* always start with reliable default values */
8165   for (p = 0; p < MAX_PLAYERS; p++)
8166   {
8167     for (i = 0; i < SPR_MAX; i++)
8168     {
8169       player_mapping[p][i].element_rnd = EL_UNKNOWN;
8170       player_mapping[p][i].action = ACTION_DEFAULT;
8171       player_mapping[p][i].direction = MV_NONE;
8172     }
8173   }
8174
8175   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8176   {
8177     int e = em_object_mapping_list[i].element_em;
8178
8179     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8180     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8181
8182     if (em_object_mapping_list[i].action != -1)
8183       object_mapping[e].action = em_object_mapping_list[i].action;
8184
8185     if (em_object_mapping_list[i].direction != -1)
8186       object_mapping[e].direction =
8187         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8188   }
8189
8190   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8191   {
8192     int a = em_player_mapping_list[i].action_em;
8193     int p = em_player_mapping_list[i].player_nr;
8194
8195     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8196
8197     if (em_player_mapping_list[i].action != -1)
8198       player_mapping[p][a].action = em_player_mapping_list[i].action;
8199
8200     if (em_player_mapping_list[i].direction != -1)
8201       player_mapping[p][a].direction =
8202         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8203   }
8204
8205   for (i = 0; i < TILE_MAX; i++)
8206   {
8207     int element = object_mapping[i].element_rnd;
8208     int action = object_mapping[i].action;
8209     int direction = object_mapping[i].direction;
8210     boolean is_backside = object_mapping[i].is_backside;
8211 #if 0
8212     boolean action_removing = (action == ACTION_DIGGING ||
8213                                action == ACTION_SNAPPING ||
8214                                action == ACTION_COLLECTING);
8215 #endif
8216     boolean action_exploding = ((action == ACTION_EXPLODING ||
8217                                  action == ACTION_SMASHED_BY_ROCK ||
8218                                  action == ACTION_SMASHED_BY_SPRING) &&
8219                                 element != EL_DIAMOND);
8220     boolean action_active = (action == ACTION_ACTIVE);
8221     boolean action_other = (action == ACTION_OTHER);
8222
8223     for (j = 0; j < 8; j++)
8224     {
8225 #if 1
8226       int effective_element = get_effective_element_EM(i, j);
8227 #else
8228       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8229                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8230                                j < 7 ? element :
8231                                i == Xdrip_stretch ? element :
8232                                i == Xdrip_stretchB ? element :
8233                                i == Ydrip_s1 ? element :
8234                                i == Ydrip_s1B ? element :
8235                                i == Xball_1B ? element :
8236                                i == Xball_2 ? element :
8237                                i == Xball_2B ? element :
8238                                i == Yball_eat ? element :
8239                                i == Ykey_1_eat ? element :
8240                                i == Ykey_2_eat ? element :
8241                                i == Ykey_3_eat ? element :
8242                                i == Ykey_4_eat ? element :
8243                                i == Ykey_5_eat ? element :
8244                                i == Ykey_6_eat ? element :
8245                                i == Ykey_7_eat ? element :
8246                                i == Ykey_8_eat ? element :
8247                                i == Ylenses_eat ? element :
8248                                i == Ymagnify_eat ? element :
8249                                i == Ygrass_eat ? element :
8250                                i == Ydirt_eat ? element :
8251                                i == Yemerald_stone ? EL_EMERALD :
8252                                i == Ydiamond_stone ? EL_ROCK :
8253                                i == Xsand_stonein_1 ? element :
8254                                i == Xsand_stonein_2 ? element :
8255                                i == Xsand_stonein_3 ? element :
8256                                i == Xsand_stonein_4 ? element :
8257                                is_backside ? EL_EMPTY :
8258                                action_removing ? EL_EMPTY :
8259                                element);
8260 #endif
8261       int effective_action = (j < 7 ? action :
8262                               i == Xdrip_stretch ? action :
8263                               i == Xdrip_stretchB ? action :
8264                               i == Ydrip_s1 ? action :
8265                               i == Ydrip_s1B ? action :
8266                               i == Xball_1B ? action :
8267                               i == Xball_2 ? action :
8268                               i == Xball_2B ? action :
8269                               i == Yball_eat ? action :
8270                               i == Ykey_1_eat ? action :
8271                               i == Ykey_2_eat ? action :
8272                               i == Ykey_3_eat ? action :
8273                               i == Ykey_4_eat ? action :
8274                               i == Ykey_5_eat ? action :
8275                               i == Ykey_6_eat ? action :
8276                               i == Ykey_7_eat ? action :
8277                               i == Ykey_8_eat ? action :
8278                               i == Ylenses_eat ? action :
8279                               i == Ymagnify_eat ? action :
8280                               i == Ygrass_eat ? action :
8281                               i == Ydirt_eat ? action :
8282                               i == Xsand_stonein_1 ? action :
8283                               i == Xsand_stonein_2 ? action :
8284                               i == Xsand_stonein_3 ? action :
8285                               i == Xsand_stonein_4 ? action :
8286                               i == Xsand_stoneout_1 ? action :
8287                               i == Xsand_stoneout_2 ? action :
8288                               i == Xboom_android ? ACTION_EXPLODING :
8289                               action_exploding ? ACTION_EXPLODING :
8290                               action_active ? action :
8291                               action_other ? action :
8292                               ACTION_DEFAULT);
8293       int graphic = (el_act_dir2img(effective_element, effective_action,
8294                                     direction));
8295       int crumbled = (el_act_dir2crm(effective_element, effective_action,
8296                                      direction));
8297       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8298       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8299       boolean has_action_graphics = (graphic != base_graphic);
8300       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8301       struct GraphicInfo *g = &graphic_info[graphic];
8302 #if 0
8303       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8304 #endif
8305       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8306       Bitmap *src_bitmap;
8307       int src_x, src_y;
8308       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8309       boolean special_animation = (action != ACTION_DEFAULT &&
8310                                    g->anim_frames == 3 &&
8311                                    g->anim_delay == 2 &&
8312                                    g->anim_mode & ANIM_LINEAR);
8313       int sync_frame = (i == Xdrip_stretch ? 7 :
8314                         i == Xdrip_stretchB ? 7 :
8315                         i == Ydrip_s2 ? j + 8 :
8316                         i == Ydrip_s2B ? j + 8 :
8317                         i == Xacid_1 ? 0 :
8318                         i == Xacid_2 ? 10 :
8319                         i == Xacid_3 ? 20 :
8320                         i == Xacid_4 ? 30 :
8321                         i == Xacid_5 ? 40 :
8322                         i == Xacid_6 ? 50 :
8323                         i == Xacid_7 ? 60 :
8324                         i == Xacid_8 ? 70 :
8325                         i == Xfake_acid_1 ? 0 :
8326                         i == Xfake_acid_2 ? 10 :
8327                         i == Xfake_acid_3 ? 20 :
8328                         i == Xfake_acid_4 ? 30 :
8329                         i == Xfake_acid_5 ? 40 :
8330                         i == Xfake_acid_6 ? 50 :
8331                         i == Xfake_acid_7 ? 60 :
8332                         i == Xfake_acid_8 ? 70 :
8333                         i == Xball_2 ? 7 :
8334                         i == Xball_2B ? j + 8 :
8335                         i == Yball_eat ? j + 1 :
8336                         i == Ykey_1_eat ? j + 1 :
8337                         i == Ykey_2_eat ? j + 1 :
8338                         i == Ykey_3_eat ? j + 1 :
8339                         i == Ykey_4_eat ? j + 1 :
8340                         i == Ykey_5_eat ? j + 1 :
8341                         i == Ykey_6_eat ? j + 1 :
8342                         i == Ykey_7_eat ? j + 1 :
8343                         i == Ykey_8_eat ? j + 1 :
8344                         i == Ylenses_eat ? j + 1 :
8345                         i == Ymagnify_eat ? j + 1 :
8346                         i == Ygrass_eat ? j + 1 :
8347                         i == Ydirt_eat ? j + 1 :
8348                         i == Xamoeba_1 ? 0 :
8349                         i == Xamoeba_2 ? 1 :
8350                         i == Xamoeba_3 ? 2 :
8351                         i == Xamoeba_4 ? 3 :
8352                         i == Xamoeba_5 ? 0 :
8353                         i == Xamoeba_6 ? 1 :
8354                         i == Xamoeba_7 ? 2 :
8355                         i == Xamoeba_8 ? 3 :
8356                         i == Xexit_2 ? j + 8 :
8357                         i == Xexit_3 ? j + 16 :
8358                         i == Xdynamite_1 ? 0 :
8359                         i == Xdynamite_2 ? 8 :
8360                         i == Xdynamite_3 ? 16 :
8361                         i == Xdynamite_4 ? 24 :
8362                         i == Xsand_stonein_1 ? j + 1 :
8363                         i == Xsand_stonein_2 ? j + 9 :
8364                         i == Xsand_stonein_3 ? j + 17 :
8365                         i == Xsand_stonein_4 ? j + 25 :
8366                         i == Xsand_stoneout_1 && j == 0 ? 0 :
8367                         i == Xsand_stoneout_1 && j == 1 ? 0 :
8368                         i == Xsand_stoneout_1 && j == 2 ? 1 :
8369                         i == Xsand_stoneout_1 && j == 3 ? 2 :
8370                         i == Xsand_stoneout_1 && j == 4 ? 2 :
8371                         i == Xsand_stoneout_1 && j == 5 ? 3 :
8372                         i == Xsand_stoneout_1 && j == 6 ? 4 :
8373                         i == Xsand_stoneout_1 && j == 7 ? 4 :
8374                         i == Xsand_stoneout_2 && j == 0 ? 5 :
8375                         i == Xsand_stoneout_2 && j == 1 ? 6 :
8376                         i == Xsand_stoneout_2 && j == 2 ? 7 :
8377                         i == Xsand_stoneout_2 && j == 3 ? 8 :
8378                         i == Xsand_stoneout_2 && j == 4 ? 9 :
8379                         i == Xsand_stoneout_2 && j == 5 ? 11 :
8380                         i == Xsand_stoneout_2 && j == 6 ? 13 :
8381                         i == Xsand_stoneout_2 && j == 7 ? 15 :
8382                         i == Xboom_bug && j == 1 ? 2 :
8383                         i == Xboom_bug && j == 2 ? 2 :
8384                         i == Xboom_bug && j == 3 ? 4 :
8385                         i == Xboom_bug && j == 4 ? 4 :
8386                         i == Xboom_bug && j == 5 ? 2 :
8387                         i == Xboom_bug && j == 6 ? 2 :
8388                         i == Xboom_bug && j == 7 ? 0 :
8389                         i == Xboom_bomb && j == 1 ? 2 :
8390                         i == Xboom_bomb && j == 2 ? 2 :
8391                         i == Xboom_bomb && j == 3 ? 4 :
8392                         i == Xboom_bomb && j == 4 ? 4 :
8393                         i == Xboom_bomb && j == 5 ? 2 :
8394                         i == Xboom_bomb && j == 6 ? 2 :
8395                         i == Xboom_bomb && j == 7 ? 0 :
8396                         i == Xboom_android && j == 7 ? 6 :
8397                         i == Xboom_1 && j == 1 ? 2 :
8398                         i == Xboom_1 && j == 2 ? 2 :
8399                         i == Xboom_1 && j == 3 ? 4 :
8400                         i == Xboom_1 && j == 4 ? 4 :
8401                         i == Xboom_1 && j == 5 ? 6 :
8402                         i == Xboom_1 && j == 6 ? 6 :
8403                         i == Xboom_1 && j == 7 ? 8 :
8404                         i == Xboom_2 && j == 0 ? 8 :
8405                         i == Xboom_2 && j == 1 ? 8 :
8406                         i == Xboom_2 && j == 2 ? 10 :
8407                         i == Xboom_2 && j == 3 ? 10 :
8408                         i == Xboom_2 && j == 4 ? 10 :
8409                         i == Xboom_2 && j == 5 ? 12 :
8410                         i == Xboom_2 && j == 6 ? 12 :
8411                         i == Xboom_2 && j == 7 ? 12 :
8412                         special_animation && j == 4 ? 3 :
8413                         effective_action != action ? 0 :
8414                         j);
8415
8416 #if DEBUG_EM_GFX
8417       Bitmap *debug_bitmap = g_em->bitmap;
8418       int debug_src_x = g_em->src_x;
8419       int debug_src_y = g_em->src_y;
8420 #endif
8421
8422       int frame = getAnimationFrame(g->anim_frames,
8423                                     g->anim_delay,
8424                                     g->anim_mode,
8425                                     g->anim_start_frame,
8426                                     sync_frame);
8427
8428       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8429                           g->double_movement && is_backside);
8430
8431       g_em->bitmap = src_bitmap;
8432       g_em->src_x = src_x;
8433       g_em->src_y = src_y;
8434       g_em->src_offset_x = 0;
8435       g_em->src_offset_y = 0;
8436       g_em->dst_offset_x = 0;
8437       g_em->dst_offset_y = 0;
8438       g_em->width  = TILEX;
8439       g_em->height = TILEY;
8440
8441       g_em->preserve_background = FALSE;
8442
8443 #if 1
8444       set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8445                                sync_frame);
8446
8447 #else
8448
8449       g_em->crumbled_bitmap = NULL;
8450       g_em->crumbled_src_x = 0;
8451       g_em->crumbled_src_y = 0;
8452       g_em->crumbled_border_size = 0;
8453
8454       g_em->has_crumbled_graphics = FALSE;
8455
8456 #if 0
8457       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8458         printf("::: empty crumbled: %d [%s], %d, %d\n",
8459                effective_element, element_info[effective_element].token_name,
8460                effective_action, direction);
8461 #endif
8462
8463       /* if element can be crumbled, but certain action graphics are just empty
8464          space (like instantly snapping sand to empty space in 1 frame), do not
8465          treat these empty space graphics as crumbled graphics in EMC engine */
8466       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8467       {
8468         int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8469                                                g_crumbled->anim_delay,
8470                                                g_crumbled->anim_mode,
8471                                                g_crumbled->anim_start_frame,
8472                                                sync_frame);
8473
8474         getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8475
8476         g_em->has_crumbled_graphics = TRUE;
8477         g_em->crumbled_bitmap = src_bitmap;
8478         g_em->crumbled_src_x = src_x;
8479         g_em->crumbled_src_y = src_y;
8480         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8481
8482
8483 #if 0
8484         if (g_em == &graphic_info_em_object[207][0])
8485           printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8486                  graphic_info_em_object[207][0].crumbled_src_x,
8487                  graphic_info_em_object[207][0].crumbled_src_y,
8488
8489                  crumbled, frame, src_x, src_y,
8490
8491                  g->anim_frames,
8492                  g->anim_delay,
8493                  g->anim_mode,
8494                  g->anim_start_frame,
8495                  sync_frame,
8496                  gfx.anim_random_frame,
8497                  frame);
8498 #endif
8499
8500 #if 0
8501         printf("::: EMC tile %d is crumbled\n", i);
8502 #endif
8503       }
8504 #endif
8505
8506 #if 0
8507       if (element == EL_ROCK &&
8508           effective_action == ACTION_FILLING)
8509         printf("::: has_action_graphics == %d\n", has_action_graphics);
8510 #endif
8511
8512       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8513                                    effective_action == ACTION_MOVING  ||
8514                                    effective_action == ACTION_PUSHING ||
8515                                    effective_action == ACTION_EATING)) ||
8516           (!has_action_graphics && (effective_action == ACTION_FILLING ||
8517                                     effective_action == ACTION_EMPTYING)))
8518       {
8519         int move_dir =
8520           (effective_action == ACTION_FALLING ||
8521            effective_action == ACTION_FILLING ||
8522            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8523         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8524         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
8525         int num_steps = (i == Ydrip_s1  ? 16 :
8526                          i == Ydrip_s1B ? 16 :
8527                          i == Ydrip_s2  ? 16 :
8528                          i == Ydrip_s2B ? 16 :
8529                          i == Xsand_stonein_1 ? 32 :
8530                          i == Xsand_stonein_2 ? 32 :
8531                          i == Xsand_stonein_3 ? 32 :
8532                          i == Xsand_stonein_4 ? 32 :
8533                          i == Xsand_stoneout_1 ? 16 :
8534                          i == Xsand_stoneout_2 ? 16 : 8);
8535         int cx = ABS(dx) * (TILEX / num_steps);
8536         int cy = ABS(dy) * (TILEY / num_steps);
8537         int step_frame = (i == Ydrip_s2         ? j + 8 :
8538                           i == Ydrip_s2B        ? j + 8 :
8539                           i == Xsand_stonein_2  ? j + 8 :
8540                           i == Xsand_stonein_3  ? j + 16 :
8541                           i == Xsand_stonein_4  ? j + 24 :
8542                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8543         int step = (is_backside ? step_frame : num_steps - step_frame);
8544
8545         if (is_backside)        /* tile where movement starts */
8546         {
8547           if (dx < 0 || dy < 0)
8548           {
8549             g_em->src_offset_x = cx * step;
8550             g_em->src_offset_y = cy * step;
8551           }
8552           else
8553           {
8554             g_em->dst_offset_x = cx * step;
8555             g_em->dst_offset_y = cy * step;
8556           }
8557         }
8558         else                    /* tile where movement ends */
8559         {
8560           if (dx < 0 || dy < 0)
8561           {
8562             g_em->dst_offset_x = cx * step;
8563             g_em->dst_offset_y = cy * step;
8564           }
8565           else
8566           {
8567             g_em->src_offset_x = cx * step;
8568             g_em->src_offset_y = cy * step;
8569           }
8570         }
8571
8572         g_em->width  = TILEX - cx * step;
8573         g_em->height = TILEY - cy * step;
8574       }
8575
8576       /* create unique graphic identifier to decide if tile must be redrawn */
8577       /* bit 31 - 16 (16 bit): EM style graphic
8578          bit 15 - 12 ( 4 bit): EM style frame
8579          bit 11 -  6 ( 6 bit): graphic width
8580          bit  5 -  0 ( 6 bit): graphic height */
8581       g_em->unique_identifier =
8582         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8583
8584 #if DEBUG_EM_GFX
8585
8586       /* skip check for EMC elements not contained in original EMC artwork */
8587       if (element == EL_EMC_FAKE_ACID)
8588         continue;
8589
8590       if (g_em->bitmap != debug_bitmap ||
8591           g_em->src_x != debug_src_x ||
8592           g_em->src_y != debug_src_y ||
8593           g_em->src_offset_x != 0 ||
8594           g_em->src_offset_y != 0 ||
8595           g_em->dst_offset_x != 0 ||
8596           g_em->dst_offset_y != 0 ||
8597           g_em->width != TILEX ||
8598           g_em->height != TILEY)
8599       {
8600         static int last_i = -1;
8601
8602         if (i != last_i)
8603         {
8604           printf("\n");
8605           last_i = i;
8606         }
8607
8608         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8609                i, element, element_info[element].token_name,
8610                element_action_info[effective_action].suffix, direction);
8611
8612         if (element != effective_element)
8613           printf(" [%d ('%s')]",
8614                  effective_element,
8615                  element_info[effective_element].token_name);
8616
8617         printf("\n");
8618
8619         if (g_em->bitmap != debug_bitmap)
8620           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8621                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8622
8623         if (g_em->src_x != debug_src_x ||
8624             g_em->src_y != debug_src_y)
8625           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8626                  j, (is_backside ? 'B' : 'F'),
8627                  g_em->src_x, g_em->src_y,
8628                  g_em->src_x / 32, g_em->src_y / 32,
8629                  debug_src_x, debug_src_y,
8630                  debug_src_x / 32, debug_src_y / 32);
8631
8632         if (g_em->src_offset_x != 0 ||
8633             g_em->src_offset_y != 0 ||
8634             g_em->dst_offset_x != 0 ||
8635             g_em->dst_offset_y != 0)
8636           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8637                  j, is_backside,
8638                  g_em->src_offset_x, g_em->src_offset_y,
8639                  g_em->dst_offset_x, g_em->dst_offset_y);
8640
8641         if (g_em->width != TILEX ||
8642             g_em->height != TILEY)
8643           printf("    %d (%d): size %d,%d should be %d,%d\n",
8644                  j, is_backside,
8645                  g_em->width, g_em->height, TILEX, TILEY);
8646
8647         num_em_gfx_errors++;
8648       }
8649 #endif
8650
8651     }
8652   }
8653
8654   for (i = 0; i < TILE_MAX; i++)
8655   {
8656     for (j = 0; j < 8; j++)
8657     {
8658       int element = object_mapping[i].element_rnd;
8659       int action = object_mapping[i].action;
8660       int direction = object_mapping[i].direction;
8661       boolean is_backside = object_mapping[i].is_backside;
8662       int graphic_action  = el_act_dir2img(element, action, direction);
8663       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8664
8665       if ((action == ACTION_SMASHED_BY_ROCK ||
8666            action == ACTION_SMASHED_BY_SPRING ||
8667            action == ACTION_EATING) &&
8668           graphic_action == graphic_default)
8669       {
8670         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
8671                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8672                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
8673                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8674                  Xspring);
8675
8676         /* no separate animation for "smashed by rock" -- use rock instead */
8677         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8678         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8679
8680         g_em->bitmap            = g_xx->bitmap;
8681         g_em->src_x             = g_xx->src_x;
8682         g_em->src_y             = g_xx->src_y;
8683         g_em->src_offset_x      = g_xx->src_offset_x;
8684         g_em->src_offset_y      = g_xx->src_offset_y;
8685         g_em->dst_offset_x      = g_xx->dst_offset_x;
8686         g_em->dst_offset_y      = g_xx->dst_offset_y;
8687         g_em->width             = g_xx->width;
8688         g_em->height            = g_xx->height;
8689         g_em->unique_identifier = g_xx->unique_identifier;
8690
8691         if (!is_backside)
8692           g_em->preserve_background = TRUE;
8693       }
8694     }
8695   }
8696
8697   for (p = 0; p < MAX_PLAYERS; p++)
8698   {
8699     for (i = 0; i < SPR_MAX; i++)
8700     {
8701       int element = player_mapping[p][i].element_rnd;
8702       int action = player_mapping[p][i].action;
8703       int direction = player_mapping[p][i].direction;
8704
8705       for (j = 0; j < 8; j++)
8706       {
8707         int effective_element = element;
8708         int effective_action = action;
8709         int graphic = (direction == MV_NONE ?
8710                        el_act2img(effective_element, effective_action) :
8711                        el_act_dir2img(effective_element, effective_action,
8712                                       direction));
8713         struct GraphicInfo *g = &graphic_info[graphic];
8714         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8715         Bitmap *src_bitmap;
8716         int src_x, src_y;
8717         int sync_frame = j;
8718
8719 #if DEBUG_EM_GFX
8720         Bitmap *debug_bitmap = g_em->bitmap;
8721         int debug_src_x = g_em->src_x;
8722         int debug_src_y = g_em->src_y;
8723 #endif
8724
8725         int frame = getAnimationFrame(g->anim_frames,
8726                                       g->anim_delay,
8727                                       g->anim_mode,
8728                                       g->anim_start_frame,
8729                                       sync_frame);
8730
8731         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8732
8733         g_em->bitmap = src_bitmap;
8734         g_em->src_x = src_x;
8735         g_em->src_y = src_y;
8736         g_em->src_offset_x = 0;
8737         g_em->src_offset_y = 0;
8738         g_em->dst_offset_x = 0;
8739         g_em->dst_offset_y = 0;
8740         g_em->width  = TILEX;
8741         g_em->height = TILEY;
8742
8743 #if DEBUG_EM_GFX
8744
8745         /* skip check for EMC elements not contained in original EMC artwork */
8746         if (element == EL_PLAYER_3 ||
8747             element == EL_PLAYER_4)
8748           continue;
8749
8750         if (g_em->bitmap != debug_bitmap ||
8751             g_em->src_x != debug_src_x ||
8752             g_em->src_y != debug_src_y)
8753         {
8754           static int last_i = -1;
8755
8756           if (i != last_i)
8757           {
8758             printf("\n");
8759             last_i = i;
8760           }
8761
8762           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8763                  p, i, element, element_info[element].token_name,
8764                  element_action_info[effective_action].suffix, direction);
8765
8766           if (element != effective_element)
8767             printf(" [%d ('%s')]",
8768                    effective_element,
8769                    element_info[effective_element].token_name);
8770
8771           printf("\n");
8772
8773           if (g_em->bitmap != debug_bitmap)
8774             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
8775                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
8776
8777           if (g_em->src_x != debug_src_x ||
8778               g_em->src_y != debug_src_y)
8779             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8780                    j,
8781                    g_em->src_x, g_em->src_y,
8782                    g_em->src_x / 32, g_em->src_y / 32,
8783                    debug_src_x, debug_src_y,
8784                    debug_src_x / 32, debug_src_y / 32);
8785
8786           num_em_gfx_errors++;
8787         }
8788 #endif
8789
8790       }
8791     }
8792   }
8793
8794 #if DEBUG_EM_GFX
8795   printf("\n");
8796   printf("::: [%d errors found]\n", num_em_gfx_errors);
8797
8798   exit(0);
8799 #endif
8800 }
8801
8802 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8803                             boolean any_player_moving,
8804                             boolean player_is_dropping)
8805 {
8806   int i;
8807
8808   if (tape.single_step && tape.recording && !tape.pausing)
8809   {
8810     boolean active_players = FALSE;
8811
8812     for (i = 0; i < MAX_PLAYERS; i++)
8813       if (action[i] != JOY_NO_ACTION)
8814         active_players = TRUE;
8815
8816     // if (frame == 0)
8817     if (frame == 0 && !player_is_dropping)
8818       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8819   }
8820 }
8821
8822 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8823                             boolean murphy_is_dropping)
8824 {
8825 #if 0
8826   printf("::: waiting: %d, dropping: %d\n",
8827          murphy_is_waiting, murphy_is_dropping);
8828 #endif
8829
8830   if (tape.single_step && tape.recording && !tape.pausing)
8831   {
8832     // if (murphy_is_waiting || murphy_is_dropping)
8833     if (murphy_is_waiting)
8834     {
8835 #if 0
8836       printf("::: murphy is waiting -> pause mode\n");
8837 #endif
8838
8839       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8840     }
8841   }
8842 }
8843
8844 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8845                          int graphic, int sync_frame, int x, int y)
8846 {
8847   int frame = getGraphicAnimationFrame(graphic, sync_frame);
8848
8849   getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8850 }
8851
8852 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8853 {
8854   return (IS_NEXT_FRAME(sync_frame, graphic));
8855 }
8856
8857 int getGraphicInfo_Delay(int graphic)
8858 {
8859   return graphic_info[graphic].anim_delay;
8860 }
8861
8862 void PlayMenuSoundExt(int sound)
8863 {
8864   if (sound == SND_UNDEFINED)
8865     return;
8866
8867   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8868       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8869     return;
8870
8871   if (IS_LOOP_SOUND(sound))
8872     PlaySoundLoop(sound);
8873   else
8874     PlaySound(sound);
8875 }
8876
8877 void PlayMenuSound()
8878 {
8879   PlayMenuSoundExt(menu.sound[game_status]);
8880 }
8881
8882 void PlayMenuSoundStereo(int sound, int stereo_position)
8883 {
8884   if (sound == SND_UNDEFINED)
8885     return;
8886
8887   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8888       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8889     return;
8890
8891   if (IS_LOOP_SOUND(sound))
8892     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8893   else
8894     PlaySoundStereo(sound, stereo_position);
8895 }
8896
8897 void PlayMenuSoundIfLoopExt(int sound)
8898 {
8899   if (sound == SND_UNDEFINED)
8900     return;
8901
8902   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8903       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8904     return;
8905
8906   if (IS_LOOP_SOUND(sound))
8907     PlaySoundLoop(sound);
8908 }
8909
8910 void PlayMenuSoundIfLoop()
8911 {
8912   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8913 }
8914
8915 void PlayMenuMusicExt(int music)
8916 {
8917   if (music == MUS_UNDEFINED)
8918     return;
8919
8920   if (!setup.sound_music)
8921     return;
8922
8923   PlayMusic(music);
8924 }
8925
8926 void PlayMenuMusic()
8927 {
8928   PlayMenuMusicExt(menu.music[game_status]);
8929 }
8930
8931 void PlaySoundActivating()
8932 {
8933 #if 0
8934   PlaySound(SND_MENU_ITEM_ACTIVATING);
8935 #endif
8936 }
8937
8938 void PlaySoundSelecting()
8939 {
8940 #if 0
8941   PlaySound(SND_MENU_ITEM_SELECTING);
8942 #endif
8943 }
8944
8945 void ToggleFullscreenIfNeeded()
8946 {
8947   boolean change_fullscreen = (setup.fullscreen !=
8948                                video.fullscreen_enabled);
8949   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8950                                     !strEqual(setup.fullscreen_mode,
8951                                               video.fullscreen_mode_current));
8952
8953   if (!video.fullscreen_available)
8954     return;
8955
8956   if (change_fullscreen || change_fullscreen_mode)
8957   {
8958     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8959
8960     /* save backbuffer content which gets lost when toggling fullscreen mode */
8961     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8962
8963     if (change_fullscreen_mode)
8964     {
8965       /* keep fullscreen, but change fullscreen mode (screen resolution) */
8966       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
8967     }
8968
8969     /* toggle fullscreen */
8970     ChangeVideoModeIfNeeded(setup.fullscreen);
8971
8972     setup.fullscreen = video.fullscreen_enabled;
8973
8974     /* restore backbuffer content from temporary backbuffer backup bitmap */
8975     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8976
8977     FreeBitmap(tmp_backbuffer);
8978
8979 #if 1
8980     /* update visible window/screen */
8981     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8982 #else
8983     redraw_mask = REDRAW_ALL;
8984 #endif
8985   }
8986 }
8987
8988 void ChangeViewportPropertiesIfNeeded()
8989 {
8990   int *door_1_x = &DX;
8991   int *door_1_y = &DY;
8992   int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
8993   int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
8994   int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
8995                        game_status == GAME_MODE_EDITOR ? game_status :
8996                        GAME_MODE_MAIN);
8997   struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8998   struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8999   struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
9000   int border_size = vp_playfield->border_size;
9001   int new_sx = vp_playfield->x + border_size;
9002   int new_sy = vp_playfield->y + border_size;
9003   int new_sxsize = vp_playfield->width  - 2 * border_size;
9004   int new_sysize = vp_playfield->height - 2 * border_size;
9005   int new_real_sx = vp_playfield->x;
9006   int new_real_sy = vp_playfield->y;
9007   int new_full_sxsize = vp_playfield->width;
9008   int new_full_sysize = vp_playfield->height;
9009 #if NEW_TILESIZE
9010   int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
9011   int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9012                   gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9013   int new_scr_fieldx = new_sxsize / tilesize;
9014   int new_scr_fieldy = new_sysize / tilesize;
9015   int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9016   int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9017 #else
9018   int new_scr_fieldx = (vp_playfield->width  - 2 * border_size) / TILESIZE;
9019   int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
9020 #endif
9021   boolean init_gfx_buffers = FALSE;
9022   boolean init_video_buffer = FALSE;
9023   boolean init_gadgets_and_toons = FALSE;
9024
9025 #if 0
9026   /* !!! TEST ONLY !!! */
9027   // InitGfxBuffers();
9028   return;
9029 #endif
9030
9031   if (viewport.window.width  != WIN_XSIZE ||
9032       viewport.window.height != WIN_YSIZE)
9033   {
9034     WIN_XSIZE = viewport.window.width;
9035     WIN_YSIZE = viewport.window.height;
9036
9037 #if 1
9038     init_video_buffer = TRUE;
9039     init_gfx_buffers = TRUE;
9040 #else
9041     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9042     InitGfxBuffers();
9043
9044 #if 1
9045     SetDrawDeactivationMask(REDRAW_NONE);
9046     SetDrawBackgroundMask(REDRAW_FIELD);
9047
9048     // RedrawBackground();
9049 #endif
9050 #endif
9051
9052     // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9053   }
9054
9055   if (new_scr_fieldx != SCR_FIELDX ||
9056       new_scr_fieldy != SCR_FIELDY)
9057   {
9058     /* this always toggles between MAIN and GAME when using small tile size */
9059
9060     SCR_FIELDX = new_scr_fieldx;
9061     SCR_FIELDY = new_scr_fieldy;
9062
9063     // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9064   }
9065
9066 #if 0
9067   if (new_tilesize_var != TILESIZE_VAR &&
9068       gfx_game_mode == GAME_MODE_PLAYING)
9069   {
9070     /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
9071
9072     TILESIZE_VAR = new_tilesize_var;
9073
9074     init_gfx_buffers = TRUE;
9075
9076     // printf("::: tilesize: init_gfx_buffers\n");
9077   }
9078 #endif
9079
9080   if (new_sx != SX ||
9081       new_sy != SY ||
9082       new_sxsize != SXSIZE ||
9083       new_sysize != SYSIZE ||
9084       new_real_sx != REAL_SX ||
9085       new_real_sy != REAL_SY ||
9086       new_full_sxsize != FULL_SXSIZE ||
9087       new_full_sysize != FULL_SYSIZE ||
9088       new_tilesize_var != TILESIZE_VAR ||
9089       vp_door_1->x != *door_1_x ||
9090       vp_door_1->y != *door_1_y ||
9091       vp_door_2->x != *door_2_x ||
9092       vp_door_2->y != *door_2_y)
9093   {
9094     SX = new_sx;
9095     SY = new_sy;
9096     SXSIZE = new_sxsize;
9097     SYSIZE = new_sysize;
9098     REAL_SX = new_real_sx;
9099     REAL_SY = new_real_sy;
9100     FULL_SXSIZE = new_full_sxsize;
9101     FULL_SYSIZE = new_full_sysize;
9102     TILESIZE_VAR = new_tilesize_var;
9103
9104 #if 0
9105     printf("::: %d, %d, %d [%d]\n",
9106            SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
9107            setup.small_game_graphics);
9108 #endif
9109
9110     *door_1_x = vp_door_1->x;
9111     *door_1_y = vp_door_1->y;
9112     *door_2_x = vp_door_2->x;
9113     *door_2_y = vp_door_2->y;
9114
9115 #if 1
9116     init_gfx_buffers = TRUE;
9117
9118     // printf("::: viewports: init_gfx_buffers\n");
9119 #else
9120     InitGfxBuffers();
9121 #endif
9122
9123     if (gfx_game_mode == GAME_MODE_MAIN)
9124     {
9125 #if 1
9126       init_gadgets_and_toons = TRUE;
9127
9128       // printf("::: viewports: init_gadgets_and_toons\n");
9129 #else
9130       InitGadgets();
9131       InitToons();
9132 #endif
9133     }
9134   }
9135
9136   if (init_gfx_buffers)
9137   {
9138     // printf("::: init_gfx_buffers\n");
9139
9140     SCR_FIELDX = new_scr_fieldx_buffers;
9141     SCR_FIELDY = new_scr_fieldy_buffers;
9142
9143     InitGfxBuffers();
9144
9145     SCR_FIELDX = new_scr_fieldx;
9146     SCR_FIELDY = new_scr_fieldy;
9147   }
9148
9149   if (init_video_buffer)
9150   {
9151     // printf("::: init_video_buffer\n");
9152
9153     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9154
9155     SetDrawDeactivationMask(REDRAW_NONE);
9156     SetDrawBackgroundMask(REDRAW_FIELD);
9157   }
9158
9159   if (init_gadgets_and_toons)
9160   {
9161     // printf("::: init_gadgets_and_toons\n");
9162
9163     InitGadgets();
9164     InitToons();
9165   }
9166
9167 #if 0
9168   printf("::: %d, %d  /  %d, %d [%d]\n", VX, VY, EX, EY, game_status);
9169 #endif
9170 }