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