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