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