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