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