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