1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX 0
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
38 #define NUM_TOOL_BUTTONS 7
40 /* forward declaration for internal use */
41 static void UnmapToolButtons();
42 static void HandleToolButtons(struct GadgetInfo *);
43 static int el_act_dir2crm(int, int, int);
44 static int el_act2crm(int, int);
46 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
47 static int request_gadget_id = -1;
49 static char *print_if_not_empty(int element)
51 static char *s = NULL;
52 char *token_name = element_info[element].token_name;
57 s = checked_malloc(strlen(token_name) + 10 + 1);
59 if (element != EL_EMPTY)
60 sprintf(s, "%d\t['%s']", element, token_name);
62 sprintf(s, "%d", element);
67 void DumpTile(int x, int y)
72 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
79 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
82 if (!IN_LEV_FIELD(x, y))
84 printf("(not in level field)\n");
90 printf(" Feld: %d\t['%s']\n", Feld[x][y],
91 element_info[Feld[x][y]].token_name);
92 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
93 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
94 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
95 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
96 printf(" MovPos: %d\n", MovPos[x][y]);
97 printf(" MovDir: %d\n", MovDir[x][y]);
98 printf(" MovDelay: %d\n", MovDelay[x][y]);
99 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
100 printf(" CustomValue: %d\n", CustomValue[x][y]);
101 printf(" GfxElement: %d\n", GfxElement[x][y]);
102 printf(" GfxAction: %d\n", GfxAction[x][y]);
103 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
107 void SetDrawtoField(int mode)
109 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
117 BX2 = SCR_FIELDX + 1;
118 BY2 = SCR_FIELDY + 1;
137 BX2 = SCR_FIELDX + 1;
138 BY2 = SCR_FIELDY + 1;
153 drawto_field = fieldbuffer;
155 else /* DRAW_BACKBUFFER */
161 BX2 = SCR_FIELDX - 1;
162 BY2 = SCR_FIELDY - 1;
166 drawto_field = backbuffer;
170 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
172 if (game_status == GAME_MODE_PLAYING &&
173 level.game_engine_type == GAME_ENGINE_TYPE_EM)
175 /* currently there is no partial redraw -- always redraw whole playfield */
176 RedrawPlayfield_EM(TRUE);
178 /* blit playfield from scroll buffer to normal back buffer for fading in */
179 BlitScreenToBitmap_EM(backbuffer);
181 else if (game_status == GAME_MODE_PLAYING &&
182 level.game_engine_type == GAME_ENGINE_TYPE_SP)
184 /* currently there is no partial redraw -- always redraw whole playfield */
185 RedrawPlayfield_SP(TRUE);
187 /* blit playfield from scroll buffer to normal back buffer for fading in */
188 BlitScreenToBitmap_SP(backbuffer);
190 else if (game_status == GAME_MODE_PLAYING &&
191 !game.envelope_active)
197 width = gfx.sxsize + 2 * TILEX;
198 height = gfx.sysize + 2 * TILEY;
204 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
205 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
207 for (xx = BX1; xx <= BX2; xx++)
208 for (yy = BY1; yy <= BY2; yy++)
209 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
210 DrawScreenField(xx, yy);
214 if (setup.soft_scrolling)
216 int fx = FX, fy = FY;
218 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
219 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
221 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
233 BlitBitmap(drawto, window, x, y, width, height, x, y);
236 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
238 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
240 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
241 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
244 void DrawMaskedBorder_FIELD()
246 if (global.border_status >= GAME_MODE_TITLE &&
247 global.border_status <= GAME_MODE_PLAYING &&
248 border.draw_masked[global.border_status])
249 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
252 void DrawMaskedBorder_DOOR_1()
254 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
255 (global.border_status != GAME_MODE_EDITOR ||
256 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
257 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
260 void DrawMaskedBorder_DOOR_2()
262 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
263 global.border_status != GAME_MODE_EDITOR)
264 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
267 void DrawMaskedBorder_DOOR_3()
269 /* currently not available */
272 void DrawMaskedBorder_ALL()
274 DrawMaskedBorder_FIELD();
275 DrawMaskedBorder_DOOR_1();
276 DrawMaskedBorder_DOOR_2();
277 DrawMaskedBorder_DOOR_3();
280 void DrawMaskedBorder(int redraw_mask)
282 /* never draw masked screen borders on borderless screens */
283 if (effectiveGameStatus() == GAME_MODE_LOADING ||
284 effectiveGameStatus() == GAME_MODE_TITLE)
287 /* never draw masked screen borders when displaying request outside door */
288 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
289 global.use_envelope_request)
292 if (redraw_mask & REDRAW_ALL)
293 DrawMaskedBorder_ALL();
296 if (redraw_mask & REDRAW_FIELD)
297 DrawMaskedBorder_FIELD();
298 if (redraw_mask & REDRAW_DOOR_1)
299 DrawMaskedBorder_DOOR_1();
300 if (redraw_mask & REDRAW_DOOR_2)
301 DrawMaskedBorder_DOOR_2();
302 if (redraw_mask & REDRAW_DOOR_3)
303 DrawMaskedBorder_DOOR_3();
307 void BlitScreenToBitmap(Bitmap *target_bitmap)
309 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
310 int fx = FX, fy = FY;
313 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
314 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
315 int dx_var = dx * TILESIZE_VAR / TILESIZE;
316 int dy_var = dy * TILESIZE_VAR / TILESIZE;
319 // fx += dx * TILESIZE_VAR / TILESIZE;
320 // fy += dy * TILESIZE_VAR / TILESIZE;
322 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
323 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
326 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
327 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
329 if (EVEN(SCR_FIELDX))
331 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
332 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
334 fx += (dx_var > 0 ? TILEX_VAR : 0);
341 if (EVEN(SCR_FIELDY))
343 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
344 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
346 fy += (dy_var > 0 ? TILEY_VAR : 0);
354 printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
357 SBY_Upper, SBY_Lower,
361 if (border.draw_masked[GAME_MODE_PLAYING])
363 if (buffer != backbuffer)
365 /* copy playfield buffer to backbuffer to add masked border */
366 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
367 DrawMaskedBorder(REDRAW_FIELD);
370 BlitBitmap(backbuffer, target_bitmap,
371 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
376 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
383 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
386 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
387 for (x = 0; x < SCR_FIELDX; x++)
388 for (y = 0 ; y < SCR_FIELDY; y++)
389 if (redraw[redraw_x1 + x][redraw_y1 + y])
390 printf("::: - %d, %d [%s]\n",
391 LEVELX(x), LEVELY(y),
392 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
395 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
396 redraw_mask |= REDRAW_FIELD;
399 // never redraw single tiles, always redraw the whole field
400 // (redrawing single tiles up to a certain threshold was faster on old,
401 // now legacy graphics, but slows things down on modern graphics now)
402 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
403 if (redraw_mask & REDRAW_TILES)
404 redraw_mask |= REDRAW_FIELD;
408 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
409 /* (force full redraw) */
410 if (game_status == GAME_MODE_PLAYING)
411 redraw_mask |= REDRAW_FIELD;
414 if (redraw_mask & REDRAW_FIELD)
415 redraw_mask &= ~REDRAW_TILES;
417 if (redraw_mask == REDRAW_NONE)
422 if (redraw_mask & REDRAW_ALL)
423 printf("[REDRAW_ALL]");
424 if (redraw_mask & REDRAW_FIELD)
425 printf("[REDRAW_FIELD]");
426 if (redraw_mask & REDRAW_TILES)
427 printf("[REDRAW_TILES]");
428 if (redraw_mask & REDRAW_DOOR_1)
429 printf("[REDRAW_DOOR_1]");
430 if (redraw_mask & REDRAW_DOOR_2)
431 printf("[REDRAW_DOOR_2]");
432 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
433 printf("[REDRAW_FROM_BACKBUFFER]");
434 printf(" [%d]\n", FrameCounter);
437 if (redraw_mask & REDRAW_TILES &&
438 game_status == GAME_MODE_PLAYING &&
439 border.draw_masked[GAME_MODE_PLAYING])
440 redraw_mask |= REDRAW_FIELD;
442 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
444 static boolean last_frame_skipped = FALSE;
445 boolean skip_even_when_not_scrolling = TRUE;
446 boolean just_scrolling = (ScreenMovDir != 0);
447 boolean verbose = FALSE;
449 if (global.fps_slowdown_factor > 1 &&
450 (FrameCounter % global.fps_slowdown_factor) &&
451 (just_scrolling || skip_even_when_not_scrolling))
453 redraw_mask &= ~REDRAW_MAIN;
455 last_frame_skipped = TRUE;
458 printf("FRAME SKIPPED\n");
462 if (last_frame_skipped)
463 redraw_mask |= REDRAW_FIELD;
465 last_frame_skipped = FALSE;
468 printf("frame not skipped\n");
472 /* synchronize X11 graphics at this point; if we would synchronize the
473 display immediately after the buffer switching (after the XFlush),
474 this could mean that we have to wait for the graphics to complete,
475 although we could go on doing calculations for the next frame */
479 /* never draw masked border to backbuffer when using playfield buffer */
480 if (game_status != GAME_MODE_PLAYING ||
481 redraw_mask & REDRAW_FROM_BACKBUFFER ||
482 buffer == backbuffer)
483 DrawMaskedBorder(redraw_mask);
485 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
487 if (redraw_mask & REDRAW_ALL)
489 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
491 redraw_mask = REDRAW_NONE;
494 if (redraw_mask & REDRAW_FIELD)
497 printf("::: REDRAW_FIELD\n");
500 if (game_status != GAME_MODE_PLAYING ||
501 redraw_mask & REDRAW_FROM_BACKBUFFER)
503 BlitBitmap(backbuffer, window,
504 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
509 BlitScreenToBitmap(window);
511 int fx = FX, fy = FY;
514 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
515 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
516 int dx_var = dx * TILESIZE_VAR / TILESIZE;
517 int dy_var = dy * TILESIZE_VAR / TILESIZE;
520 // fx += dx * TILESIZE_VAR / TILESIZE;
521 // fy += dy * TILESIZE_VAR / TILESIZE;
523 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
524 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
527 /* !!! THIS WORKS !!! */
529 printf("::: %d, %d\n", scroll_x, scroll_y);
531 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
532 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
534 if (EVEN(SCR_FIELDX))
536 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
537 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
539 fx += (dx > 0 ? TILEX_VAR : 0);
546 if (EVEN(SCR_FIELDY))
548 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
549 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
551 fy += (dy > 0 ? TILEY_VAR : 0);
558 if (border.draw_masked[GAME_MODE_PLAYING])
560 if (buffer != backbuffer)
562 /* copy playfield buffer to backbuffer to add masked border */
563 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
564 DrawMaskedBorder(REDRAW_FIELD);
567 BlitBitmap(backbuffer, window,
568 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
573 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
579 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
581 (setup.soft_scrolling ?
582 "setup.soft_scrolling" :
583 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
584 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
585 ABS(ScreenGfxPos) == ScrollStepSize ?
586 "ABS(ScreenGfxPos) == ScrollStepSize" :
587 "redraw_tiles > REDRAWTILES_THRESHOLD"));
592 redraw_mask &= ~REDRAW_MAIN;
595 if (redraw_mask & REDRAW_DOORS)
597 if (redraw_mask & REDRAW_DOOR_1)
598 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
600 if (redraw_mask & REDRAW_DOOR_2)
601 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
603 if (redraw_mask & REDRAW_DOOR_3)
604 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
606 redraw_mask &= ~REDRAW_DOORS;
609 if (redraw_mask & REDRAW_MICROLEVEL)
611 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
612 SX, SY + 10 * TILEY);
614 redraw_mask &= ~REDRAW_MICROLEVEL;
617 if (redraw_mask & REDRAW_TILES)
620 printf("::: REDRAW_TILES\n");
626 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
629 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
630 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
633 int dx_var = dx * TILESIZE_VAR / TILESIZE;
634 int dy_var = dy * TILESIZE_VAR / TILESIZE;
636 int fx = FX, fy = FY;
638 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
639 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
641 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
642 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
644 if (EVEN(SCR_FIELDX))
646 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
648 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
657 fx += (dx_var > 0 ? TILEX_VAR : 0);
661 if (EVEN(SCR_FIELDY))
663 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
665 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
674 fy += (dy_var > 0 ? TILEY_VAR : 0);
679 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
682 for (x = 0; x < scr_fieldx; x++)
683 for (y = 0 ; y < scr_fieldy; y++)
684 if (redraw[redraw_x1 + x][redraw_y1 + y])
685 BlitBitmap(buffer, window,
686 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
687 TILEX_VAR, TILEY_VAR,
688 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
691 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
693 for (x = 0; x < SCR_FIELDX; x++)
694 for (y = 0 ; y < SCR_FIELDY; y++)
695 if (redraw[redraw_x1 + x][redraw_y1 + y])
696 BlitBitmap(buffer, window,
697 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
698 TILEX_VAR, TILEY_VAR,
699 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
703 for (x = 0; x < SCR_FIELDX; x++)
704 for (y = 0 ; y < SCR_FIELDY; y++)
705 if (redraw[redraw_x1 + x][redraw_y1 + y])
706 BlitBitmap(buffer, window,
707 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
708 SX + x * TILEX, SY + y * TILEY);
712 if (redraw_mask & REDRAW_FPS) /* display frames per second */
717 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
718 if (!global.fps_slowdown)
721 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
723 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
725 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
731 for (x = 0; x < MAX_BUF_XSIZE; x++)
732 for (y = 0; y < MAX_BUF_YSIZE; y++)
735 redraw_mask = REDRAW_NONE;
738 static void FadeCrossSaveBackbuffer()
740 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
743 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
745 static int fade_type_skip = FADE_TYPE_NONE;
746 void (*draw_border_function)(void) = NULL;
747 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
748 int x, y, width, height;
749 int fade_delay, post_delay;
751 if (fade_type == FADE_TYPE_FADE_OUT)
753 if (fade_type_skip != FADE_TYPE_NONE)
756 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
759 /* skip all fade operations until specified fade operation */
760 if (fade_type & fade_type_skip)
761 fade_type_skip = FADE_TYPE_NONE;
766 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
768 FadeCrossSaveBackbuffer();
774 redraw_mask |= fade_mask;
776 if (fade_type == FADE_TYPE_SKIP)
779 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
782 fade_type_skip = fade_mode;
788 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
793 fade_delay = fading.fade_delay;
794 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
797 if (fade_type_skip != FADE_TYPE_NONE)
800 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
803 /* skip all fade operations until specified fade operation */
804 if (fade_type & fade_type_skip)
805 fade_type_skip = FADE_TYPE_NONE;
815 if (global.autoplay_leveldir)
817 // fading.fade_mode = FADE_MODE_NONE;
824 if (fading.fade_mode == FADE_MODE_NONE)
832 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
835 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
839 if (fade_mask == REDRAW_NONE)
840 fade_mask = REDRAW_FIELD;
843 // if (fade_mask & REDRAW_FIELD)
844 if (fade_mask == REDRAW_FIELD)
849 height = FULL_SYSIZE;
852 fade_delay = fading.fade_delay;
853 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
856 if (border.draw_masked_when_fading)
857 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
859 DrawMaskedBorder_FIELD(); /* draw once */
861 else /* REDRAW_ALL */
869 fade_delay = fading.fade_delay;
870 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
875 if (!setup.fade_screens ||
877 fading.fade_mode == FADE_MODE_NONE)
879 if (!setup.fade_screens || fade_delay == 0)
882 if (fade_mode == FADE_MODE_FADE_OUT)
886 if (fade_mode == FADE_MODE_FADE_OUT &&
887 fading.fade_mode != FADE_MODE_NONE)
888 ClearRectangle(backbuffer, x, y, width, height);
892 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
893 redraw_mask = REDRAW_NONE;
901 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
902 draw_border_function);
904 redraw_mask &= ~fade_mask;
907 void FadeIn(int fade_mask)
909 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
910 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
912 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
915 void FadeOut(int fade_mask)
917 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
918 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
920 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
922 global.border_status = game_status;
925 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
927 static struct TitleFadingInfo fading_leave_stored;
930 fading_leave_stored = fading_leave;
932 fading = fading_leave_stored;
935 void FadeSetEnterMenu()
937 fading = menu.enter_menu;
940 printf("::: storing enter_menu\n");
943 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
946 void FadeSetLeaveMenu()
948 fading = menu.leave_menu;
951 printf("::: storing leave_menu\n");
954 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
957 void FadeSetEnterScreen()
959 fading = menu.enter_screen[game_status];
962 printf("::: storing leave_screen[%d]\n", game_status);
965 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
968 void FadeSetNextScreen()
970 fading = menu.next_screen;
973 printf("::: storing next_screen\n");
976 // (do not overwrite fade mode set by FadeSetEnterScreen)
977 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
980 void FadeSetLeaveScreen()
983 printf("::: recalling last stored value\n");
986 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
989 void FadeSetFromType(int type)
991 if (type & TYPE_ENTER_SCREEN)
992 FadeSetEnterScreen();
993 else if (type & TYPE_ENTER)
995 else if (type & TYPE_LEAVE)
999 void FadeSetDisabled()
1001 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1003 fading = fading_none;
1006 void FadeSkipNextFadeIn()
1008 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1011 void FadeSkipNextFadeOut()
1013 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1016 void SetWindowBackgroundImageIfDefined(int graphic)
1018 if (graphic_info[graphic].bitmap)
1019 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1022 void SetMainBackgroundImageIfDefined(int graphic)
1024 if (graphic_info[graphic].bitmap)
1025 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1028 void SetDoorBackgroundImageIfDefined(int graphic)
1030 if (graphic_info[graphic].bitmap)
1031 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1034 void SetWindowBackgroundImage(int graphic)
1036 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1037 graphic_info[graphic].bitmap ?
1038 graphic_info[graphic].bitmap :
1039 graphic_info[IMG_BACKGROUND].bitmap);
1042 void SetMainBackgroundImage(int graphic)
1044 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1045 graphic_info[graphic].bitmap ?
1046 graphic_info[graphic].bitmap :
1047 graphic_info[IMG_BACKGROUND].bitmap);
1050 void SetDoorBackgroundImage(int graphic)
1052 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1053 graphic_info[graphic].bitmap ?
1054 graphic_info[graphic].bitmap :
1055 graphic_info[IMG_BACKGROUND].bitmap);
1058 void SetPanelBackground()
1061 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1064 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1065 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1067 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1068 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1069 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1070 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1073 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1074 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1077 SetDoorBackgroundBitmap(bitmap_db_panel);
1080 void DrawBackground(int x, int y, int width, int height)
1082 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1083 /* (when entering hall of fame after playing) */
1085 ClearRectangleOnBackground(drawto, x, y, width, height);
1087 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1091 /* (this only works for the current arrangement of playfield and panels) */
1093 redraw_mask |= REDRAW_FIELD;
1094 else if (y < gfx.vy)
1095 redraw_mask |= REDRAW_DOOR_1;
1097 redraw_mask |= REDRAW_DOOR_2;
1099 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1100 redraw_mask |= REDRAW_FIELD;
1104 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1106 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1108 if (font->bitmap == NULL)
1111 DrawBackground(x, y, width, height);
1114 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1116 struct GraphicInfo *g = &graphic_info[graphic];
1118 if (g->bitmap == NULL)
1121 DrawBackground(x, y, width, height);
1126 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1127 /* (when entering hall of fame after playing) */
1128 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1130 /* !!! maybe this should be done before clearing the background !!! */
1131 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1133 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1134 SetDrawtoField(DRAW_BUFFERED);
1137 SetDrawtoField(DRAW_BACKBUFFER);
1140 void MarkTileDirty(int x, int y)
1142 int xx = redraw_x1 + x;
1143 int yy = redraw_y1 + y;
1145 if (!redraw[xx][yy])
1148 redraw[xx][yy] = TRUE;
1149 redraw_mask |= REDRAW_TILES;
1152 void SetBorderElement()
1156 BorderElement = EL_EMPTY;
1158 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1160 for (x = 0; x < lev_fieldx; x++)
1162 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1163 BorderElement = EL_STEELWALL;
1165 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1171 void FloodFillLevel(int from_x, int from_y, int fill_element,
1172 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1173 int max_fieldx, int max_fieldy)
1177 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1178 static int safety = 0;
1180 /* check if starting field still has the desired content */
1181 if (field[from_x][from_y] == fill_element)
1186 if (safety > max_fieldx * max_fieldy)
1187 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1189 old_element = field[from_x][from_y];
1190 field[from_x][from_y] = fill_element;
1192 for (i = 0; i < 4; i++)
1194 x = from_x + check[i][0];
1195 y = from_y + check[i][1];
1197 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1198 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1204 void SetRandomAnimationValue(int x, int y)
1206 gfx.anim_random_frame = GfxRandom[x][y];
1209 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1211 /* animation synchronized with global frame counter, not move position */
1212 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1213 sync_frame = FrameCounter;
1215 return getAnimationFrame(graphic_info[graphic].anim_frames,
1216 graphic_info[graphic].anim_delay,
1217 graphic_info[graphic].anim_mode,
1218 graphic_info[graphic].anim_start_frame,
1222 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1223 Bitmap **bitmap, int *x, int *y,
1224 boolean get_backside)
1228 int width_mult, width_div;
1229 int height_mult, height_div;
1233 { 15, 16, 2, 3 }, /* 1 x 1 */
1234 { 7, 8, 2, 3 }, /* 2 x 2 */
1235 { 3, 4, 2, 3 }, /* 4 x 4 */
1236 { 1, 2, 2, 3 }, /* 8 x 8 */
1237 { 0, 1, 2, 3 }, /* 16 x 16 */
1238 { 0, 1, 0, 1 }, /* 32 x 32 */
1240 struct GraphicInfo *g = &graphic_info[graphic];
1241 Bitmap *src_bitmap = g->bitmap;
1242 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1243 int offset_calc_pos = log_2(tilesize);
1244 int width_mult = offset_calc[offset_calc_pos].width_mult;
1245 int width_div = offset_calc[offset_calc_pos].width_div;
1246 int height_mult = offset_calc[offset_calc_pos].height_mult;
1247 int height_div = offset_calc[offset_calc_pos].height_div;
1248 int startx = src_bitmap->width * width_mult / width_div;
1249 int starty = src_bitmap->height * height_mult / height_div;
1251 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1252 tilesize / TILESIZE;
1253 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1254 tilesize / TILESIZE;
1256 int src_x = g->src_x * tilesize / TILESIZE;
1257 int src_y = g->src_y * tilesize / TILESIZE;
1259 int width = g->width * tilesize / TILESIZE;
1260 int height = g->height * tilesize / TILESIZE;
1261 int offset_x = g->offset_x * tilesize / TILESIZE;
1262 int offset_y = g->offset_y * tilesize / TILESIZE;
1264 if (g->offset_y == 0) /* frames are ordered horizontally */
1266 int max_width = g->anim_frames_per_line * width;
1267 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1269 src_x = pos % max_width;
1270 src_y = src_y % height + pos / max_width * height;
1272 else if (g->offset_x == 0) /* frames are ordered vertically */
1274 int max_height = g->anim_frames_per_line * height;
1275 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1277 src_x = src_x % width + pos / max_height * width;
1278 src_y = pos % max_height;
1280 else /* frames are ordered diagonally */
1282 src_x = src_x + frame * offset_x;
1283 src_y = src_y + frame * offset_y;
1286 *bitmap = src_bitmap;
1287 *x = startx + src_x;
1288 *y = starty + src_y;
1291 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1292 int *x, int *y, boolean get_backside)
1294 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1298 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1299 Bitmap **bitmap, int *x, int *y)
1301 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1304 void getFixedGraphicSource(int graphic, int frame,
1305 Bitmap **bitmap, int *x, int *y)
1307 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1310 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1313 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1315 struct GraphicInfo *g = &graphic_info[graphic];
1316 int mini_startx = 0;
1317 int mini_starty = g->bitmap->height * 2 / 3;
1319 *bitmap = g->bitmap;
1320 *x = mini_startx + g->src_x / 2;
1321 *y = mini_starty + g->src_y / 2;
1325 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1326 int *x, int *y, boolean get_backside)
1328 struct GraphicInfo *g = &graphic_info[graphic];
1329 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1330 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1333 if (TILESIZE_VAR != TILESIZE)
1334 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1338 *bitmap = g->bitmap;
1340 if (g->offset_y == 0) /* frames are ordered horizontally */
1342 int max_width = g->anim_frames_per_line * g->width;
1343 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1345 *x = pos % max_width;
1346 *y = src_y % g->height + pos / max_width * g->height;
1348 else if (g->offset_x == 0) /* frames are ordered vertically */
1350 int max_height = g->anim_frames_per_line * g->height;
1351 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1353 *x = src_x % g->width + pos / max_height * g->width;
1354 *y = pos % max_height;
1356 else /* frames are ordered diagonally */
1358 *x = src_x + frame * g->offset_x;
1359 *y = src_y + frame * g->offset_y;
1363 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1365 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1368 void DrawGraphic(int x, int y, int graphic, int frame)
1371 if (!IN_SCR_FIELD(x, y))
1373 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1374 printf("DrawGraphic(): This should never happen!\n");
1380 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1383 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1385 MarkTileDirty(x, y);
1388 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1391 if (!IN_SCR_FIELD(x, y))
1393 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1394 printf("DrawGraphic(): This should never happen!\n");
1399 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1401 MarkTileDirty(x, y);
1404 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1410 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1412 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1414 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1418 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1424 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1425 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1428 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1431 if (!IN_SCR_FIELD(x, y))
1433 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1434 printf("DrawGraphicThruMask(): This should never happen!\n");
1440 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1443 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1446 MarkTileDirty(x, y);
1449 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1452 if (!IN_SCR_FIELD(x, y))
1454 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1455 printf("DrawGraphicThruMask(): This should never happen!\n");
1460 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1462 MarkTileDirty(x, y);
1465 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1471 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1473 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1474 dst_x - src_x, dst_y - src_y);
1476 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1479 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1483 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1484 int graphic, int frame)
1489 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1491 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1492 dst_x - src_x, dst_y - src_y);
1493 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1496 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1498 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1500 MarkTileDirty(x / tilesize, y / tilesize);
1503 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1509 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1510 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1513 void DrawMiniGraphic(int x, int y, int graphic)
1515 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1516 MarkTileDirty(x / 2, y / 2);
1519 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1524 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1525 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1528 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1529 int graphic, int frame,
1530 int cut_mode, int mask_mode)
1535 int width = TILEX, height = TILEY;
1538 if (dx || dy) /* shifted graphic */
1540 if (x < BX1) /* object enters playfield from the left */
1547 else if (x > BX2) /* object enters playfield from the right */
1553 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1559 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1561 else if (dx) /* general horizontal movement */
1562 MarkTileDirty(x + SIGN(dx), y);
1564 if (y < BY1) /* object enters playfield from the top */
1566 if (cut_mode==CUT_BELOW) /* object completely above top border */
1574 else if (y > BY2) /* object enters playfield from the bottom */
1580 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1586 else if (dy > 0 && cut_mode == CUT_ABOVE)
1588 if (y == BY2) /* object completely above bottom border */
1594 MarkTileDirty(x, y + 1);
1595 } /* object leaves playfield to the bottom */
1596 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1598 else if (dy) /* general vertical movement */
1599 MarkTileDirty(x, y + SIGN(dy));
1603 if (!IN_SCR_FIELD(x, y))
1605 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1606 printf("DrawGraphicShifted(): This should never happen!\n");
1612 width = width * TILESIZE_VAR / TILESIZE;
1613 height = height * TILESIZE_VAR / TILESIZE;
1614 cx = cx * TILESIZE_VAR / TILESIZE;
1615 cy = cy * TILESIZE_VAR / TILESIZE;
1616 dx = dx * TILESIZE_VAR / TILESIZE;
1617 dy = dy * TILESIZE_VAR / TILESIZE;
1620 if (width > 0 && height > 0)
1622 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1628 dst_x = FX + x * TILEX_VAR + dx;
1629 dst_y = FY + y * TILEY_VAR + dy;
1631 dst_x = FX + x * TILEX + dx;
1632 dst_y = FY + y * TILEY + dy;
1635 if (mask_mode == USE_MASKING)
1637 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1638 dst_x - src_x, dst_y - src_y);
1639 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1643 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1646 MarkTileDirty(x, y);
1650 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1651 int graphic, int frame,
1652 int cut_mode, int mask_mode)
1658 int width = TILEX_VAR, height = TILEY_VAR;
1660 int width = TILEX, height = TILEY;
1664 int x2 = x + SIGN(dx);
1665 int y2 = y + SIGN(dy);
1667 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1668 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1670 /* movement with two-tile animations must be sync'ed with movement position,
1671 not with current GfxFrame (which can be higher when using slow movement) */
1672 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1673 int anim_frames = graphic_info[graphic].anim_frames;
1675 /* (we also need anim_delay here for movement animations with less frames) */
1676 int anim_delay = graphic_info[graphic].anim_delay;
1677 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1679 int sync_frame = anim_pos * anim_frames / TILESIZE;
1682 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1683 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1685 /* re-calculate animation frame for two-tile movement animation */
1686 frame = getGraphicAnimationFrame(graphic, sync_frame);
1690 printf("::: %d, %d, %d => %d [%d]\n",
1691 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1693 printf("::: %d, %d => %d\n",
1694 anim_pos, anim_frames, sync_frame);
1699 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1700 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1703 /* check if movement start graphic inside screen area and should be drawn */
1704 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1706 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1709 dst_x = FX + x1 * TILEX_VAR;
1710 dst_y = FY + y1 * TILEY_VAR;
1712 dst_x = FX + x1 * TILEX;
1713 dst_y = FY + y1 * TILEY;
1716 if (mask_mode == USE_MASKING)
1718 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1719 dst_x - src_x, dst_y - src_y);
1720 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1724 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1727 MarkTileDirty(x1, y1);
1730 /* check if movement end graphic inside screen area and should be drawn */
1731 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1733 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1736 dst_x = FX + x2 * TILEX_VAR;
1737 dst_y = FY + y2 * TILEY_VAR;
1739 dst_x = FX + x2 * TILEX;
1740 dst_y = FY + y2 * TILEY;
1743 if (mask_mode == USE_MASKING)
1745 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1746 dst_x - src_x, dst_y - src_y);
1747 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1751 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1754 MarkTileDirty(x2, y2);
1758 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1759 int graphic, int frame,
1760 int cut_mode, int mask_mode)
1764 DrawGraphic(x, y, graphic, frame);
1769 if (graphic_info[graphic].double_movement) /* EM style movement images */
1770 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1772 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1775 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1776 int frame, int cut_mode)
1778 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1781 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1782 int cut_mode, int mask_mode)
1784 int lx = LEVELX(x), ly = LEVELY(y);
1788 if (IN_LEV_FIELD(lx, ly))
1790 SetRandomAnimationValue(lx, ly);
1792 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1793 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1795 /* do not use double (EM style) movement graphic when not moving */
1796 if (graphic_info[graphic].double_movement && !dx && !dy)
1798 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1799 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1802 else /* border element */
1804 graphic = el2img(element);
1805 frame = getGraphicAnimationFrame(graphic, -1);
1808 if (element == EL_EXPANDABLE_WALL)
1810 boolean left_stopped = FALSE, right_stopped = FALSE;
1812 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1813 left_stopped = TRUE;
1814 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1815 right_stopped = TRUE;
1817 if (left_stopped && right_stopped)
1819 else if (left_stopped)
1821 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1822 frame = graphic_info[graphic].anim_frames - 1;
1824 else if (right_stopped)
1826 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1827 frame = graphic_info[graphic].anim_frames - 1;
1832 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1833 else if (mask_mode == USE_MASKING)
1834 DrawGraphicThruMask(x, y, graphic, frame);
1836 DrawGraphic(x, y, graphic, frame);
1839 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1840 int cut_mode, int mask_mode)
1842 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1843 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1844 cut_mode, mask_mode);
1847 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1850 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1853 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1856 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1859 void DrawLevelElementThruMask(int x, int y, int element)
1861 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1864 void DrawLevelFieldThruMask(int x, int y)
1866 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1869 /* !!! implementation of quicksand is totally broken !!! */
1870 #define IS_CRUMBLED_TILE(x, y, e) \
1871 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1872 !IS_MOVING(x, y) || \
1873 (e) == EL_QUICKSAND_EMPTYING || \
1874 (e) == EL_QUICKSAND_FAST_EMPTYING))
1876 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1881 int width, height, cx, cy;
1882 int sx = SCREENX(x), sy = SCREENY(y);
1883 int crumbled_border_size = graphic_info[graphic].border_size;
1886 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1888 for (i = 1; i < 4; i++)
1890 int dxx = (i & 1 ? dx : 0);
1891 int dyy = (i & 2 ? dy : 0);
1894 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1897 /* check if neighbour field is of same crumble type */
1898 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1899 graphic_info[graphic].class ==
1900 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1902 /* return if check prevents inner corner */
1903 if (same == (dxx == dx && dyy == dy))
1907 /* if we reach this point, we have an inner corner */
1909 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1912 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1913 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1914 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1915 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1917 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1918 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1920 width = crumbled_border_size;
1921 height = crumbled_border_size;
1922 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1923 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1925 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1926 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1930 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1935 int width, height, bx, by, cx, cy;
1936 int sx = SCREENX(x), sy = SCREENY(y);
1937 int crumbled_border_size = graphic_info[graphic].border_size;
1940 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1942 /* draw simple, sloppy, non-corner-accurate crumbled border */
1945 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1946 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1947 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1948 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1950 if (dir == 1 || dir == 2) /* left or right crumbled border */
1952 width = crumbled_border_size;
1954 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1957 else /* top or bottom crumbled border */
1960 height = crumbled_border_size;
1962 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1967 BlitBitmap(src_bitmap, drawto_field,
1968 src_x + cx * TILESIZE_VAR / TILESIZE,
1969 src_y + cy * TILESIZE_VAR / TILESIZE,
1970 width * TILESIZE_VAR / TILESIZE,
1971 height * TILESIZE_VAR / TILESIZE,
1972 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
1973 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
1975 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1976 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1979 /* (remaining middle border part must be at least as big as corner part) */
1980 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1981 crumbled_border_size >= TILESIZE / 3)
1984 /* correct corners of crumbled border, if needed */
1987 for (i = -1; i <= 1; i+=2)
1989 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1990 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1991 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1994 /* check if neighbour field is of same crumble type */
1995 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1996 graphic_info[graphic].class ==
1997 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1999 /* no crumbled corner, but continued crumbled border */
2001 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2002 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2003 int b1 = (i == 1 ? crumbled_border_size :
2004 TILESIZE - 2 * crumbled_border_size);
2006 width = crumbled_border_size;
2007 height = crumbled_border_size;
2009 if (dir == 1 || dir == 2)
2025 BlitBitmap(src_bitmap, drawto_field,
2026 src_x + bx * TILESIZE_VAR / TILESIZE,
2027 src_y + by * TILESIZE_VAR / TILESIZE,
2028 width * TILESIZE_VAR / TILESIZE,
2029 height * TILESIZE_VAR / TILESIZE,
2030 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2031 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2033 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2034 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2039 if (dir == 1 || dir == 2) /* left or right crumbled border */
2041 for (i = -1; i <= 1; i+=2)
2045 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2048 /* check if neighbour field is of same crumble type */
2049 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2050 graphic_info[graphic].class ==
2051 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2053 /* no crumbled corner, but continued crumbled border */
2055 width = crumbled_border_size;
2056 height = crumbled_border_size;
2057 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2058 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2060 by = (i == 1 ? crumbled_border_size :
2061 TILEY - 2 * crumbled_border_size);
2063 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2064 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2068 else /* top or bottom crumbled border */
2070 for (i = -1; i <= 1; i+=2)
2074 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2077 /* check if neighbour field is of same crumble type */
2078 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2079 graphic_info[graphic].class ==
2080 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2082 /* no crumbled corner, but continued crumbled border */
2084 width = crumbled_border_size;
2085 height = crumbled_border_size;
2086 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2087 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2088 bx = (i == 1 ? crumbled_border_size :
2089 TILEX - 2 * crumbled_border_size);
2092 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2093 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2100 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2102 int sx = SCREENX(x), sy = SCREENY(y);
2105 static int xy[4][2] =
2113 if (!IN_LEV_FIELD(x, y))
2116 element = TILE_GFX_ELEMENT(x, y);
2118 /* crumble field itself */
2119 if (IS_CRUMBLED_TILE(x, y, element))
2121 if (!IN_SCR_FIELD(sx, sy))
2124 for (i = 0; i < 4; i++)
2126 int xx = x + xy[i][0];
2127 int yy = y + xy[i][1];
2129 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2132 /* check if neighbour field is of same crumble type */
2134 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2135 graphic_info[graphic].class ==
2136 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2139 if (IS_CRUMBLED_TILE(xx, yy, element))
2143 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2146 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2147 graphic_info[graphic].anim_frames == 2)
2149 for (i = 0; i < 4; i++)
2151 int dx = (i & 1 ? +1 : -1);
2152 int dy = (i & 2 ? +1 : -1);
2154 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2158 MarkTileDirty(sx, sy);
2160 else /* center field not crumbled -- crumble neighbour fields */
2162 for (i = 0; i < 4; i++)
2164 int xx = x + xy[i][0];
2165 int yy = y + xy[i][1];
2166 int sxx = sx + xy[i][0];
2167 int syy = sy + xy[i][1];
2169 if (!IN_LEV_FIELD(xx, yy) ||
2170 !IN_SCR_FIELD(sxx, syy))
2173 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2176 element = TILE_GFX_ELEMENT(xx, yy);
2178 if (!IS_CRUMBLED_TILE(xx, yy, element))
2181 graphic = el_act2crm(element, ACTION_DEFAULT);
2183 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2185 MarkTileDirty(sxx, syy);
2190 void DrawLevelFieldCrumbled(int x, int y)
2194 if (!IN_LEV_FIELD(x, y))
2198 /* !!! CHECK THIS !!! */
2201 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2202 GFX_CRUMBLED(GfxElement[x][y]))
2205 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2206 GfxElement[x][y] != EL_UNDEFINED &&
2207 GFX_CRUMBLED(GfxElement[x][y]))
2209 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2216 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2218 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2221 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2224 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2227 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2228 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2229 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2230 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2231 int sx = SCREENX(x), sy = SCREENY(y);
2233 DrawGraphic(sx, sy, graphic1, frame1);
2234 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2237 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2239 int sx = SCREENX(x), sy = SCREENY(y);
2240 static int xy[4][2] =
2249 for (i = 0; i < 4; i++)
2251 int xx = x + xy[i][0];
2252 int yy = y + xy[i][1];
2253 int sxx = sx + xy[i][0];
2254 int syy = sy + xy[i][1];
2256 if (!IN_LEV_FIELD(xx, yy) ||
2257 !IN_SCR_FIELD(sxx, syy) ||
2258 !GFX_CRUMBLED(Feld[xx][yy]) ||
2262 DrawLevelField(xx, yy);
2266 static int getBorderElement(int x, int y)
2270 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2271 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2272 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2273 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2274 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2275 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2276 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2278 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2279 int steel_position = (x == -1 && y == -1 ? 0 :
2280 x == lev_fieldx && y == -1 ? 1 :
2281 x == -1 && y == lev_fieldy ? 2 :
2282 x == lev_fieldx && y == lev_fieldy ? 3 :
2283 x == -1 || x == lev_fieldx ? 4 :
2284 y == -1 || y == lev_fieldy ? 5 : 6);
2286 return border[steel_position][steel_type];
2289 void DrawScreenElement(int x, int y, int element)
2291 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2292 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2295 void DrawLevelElement(int x, int y, int element)
2297 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2298 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2301 void DrawScreenField(int x, int y)
2303 int lx = LEVELX(x), ly = LEVELY(y);
2304 int element, content;
2306 if (!IN_LEV_FIELD(lx, ly))
2308 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2311 element = getBorderElement(lx, ly);
2313 DrawScreenElement(x, y, element);
2318 element = Feld[lx][ly];
2319 content = Store[lx][ly];
2321 if (IS_MOVING(lx, ly))
2323 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2324 boolean cut_mode = NO_CUTTING;
2326 if (element == EL_QUICKSAND_EMPTYING ||
2327 element == EL_QUICKSAND_FAST_EMPTYING ||
2328 element == EL_MAGIC_WALL_EMPTYING ||
2329 element == EL_BD_MAGIC_WALL_EMPTYING ||
2330 element == EL_DC_MAGIC_WALL_EMPTYING ||
2331 element == EL_AMOEBA_DROPPING)
2332 cut_mode = CUT_ABOVE;
2333 else if (element == EL_QUICKSAND_FILLING ||
2334 element == EL_QUICKSAND_FAST_FILLING ||
2335 element == EL_MAGIC_WALL_FILLING ||
2336 element == EL_BD_MAGIC_WALL_FILLING ||
2337 element == EL_DC_MAGIC_WALL_FILLING)
2338 cut_mode = CUT_BELOW;
2341 if (lx == 9 && ly == 1)
2342 printf("::: %s [%d] [%d, %d] [%d]\n",
2343 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2344 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2345 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2346 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2347 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2350 if (cut_mode == CUT_ABOVE)
2352 DrawScreenElement(x, y, element);
2354 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2357 DrawScreenElement(x, y, EL_EMPTY);
2360 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2361 else if (cut_mode == NO_CUTTING)
2362 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2365 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2368 if (cut_mode == CUT_BELOW &&
2369 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2370 DrawLevelElement(lx, ly + 1, element);
2374 if (content == EL_ACID)
2376 int dir = MovDir[lx][ly];
2377 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2378 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2380 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2383 else if (IS_BLOCKED(lx, ly))
2388 boolean cut_mode = NO_CUTTING;
2389 int element_old, content_old;
2391 Blocked2Moving(lx, ly, &oldx, &oldy);
2394 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2395 MovDir[oldx][oldy] == MV_RIGHT);
2397 element_old = Feld[oldx][oldy];
2398 content_old = Store[oldx][oldy];
2400 if (element_old == EL_QUICKSAND_EMPTYING ||
2401 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2402 element_old == EL_MAGIC_WALL_EMPTYING ||
2403 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2404 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2405 element_old == EL_AMOEBA_DROPPING)
2406 cut_mode = CUT_ABOVE;
2408 DrawScreenElement(x, y, EL_EMPTY);
2411 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2413 else if (cut_mode == NO_CUTTING)
2414 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2417 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2420 else if (IS_DRAWABLE(element))
2421 DrawScreenElement(x, y, element);
2423 DrawScreenElement(x, y, EL_EMPTY);
2426 void DrawLevelField(int x, int y)
2428 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2429 DrawScreenField(SCREENX(x), SCREENY(y));
2430 else if (IS_MOVING(x, y))
2434 Moving2Blocked(x, y, &newx, &newy);
2435 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2436 DrawScreenField(SCREENX(newx), SCREENY(newy));
2438 else if (IS_BLOCKED(x, y))
2442 Blocked2Moving(x, y, &oldx, &oldy);
2443 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2444 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2448 void DrawMiniElement(int x, int y, int element)
2452 graphic = el2edimg(element);
2453 DrawMiniGraphic(x, y, graphic);
2456 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2458 int x = sx + scroll_x, y = sy + scroll_y;
2460 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2461 DrawMiniElement(sx, sy, EL_EMPTY);
2462 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2463 DrawMiniElement(sx, sy, Feld[x][y]);
2465 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2468 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2469 int x, int y, int xsize, int ysize,
2470 int tile_width, int tile_height)
2474 int dst_x = startx + x * tile_width;
2475 int dst_y = starty + y * tile_height;
2476 int width = graphic_info[graphic].width;
2477 int height = graphic_info[graphic].height;
2478 int inner_width = MAX(width - 2 * tile_width, tile_width);
2479 int inner_height = MAX(height - 2 * tile_height, tile_height);
2480 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2481 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2482 boolean draw_masked = graphic_info[graphic].draw_masked;
2484 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2486 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2488 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2492 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2493 inner_sx + (x - 1) * tile_width % inner_width);
2494 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2495 inner_sy + (y - 1) * tile_height % inner_height);
2499 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2500 dst_x - src_x, dst_y - src_y);
2501 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2505 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2509 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2510 int x, int y, int xsize, int ysize, int font_nr)
2512 int font_width = getFontWidth(font_nr);
2513 int font_height = getFontHeight(font_nr);
2515 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2516 font_width, font_height);
2519 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2521 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2522 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2523 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2524 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2525 boolean no_delay = (tape.warp_forward);
2526 unsigned int anim_delay = 0;
2527 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2528 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2529 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2530 int font_width = getFontWidth(font_nr);
2531 int font_height = getFontHeight(font_nr);
2532 int max_xsize = level.envelope[envelope_nr].xsize;
2533 int max_ysize = level.envelope[envelope_nr].ysize;
2534 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2535 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2536 int xend = max_xsize;
2537 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2538 int xstep = (xstart < xend ? 1 : 0);
2539 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2542 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2544 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2545 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2546 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2547 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2550 SetDrawtoField(DRAW_BUFFERED);
2553 BlitScreenToBitmap(backbuffer);
2555 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2558 SetDrawtoField(DRAW_BACKBUFFER);
2560 for (yy = 0; yy < ysize; yy++)
2561 for (xx = 0; xx < xsize; xx++)
2562 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2565 DrawTextBuffer(sx + font_width, sy + font_height,
2566 level.envelope[envelope_nr].text, font_nr, max_xsize,
2567 xsize - 2, ysize - 2, 0, mask_mode,
2568 level.envelope[envelope_nr].autowrap,
2569 level.envelope[envelope_nr].centered, FALSE);
2571 DrawTextToTextArea(sx + font_width, sy + font_height,
2572 level.envelope[envelope_nr].text, font_nr, max_xsize,
2573 xsize - 2, ysize - 2, mask_mode);
2576 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2579 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2583 void ShowEnvelope(int envelope_nr)
2585 int element = EL_ENVELOPE_1 + envelope_nr;
2586 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2587 int sound_opening = element_info[element].sound[ACTION_OPENING];
2588 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2589 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2590 boolean no_delay = (tape.warp_forward);
2591 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2592 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2593 int anim_mode = graphic_info[graphic].anim_mode;
2594 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2595 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2597 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2599 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2601 if (anim_mode == ANIM_DEFAULT)
2602 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2604 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2607 Delay(wait_delay_value);
2609 WaitForEventToContinue();
2611 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2613 if (anim_mode != ANIM_NONE)
2614 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2616 if (anim_mode == ANIM_DEFAULT)
2617 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2619 game.envelope_active = FALSE;
2621 SetDrawtoField(DRAW_BUFFERED);
2623 redraw_mask |= REDRAW_FIELD;
2627 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2629 int border_size = request.border_size;
2630 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2631 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2632 int sx = sx_center - request.width / 2;
2633 int sy = sy_center - request.height / 2;
2635 if (add_border_size)
2645 void DrawEnvelopeRequest(char *text)
2647 int graphic = IMG_BACKGROUND_REQUEST;
2648 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2649 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2650 int font_nr = FONT_REQUEST;
2651 int font_width = getFontWidth(font_nr);
2652 int font_height = getFontHeight(font_nr);
2653 int border_size = request.border_size;
2654 int line_spacing = request.line_spacing;
2655 int line_height = font_height + line_spacing;
2656 int text_width = request.width - 2 * border_size;
2657 int text_height = request.height - 2 * border_size;
2658 int line_length = text_width / font_width;
2659 int max_lines = text_height / line_height;
2660 boolean autowrap = FALSE;
2661 boolean centered = TRUE;
2662 int width = request.width;
2663 int height = request.height;
2664 int tile_size = request.step_offset;
2665 int x_steps = width / tile_size;
2666 int y_steps = height / tile_size;
2670 setRequestPosition(&sx, &sy, FALSE);
2672 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2674 for (y = 0; y < y_steps; y++)
2675 for (x = 0; x < x_steps; x++)
2676 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2677 x, y, x_steps, y_steps,
2678 tile_size, tile_size);
2680 DrawTextBuffer(sx + border_size, sy + border_size, text, font_nr,
2681 line_length, -1, max_lines, line_spacing, mask_mode,
2682 autowrap, centered, FALSE);
2684 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2685 RedrawGadget(tool_gadget[i]);
2687 // store readily prepared envelope request for later use when animating
2688 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2692 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2693 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
2695 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2700 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2702 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2711 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
2713 int graphic = IMG_BACKGROUND_REQUEST;
2714 boolean draw_masked = graphic_info[graphic].draw_masked;
2716 int delay_value_normal = request.step_delay;
2717 int delay_value_fast = delay_value_normal / 2;
2719 int delay_value_normal = GameFrameDelay;
2720 int delay_value_fast = FfwdFrameDelay;
2722 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2723 boolean no_delay = (tape.warp_forward);
2724 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2725 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
2726 unsigned int anim_delay = 0;
2728 int width = request.width;
2729 int height = request.height;
2730 int tile_size = request.step_offset;
2731 int max_xsize = width / tile_size;
2732 int max_ysize = height / tile_size;
2733 int max_xsize_inner = max_xsize - 2;
2734 int max_ysize_inner = max_ysize - 2;
2736 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2737 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2738 int xend = max_xsize_inner;
2739 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2740 int xstep = (xstart < xend ? 1 : 0);
2741 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2744 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2746 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2747 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2748 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2749 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2750 int src_x = sx_center - width / 2;
2751 int src_y = sy_center - height / 2;
2752 int dst_x = sx_center - xsize * tile_size / 2;
2753 int dst_y = sy_center - ysize * tile_size / 2;
2754 int xsize_size_left = (xsize - 1) * tile_size;
2755 int ysize_size_top = (ysize - 1) * tile_size;
2756 int max_xsize_pos = (max_xsize - 1) * tile_size;
2757 int max_ysize_pos = (max_ysize - 1) * tile_size;
2760 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2763 for (yy = 0; yy < 2; yy++)
2765 for (xx = 0; xx < 2; xx++)
2767 int src_xx = src_x + xx * max_xsize_pos;
2768 int src_yy = src_y + yy * max_ysize_pos;
2769 int dst_xx = dst_x + xx * xsize_size_left;
2770 int dst_yy = dst_y + yy * ysize_size_top;
2771 int xx_size = (xx ? tile_size : xsize_size_left);
2772 int yy_size = (yy ? tile_size : ysize_size_top);
2775 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2776 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2778 BlitBitmap(bitmap_db_cross, backbuffer,
2779 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2783 BlitBitmap(bitmap_db_cross, backbuffer,
2785 xsize_size_left, ysize_size_top,
2787 BlitBitmap(bitmap_db_cross, backbuffer,
2788 src_x + max_xsize_pos, src_y,
2789 tile_size, ysize_size_top,
2790 dst_x + xsize_size_left, dst_y);
2791 BlitBitmap(bitmap_db_cross, backbuffer,
2792 src_x, src_y + max_ysize_pos,
2793 xsize_size_left, tile_size,
2794 dst_x, dst_y + ysize_size_top);
2795 BlitBitmap(bitmap_db_cross, backbuffer,
2796 src_x + max_xsize_pos, src_y + max_ysize_pos,
2797 tile_size, tile_size,
2798 dst_x + xsize_size_left, dst_y + ysize_size_top);
2802 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2803 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2805 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2815 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2821 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
2824 int envelope_nr = 0;
2827 int graphic = IMG_BACKGROUND_REQUEST;
2829 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2831 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2832 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2833 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2834 boolean no_delay = (tape.warp_forward);
2835 unsigned int anim_delay = 0;
2836 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2837 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
2839 int max_word_len = maxWordLengthInString(text);
2840 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2842 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2844 int font_width = getFontWidth(font_nr);
2845 int font_height = getFontHeight(font_nr);
2846 int line_spacing = 2 * 1;
2850 int max_xsize = DXSIZE / font_width;
2851 // int max_ysize = DYSIZE / font_height;
2852 int max_ysize = DYSIZE / (font_height + line_spacing);
2854 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2855 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
2859 int max_xsize = level.envelope[envelope_nr].xsize;
2860 int max_ysize = level.envelope[envelope_nr].ysize;
2862 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2863 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2864 int xend = max_xsize;
2865 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2866 int xstep = (xstart < xend ? 1 : 0);
2867 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2872 char *text_copy = getStringCopy(text);
2875 font_nr = FONT_TEXT_2;
2877 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2879 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2880 font_nr = FONT_TEXT_1;
2883 int max_word_len = 0;
2885 char *text_copy = getStringCopy(text);
2887 font_nr = FONT_TEXT_2;
2889 for (text_ptr = text; *text_ptr; text_ptr++)
2891 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2893 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2895 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2896 font_nr = FONT_TEXT_1;
2905 for (text_ptr = text_copy; *text_ptr; text_ptr++)
2906 if (*text_ptr == ' ')
2911 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2912 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2914 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
2915 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2918 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2920 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2921 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2922 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2923 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
2924 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
2928 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2930 SetDrawtoField(DRAW_BUFFERED);
2933 BlitScreenToBitmap(backbuffer);
2935 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2938 SetDrawtoField(DRAW_BACKBUFFER);
2941 for (yy = 0; yy < ysize; yy++)
2942 for (xx = 0; xx < xsize; xx++)
2943 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
2944 getFontWidth(font_nr),
2945 getFontHeight(font_nr) + line_spacing);
2950 DrawTextBuffer(sx + font_width, sy + font_height + 8,
2951 text_copy, font_nr, max_xsize,
2952 xsize - 2, ysize - 2, line_spacing, mask_mode,
2953 FALSE, TRUE, FALSE);
2955 DrawTextBuffer(sx + font_width, sy + font_height,
2956 level.envelope[envelope_nr].text, font_nr, max_xsize,
2957 xsize - 2, ysize - 2, 0, mask_mode,
2958 level.envelope[envelope_nr].autowrap,
2959 level.envelope[envelope_nr].centered, FALSE);
2963 DrawTextToTextArea(sx + font_width, sy + font_height,
2964 level.envelope[envelope_nr].text, font_nr, max_xsize,
2965 xsize - 2, ysize - 2, mask_mode);
2968 /* copy request gadgets to door backbuffer */
2971 if ((ysize - 2) > 13)
2972 BlitBitmap(bitmap_db_door, drawto,
2973 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2974 DOOR_GFX_PAGEY1 + 13 * font_height,
2975 (xsize - 2) * font_width,
2976 (ysize - 2 - 13) * font_height,
2978 sy + font_height * (1 + 13));
2980 if ((ysize - 2) > 13)
2981 BlitBitmap(bitmap_db_door, drawto,
2982 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2983 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
2984 (xsize - 2) * font_width,
2985 (ysize - 2 - 13) * (font_height + line_spacing),
2987 sy + (font_height + line_spacing) * (1 + 13));
2989 if ((ysize - 2) > 13)
2990 BlitBitmap(bitmap_db_door, drawto,
2991 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2992 DOOR_GFX_PAGEY1 + 13 * font_height,
2993 (xsize - 2) * font_width,
2994 (ysize - 2 - 13) * font_height,
2996 sy + font_height * (1 + 13));
3000 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3001 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3003 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3013 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3023 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3026 int last_game_status = game_status; /* save current game status */
3027 // int last_draw_background_mask = gfx.draw_background_mask;
3030 int graphic = IMG_BACKGROUND_REQUEST;
3031 int sound_opening = SND_REQUEST_OPENING;
3032 int sound_closing = SND_REQUEST_CLOSING;
3034 int envelope_nr = 0;
3035 int element = EL_ENVELOPE_1 + envelope_nr;
3036 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3037 int sound_opening = element_info[element].sound[ACTION_OPENING];
3038 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3041 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3042 boolean no_delay = (tape.warp_forward);
3043 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3044 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3046 int anim_mode = graphic_info[graphic].anim_mode;
3047 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3048 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3049 char *text_copy = getStringCopy(text);
3052 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3053 if (*text_ptr == ' ')
3057 if (game_status == GAME_MODE_PLAYING)
3059 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3060 BlitScreenToBitmap_EM(backbuffer);
3061 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3062 BlitScreenToBitmap_SP(backbuffer);
3065 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3069 SetDrawtoField(DRAW_BACKBUFFER);
3071 // SetDrawBackgroundMask(REDRAW_NONE);
3073 if (action == ACTION_OPENING)
3075 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3078 if (req_state & REQ_ASK)
3080 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3081 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3083 else if (req_state & REQ_CONFIRM)
3085 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3087 else if (req_state & REQ_PLAYER)
3089 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3090 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3091 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3092 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3096 DrawEnvelopeRequest(text_copy);
3098 if (game_status != GAME_MODE_MAIN)
3102 /* force DOOR font inside door area */
3103 game_status = GAME_MODE_PSEUDO_DOOR;
3106 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3108 if (action == ACTION_OPENING)
3110 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3112 if (anim_mode == ANIM_DEFAULT)
3113 AnimateEnvelopeRequest(text, ANIM_DEFAULT, ACTION_OPENING);
3115 AnimateEnvelopeRequest(text, main_anim_mode, ACTION_OPENING);
3119 Delay(wait_delay_value);
3121 WaitForEventToContinue();
3126 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3128 if (anim_mode != ANIM_NONE)
3129 AnimateEnvelopeRequest(text, main_anim_mode, ACTION_CLOSING);
3131 if (anim_mode == ANIM_DEFAULT)
3132 AnimateEnvelopeRequest(text, ANIM_DEFAULT, ACTION_CLOSING);
3135 game.envelope_active = FALSE;
3138 // game_status = last_game_status; /* restore current game status */
3140 if (action == ACTION_CLOSING)
3142 if (game_status != GAME_MODE_MAIN)
3145 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3148 SetDrawtoField(DRAW_BUFFERED);
3151 // SetDrawBackgroundMask(last_draw_background_mask);
3154 redraw_mask = REDRAW_FIELD;
3155 // redraw_mask |= REDRAW_ALL;
3157 redraw_mask |= REDRAW_FIELD;
3161 if (game_status == GAME_MODE_MAIN)
3166 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3167 game_status = last_game_status; /* restore current game status */
3170 if (action == ACTION_CLOSING &&
3171 game_status == GAME_MODE_PLAYING &&
3172 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3173 SetDrawtoField(DRAW_BUFFERED);
3175 if (game_status == GAME_MODE_PLAYING &&
3176 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3177 SetDrawtoField(DRAW_BUFFERED);
3187 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3191 int graphic = el2preimg(element);
3193 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3194 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3202 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3203 SetDrawBackgroundMask(REDRAW_FIELD);
3205 SetDrawBackgroundMask(REDRAW_NONE);
3210 for (x = BX1; x <= BX2; x++)
3211 for (y = BY1; y <= BY2; y++)
3212 DrawScreenField(x, y);
3214 redraw_mask |= REDRAW_FIELD;
3217 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3221 for (x = 0; x < size_x; x++)
3222 for (y = 0; y < size_y; y++)
3223 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3225 redraw_mask |= REDRAW_FIELD;
3228 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3230 boolean show_level_border = (BorderElement != EL_EMPTY);
3231 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3232 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3233 int tile_size = preview.tile_size;
3234 int preview_width = preview.xsize * tile_size;
3235 int preview_height = preview.ysize * tile_size;
3236 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3237 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3238 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3239 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3242 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3244 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
3245 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
3247 for (x = 0; x < real_preview_xsize; x++)
3249 for (y = 0; y < real_preview_ysize; y++)
3251 int lx = from_x + x + (show_level_border ? -1 : 0);
3252 int ly = from_y + y + (show_level_border ? -1 : 0);
3253 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3254 getBorderElement(lx, ly));
3256 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3257 element, tile_size);
3261 redraw_mask |= REDRAW_MICROLEVEL;
3264 #define MICROLABEL_EMPTY 0
3265 #define MICROLABEL_LEVEL_NAME 1
3266 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3267 #define MICROLABEL_LEVEL_AUTHOR 3
3268 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3269 #define MICROLABEL_IMPORTED_FROM 5
3270 #define MICROLABEL_IMPORTED_BY_HEAD 6
3271 #define MICROLABEL_IMPORTED_BY 7
3273 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3275 int max_text_width = SXSIZE;
3276 int font_width = getFontWidth(font_nr);
3278 if (pos->align == ALIGN_CENTER)
3279 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3280 else if (pos->align == ALIGN_RIGHT)
3281 max_text_width = pos->x;
3283 max_text_width = SXSIZE - pos->x;
3285 return max_text_width / font_width;
3288 static void DrawPreviewLevelLabelExt(int mode)
3290 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3291 char label_text[MAX_OUTPUT_LINESIZE + 1];
3292 int max_len_label_text;
3294 int font_nr = pos->font;
3297 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3298 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3299 mode == MICROLABEL_IMPORTED_BY_HEAD)
3300 font_nr = pos->font_alt;
3302 int font_nr = FONT_TEXT_2;
3305 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3306 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3307 mode == MICROLABEL_IMPORTED_BY_HEAD)
3308 font_nr = FONT_TEXT_3;
3312 max_len_label_text = getMaxTextLength(pos, font_nr);
3314 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3318 if (pos->size != -1)
3319 max_len_label_text = pos->size;
3322 for (i = 0; i < max_len_label_text; i++)
3323 label_text[i] = ' ';
3324 label_text[max_len_label_text] = '\0';
3326 if (strlen(label_text) > 0)
3329 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3331 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3332 int lypos = MICROLABEL2_YPOS;
3334 DrawText(lxpos, lypos, label_text, font_nr);
3339 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3340 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3341 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3342 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3343 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3344 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3345 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3346 max_len_label_text);
3347 label_text[max_len_label_text] = '\0';
3349 if (strlen(label_text) > 0)
3352 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3354 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3355 int lypos = MICROLABEL2_YPOS;
3357 DrawText(lxpos, lypos, label_text, font_nr);
3361 redraw_mask |= REDRAW_MICROLEVEL;
3364 static void DrawPreviewLevelExt(boolean restart)
3366 static unsigned int scroll_delay = 0;
3367 static unsigned int label_delay = 0;
3368 static int from_x, from_y, scroll_direction;
3369 static int label_state, label_counter;
3370 unsigned int scroll_delay_value = preview.step_delay;
3371 boolean show_level_border = (BorderElement != EL_EMPTY);
3372 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3373 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3374 int last_game_status = game_status; /* save current game status */
3377 /* force PREVIEW font on preview level */
3378 game_status = GAME_MODE_PSEUDO_PREVIEW;
3386 if (preview.anim_mode == ANIM_CENTERED)
3388 if (level_xsize > preview.xsize)
3389 from_x = (level_xsize - preview.xsize) / 2;
3390 if (level_ysize > preview.ysize)
3391 from_y = (level_ysize - preview.ysize) / 2;
3394 from_x += preview.xoffset;
3395 from_y += preview.yoffset;
3397 scroll_direction = MV_RIGHT;
3401 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3402 DrawPreviewLevelLabelExt(label_state);
3404 /* initialize delay counters */
3405 DelayReached(&scroll_delay, 0);
3406 DelayReached(&label_delay, 0);
3408 if (leveldir_current->name)
3410 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3411 char label_text[MAX_OUTPUT_LINESIZE + 1];
3413 int font_nr = pos->font;
3415 int font_nr = FONT_TEXT_1;
3418 int max_len_label_text = getMaxTextLength(pos, font_nr);
3420 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3428 if (pos->size != -1)
3429 max_len_label_text = pos->size;
3432 strncpy(label_text, leveldir_current->name, max_len_label_text);
3433 label_text[max_len_label_text] = '\0';
3436 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3438 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3439 lypos = SY + MICROLABEL1_YPOS;
3441 DrawText(lxpos, lypos, label_text, font_nr);
3445 game_status = last_game_status; /* restore current game status */
3450 /* scroll preview level, if needed */
3451 if (preview.anim_mode != ANIM_NONE &&
3452 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3453 DelayReached(&scroll_delay, scroll_delay_value))
3455 switch (scroll_direction)
3460 from_x -= preview.step_offset;
3461 from_x = (from_x < 0 ? 0 : from_x);
3464 scroll_direction = MV_UP;
3468 if (from_x < level_xsize - preview.xsize)
3470 from_x += preview.step_offset;
3471 from_x = (from_x > level_xsize - preview.xsize ?
3472 level_xsize - preview.xsize : from_x);
3475 scroll_direction = MV_DOWN;
3481 from_y -= preview.step_offset;
3482 from_y = (from_y < 0 ? 0 : from_y);
3485 scroll_direction = MV_RIGHT;
3489 if (from_y < level_ysize - preview.ysize)
3491 from_y += preview.step_offset;
3492 from_y = (from_y > level_ysize - preview.ysize ?
3493 level_ysize - preview.ysize : from_y);
3496 scroll_direction = MV_LEFT;
3503 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3506 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3507 /* redraw micro level label, if needed */
3508 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3509 !strEqual(level.author, ANONYMOUS_NAME) &&
3510 !strEqual(level.author, leveldir_current->name) &&
3511 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3513 int max_label_counter = 23;
3515 if (leveldir_current->imported_from != NULL &&
3516 strlen(leveldir_current->imported_from) > 0)
3517 max_label_counter += 14;
3518 if (leveldir_current->imported_by != NULL &&
3519 strlen(leveldir_current->imported_by) > 0)
3520 max_label_counter += 14;
3522 label_counter = (label_counter + 1) % max_label_counter;
3523 label_state = (label_counter >= 0 && label_counter <= 7 ?
3524 MICROLABEL_LEVEL_NAME :
3525 label_counter >= 9 && label_counter <= 12 ?
3526 MICROLABEL_LEVEL_AUTHOR_HEAD :
3527 label_counter >= 14 && label_counter <= 21 ?
3528 MICROLABEL_LEVEL_AUTHOR :
3529 label_counter >= 23 && label_counter <= 26 ?
3530 MICROLABEL_IMPORTED_FROM_HEAD :
3531 label_counter >= 28 && label_counter <= 35 ?
3532 MICROLABEL_IMPORTED_FROM :
3533 label_counter >= 37 && label_counter <= 40 ?
3534 MICROLABEL_IMPORTED_BY_HEAD :
3535 label_counter >= 42 && label_counter <= 49 ?
3536 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3538 if (leveldir_current->imported_from == NULL &&
3539 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3540 label_state == MICROLABEL_IMPORTED_FROM))
3541 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3542 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3544 DrawPreviewLevelLabelExt(label_state);
3547 game_status = last_game_status; /* restore current game status */
3550 void DrawPreviewLevelInitial()
3552 DrawPreviewLevelExt(TRUE);
3555 void DrawPreviewLevelAnimation()
3557 DrawPreviewLevelExt(FALSE);
3560 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3561 int graphic, int sync_frame, int mask_mode)
3563 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3565 if (mask_mode == USE_MASKING)
3566 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3568 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3571 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3572 int graphic, int sync_frame,
3575 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3577 if (mask_mode == USE_MASKING)
3578 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3580 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3583 inline void DrawGraphicAnimation(int x, int y, int graphic)
3585 int lx = LEVELX(x), ly = LEVELY(y);
3587 if (!IN_SCR_FIELD(x, y))
3591 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3592 graphic, GfxFrame[lx][ly], NO_MASKING);
3594 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3595 graphic, GfxFrame[lx][ly], NO_MASKING);
3597 MarkTileDirty(x, y);
3600 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3602 int lx = LEVELX(x), ly = LEVELY(y);
3604 if (!IN_SCR_FIELD(x, y))
3607 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3608 graphic, GfxFrame[lx][ly], NO_MASKING);
3609 MarkTileDirty(x, y);
3612 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3614 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3617 void DrawLevelElementAnimation(int x, int y, int element)
3619 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3621 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3624 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3626 int sx = SCREENX(x), sy = SCREENY(y);
3628 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3631 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3634 DrawGraphicAnimation(sx, sy, graphic);
3637 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3638 DrawLevelFieldCrumbled(x, y);
3640 if (GFX_CRUMBLED(Feld[x][y]))
3641 DrawLevelFieldCrumbled(x, y);
3645 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3647 int sx = SCREENX(x), sy = SCREENY(y);
3650 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3653 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3655 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3658 DrawGraphicAnimation(sx, sy, graphic);
3660 if (GFX_CRUMBLED(element))
3661 DrawLevelFieldCrumbled(x, y);
3664 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3666 if (player->use_murphy)
3668 /* this works only because currently only one player can be "murphy" ... */
3669 static int last_horizontal_dir = MV_LEFT;
3670 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3672 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3673 last_horizontal_dir = move_dir;
3675 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3677 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3679 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3685 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3688 static boolean equalGraphics(int graphic1, int graphic2)
3690 struct GraphicInfo *g1 = &graphic_info[graphic1];
3691 struct GraphicInfo *g2 = &graphic_info[graphic2];
3693 return (g1->bitmap == g2->bitmap &&
3694 g1->src_x == g2->src_x &&
3695 g1->src_y == g2->src_y &&
3696 g1->anim_frames == g2->anim_frames &&
3697 g1->anim_delay == g2->anim_delay &&
3698 g1->anim_mode == g2->anim_mode);
3701 void DrawAllPlayers()
3705 for (i = 0; i < MAX_PLAYERS; i++)
3706 if (stored_player[i].active)
3707 DrawPlayer(&stored_player[i]);
3710 void DrawPlayerField(int x, int y)
3712 if (!IS_PLAYER(x, y))
3715 DrawPlayer(PLAYERINFO(x, y));
3718 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3720 void DrawPlayer(struct PlayerInfo *player)
3722 int jx = player->jx;
3723 int jy = player->jy;
3724 int move_dir = player->MovDir;
3725 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3726 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3727 int last_jx = (player->is_moving ? jx - dx : jx);
3728 int last_jy = (player->is_moving ? jy - dy : jy);
3729 int next_jx = jx + dx;
3730 int next_jy = jy + dy;
3731 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3732 boolean player_is_opaque = FALSE;
3733 int sx = SCREENX(jx), sy = SCREENY(jy);
3734 int sxx = 0, syy = 0;
3735 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3737 int action = ACTION_DEFAULT;
3738 int last_player_graphic = getPlayerGraphic(player, move_dir);
3739 int last_player_frame = player->Frame;
3742 /* GfxElement[][] is set to the element the player is digging or collecting;
3743 remove also for off-screen player if the player is not moving anymore */
3744 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3745 GfxElement[jx][jy] = EL_UNDEFINED;
3747 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3751 if (!IN_LEV_FIELD(jx, jy))
3753 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3754 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3755 printf("DrawPlayerField(): This should never happen!\n");
3760 if (element == EL_EXPLOSION)
3763 action = (player->is_pushing ? ACTION_PUSHING :
3764 player->is_digging ? ACTION_DIGGING :
3765 player->is_collecting ? ACTION_COLLECTING :
3766 player->is_moving ? ACTION_MOVING :
3767 player->is_snapping ? ACTION_SNAPPING :
3768 player->is_dropping ? ACTION_DROPPING :
3769 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3771 if (player->is_waiting)
3772 move_dir = player->dir_waiting;
3774 InitPlayerGfxAnimation(player, action, move_dir);
3776 /* ----------------------------------------------------------------------- */
3777 /* draw things in the field the player is leaving, if needed */
3778 /* ----------------------------------------------------------------------- */
3780 if (player->is_moving)
3782 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3784 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3786 if (last_element == EL_DYNAMITE_ACTIVE ||
3787 last_element == EL_EM_DYNAMITE_ACTIVE ||
3788 last_element == EL_SP_DISK_RED_ACTIVE)
3789 DrawDynamite(last_jx, last_jy);
3791 DrawLevelFieldThruMask(last_jx, last_jy);
3793 else if (last_element == EL_DYNAMITE_ACTIVE ||
3794 last_element == EL_EM_DYNAMITE_ACTIVE ||
3795 last_element == EL_SP_DISK_RED_ACTIVE)
3796 DrawDynamite(last_jx, last_jy);
3798 /* !!! this is not enough to prevent flickering of players which are
3799 moving next to each others without a free tile between them -- this
3800 can only be solved by drawing all players layer by layer (first the
3801 background, then the foreground etc.) !!! => TODO */
3802 else if (!IS_PLAYER(last_jx, last_jy))
3803 DrawLevelField(last_jx, last_jy);
3806 DrawLevelField(last_jx, last_jy);
3809 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3810 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3813 if (!IN_SCR_FIELD(sx, sy))
3816 /* ----------------------------------------------------------------------- */
3817 /* draw things behind the player, if needed */
3818 /* ----------------------------------------------------------------------- */
3821 DrawLevelElement(jx, jy, Back[jx][jy]);
3822 else if (IS_ACTIVE_BOMB(element))
3823 DrawLevelElement(jx, jy, EL_EMPTY);
3826 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3828 int old_element = GfxElement[jx][jy];
3829 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3830 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3832 if (GFX_CRUMBLED(old_element))
3833 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3835 DrawGraphic(sx, sy, old_graphic, frame);
3837 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3838 player_is_opaque = TRUE;
3842 GfxElement[jx][jy] = EL_UNDEFINED;
3844 /* make sure that pushed elements are drawn with correct frame rate */
3846 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3848 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3849 GfxFrame[jx][jy] = player->StepFrame;
3851 if (player->is_pushing && player->is_moving)
3852 GfxFrame[jx][jy] = player->StepFrame;
3855 DrawLevelField(jx, jy);
3859 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3860 /* ----------------------------------------------------------------------- */
3861 /* draw player himself */
3862 /* ----------------------------------------------------------------------- */
3864 graphic = getPlayerGraphic(player, move_dir);
3866 /* in the case of changed player action or direction, prevent the current
3867 animation frame from being restarted for identical animations */
3868 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3869 player->Frame = last_player_frame;
3871 frame = getGraphicAnimationFrame(graphic, player->Frame);
3875 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3876 sxx = player->GfxPos;
3878 syy = player->GfxPos;
3881 if (!setup.soft_scrolling && ScreenMovPos)
3884 if (player_is_opaque)
3885 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3887 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3889 if (SHIELD_ON(player))
3891 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3892 IMG_SHIELD_NORMAL_ACTIVE);
3893 int frame = getGraphicAnimationFrame(graphic, -1);
3895 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3899 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3902 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3903 sxx = player->GfxPos;
3905 syy = player->GfxPos;
3909 /* ----------------------------------------------------------------------- */
3910 /* draw things the player is pushing, if needed */
3911 /* ----------------------------------------------------------------------- */
3914 printf("::: %d, %d [%d, %d] [%d]\n",
3915 player->is_pushing, player_is_moving, player->GfxAction,
3916 player->is_moving, player_is_moving);
3920 if (player->is_pushing && player->is_moving)
3922 int px = SCREENX(jx), py = SCREENY(jy);
3923 int pxx = (TILEX - ABS(sxx)) * dx;
3924 int pyy = (TILEY - ABS(syy)) * dy;
3925 int gfx_frame = GfxFrame[jx][jy];
3931 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3933 element = Feld[next_jx][next_jy];
3934 gfx_frame = GfxFrame[next_jx][next_jy];
3937 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3940 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3941 frame = getGraphicAnimationFrame(graphic, sync_frame);
3943 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3946 /* draw background element under pushed element (like the Sokoban field) */
3948 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3950 /* this allows transparent pushing animation over non-black background */
3953 DrawLevelElement(jx, jy, Back[jx][jy]);
3955 DrawLevelElement(jx, jy, EL_EMPTY);
3957 if (Back[next_jx][next_jy])
3958 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3960 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3962 else if (Back[next_jx][next_jy])
3963 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3965 if (Back[next_jx][next_jy])
3966 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3970 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3971 jx, px, player->GfxPos, player->StepFrame,
3976 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3980 /* do not draw (EM style) pushing animation when pushing is finished */
3981 /* (two-tile animations usually do not contain start and end frame) */
3982 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3983 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3985 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3987 /* masked drawing is needed for EMC style (double) movement graphics */
3988 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3989 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3994 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3995 /* ----------------------------------------------------------------------- */
3996 /* draw player himself */
3997 /* ----------------------------------------------------------------------- */
3999 graphic = getPlayerGraphic(player, move_dir);
4001 /* in the case of changed player action or direction, prevent the current
4002 animation frame from being restarted for identical animations */
4003 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4004 player->Frame = last_player_frame;
4006 frame = getGraphicAnimationFrame(graphic, player->Frame);
4010 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4011 sxx = player->GfxPos;
4013 syy = player->GfxPos;
4016 if (!setup.soft_scrolling && ScreenMovPos)
4019 if (player_is_opaque)
4020 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4022 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4024 if (SHIELD_ON(player))
4026 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4027 IMG_SHIELD_NORMAL_ACTIVE);
4028 int frame = getGraphicAnimationFrame(graphic, -1);
4030 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4034 /* ----------------------------------------------------------------------- */
4035 /* draw things in front of player (active dynamite or dynabombs) */
4036 /* ----------------------------------------------------------------------- */
4038 if (IS_ACTIVE_BOMB(element))
4040 graphic = el2img(element);
4041 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4043 if (game.emulation == EMU_SUPAPLEX)
4044 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4046 DrawGraphicThruMask(sx, sy, graphic, frame);
4049 if (player_is_moving && last_element == EL_EXPLOSION)
4051 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4052 GfxElement[last_jx][last_jy] : EL_EMPTY);
4053 int graphic = el_act2img(element, ACTION_EXPLODING);
4054 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4055 int phase = ExplodePhase[last_jx][last_jy] - 1;
4056 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4059 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4062 /* ----------------------------------------------------------------------- */
4063 /* draw elements the player is just walking/passing through/under */
4064 /* ----------------------------------------------------------------------- */
4066 if (player_is_moving)
4068 /* handle the field the player is leaving ... */
4069 if (IS_ACCESSIBLE_INSIDE(last_element))
4070 DrawLevelField(last_jx, last_jy);
4071 else if (IS_ACCESSIBLE_UNDER(last_element))
4072 DrawLevelFieldThruMask(last_jx, last_jy);
4075 /* do not redraw accessible elements if the player is just pushing them */
4076 if (!player_is_moving || !player->is_pushing)
4078 /* ... and the field the player is entering */
4079 if (IS_ACCESSIBLE_INSIDE(element))
4080 DrawLevelField(jx, jy);
4081 else if (IS_ACCESSIBLE_UNDER(element))
4082 DrawLevelFieldThruMask(jx, jy);
4085 MarkTileDirty(sx, sy);
4088 /* ------------------------------------------------------------------------- */
4090 void WaitForEventToContinue()
4092 boolean still_wait = TRUE;
4094 /* simulate releasing mouse button over last gadget, if still pressed */
4096 HandleGadgets(-1, -1, 0);
4098 button_status = MB_RELEASED;
4114 case EVENT_BUTTONPRESS:
4115 case EVENT_KEYPRESS:
4119 case EVENT_KEYRELEASE:
4120 ClearPlayerAction();
4124 HandleOtherEvents(&event);
4128 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4135 /* don't eat all CPU time */
4140 #define MAX_REQUEST_LINES 13
4141 #define MAX_REQUEST_LINE_FONT1_LEN 7
4142 #define MAX_REQUEST_LINE_FONT2_LEN 10
4146 static int RequestHandleEvents(unsigned int req_state)
4148 int last_game_status = game_status; /* save current game status */
4152 button_status = MB_RELEASED;
4154 request_gadget_id = -1;
4167 case EVENT_BUTTONPRESS:
4168 case EVENT_BUTTONRELEASE:
4169 case EVENT_MOTIONNOTIFY:
4171 if (event.type == EVENT_MOTIONNOTIFY)
4173 if (!PointerInWindow(window))
4174 continue; /* window and pointer are on different screens */
4179 motion_status = TRUE;
4180 mx = ((MotionEvent *) &event)->x;
4181 my = ((MotionEvent *) &event)->y;
4185 motion_status = FALSE;
4186 mx = ((ButtonEvent *) &event)->x;
4187 my = ((ButtonEvent *) &event)->y;
4188 if (event.type == EVENT_BUTTONPRESS)
4189 button_status = ((ButtonEvent *) &event)->button;
4191 button_status = MB_RELEASED;
4194 /* this sets 'request_gadget_id' */
4195 HandleGadgets(mx, my, button_status);
4197 switch (request_gadget_id)
4199 case TOOL_CTRL_ID_YES:
4202 case TOOL_CTRL_ID_NO:
4205 case TOOL_CTRL_ID_CONFIRM:
4206 result = TRUE | FALSE;
4209 case TOOL_CTRL_ID_PLAYER_1:
4212 case TOOL_CTRL_ID_PLAYER_2:
4215 case TOOL_CTRL_ID_PLAYER_3:
4218 case TOOL_CTRL_ID_PLAYER_4:
4229 case EVENT_KEYPRESS:
4230 switch (GetEventKey((KeyEvent *)&event, TRUE))
4233 if (req_state & REQ_CONFIRM)
4242 #if defined(TARGET_SDL2)
4252 if (req_state & REQ_PLAYER)
4256 case EVENT_KEYRELEASE:
4257 ClearPlayerAction();
4261 HandleOtherEvents(&event);
4265 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4267 int joy = AnyJoystick();
4269 if (joy & JOY_BUTTON_1)
4271 else if (joy & JOY_BUTTON_2)
4277 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4279 HandleGameActions();
4285 if (!PendingEvent()) /* delay only if no pending events */
4290 game_status = GAME_MODE_PSEUDO_DOOR;
4296 game_status = last_game_status; /* restore current game status */
4304 if (!PendingEvent()) /* delay only if no pending events */
4307 /* don't eat all CPU time */
4317 static boolean RequestDoor(char *text, unsigned int req_state)
4319 unsigned int old_door_state;
4320 int last_game_status = game_status; /* save current game status */
4321 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4322 int font_nr = FONT_TEXT_2;
4327 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4329 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4330 font_nr = FONT_TEXT_1;
4333 if (game_status == GAME_MODE_PLAYING)
4335 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4336 BlitScreenToBitmap_EM(backbuffer);
4337 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4338 BlitScreenToBitmap_SP(backbuffer);
4341 /* disable deactivated drawing when quick-loading level tape recording */
4342 if (tape.playing && tape.deactivate_display)
4343 TapeDeactivateDisplayOff(TRUE);
4345 SetMouseCursor(CURSOR_DEFAULT);
4347 #if defined(NETWORK_AVALIABLE)
4348 /* pause network game while waiting for request to answer */
4349 if (options.network &&
4350 game_status == GAME_MODE_PLAYING &&
4351 req_state & REQUEST_WAIT_FOR_INPUT)
4352 SendToServer_PausePlaying();
4355 old_door_state = GetDoorState();
4357 /* simulate releasing mouse button over last gadget, if still pressed */
4359 HandleGadgets(-1, -1, 0);
4363 /* draw released gadget before proceeding */
4366 if (old_door_state & DOOR_OPEN_1)
4368 CloseDoor(DOOR_CLOSE_1);
4370 /* save old door content */
4371 BlitBitmap(bitmap_db_door, bitmap_db_door,
4372 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4373 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4376 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4377 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4379 /* clear door drawing field */
4380 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4382 /* force DOOR font inside door area */
4383 game_status = GAME_MODE_PSEUDO_DOOR;
4385 /* write text for request */
4386 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4388 char text_line[max_request_line_len + 1];
4394 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4396 tc = *(text_ptr + tx);
4397 if (!tc || tc == ' ')
4408 strncpy(text_line, text_ptr, tl);
4411 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4412 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4413 text_line, font_nr);
4415 text_ptr += tl + (tc == ' ' ? 1 : 0);
4418 game_status = last_game_status; /* restore current game status */
4420 if (req_state & REQ_ASK)
4422 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4423 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4425 else if (req_state & REQ_CONFIRM)
4427 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4429 else if (req_state & REQ_PLAYER)
4431 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4432 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4433 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4434 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4437 /* copy request gadgets to door backbuffer */
4438 BlitBitmap(drawto, bitmap_db_door,
4439 DX, DY, DXSIZE, DYSIZE,
4440 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4442 OpenDoor(DOOR_OPEN_1);
4444 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4446 if (game_status == GAME_MODE_PLAYING)
4448 SetPanelBackground();
4449 SetDrawBackgroundMask(REDRAW_DOOR_1);
4453 SetDrawBackgroundMask(REDRAW_FIELD);
4459 if (game_status != GAME_MODE_MAIN)
4462 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4464 // ---------- handle request buttons ----------
4465 result = RequestHandleEvents(req_state);
4467 if (game_status != GAME_MODE_MAIN)
4472 if (!(req_state & REQ_STAY_OPEN))
4474 CloseDoor(DOOR_CLOSE_1);
4476 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4477 (req_state & REQ_REOPEN))
4478 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4483 if (game_status == GAME_MODE_PLAYING)
4485 SetPanelBackground();
4486 SetDrawBackgroundMask(REDRAW_DOOR_1);
4490 SetDrawBackgroundMask(REDRAW_FIELD);
4493 #if defined(NETWORK_AVALIABLE)
4494 /* continue network game after request */
4495 if (options.network &&
4496 game_status == GAME_MODE_PLAYING &&
4497 req_state & REQUEST_WAIT_FOR_INPUT)
4498 SendToServer_ContinuePlaying();
4501 /* restore deactivated drawing when quick-loading level tape recording */
4502 if (tape.playing && tape.deactivate_display)
4503 TapeDeactivateDisplayOn();
4508 static boolean RequestEnvelope(char *text, unsigned int req_state)
4515 if (game_status == GAME_MODE_PLAYING)
4517 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4518 BlitScreenToBitmap_EM(backbuffer);
4519 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4520 BlitScreenToBitmap_SP(backbuffer);
4523 /* disable deactivated drawing when quick-loading level tape recording */
4524 if (tape.playing && tape.deactivate_display)
4525 TapeDeactivateDisplayOff(TRUE);
4527 SetMouseCursor(CURSOR_DEFAULT);
4529 #if defined(NETWORK_AVALIABLE)
4530 /* pause network game while waiting for request to answer */
4531 if (options.network &&
4532 game_status == GAME_MODE_PLAYING &&
4533 req_state & REQUEST_WAIT_FOR_INPUT)
4534 SendToServer_PausePlaying();
4537 /* simulate releasing mouse button over last gadget, if still pressed */
4539 HandleGadgets(-1, -1, 0);
4543 // (replace with setting corresponding request background)
4544 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4545 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4547 /* clear door drawing field */
4548 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4551 if (global.use_envelope_request)
4555 CreateToolButtons();
4561 if (req_state & REQ_ASK)
4563 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4564 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4566 else if (req_state & REQ_CONFIRM)
4568 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4570 else if (req_state & REQ_PLAYER)
4572 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4573 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4574 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4575 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4578 if (req_state & REQ_ASK)
4580 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4581 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4583 else if (req_state & REQ_CONFIRM)
4585 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4587 else if (req_state & REQ_PLAYER)
4589 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4590 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4591 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4592 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4597 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4600 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4602 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4603 i == TOOL_CTRL_ID_NO)) ||
4604 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4605 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4606 i == TOOL_CTRL_ID_PLAYER_2 &&
4607 i == TOOL_CTRL_ID_PLAYER_3 &&
4608 i == TOOL_CTRL_ID_PLAYER_4)))
4610 int x = tool_gadget[i]->x + dDX;
4611 int y = tool_gadget[i]->y + dDY;
4613 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4618 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4620 if (game_status == GAME_MODE_PLAYING)
4622 SetPanelBackground();
4623 SetDrawBackgroundMask(REDRAW_DOOR_1);
4627 SetDrawBackgroundMask(REDRAW_FIELD);
4634 if (game_status != GAME_MODE_MAIN)
4638 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4640 // ---------- handle request buttons ----------
4641 result = RequestHandleEvents(req_state);
4643 if (game_status != GAME_MODE_MAIN)
4648 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4652 if (game_status == GAME_MODE_PLAYING)
4654 SetPanelBackground();
4655 SetDrawBackgroundMask(REDRAW_DOOR_1);
4659 SetDrawBackgroundMask(REDRAW_FIELD);
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();
4670 /* restore deactivated drawing when quick-loading level tape recording */
4671 if (tape.playing && tape.deactivate_display)
4672 TapeDeactivateDisplayOn();
4677 boolean Request(char *text, unsigned int req_state)
4679 if (global.use_envelope_request)
4680 return RequestEnvelope(text, req_state);
4682 return RequestDoor(text, req_state);
4685 #else // =====================================================================
4687 boolean Request(char *text, unsigned int req_state)
4689 int mx, my, ty, result = -1;
4690 unsigned int old_door_state;
4691 int last_game_status = game_status; /* save current game status */
4692 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4693 int font_nr = FONT_TEXT_2;
4695 int max_word_len = 0;
4701 global.use_envelope_request = 1;
4705 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4707 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4708 font_nr = FONT_TEXT_1;
4711 for (text_ptr = text; *text_ptr; text_ptr++)
4713 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
4715 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
4717 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4719 font_nr = FONT_TEXT_1;
4721 font_nr = FONT_LEVEL_NUMBER;
4729 if (game_status == GAME_MODE_PLAYING)
4731 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4732 BlitScreenToBitmap_EM(backbuffer);
4733 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4734 BlitScreenToBitmap_SP(backbuffer);
4737 /* disable deactivated drawing when quick-loading level tape recording */
4738 if (tape.playing && tape.deactivate_display)
4739 TapeDeactivateDisplayOff(TRUE);
4741 SetMouseCursor(CURSOR_DEFAULT);
4743 #if defined(NETWORK_AVALIABLE)
4744 /* pause network game while waiting for request to answer */
4745 if (options.network &&
4746 game_status == GAME_MODE_PLAYING &&
4747 req_state & REQUEST_WAIT_FOR_INPUT)
4748 SendToServer_PausePlaying();
4751 old_door_state = GetDoorState();
4753 /* simulate releasing mouse button over last gadget, if still pressed */
4755 HandleGadgets(-1, -1, 0);
4759 /* draw released gadget before proceeding */
4763 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
4765 if (old_door_state & DOOR_OPEN_1)
4769 if (!global.use_envelope_request)
4770 CloseDoor(DOOR_CLOSE_1);
4772 CloseDoor(DOOR_CLOSE_1);
4775 /* save old door content */
4776 BlitBitmap(bitmap_db_door, bitmap_db_door,
4777 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4778 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4782 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4785 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4787 /* clear door drawing field */
4788 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4790 /* force DOOR font inside door area */
4791 game_status = GAME_MODE_PSEUDO_DOOR;
4793 /* write text for request */
4794 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4796 char text_line[max_request_line_len + 1];
4802 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4804 tc = *(text_ptr + tx);
4805 if (!tc || tc == ' ')
4816 strncpy(text_line, text_ptr, tl);
4819 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4820 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4821 text_line, font_nr);
4823 text_ptr += tl + (tc == ' ' ? 1 : 0);
4826 game_status = last_game_status; /* restore current game status */
4829 if (global.use_envelope_request)
4833 CreateToolButtons();
4837 if (req_state & REQ_ASK)
4839 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4840 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4842 else if (req_state & REQ_CONFIRM)
4844 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4846 else if (req_state & REQ_PLAYER)
4848 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4849 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4850 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4851 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4854 /* copy request gadgets to door backbuffer */
4855 BlitBitmap(drawto, bitmap_db_door,
4856 DX, DY, DXSIZE, DYSIZE,
4857 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4860 if (global.use_envelope_request)
4862 ShowEnvelopeRequest(text, ACTION_OPENING);
4864 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4866 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4867 i == TOOL_CTRL_ID_NO)) ||
4868 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4869 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4870 i == TOOL_CTRL_ID_PLAYER_2 &&
4871 i == TOOL_CTRL_ID_PLAYER_3 &&
4872 i == TOOL_CTRL_ID_PLAYER_4)))
4874 int x = tool_gadget[i]->x + dDX;
4875 int y = tool_gadget[i]->y + dDY;
4877 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4884 if (!global.use_envelope_request)
4885 OpenDoor(DOOR_OPEN_1);
4887 OpenDoor(DOOR_OPEN_1);
4890 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4892 if (game_status == GAME_MODE_PLAYING)
4894 SetPanelBackground();
4895 SetDrawBackgroundMask(REDRAW_DOOR_1);
4899 SetDrawBackgroundMask(REDRAW_FIELD);
4906 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
4909 if (game_status != GAME_MODE_MAIN)
4913 button_status = MB_RELEASED;
4915 request_gadget_id = -1;
4917 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4929 case EVENT_BUTTONPRESS:
4930 case EVENT_BUTTONRELEASE:
4931 case EVENT_MOTIONNOTIFY:
4933 if (event.type == EVENT_MOTIONNOTIFY)
4935 if (!PointerInWindow(window))
4936 continue; /* window and pointer are on different screens */
4941 motion_status = TRUE;
4942 mx = ((MotionEvent *) &event)->x;
4943 my = ((MotionEvent *) &event)->y;
4947 motion_status = FALSE;
4948 mx = ((ButtonEvent *) &event)->x;
4949 my = ((ButtonEvent *) &event)->y;
4950 if (event.type == EVENT_BUTTONPRESS)
4951 button_status = ((ButtonEvent *) &event)->button;
4953 button_status = MB_RELEASED;
4956 /* this sets 'request_gadget_id' */
4957 HandleGadgets(mx, my, button_status);
4959 switch (request_gadget_id)
4961 case TOOL_CTRL_ID_YES:
4964 case TOOL_CTRL_ID_NO:
4967 case TOOL_CTRL_ID_CONFIRM:
4968 result = TRUE | FALSE;
4971 case TOOL_CTRL_ID_PLAYER_1:
4974 case TOOL_CTRL_ID_PLAYER_2:
4977 case TOOL_CTRL_ID_PLAYER_3:
4980 case TOOL_CTRL_ID_PLAYER_4:
4991 case EVENT_KEYPRESS:
4992 switch (GetEventKey((KeyEvent *)&event, TRUE))
4995 if (req_state & REQ_CONFIRM)
5004 #if defined(TARGET_SDL2)
5014 if (req_state & REQ_PLAYER)
5018 case EVENT_KEYRELEASE:
5019 ClearPlayerAction();
5023 HandleOtherEvents(&event);
5027 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5029 int joy = AnyJoystick();
5031 if (joy & JOY_BUTTON_1)
5033 else if (joy & JOY_BUTTON_2)
5039 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5041 HandleGameActions();
5047 if (!PendingEvent()) /* delay only if no pending events */
5052 game_status = GAME_MODE_PSEUDO_DOOR;
5058 game_status = last_game_status; /* restore current game status */
5066 if (!PendingEvent()) /* delay only if no pending events */
5069 /* don't eat all CPU time */
5076 if (game_status != GAME_MODE_MAIN)
5082 if (global.use_envelope_request)
5083 ShowEnvelopeRequest(text, ACTION_CLOSING);
5087 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5089 if (!(req_state & REQ_STAY_OPEN))
5092 CloseDoor(DOOR_CLOSE_1);
5094 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5095 (req_state & REQ_REOPEN))
5096 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5101 if (game_status == GAME_MODE_PLAYING)
5103 SetPanelBackground();
5104 SetDrawBackgroundMask(REDRAW_DOOR_1);
5108 SetDrawBackgroundMask(REDRAW_FIELD);
5111 #if defined(NETWORK_AVALIABLE)
5112 /* continue network game after request */
5113 if (options.network &&
5114 game_status == GAME_MODE_PLAYING &&
5115 req_state & REQUEST_WAIT_FOR_INPUT)
5116 SendToServer_ContinuePlaying();
5119 /* restore deactivated drawing when quick-loading level tape recording */
5120 if (tape.playing && tape.deactivate_display)
5121 TapeDeactivateDisplayOn();
5128 unsigned int OpenDoor(unsigned int door_state)
5130 if (door_state & DOOR_COPY_BACK)
5132 if (door_state & DOOR_OPEN_1)
5133 BlitBitmap(bitmap_db_door, bitmap_db_door,
5134 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5135 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5137 if (door_state & DOOR_OPEN_2)
5138 BlitBitmap(bitmap_db_door, bitmap_db_door,
5139 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5140 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5142 door_state &= ~DOOR_COPY_BACK;
5145 return MoveDoor(door_state);
5148 unsigned int CloseDoor(unsigned int door_state)
5150 unsigned int old_door_state = GetDoorState();
5152 if (!(door_state & DOOR_NO_COPY_BACK))
5154 if (old_door_state & DOOR_OPEN_1)
5155 BlitBitmap(backbuffer, bitmap_db_door,
5156 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5158 if (old_door_state & DOOR_OPEN_2)
5159 BlitBitmap(backbuffer, bitmap_db_door,
5160 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5162 door_state &= ~DOOR_NO_COPY_BACK;
5165 return MoveDoor(door_state);
5168 unsigned int GetDoorState()
5170 return MoveDoor(DOOR_GET_STATE);
5173 unsigned int SetDoorState(unsigned int door_state)
5175 return MoveDoor(door_state | DOOR_SET_STATE);
5178 unsigned int MoveDoor(unsigned int door_state)
5180 static int door1 = DOOR_OPEN_1;
5181 static int door2 = DOOR_CLOSE_2;
5182 unsigned int door_delay = 0;
5183 unsigned int door_delay_value;
5186 if (door_1.width < 0 || door_1.width > DXSIZE)
5187 door_1.width = DXSIZE;
5188 if (door_1.height < 0 || door_1.height > DYSIZE)
5189 door_1.height = DYSIZE;
5190 if (door_2.width < 0 || door_2.width > VXSIZE)
5191 door_2.width = VXSIZE;
5192 if (door_2.height < 0 || door_2.height > VYSIZE)
5193 door_2.height = VYSIZE;
5195 if (door_state == DOOR_GET_STATE)
5196 return (door1 | door2);
5198 if (door_state & DOOR_SET_STATE)
5200 if (door_state & DOOR_ACTION_1)
5201 door1 = door_state & DOOR_ACTION_1;
5202 if (door_state & DOOR_ACTION_2)
5203 door2 = door_state & DOOR_ACTION_2;
5205 return (door1 | door2);
5208 if (!(door_state & DOOR_FORCE_REDRAW))
5210 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5211 door_state &= ~DOOR_OPEN_1;
5212 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5213 door_state &= ~DOOR_CLOSE_1;
5214 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5215 door_state &= ~DOOR_OPEN_2;
5216 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5217 door_state &= ~DOOR_CLOSE_2;
5220 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5223 if (setup.quick_doors)
5225 stepsize = 20; /* must be chosen to always draw last frame */
5226 door_delay_value = 0;
5229 if (global.autoplay_leveldir)
5231 door_state |= DOOR_NO_DELAY;
5232 door_state &= ~DOOR_CLOSE_ALL;
5236 if (game_status == GAME_MODE_EDITOR)
5237 door_state |= DOOR_NO_DELAY;
5240 if (door_state & DOOR_ACTION)
5242 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
5243 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
5244 boolean door_1_done = (!handle_door_1);
5245 boolean door_2_done = (!handle_door_2);
5246 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
5247 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
5248 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
5249 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
5250 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
5251 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
5252 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
5253 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
5254 int door_skip = max_door_size - door_size;
5255 int end = door_size;
5256 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
5259 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
5261 /* opening door sound has priority over simultaneously closing door */
5262 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
5263 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
5264 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
5265 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
5268 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
5271 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5272 GC gc = bitmap->stored_clip_gc;
5274 if (door_state & DOOR_ACTION_1)
5276 int a = MIN(x * door_1.step_offset, end);
5277 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
5278 int i = p + door_skip;
5280 if (door_1.anim_mode & ANIM_STATIC_PANEL)
5282 BlitBitmap(bitmap_db_door, drawto,
5283 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
5284 DXSIZE, DYSIZE, DX, DY);
5288 BlitBitmap(bitmap_db_door, drawto,
5289 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
5290 DXSIZE, DYSIZE - p / 2, DX, DY);
5292 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
5295 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
5297 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
5298 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
5299 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
5300 int dst2_x = DX, dst2_y = DY;
5301 int width = i, height = DYSIZE;
5303 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
5304 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
5307 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
5308 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
5311 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
5313 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
5314 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
5315 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
5316 int dst2_x = DX, dst2_y = DY;
5317 int width = DXSIZE, height = i;
5319 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
5320 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
5323 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
5324 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
5327 else if (x <= DXSIZE) /* ANIM_DEFAULT */
5329 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
5331 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
5332 BlitBitmapMasked(bitmap, drawto,
5333 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
5334 DX + DXSIZE - i, DY + j);
5335 BlitBitmapMasked(bitmap, drawto,
5336 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
5337 DX + DXSIZE - i, DY + 140 + j);
5338 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
5339 DY - (DOOR_GFX_PAGEY1 + j));
5340 BlitBitmapMasked(bitmap, drawto,
5341 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
5343 BlitBitmapMasked(bitmap, drawto,
5344 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
5347 BlitBitmapMasked(bitmap, drawto,
5348 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
5350 BlitBitmapMasked(bitmap, drawto,
5351 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
5353 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
5354 BlitBitmapMasked(bitmap, drawto,
5355 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
5356 DX + DXSIZE - i, DY + 77 + j);
5357 BlitBitmapMasked(bitmap, drawto,
5358 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
5359 DX + DXSIZE - i, DY + 203 + j);
5362 redraw_mask |= REDRAW_DOOR_1;
5363 door_1_done = (a == end);
5366 if (door_state & DOOR_ACTION_2)
5368 int a = MIN(x * door_2.step_offset, door_size);
5369 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
5370 int i = p + door_skip;
5372 if (door_2.anim_mode & ANIM_STATIC_PANEL)
5374 BlitBitmap(bitmap_db_door, drawto,
5375 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
5376 VXSIZE, VYSIZE, VX, VY);
5378 else if (x <= VYSIZE)
5380 BlitBitmap(bitmap_db_door, drawto,
5381 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
5382 VXSIZE, VYSIZE - p / 2, VX, VY);
5384 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
5387 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
5389 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
5390 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
5391 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
5392 int dst2_x = VX, dst2_y = VY;
5393 int width = i, height = VYSIZE;
5395 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
5396 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
5399 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
5400 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
5403 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
5405 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
5406 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
5407 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
5408 int dst2_x = VX, dst2_y = VY;
5409 int width = VXSIZE, height = i;
5411 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
5412 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
5415 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
5416 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
5419 else if (x <= VXSIZE) /* ANIM_DEFAULT */
5421 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
5423 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
5424 BlitBitmapMasked(bitmap, drawto,
5425 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
5426 VX + VXSIZE - i, VY + j);
5427 SetClipOrigin(bitmap, gc,
5428 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
5429 BlitBitmapMasked(bitmap, drawto,
5430 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
5433 BlitBitmapMasked(bitmap, drawto,
5434 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
5435 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
5436 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
5437 BlitBitmapMasked(bitmap, drawto,
5438 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
5440 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
5443 redraw_mask |= REDRAW_DOOR_2;
5444 door_2_done = (a == VXSIZE);
5447 if (!(door_state & DOOR_NO_DELAY))
5451 if (game_status == GAME_MODE_MAIN)
5454 WaitUntilDelayReached(&door_delay, door_delay_value);
5459 if (door_state & DOOR_ACTION_1)
5460 door1 = door_state & DOOR_ACTION_1;
5461 if (door_state & DOOR_ACTION_2)
5462 door2 = door_state & DOOR_ACTION_2;
5464 return (door1 | door2);
5467 void DrawSpecialEditorDoor()
5469 /* draw bigger toolbox window */
5470 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
5471 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
5473 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5474 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
5477 redraw_mask |= REDRAW_ALL;
5480 void UndrawSpecialEditorDoor()
5482 /* draw normal tape recorder window */
5483 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5484 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
5487 redraw_mask |= REDRAW_ALL;
5491 /* ---------- new tool button stuff ---------------------------------------- */
5498 struct TextPosInfo *pos;
5501 } toolbutton_info[NUM_TOOL_BUTTONS] =
5504 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
5505 TOOL_CTRL_ID_YES, "yes"
5508 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
5509 TOOL_CTRL_ID_NO, "no"
5512 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
5513 TOOL_CTRL_ID_CONFIRM, "confirm"
5516 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
5517 TOOL_CTRL_ID_PLAYER_1, "player 1"
5520 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
5521 TOOL_CTRL_ID_PLAYER_2, "player 2"
5524 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
5525 TOOL_CTRL_ID_PLAYER_3, "player 3"
5528 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
5529 TOOL_CTRL_ID_PLAYER_4, "player 4"
5533 void CreateToolButtons()
5537 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5539 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
5540 struct TextPosInfo *pos = toolbutton_info[i].pos;
5541 struct GadgetInfo *gi;
5542 Bitmap *deco_bitmap = None;
5543 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5544 unsigned int event_mask = GD_EVENT_RELEASED;
5547 int gd_x = gfx->src_x;
5548 int gd_y = gfx->src_y;
5549 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
5550 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
5553 if (global.use_envelope_request)
5554 setRequestPosition(&dx, &dy, TRUE);
5556 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5558 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5560 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
5561 pos->size, &deco_bitmap, &deco_x, &deco_y);
5562 deco_xpos = (gfx->width - pos->size) / 2;
5563 deco_ypos = (gfx->height - pos->size) / 2;
5566 gi = CreateGadget(GDI_CUSTOM_ID, id,
5567 GDI_INFO_TEXT, toolbutton_info[i].infotext,
5570 GDI_WIDTH, gfx->width,
5571 GDI_HEIGHT, gfx->height,
5572 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5573 GDI_STATE, GD_BUTTON_UNPRESSED,
5574 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
5575 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
5576 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5577 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5578 GDI_DECORATION_SIZE, pos->size, pos->size,
5579 GDI_DECORATION_SHIFTING, 1, 1,
5580 GDI_DIRECT_DRAW, FALSE,
5581 GDI_EVENT_MASK, event_mask,
5582 GDI_CALLBACK_ACTION, HandleToolButtons,
5586 Error(ERR_EXIT, "cannot create gadget");
5588 tool_gadget[id] = gi;
5594 /* graphic position values for tool buttons */
5595 #define TOOL_BUTTON_YES_XPOS 2
5596 #define TOOL_BUTTON_YES_YPOS 250
5597 #define TOOL_BUTTON_YES_GFX_YPOS 0
5598 #define TOOL_BUTTON_YES_XSIZE 46
5599 #define TOOL_BUTTON_YES_YSIZE 28
5600 #define TOOL_BUTTON_NO_XPOS 52
5601 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
5602 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
5603 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
5604 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
5605 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
5606 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
5607 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
5608 #define TOOL_BUTTON_CONFIRM_XSIZE 96
5609 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
5610 #define TOOL_BUTTON_PLAYER_XSIZE 30
5611 #define TOOL_BUTTON_PLAYER_YSIZE 30
5612 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
5613 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
5614 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
5615 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
5616 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
5617 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
5618 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
5619 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
5620 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
5621 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
5622 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
5623 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
5624 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
5625 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
5626 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
5627 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
5628 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
5629 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
5630 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
5631 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
5640 } toolbutton_info[NUM_TOOL_BUTTONS] =
5643 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
5644 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
5645 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
5650 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
5651 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
5652 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
5657 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
5658 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
5659 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
5660 TOOL_CTRL_ID_CONFIRM,
5664 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
5665 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
5666 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
5667 TOOL_CTRL_ID_PLAYER_1,
5671 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
5672 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
5673 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
5674 TOOL_CTRL_ID_PLAYER_2,
5678 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
5679 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
5680 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
5681 TOOL_CTRL_ID_PLAYER_3,
5685 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
5686 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
5687 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
5688 TOOL_CTRL_ID_PLAYER_4,
5693 void CreateToolButtons()
5697 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5699 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5700 Bitmap *deco_bitmap = None;
5701 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5702 struct GadgetInfo *gi;
5703 unsigned int event_mask;
5704 int gd_xoffset, gd_yoffset;
5705 int gd_x1, gd_x2, gd_y;
5708 event_mask = GD_EVENT_RELEASED;
5710 gd_xoffset = toolbutton_info[i].xpos;
5711 gd_yoffset = toolbutton_info[i].ypos;
5712 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
5713 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
5714 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
5716 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5718 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5720 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
5721 &deco_bitmap, &deco_x, &deco_y);
5722 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
5723 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
5726 gi = CreateGadget(GDI_CUSTOM_ID, id,
5727 GDI_INFO_TEXT, toolbutton_info[i].infotext,
5728 GDI_X, DX + toolbutton_info[i].x,
5729 GDI_Y, DY + toolbutton_info[i].y,
5730 GDI_WIDTH, toolbutton_info[i].width,
5731 GDI_HEIGHT, toolbutton_info[i].height,
5732 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5733 GDI_STATE, GD_BUTTON_UNPRESSED,
5734 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
5735 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
5736 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5737 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5738 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
5739 GDI_DECORATION_SHIFTING, 1, 1,
5740 GDI_DIRECT_DRAW, FALSE,
5741 GDI_EVENT_MASK, event_mask,
5742 GDI_CALLBACK_ACTION, HandleToolButtons,
5746 Error(ERR_EXIT, "cannot create gadget");
5748 tool_gadget[id] = gi;
5754 void FreeToolButtons()
5758 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5759 FreeGadget(tool_gadget[i]);
5762 static void UnmapToolButtons()
5766 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5767 UnmapGadget(tool_gadget[i]);
5770 static void HandleToolButtons(struct GadgetInfo *gi)
5772 request_gadget_id = gi->custom_id;
5775 static struct Mapping_EM_to_RND_object
5778 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
5779 boolean is_backside; /* backside of moving element */
5785 em_object_mapping_list[] =
5788 Xblank, TRUE, FALSE,
5792 Yacid_splash_eB, FALSE, FALSE,
5793 EL_ACID_SPLASH_RIGHT, -1, -1
5796 Yacid_splash_wB, FALSE, FALSE,
5797 EL_ACID_SPLASH_LEFT, -1, -1
5800 #ifdef EM_ENGINE_BAD_ROLL
5802 Xstone_force_e, FALSE, FALSE,
5803 EL_ROCK, -1, MV_BIT_RIGHT
5806 Xstone_force_w, FALSE, FALSE,
5807 EL_ROCK, -1, MV_BIT_LEFT
5810 Xnut_force_e, FALSE, FALSE,
5811 EL_NUT, -1, MV_BIT_RIGHT
5814 Xnut_force_w, FALSE, FALSE,
5815 EL_NUT, -1, MV_BIT_LEFT
5818 Xspring_force_e, FALSE, FALSE,
5819 EL_SPRING, -1, MV_BIT_RIGHT
5822 Xspring_force_w, FALSE, FALSE,
5823 EL_SPRING, -1, MV_BIT_LEFT
5826 Xemerald_force_e, FALSE, FALSE,
5827 EL_EMERALD, -1, MV_BIT_RIGHT
5830 Xemerald_force_w, FALSE, FALSE,
5831 EL_EMERALD, -1, MV_BIT_LEFT
5834 Xdiamond_force_e, FALSE, FALSE,
5835 EL_DIAMOND, -1, MV_BIT_RIGHT
5838 Xdiamond_force_w, FALSE, FALSE,
5839 EL_DIAMOND, -1, MV_BIT_LEFT
5842 Xbomb_force_e, FALSE, FALSE,
5843 EL_BOMB, -1, MV_BIT_RIGHT
5846 Xbomb_force_w, FALSE, FALSE,
5847 EL_BOMB, -1, MV_BIT_LEFT
5849 #endif /* EM_ENGINE_BAD_ROLL */
5852 Xstone, TRUE, FALSE,
5856 Xstone_pause, FALSE, FALSE,
5860 Xstone_fall, FALSE, FALSE,
5864 Ystone_s, FALSE, FALSE,
5865 EL_ROCK, ACTION_FALLING, -1
5868 Ystone_sB, FALSE, TRUE,
5869 EL_ROCK, ACTION_FALLING, -1
5872 Ystone_e, FALSE, FALSE,
5873 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5876 Ystone_eB, FALSE, TRUE,
5877 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5880 Ystone_w, FALSE, FALSE,
5881 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5884 Ystone_wB, FALSE, TRUE,
5885 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5892 Xnut_pause, FALSE, FALSE,
5896 Xnut_fall, FALSE, FALSE,
5900 Ynut_s, FALSE, FALSE,
5901 EL_NUT, ACTION_FALLING, -1
5904 Ynut_sB, FALSE, TRUE,
5905 EL_NUT, ACTION_FALLING, -1
5908 Ynut_e, FALSE, FALSE,
5909 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5912 Ynut_eB, FALSE, TRUE,
5913 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5916 Ynut_w, FALSE, FALSE,
5917 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5920 Ynut_wB, FALSE, TRUE,
5921 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5924 Xbug_n, TRUE, FALSE,
5928 Xbug_e, TRUE, FALSE,
5929 EL_BUG_RIGHT, -1, -1
5932 Xbug_s, TRUE, FALSE,
5936 Xbug_w, TRUE, FALSE,
5940 Xbug_gon, FALSE, FALSE,
5944 Xbug_goe, FALSE, FALSE,
5945 EL_BUG_RIGHT, -1, -1
5948 Xbug_gos, FALSE, FALSE,
5952 Xbug_gow, FALSE, FALSE,
5956 Ybug_n, FALSE, FALSE,
5957 EL_BUG, ACTION_MOVING, MV_BIT_UP
5960 Ybug_nB, FALSE, TRUE,
5961 EL_BUG, ACTION_MOVING, MV_BIT_UP
5964 Ybug_e, FALSE, FALSE,
5965 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5968 Ybug_eB, FALSE, TRUE,
5969 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5972 Ybug_s, FALSE, FALSE,
5973 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5976 Ybug_sB, FALSE, TRUE,
5977 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5980 Ybug_w, FALSE, FALSE,
5981 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5984 Ybug_wB, FALSE, TRUE,
5985 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5988 Ybug_w_n, FALSE, FALSE,
5989 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5992 Ybug_n_e, FALSE, FALSE,
5993 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5996 Ybug_e_s, FALSE, FALSE,
5997 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
6000 Ybug_s_w, FALSE, FALSE,
6001 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
6004 Ybug_e_n, FALSE, FALSE,
6005 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
6008 Ybug_s_e, FALSE, FALSE,
6009 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
6012 Ybug_w_s, FALSE, FALSE,
6013 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
6016 Ybug_n_w, FALSE, FALSE,
6017 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
6020 Ybug_stone, FALSE, FALSE,
6021 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
6024 Ybug_spring, FALSE, FALSE,
6025 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
6028 Xtank_n, TRUE, FALSE,
6029 EL_SPACESHIP_UP, -1, -1
6032 Xtank_e, TRUE, FALSE,
6033 EL_SPACESHIP_RIGHT, -1, -1
6036 Xtank_s, TRUE, FALSE,
6037 EL_SPACESHIP_DOWN, -1, -1
6040 Xtank_w, TRUE, FALSE,
6041 EL_SPACESHIP_LEFT, -1, -1
6044 Xtank_gon, FALSE, FALSE,
6045 EL_SPACESHIP_UP, -1, -1
6048 Xtank_goe, FALSE, FALSE,
6049 EL_SPACESHIP_RIGHT, -1, -1
6052 Xtank_gos, FALSE, FALSE,
6053 EL_SPACESHIP_DOWN, -1, -1
6056 Xtank_gow, FALSE, FALSE,
6057 EL_SPACESHIP_LEFT, -1, -1
6060 Ytank_n, FALSE, FALSE,
6061 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
6064 Ytank_nB, FALSE, TRUE,
6065 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
6068 Ytank_e, FALSE, FALSE,
6069 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
6072 Ytank_eB, FALSE, TRUE,
6073 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
6076 Ytank_s, FALSE, FALSE,
6077 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
6080 Ytank_sB, FALSE, TRUE,
6081 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
6084 Ytank_w, FALSE, FALSE,
6085 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
6088 Ytank_wB, FALSE, TRUE,
6089 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
6092 Ytank_w_n, FALSE, FALSE,
6093 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
6096 Ytank_n_e, FALSE, FALSE,
6097 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
6100 Ytank_e_s, FALSE, FALSE,
6101 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
6104 Ytank_s_w, FALSE, FALSE,
6105 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
6108 Ytank_e_n, FALSE, FALSE,
6109 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
6112 Ytank_s_e, FALSE, FALSE,
6113 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
6116 Ytank_w_s, FALSE, FALSE,
6117 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
6120 Ytank_n_w, FALSE, FALSE,
6121 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
6124 Ytank_stone, FALSE, FALSE,
6125 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
6128 Ytank_spring, FALSE, FALSE,
6129 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
6132 Xandroid, TRUE, FALSE,
6133 EL_EMC_ANDROID, ACTION_ACTIVE, -1
6136 Xandroid_1_n, FALSE, FALSE,
6137 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
6140 Xandroid_2_n, FALSE, FALSE,
6141 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
6144 Xandroid_1_e, FALSE, FALSE,
6145 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
6148 Xandroid_2_e, FALSE, FALSE,
6149 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
6152 Xandroid_1_w, FALSE, FALSE,
6153 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
6156 Xandroid_2_w, FALSE, FALSE,
6157 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
6160 Xandroid_1_s, FALSE, FALSE,
6161 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
6164 Xandroid_2_s, FALSE, FALSE,
6165 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
6168 Yandroid_n, FALSE, FALSE,
6169 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
6172 Yandroid_nB, FALSE, TRUE,
6173 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
6176 Yandroid_ne, FALSE, FALSE,
6177 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
6180 Yandroid_neB, FALSE, TRUE,
6181 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
6184 Yandroid_e, FALSE, FALSE,
6185 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
6188 Yandroid_eB, FALSE, TRUE,
6189 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
6192 Yandroid_se, FALSE, FALSE,
6193 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
6196 Yandroid_seB, FALSE, TRUE,
6197 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
6200 Yandroid_s, FALSE, FALSE,
6201 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
6204 Yandroid_sB, FALSE, TRUE,
6205 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
6208 Yandroid_sw, FALSE, FALSE,
6209 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
6212 Yandroid_swB, FALSE, TRUE,
6213 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
6216 Yandroid_w, FALSE, FALSE,
6217 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
6220 Yandroid_wB, FALSE, TRUE,
6221 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
6224 Yandroid_nw, FALSE, FALSE,
6225 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
6228 Yandroid_nwB, FALSE, TRUE,
6229 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
6232 Xspring, TRUE, FALSE,
6236 Xspring_pause, FALSE, FALSE,
6240 Xspring_e, FALSE, FALSE,
6244 Xspring_w, FALSE, FALSE,
6248 Xspring_fall, FALSE, FALSE,
6252 Yspring_s, FALSE, FALSE,
6253 EL_SPRING, ACTION_FALLING, -1
6256 Yspring_sB, FALSE, TRUE,
6257 EL_SPRING, ACTION_FALLING, -1
6260 Yspring_e, FALSE, FALSE,
6261 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
6264 Yspring_eB, FALSE, TRUE,
6265 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
6268 Yspring_w, FALSE, FALSE,
6269 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
6272 Yspring_wB, FALSE, TRUE,
6273 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
6276 Yspring_kill_e, FALSE, FALSE,
6277 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
6280 Yspring_kill_eB, FALSE, TRUE,
6281 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
6284 Yspring_kill_w, FALSE, FALSE,
6285 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
6288 Yspring_kill_wB, FALSE, TRUE,
6289 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
6292 Xeater_n, TRUE, FALSE,
6293 EL_YAMYAM_UP, -1, -1
6296 Xeater_e, TRUE, FALSE,
6297 EL_YAMYAM_RIGHT, -1, -1
6300 Xeater_w, TRUE, FALSE,
6301 EL_YAMYAM_LEFT, -1, -1
6304 Xeater_s, TRUE, FALSE,
6305 EL_YAMYAM_DOWN, -1, -1
6308 Yeater_n, FALSE, FALSE,
6309 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
6312 Yeater_nB, FALSE, TRUE,
6313 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
6316 Yeater_e, FALSE, FALSE,
6317 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
6320 Yeater_eB, FALSE, TRUE,
6321 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
6324 Yeater_s, FALSE, FALSE,
6325 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
6328 Yeater_sB, FALSE, TRUE,
6329 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
6332 Yeater_w, FALSE, FALSE,
6333 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
6336 Yeater_wB, FALSE, TRUE,
6337 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
6340 Yeater_stone, FALSE, FALSE,
6341 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
6344 Yeater_spring, FALSE, FALSE,
6345 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
6348 Xalien, TRUE, FALSE,
6352 Xalien_pause, FALSE, FALSE,
6356 Yalien_n, FALSE, FALSE,
6357 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
6360 Yalien_nB, FALSE, TRUE,
6361 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
6364 Yalien_e, FALSE, FALSE,
6365 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
6368 Yalien_eB, FALSE, TRUE,
6369 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
6372 Yalien_s, FALSE, FALSE,
6373 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
6376 Yalien_sB, FALSE, TRUE,
6377 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
6380 Yalien_w, FALSE, FALSE,
6381 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
6384 Yalien_wB, FALSE, TRUE,
6385 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
6388 Yalien_stone, FALSE, FALSE,
6389 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
6392 Yalien_spring, FALSE, FALSE,
6393 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
6396 Xemerald, TRUE, FALSE,
6400 Xemerald_pause, FALSE, FALSE,
6404 Xemerald_fall, FALSE, FALSE,
6408 Xemerald_shine, FALSE, FALSE,
6409 EL_EMERALD, ACTION_TWINKLING, -1
6412 Yemerald_s, FALSE, FALSE,
6413 EL_EMERALD, ACTION_FALLING, -1
6416 Yemerald_sB, FALSE, TRUE,
6417 EL_EMERALD, ACTION_FALLING, -1
6420 Yemerald_e, FALSE, FALSE,
6421 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
6424 Yemerald_eB, FALSE, TRUE,
6425 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
6428 Yemerald_w, FALSE, FALSE,
6429 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6432 Yemerald_wB, FALSE, TRUE,
6433 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6436 Yemerald_eat, FALSE, FALSE,
6437 EL_EMERALD, ACTION_COLLECTING, -1
6440 Yemerald_stone, FALSE, FALSE,
6441 EL_NUT, ACTION_BREAKING, -1
6444 Xdiamond, TRUE, FALSE,
6448 Xdiamond_pause, FALSE, FALSE,
6452 Xdiamond_fall, FALSE, FALSE,
6456 Xdiamond_shine, FALSE, FALSE,
6457 EL_DIAMOND, ACTION_TWINKLING, -1
6460 Ydiamond_s, FALSE, FALSE,
6461 EL_DIAMOND, ACTION_FALLING, -1
6464 Ydiamond_sB, FALSE, TRUE,
6465 EL_DIAMOND, ACTION_FALLING, -1
6468 Ydiamond_e, FALSE, FALSE,
6469 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6472 Ydiamond_eB, FALSE, TRUE,
6473 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6476 Ydiamond_w, FALSE, FALSE,
6477 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6480 Ydiamond_wB, FALSE, TRUE,
6481 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6484 Ydiamond_eat, FALSE, FALSE,
6485 EL_DIAMOND, ACTION_COLLECTING, -1
6488 Ydiamond_stone, FALSE, FALSE,
6489 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
6492 Xdrip_fall, TRUE, FALSE,
6493 EL_AMOEBA_DROP, -1, -1
6496 Xdrip_stretch, FALSE, FALSE,
6497 EL_AMOEBA_DROP, ACTION_FALLING, -1
6500 Xdrip_stretchB, FALSE, TRUE,
6501 EL_AMOEBA_DROP, ACTION_FALLING, -1
6504 Xdrip_eat, FALSE, FALSE,
6505 EL_AMOEBA_DROP, ACTION_GROWING, -1
6508 Ydrip_s1, FALSE, FALSE,
6509 EL_AMOEBA_DROP, ACTION_FALLING, -1
6512 Ydrip_s1B, FALSE, TRUE,
6513 EL_AMOEBA_DROP, ACTION_FALLING, -1
6516 Ydrip_s2, FALSE, FALSE,
6517 EL_AMOEBA_DROP, ACTION_FALLING, -1
6520 Ydrip_s2B, FALSE, TRUE,
6521 EL_AMOEBA_DROP, ACTION_FALLING, -1
6528 Xbomb_pause, FALSE, FALSE,
6532 Xbomb_fall, FALSE, FALSE,
6536 Ybomb_s, FALSE, FALSE,
6537 EL_BOMB, ACTION_FALLING, -1
6540 Ybomb_sB, FALSE, TRUE,
6541 EL_BOMB, ACTION_FALLING, -1
6544 Ybomb_e, FALSE, FALSE,
6545 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6548 Ybomb_eB, FALSE, TRUE,
6549 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6552 Ybomb_w, FALSE, FALSE,
6553 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6556 Ybomb_wB, FALSE, TRUE,
6557 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6560 Ybomb_eat, FALSE, FALSE,
6561 EL_BOMB, ACTION_ACTIVATING, -1
6564 Xballoon, TRUE, FALSE,
6568 Yballoon_n, FALSE, FALSE,
6569 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6572 Yballoon_nB, FALSE, TRUE,
6573 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6576 Yballoon_e, FALSE, FALSE,
6577 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6580 Yballoon_eB, FALSE, TRUE,
6581 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6584 Yballoon_s, FALSE, FALSE,
6585 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6588 Yballoon_sB, FALSE, TRUE,
6589 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6592 Yballoon_w, FALSE, FALSE,
6593 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6596 Yballoon_wB, FALSE, TRUE,
6597 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6600 Xgrass, TRUE, FALSE,
6601 EL_EMC_GRASS, -1, -1
6604 Ygrass_nB, FALSE, FALSE,
6605 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
6608 Ygrass_eB, FALSE, FALSE,
6609 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
6612 Ygrass_sB, FALSE, FALSE,
6613 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
6616 Ygrass_wB, FALSE, FALSE,
6617 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
6624 Ydirt_nB, FALSE, FALSE,
6625 EL_SAND, ACTION_DIGGING, MV_BIT_UP
6628 Ydirt_eB, FALSE, FALSE,
6629 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
6632 Ydirt_sB, FALSE, FALSE,
6633 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
6636 Ydirt_wB, FALSE, FALSE,
6637 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
6640 Xacid_ne, TRUE, FALSE,
6641 EL_ACID_POOL_TOPRIGHT, -1, -1
6644 Xacid_se, TRUE, FALSE,
6645 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
6648 Xacid_s, TRUE, FALSE,
6649 EL_ACID_POOL_BOTTOM, -1, -1
6652 Xacid_sw, TRUE, FALSE,
6653 EL_ACID_POOL_BOTTOMLEFT, -1, -1
6656 Xacid_nw, TRUE, FALSE,
6657 EL_ACID_POOL_TOPLEFT, -1, -1
6660 Xacid_1, TRUE, FALSE,
6664 Xacid_2, FALSE, FALSE,
6668 Xacid_3, FALSE, FALSE,
6672 Xacid_4, FALSE, FALSE,
6676 Xacid_5, FALSE, FALSE,
6680 Xacid_6, FALSE, FALSE,
6684 Xacid_7, FALSE, FALSE,
6688 Xacid_8, FALSE, FALSE,
6692 Xball_1, TRUE, FALSE,
6693 EL_EMC_MAGIC_BALL, -1, -1
6696 Xball_1B, FALSE, FALSE,
6697 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6700 Xball_2, FALSE, FALSE,
6701 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6704 Xball_2B, FALSE, FALSE,
6705 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6708 Yball_eat, FALSE, FALSE,
6709 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
6712 Ykey_1_eat, FALSE, FALSE,
6713 EL_EM_KEY_1, ACTION_COLLECTING, -1
6716 Ykey_2_eat, FALSE, FALSE,
6717 EL_EM_KEY_2, ACTION_COLLECTING, -1
6720 Ykey_3_eat, FALSE, FALSE,
6721 EL_EM_KEY_3, ACTION_COLLECTING, -1
6724 Ykey_4_eat, FALSE, FALSE,
6725 EL_EM_KEY_4, ACTION_COLLECTING, -1
6728 Ykey_5_eat, FALSE, FALSE,
6729 EL_EMC_KEY_5, ACTION_COLLECTING, -1
6732 Ykey_6_eat, FALSE, FALSE,
6733 EL_EMC_KEY_6, ACTION_COLLECTING, -1
6736 Ykey_7_eat, FALSE, FALSE,
6737 EL_EMC_KEY_7, ACTION_COLLECTING, -1
6740 Ykey_8_eat, FALSE, FALSE,
6741 EL_EMC_KEY_8, ACTION_COLLECTING, -1
6744 Ylenses_eat, FALSE, FALSE,
6745 EL_EMC_LENSES, ACTION_COLLECTING, -1
6748 Ymagnify_eat, FALSE, FALSE,
6749 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
6752 Ygrass_eat, FALSE, FALSE,
6753 EL_EMC_GRASS, ACTION_SNAPPING, -1
6756 Ydirt_eat, FALSE, FALSE,
6757 EL_SAND, ACTION_SNAPPING, -1
6760 Xgrow_ns, TRUE, FALSE,
6761 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
6764 Ygrow_ns_eat, FALSE, FALSE,
6765 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
6768 Xgrow_ew, TRUE, FALSE,
6769 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
6772 Ygrow_ew_eat, FALSE, FALSE,
6773 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
6776 Xwonderwall, TRUE, FALSE,
6777 EL_MAGIC_WALL, -1, -1
6780 XwonderwallB, FALSE, FALSE,
6781 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6784 Xamoeba_1, TRUE, FALSE,
6785 EL_AMOEBA_DRY, ACTION_OTHER, -1
6788 Xamoeba_2, FALSE, FALSE,
6789 EL_AMOEBA_DRY, ACTION_OTHER, -1
6792 Xamoeba_3, FALSE, FALSE,
6793 EL_AMOEBA_DRY, ACTION_OTHER, -1
6796 Xamoeba_4, FALSE, FALSE,
6797 EL_AMOEBA_DRY, ACTION_OTHER, -1
6800 Xamoeba_5, TRUE, FALSE,
6801 EL_AMOEBA_WET, ACTION_OTHER, -1
6804 Xamoeba_6, FALSE, FALSE,
6805 EL_AMOEBA_WET, ACTION_OTHER, -1
6808 Xamoeba_7, FALSE, FALSE,
6809 EL_AMOEBA_WET, ACTION_OTHER, -1
6812 Xamoeba_8, FALSE, FALSE,
6813 EL_AMOEBA_WET, ACTION_OTHER, -1
6816 Xdoor_1, TRUE, FALSE,
6817 EL_EM_GATE_1, -1, -1
6820 Xdoor_2, TRUE, FALSE,
6821 EL_EM_GATE_2, -1, -1
6824 Xdoor_3, TRUE, FALSE,
6825 EL_EM_GATE_3, -1, -1
6828 Xdoor_4, TRUE, FALSE,
6829 EL_EM_GATE_4, -1, -1
6832 Xdoor_5, TRUE, FALSE,
6833 EL_EMC_GATE_5, -1, -1
6836 Xdoor_6, TRUE, FALSE,
6837 EL_EMC_GATE_6, -1, -1
6840 Xdoor_7, TRUE, FALSE,
6841 EL_EMC_GATE_7, -1, -1
6844 Xdoor_8, TRUE, FALSE,
6845 EL_EMC_GATE_8, -1, -1
6848 Xkey_1, TRUE, FALSE,
6852 Xkey_2, TRUE, FALSE,
6856 Xkey_3, TRUE, FALSE,
6860 Xkey_4, TRUE, FALSE,
6864 Xkey_5, TRUE, FALSE,
6865 EL_EMC_KEY_5, -1, -1
6868 Xkey_6, TRUE, FALSE,
6869 EL_EMC_KEY_6, -1, -1
6872 Xkey_7, TRUE, FALSE,
6873 EL_EMC_KEY_7, -1, -1
6876 Xkey_8, TRUE, FALSE,
6877 EL_EMC_KEY_8, -1, -1
6880 Xwind_n, TRUE, FALSE,
6881 EL_BALLOON_SWITCH_UP, -1, -1
6884 Xwind_e, TRUE, FALSE,
6885 EL_BALLOON_SWITCH_RIGHT, -1, -1
6888 Xwind_s, TRUE, FALSE,
6889 EL_BALLOON_SWITCH_DOWN, -1, -1
6892 Xwind_w, TRUE, FALSE,
6893 EL_BALLOON_SWITCH_LEFT, -1, -1
6896 Xwind_nesw, TRUE, FALSE,
6897 EL_BALLOON_SWITCH_ANY, -1, -1
6900 Xwind_stop, TRUE, FALSE,
6901 EL_BALLOON_SWITCH_NONE, -1, -1
6905 EL_EM_EXIT_CLOSED, -1, -1
6908 Xexit_1, TRUE, FALSE,
6909 EL_EM_EXIT_OPEN, -1, -1
6912 Xexit_2, FALSE, FALSE,
6913 EL_EM_EXIT_OPEN, -1, -1
6916 Xexit_3, FALSE, FALSE,
6917 EL_EM_EXIT_OPEN, -1, -1
6920 Xdynamite, TRUE, FALSE,
6921 EL_EM_DYNAMITE, -1, -1
6924 Ydynamite_eat, FALSE, FALSE,
6925 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6928 Xdynamite_1, TRUE, FALSE,
6929 EL_EM_DYNAMITE_ACTIVE, -1, -1
6932 Xdynamite_2, FALSE, FALSE,
6933 EL_EM_DYNAMITE_ACTIVE, -1, -1
6936 Xdynamite_3, FALSE, FALSE,
6937 EL_EM_DYNAMITE_ACTIVE, -1, -1
6940 Xdynamite_4, FALSE, FALSE,
6941 EL_EM_DYNAMITE_ACTIVE, -1, -1
6944 Xbumper, TRUE, FALSE,
6945 EL_EMC_SPRING_BUMPER, -1, -1
6948 XbumperB, FALSE, FALSE,
6949 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6952 Xwheel, TRUE, FALSE,
6953 EL_ROBOT_WHEEL, -1, -1
6956 XwheelB, FALSE, FALSE,
6957 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6960 Xswitch, TRUE, FALSE,
6961 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6964 XswitchB, FALSE, FALSE,
6965 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6969 EL_QUICKSAND_EMPTY, -1, -1
6972 Xsand_stone, TRUE, FALSE,
6973 EL_QUICKSAND_FULL, -1, -1
6976 Xsand_stonein_1, FALSE, TRUE,
6977 EL_ROCK, ACTION_FILLING, -1
6980 Xsand_stonein_2, FALSE, TRUE,
6981 EL_ROCK, ACTION_FILLING, -1
6984 Xsand_stonein_3, FALSE, TRUE,
6985 EL_ROCK, ACTION_FILLING, -1
6988 Xsand_stonein_4, FALSE, TRUE,
6989 EL_ROCK, ACTION_FILLING, -1
6993 Xsand_stonesand_1, FALSE, FALSE,
6994 EL_QUICKSAND_EMPTYING, -1, -1
6997 Xsand_stonesand_2, FALSE, FALSE,
6998 EL_QUICKSAND_EMPTYING, -1, -1
7001 Xsand_stonesand_3, FALSE, FALSE,
7002 EL_QUICKSAND_EMPTYING, -1, -1
7005 Xsand_stonesand_4, FALSE, FALSE,
7006 EL_QUICKSAND_EMPTYING, -1, -1
7009 Xsand_stonesand_quickout_1, FALSE, FALSE,
7010 EL_QUICKSAND_EMPTYING, -1, -1
7013 Xsand_stonesand_quickout_2, FALSE, FALSE,
7014 EL_QUICKSAND_EMPTYING, -1, -1
7018 Xsand_stonesand_1, FALSE, FALSE,
7019 EL_QUICKSAND_FULL, -1, -1
7022 Xsand_stonesand_2, FALSE, FALSE,
7023 EL_QUICKSAND_FULL, -1, -1
7026 Xsand_stonesand_3, FALSE, FALSE,
7027 EL_QUICKSAND_FULL, -1, -1
7030 Xsand_stonesand_4, FALSE, FALSE,
7031 EL_QUICKSAND_FULL, -1, -1
7035 Xsand_stoneout_1, FALSE, FALSE,
7036 EL_ROCK, ACTION_EMPTYING, -1
7039 Xsand_stoneout_2, FALSE, FALSE,
7040 EL_ROCK, ACTION_EMPTYING, -1
7044 Xsand_sandstone_1, FALSE, FALSE,
7045 EL_QUICKSAND_FILLING, -1, -1
7048 Xsand_sandstone_2, FALSE, FALSE,
7049 EL_QUICKSAND_FILLING, -1, -1
7052 Xsand_sandstone_3, FALSE, FALSE,
7053 EL_QUICKSAND_FILLING, -1, -1
7056 Xsand_sandstone_4, FALSE, FALSE,
7057 EL_QUICKSAND_FILLING, -1, -1
7061 Xsand_sandstone_1, FALSE, FALSE,
7062 EL_QUICKSAND_FULL, -1, -1
7065 Xsand_sandstone_2, FALSE, FALSE,
7066 EL_QUICKSAND_FULL, -1, -1
7069 Xsand_sandstone_3, FALSE, FALSE,
7070 EL_QUICKSAND_FULL, -1, -1
7073 Xsand_sandstone_4, FALSE, FALSE,
7074 EL_QUICKSAND_FULL, -1, -1
7078 Xplant, TRUE, FALSE,
7079 EL_EMC_PLANT, -1, -1
7082 Yplant, FALSE, FALSE,
7083 EL_EMC_PLANT, -1, -1
7086 Xlenses, TRUE, FALSE,
7087 EL_EMC_LENSES, -1, -1
7090 Xmagnify, TRUE, FALSE,
7091 EL_EMC_MAGNIFIER, -1, -1
7094 Xdripper, TRUE, FALSE,
7095 EL_EMC_DRIPPER, -1, -1
7098 XdripperB, FALSE, FALSE,
7099 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
7102 Xfake_blank, TRUE, FALSE,
7103 EL_INVISIBLE_WALL, -1, -1
7106 Xfake_blankB, FALSE, FALSE,
7107 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
7110 Xfake_grass, TRUE, FALSE,
7111 EL_EMC_FAKE_GRASS, -1, -1
7114 Xfake_grassB, FALSE, FALSE,
7115 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
7118 Xfake_door_1, TRUE, FALSE,
7119 EL_EM_GATE_1_GRAY, -1, -1
7122 Xfake_door_2, TRUE, FALSE,
7123 EL_EM_GATE_2_GRAY, -1, -1
7126 Xfake_door_3, TRUE, FALSE,
7127 EL_EM_GATE_3_GRAY, -1, -1
7130 Xfake_door_4, TRUE, FALSE,
7131 EL_EM_GATE_4_GRAY, -1, -1
7134 Xfake_door_5, TRUE, FALSE,
7135 EL_EMC_GATE_5_GRAY, -1, -1
7138 Xfake_door_6, TRUE, FALSE,
7139 EL_EMC_GATE_6_GRAY, -1, -1
7142 Xfake_door_7, TRUE, FALSE,
7143 EL_EMC_GATE_7_GRAY, -1, -1
7146 Xfake_door_8, TRUE, FALSE,
7147 EL_EMC_GATE_8_GRAY, -1, -1
7150 Xfake_acid_1, TRUE, FALSE,
7151 EL_EMC_FAKE_ACID, -1, -1
7154 Xfake_acid_2, FALSE, FALSE,
7155 EL_EMC_FAKE_ACID, -1, -1
7158 Xfake_acid_3, FALSE, FALSE,
7159 EL_EMC_FAKE_ACID, -1, -1
7162 Xfake_acid_4, FALSE, FALSE,
7163 EL_EMC_FAKE_ACID, -1, -1
7166 Xfake_acid_5, FALSE, FALSE,
7167 EL_EMC_FAKE_ACID, -1, -1
7170 Xfake_acid_6, FALSE, FALSE,
7171 EL_EMC_FAKE_ACID, -1, -1
7174 Xfake_acid_7, FALSE, FALSE,
7175 EL_EMC_FAKE_ACID, -1, -1
7178 Xfake_acid_8, FALSE, FALSE,
7179 EL_EMC_FAKE_ACID, -1, -1
7182 Xsteel_1, TRUE, FALSE,
7183 EL_STEELWALL, -1, -1
7186 Xsteel_2, TRUE, FALSE,
7187 EL_EMC_STEELWALL_2, -1, -1
7190 Xsteel_3, TRUE, FALSE,
7191 EL_EMC_STEELWALL_3, -1, -1
7194 Xsteel_4, TRUE, FALSE,
7195 EL_EMC_STEELWALL_4, -1, -1
7198 Xwall_1, TRUE, FALSE,
7202 Xwall_2, TRUE, FALSE,
7203 EL_EMC_WALL_14, -1, -1
7206 Xwall_3, TRUE, FALSE,
7207 EL_EMC_WALL_15, -1, -1
7210 Xwall_4, TRUE, FALSE,
7211 EL_EMC_WALL_16, -1, -1
7214 Xround_wall_1, TRUE, FALSE,
7215 EL_WALL_SLIPPERY, -1, -1
7218 Xround_wall_2, TRUE, FALSE,
7219 EL_EMC_WALL_SLIPPERY_2, -1, -1
7222 Xround_wall_3, TRUE, FALSE,
7223 EL_EMC_WALL_SLIPPERY_3, -1, -1
7226 Xround_wall_4, TRUE, FALSE,
7227 EL_EMC_WALL_SLIPPERY_4, -1, -1
7230 Xdecor_1, TRUE, FALSE,
7231 EL_EMC_WALL_8, -1, -1
7234 Xdecor_2, TRUE, FALSE,
7235 EL_EMC_WALL_6, -1, -1
7238 Xdecor_3, TRUE, FALSE,
7239 EL_EMC_WALL_4, -1, -1
7242 Xdecor_4, TRUE, FALSE,
7243 EL_EMC_WALL_7, -1, -1
7246 Xdecor_5, TRUE, FALSE,
7247 EL_EMC_WALL_5, -1, -1
7250 Xdecor_6, TRUE, FALSE,
7251 EL_EMC_WALL_9, -1, -1
7254 Xdecor_7, TRUE, FALSE,
7255 EL_EMC_WALL_10, -1, -1
7258 Xdecor_8, TRUE, FALSE,
7259 EL_EMC_WALL_1, -1, -1
7262 Xdecor_9, TRUE, FALSE,
7263 EL_EMC_WALL_2, -1, -1
7266 Xdecor_10, TRUE, FALSE,
7267 EL_EMC_WALL_3, -1, -1
7270 Xdecor_11, TRUE, FALSE,
7271 EL_EMC_WALL_11, -1, -1
7274 Xdecor_12, TRUE, FALSE,
7275 EL_EMC_WALL_12, -1, -1
7278 Xalpha_0, TRUE, FALSE,
7279 EL_CHAR('0'), -1, -1
7282 Xalpha_1, TRUE, FALSE,
7283 EL_CHAR('1'), -1, -1
7286 Xalpha_2, TRUE, FALSE,
7287 EL_CHAR('2'), -1, -1
7290 Xalpha_3, TRUE, FALSE,
7291 EL_CHAR('3'), -1, -1
7294 Xalpha_4, TRUE, FALSE,
7295 EL_CHAR('4'), -1, -1
7298 Xalpha_5, TRUE, FALSE,
7299 EL_CHAR('5'), -1, -1
7302 Xalpha_6, TRUE, FALSE,
7303 EL_CHAR('6'), -1, -1
7306 Xalpha_7, TRUE, FALSE,
7307 EL_CHAR('7'), -1, -1
7310 Xalpha_8, TRUE, FALSE,
7311 EL_CHAR('8'), -1, -1
7314 Xalpha_9, TRUE, FALSE,
7315 EL_CHAR('9'), -1, -1
7318 Xalpha_excla, TRUE, FALSE,
7319 EL_CHAR('!'), -1, -1
7322 Xalpha_quote, TRUE, FALSE,
7323 EL_CHAR('"'), -1, -1
7326 Xalpha_comma, TRUE, FALSE,
7327 EL_CHAR(','), -1, -1
7330 Xalpha_minus, TRUE, FALSE,
7331 EL_CHAR('-'), -1, -1
7334 Xalpha_perio, TRUE, FALSE,
7335 EL_CHAR('.'), -1, -1
7338 Xalpha_colon, TRUE, FALSE,
7339 EL_CHAR(':'), -1, -1
7342 Xalpha_quest, TRUE, FALSE,
7343 EL_CHAR('?'), -1, -1
7346 Xalpha_a, TRUE, FALSE,
7347 EL_CHAR('A'), -1, -1
7350 Xalpha_b, TRUE, FALSE,
7351 EL_CHAR('B'), -1, -1
7354 Xalpha_c, TRUE, FALSE,
7355 EL_CHAR('C'), -1, -1
7358 Xalpha_d, TRUE, FALSE,
7359 EL_CHAR('D'), -1, -1
7362 Xalpha_e, TRUE, FALSE,
7363 EL_CHAR('E'), -1, -1
7366 Xalpha_f, TRUE, FALSE,
7367 EL_CHAR('F'), -1, -1
7370 Xalpha_g, TRUE, FALSE,
7371 EL_CHAR('G'), -1, -1
7374 Xalpha_h, TRUE, FALSE,
7375 EL_CHAR('H'), -1, -1
7378 Xalpha_i, TRUE, FALSE,
7379 EL_CHAR('I'), -1, -1
7382 Xalpha_j, TRUE, FALSE,
7383 EL_CHAR('J'), -1, -1
7386 Xalpha_k, TRUE, FALSE,
7387 EL_CHAR('K'), -1, -1
7390 Xalpha_l, TRUE, FALSE,
7391 EL_CHAR('L'), -1, -1
7394 Xalpha_m, TRUE, FALSE,
7395 EL_CHAR('M'), -1, -1
7398 Xalpha_n, TRUE, FALSE,
7399 EL_CHAR('N'), -1, -1
7402 Xalpha_o, TRUE, FALSE,
7403 EL_CHAR('O'), -1, -1
7406 Xalpha_p, TRUE, FALSE,
7407 EL_CHAR('P'), -1, -1
7410 Xalpha_q, TRUE, FALSE,
7411 EL_CHAR('Q'), -1, -1
7414 Xalpha_r, TRUE, FALSE,
7415 EL_CHAR('R'), -1, -1
7418 Xalpha_s, TRUE, FALSE,
7419 EL_CHAR('S'), -1, -1
7422 Xalpha_t, TRUE, FALSE,
7423 EL_CHAR('T'), -1, -1
7426 Xalpha_u, TRUE, FALSE,
7427 EL_CHAR('U'), -1, -1
7430 Xalpha_v, TRUE, FALSE,
7431 EL_CHAR('V'), -1, -1
7434 Xalpha_w, TRUE, FALSE,
7435 EL_CHAR('W'), -1, -1
7438 Xalpha_x, TRUE, FALSE,
7439 EL_CHAR('X'), -1, -1
7442 Xalpha_y, TRUE, FALSE,
7443 EL_CHAR('Y'), -1, -1
7446 Xalpha_z, TRUE, FALSE,
7447 EL_CHAR('Z'), -1, -1
7450 Xalpha_arrow_e, TRUE, FALSE,
7451 EL_CHAR('>'), -1, -1
7454 Xalpha_arrow_w, TRUE, FALSE,
7455 EL_CHAR('<'), -1, -1
7458 Xalpha_copyr, TRUE, FALSE,
7459 EL_CHAR('©'), -1, -1
7463 Xboom_bug, FALSE, FALSE,
7464 EL_BUG, ACTION_EXPLODING, -1
7467 Xboom_bomb, FALSE, FALSE,
7468 EL_BOMB, ACTION_EXPLODING, -1
7471 Xboom_android, FALSE, FALSE,
7472 EL_EMC_ANDROID, ACTION_OTHER, -1
7475 Xboom_1, FALSE, FALSE,
7476 EL_DEFAULT, ACTION_EXPLODING, -1
7479 Xboom_2, FALSE, FALSE,
7480 EL_DEFAULT, ACTION_EXPLODING, -1
7483 Znormal, FALSE, FALSE,
7487 Zdynamite, FALSE, FALSE,
7491 Zplayer, FALSE, FALSE,
7495 ZBORDER, FALSE, FALSE,
7505 static struct Mapping_EM_to_RND_player
7514 em_player_mapping_list[] =
7518 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
7522 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
7526 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
7530 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
7534 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
7538 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
7542 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
7546 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
7550 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
7554 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
7558 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
7562 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
7566 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
7570 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
7574 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
7578 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
7582 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
7586 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
7590 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
7594 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
7598 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
7602 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
7606 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
7610 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
7614 EL_PLAYER_1, ACTION_DEFAULT, -1,
7618 EL_PLAYER_2, ACTION_DEFAULT, -1,
7622 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
7626 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
7630 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
7634 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
7638 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
7642 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
7646 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
7650 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
7654 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
7658 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
7662 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
7666 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
7670 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
7674 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
7678 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
7682 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
7686 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
7690 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
7694 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
7698 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
7702 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
7706 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
7710 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
7714 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
7718 EL_PLAYER_3, ACTION_DEFAULT, -1,
7722 EL_PLAYER_4, ACTION_DEFAULT, -1,
7731 int map_element_RND_to_EM(int element_rnd)
7733 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
7734 static boolean mapping_initialized = FALSE;
7736 if (!mapping_initialized)
7740 /* return "Xalpha_quest" for all undefined elements in mapping array */
7741 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7742 mapping_RND_to_EM[i] = Xalpha_quest;
7744 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7745 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
7746 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
7747 em_object_mapping_list[i].element_em;
7749 mapping_initialized = TRUE;
7752 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
7753 return mapping_RND_to_EM[element_rnd];
7755 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
7760 int map_element_EM_to_RND(int element_em)
7762 static unsigned short mapping_EM_to_RND[TILE_MAX];
7763 static boolean mapping_initialized = FALSE;
7765 if (!mapping_initialized)
7769 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
7770 for (i = 0; i < TILE_MAX; i++)
7771 mapping_EM_to_RND[i] = EL_UNKNOWN;
7773 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7774 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
7775 em_object_mapping_list[i].element_rnd;
7777 mapping_initialized = TRUE;
7780 if (element_em >= 0 && element_em < TILE_MAX)
7781 return mapping_EM_to_RND[element_em];
7783 Error(ERR_WARN, "invalid EM level element %d", element_em);
7788 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
7790 struct LevelInfo_EM *level_em = level->native_em_level;
7791 struct LEVEL *lev = level_em->lev;
7794 for (i = 0; i < TILE_MAX; i++)
7795 lev->android_array[i] = Xblank;
7797 for (i = 0; i < level->num_android_clone_elements; i++)
7799 int element_rnd = level->android_clone_element[i];
7800 int element_em = map_element_RND_to_EM(element_rnd);
7802 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
7803 if (em_object_mapping_list[j].element_rnd == element_rnd)
7804 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
7808 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
7810 struct LevelInfo_EM *level_em = level->native_em_level;
7811 struct LEVEL *lev = level_em->lev;
7814 level->num_android_clone_elements = 0;
7816 for (i = 0; i < TILE_MAX; i++)
7818 int element_em = lev->android_array[i];
7820 boolean element_found = FALSE;
7822 if (element_em == Xblank)
7825 element_rnd = map_element_EM_to_RND(element_em);
7827 for (j = 0; j < level->num_android_clone_elements; j++)
7828 if (level->android_clone_element[j] == element_rnd)
7829 element_found = TRUE;
7833 level->android_clone_element[level->num_android_clone_elements++] =
7836 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7841 if (level->num_android_clone_elements == 0)
7843 level->num_android_clone_elements = 1;
7844 level->android_clone_element[0] = EL_EMPTY;
7848 int map_direction_RND_to_EM(int direction)
7850 return (direction == MV_UP ? 0 :
7851 direction == MV_RIGHT ? 1 :
7852 direction == MV_DOWN ? 2 :
7853 direction == MV_LEFT ? 3 :
7857 int map_direction_EM_to_RND(int direction)
7859 return (direction == 0 ? MV_UP :
7860 direction == 1 ? MV_RIGHT :
7861 direction == 2 ? MV_DOWN :
7862 direction == 3 ? MV_LEFT :
7866 int map_element_RND_to_SP(int element_rnd)
7868 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7870 if (element_rnd >= EL_SP_START &&
7871 element_rnd <= EL_SP_END)
7872 element_sp = element_rnd - EL_SP_START;
7873 else if (element_rnd == EL_EMPTY_SPACE)
7875 else if (element_rnd == EL_INVISIBLE_WALL)
7881 int map_element_SP_to_RND(int element_sp)
7883 int element_rnd = EL_UNKNOWN;
7885 if (element_sp >= 0x00 &&
7887 element_rnd = EL_SP_START + element_sp;
7888 else if (element_sp == 0x28)
7889 element_rnd = EL_INVISIBLE_WALL;
7894 int map_action_SP_to_RND(int action_sp)
7898 case actActive: return ACTION_ACTIVE;
7899 case actImpact: return ACTION_IMPACT;
7900 case actExploding: return ACTION_EXPLODING;
7901 case actDigging: return ACTION_DIGGING;
7902 case actSnapping: return ACTION_SNAPPING;
7903 case actCollecting: return ACTION_COLLECTING;
7904 case actPassing: return ACTION_PASSING;
7905 case actPushing: return ACTION_PUSHING;
7906 case actDropping: return ACTION_DROPPING;
7908 default: return ACTION_DEFAULT;
7912 int get_next_element(int element)
7916 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7917 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7918 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7919 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7920 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7921 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7922 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7923 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7924 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7925 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7926 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7928 default: return element;
7933 int el_act_dir2img(int element, int action, int direction)
7935 element = GFX_ELEMENT(element);
7937 if (direction == MV_NONE)
7938 return element_info[element].graphic[action];
7940 direction = MV_DIR_TO_BIT(direction);
7942 return element_info[element].direction_graphic[action][direction];
7945 int el_act_dir2img(int element, int action, int direction)
7947 element = GFX_ELEMENT(element);
7948 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7950 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7951 return element_info[element].direction_graphic[action][direction];
7956 static int el_act_dir2crm(int element, int action, int direction)
7958 element = GFX_ELEMENT(element);
7960 if (direction == MV_NONE)
7961 return element_info[element].crumbled[action];
7963 direction = MV_DIR_TO_BIT(direction);
7965 return element_info[element].direction_crumbled[action][direction];
7968 static int el_act_dir2crm(int element, int action, int direction)
7970 element = GFX_ELEMENT(element);
7971 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7973 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7974 return element_info[element].direction_crumbled[action][direction];
7978 int el_act2img(int element, int action)
7980 element = GFX_ELEMENT(element);
7982 return element_info[element].graphic[action];
7985 int el_act2crm(int element, int action)
7987 element = GFX_ELEMENT(element);
7989 return element_info[element].crumbled[action];
7992 int el_dir2img(int element, int direction)
7994 element = GFX_ELEMENT(element);
7996 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7999 int el2baseimg(int element)
8001 return element_info[element].graphic[ACTION_DEFAULT];
8004 int el2img(int element)
8006 element = GFX_ELEMENT(element);
8008 return element_info[element].graphic[ACTION_DEFAULT];
8011 int el2edimg(int element)
8013 element = GFX_ELEMENT(element);
8015 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
8018 int el2preimg(int element)
8020 element = GFX_ELEMENT(element);
8022 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
8025 int el2panelimg(int element)
8027 element = GFX_ELEMENT(element);
8029 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
8032 int font2baseimg(int font_nr)
8034 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
8037 int getBeltNrFromBeltElement(int element)
8039 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
8040 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
8041 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
8044 int getBeltNrFromBeltActiveElement(int element)
8046 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
8047 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
8048 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
8051 int getBeltNrFromBeltSwitchElement(int element)
8053 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
8054 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
8055 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
8058 int getBeltDirNrFromBeltElement(int element)
8060 static int belt_base_element[4] =
8062 EL_CONVEYOR_BELT_1_LEFT,
8063 EL_CONVEYOR_BELT_2_LEFT,
8064 EL_CONVEYOR_BELT_3_LEFT,
8065 EL_CONVEYOR_BELT_4_LEFT
8068 int belt_nr = getBeltNrFromBeltElement(element);
8069 int belt_dir_nr = element - belt_base_element[belt_nr];
8071 return (belt_dir_nr % 3);
8074 int getBeltDirNrFromBeltSwitchElement(int element)
8076 static int belt_base_element[4] =
8078 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
8079 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
8080 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
8081 EL_CONVEYOR_BELT_4_SWITCH_LEFT
8084 int belt_nr = getBeltNrFromBeltSwitchElement(element);
8085 int belt_dir_nr = element - belt_base_element[belt_nr];
8087 return (belt_dir_nr % 3);
8090 int getBeltDirFromBeltElement(int element)
8092 static int belt_move_dir[3] =
8099 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
8101 return belt_move_dir[belt_dir_nr];
8104 int getBeltDirFromBeltSwitchElement(int element)
8106 static int belt_move_dir[3] =
8113 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
8115 return belt_move_dir[belt_dir_nr];
8118 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
8120 static int belt_base_element[4] =
8122 EL_CONVEYOR_BELT_1_LEFT,
8123 EL_CONVEYOR_BELT_2_LEFT,
8124 EL_CONVEYOR_BELT_3_LEFT,
8125 EL_CONVEYOR_BELT_4_LEFT
8128 return belt_base_element[belt_nr] + belt_dir_nr;
8131 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
8133 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
8135 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
8138 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
8140 static int belt_base_element[4] =
8142 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
8143 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
8144 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
8145 EL_CONVEYOR_BELT_4_SWITCH_LEFT
8148 return belt_base_element[belt_nr] + belt_dir_nr;
8151 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
8153 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
8155 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
8158 int getNumActivePlayers_EM()
8160 int num_players = 0;
8166 for (i = 0; i < MAX_PLAYERS; i++)
8167 if (tape.player_participates[i])
8173 int getGameFrameDelay_EM(int native_em_game_frame_delay)
8175 int game_frame_delay_value;
8177 game_frame_delay_value =
8178 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
8179 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
8182 if (tape.playing && tape.warp_forward && !tape.pausing)
8183 game_frame_delay_value = 0;
8185 return game_frame_delay_value;
8188 unsigned int InitRND(int seed)
8190 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
8191 return InitEngineRandom_EM(seed);
8192 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
8193 return InitEngineRandom_SP(seed);
8195 return InitEngineRandom_RND(seed);
8199 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
8200 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
8203 inline static int get_effective_element_EM(int tile, int frame_em)
8205 int element = object_mapping[tile].element_rnd;
8206 int action = object_mapping[tile].action;
8207 boolean is_backside = object_mapping[tile].is_backside;
8208 boolean action_removing = (action == ACTION_DIGGING ||
8209 action == ACTION_SNAPPING ||
8210 action == ACTION_COLLECTING);
8216 case Yacid_splash_eB:
8217 case Yacid_splash_wB:
8218 return (frame_em > 5 ? EL_EMPTY : element);
8222 case Ydiamond_stone:
8223 // if (!game.use_native_emc_graphics_engine)
8231 else /* frame_em == 7 */
8235 case Yacid_splash_eB:
8236 case Yacid_splash_wB:
8239 case Yemerald_stone:
8242 case Ydiamond_stone:
8246 case Xdrip_stretchB:
8265 case Xsand_stonein_1:
8266 case Xsand_stonein_2:
8267 case Xsand_stonein_3:
8268 case Xsand_stonein_4:
8272 return (is_backside || action_removing ? EL_EMPTY : element);
8277 inline static boolean check_linear_animation_EM(int tile)
8281 case Xsand_stonesand_1:
8282 case Xsand_stonesand_quickout_1:
8283 case Xsand_sandstone_1:
8284 case Xsand_stonein_1:
8285 case Xsand_stoneout_1:
8305 case Yacid_splash_eB:
8306 case Yacid_splash_wB:
8307 case Yemerald_stone:
8315 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
8316 boolean has_crumbled_graphics,
8317 int crumbled, int sync_frame)
8319 /* if element can be crumbled, but certain action graphics are just empty
8320 space (like instantly snapping sand to empty space in 1 frame), do not
8321 treat these empty space graphics as crumbled graphics in EMC engine */
8322 if (crumbled == IMG_EMPTY_SPACE)
8323 has_crumbled_graphics = FALSE;
8325 if (has_crumbled_graphics)
8327 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8328 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8329 g_crumbled->anim_delay,
8330 g_crumbled->anim_mode,
8331 g_crumbled->anim_start_frame,
8334 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8335 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8337 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8339 g_em->has_crumbled_graphics = TRUE;
8343 g_em->crumbled_bitmap = NULL;
8344 g_em->crumbled_src_x = 0;
8345 g_em->crumbled_src_y = 0;
8346 g_em->crumbled_border_size = 0;
8348 g_em->has_crumbled_graphics = FALSE;
8352 void ResetGfxAnimation_EM(int x, int y, int tile)
8357 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
8358 int tile, int frame_em, int x, int y)
8360 int action = object_mapping[tile].action;
8362 int direction = object_mapping[tile].direction;
8363 int effective_element = get_effective_element_EM(tile, frame_em);
8364 int graphic = (direction == MV_NONE ?
8365 el_act2img(effective_element, action) :
8366 el_act_dir2img(effective_element, action, direction));
8367 struct GraphicInfo *g = &graphic_info[graphic];
8370 boolean action_removing = (action == ACTION_DIGGING ||
8371 action == ACTION_SNAPPING ||
8372 action == ACTION_COLLECTING);
8373 boolean action_moving = (action == ACTION_FALLING ||
8374 action == ACTION_MOVING ||
8375 action == ACTION_PUSHING ||
8376 action == ACTION_EATING ||
8377 action == ACTION_FILLING ||
8378 action == ACTION_EMPTYING);
8379 boolean action_falling = (action == ACTION_FALLING ||
8380 action == ACTION_FILLING ||
8381 action == ACTION_EMPTYING);
8383 /* special case: graphic uses "2nd movement tile" and has defined
8384 7 frames for movement animation (or less) => use default graphic
8385 for last (8th) frame which ends the movement animation */
8386 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8388 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
8389 graphic = (direction == MV_NONE ?
8390 el_act2img(effective_element, action) :
8391 el_act_dir2img(effective_element, action, direction));
8393 g = &graphic_info[graphic];
8397 if (tile == Xsand_stonesand_1 ||
8398 tile == Xsand_stonesand_2 ||
8399 tile == Xsand_stonesand_3 ||
8400 tile == Xsand_stonesand_4)
8401 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
8405 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
8409 // printf("::: resetting... [%d]\n", tile);
8412 if (action_removing || check_linear_animation_EM(tile))
8414 GfxFrame[x][y] = frame_em;
8416 // printf("::: resetting... [%d]\n", tile);
8419 else if (action_moving)
8421 boolean is_backside = object_mapping[tile].is_backside;
8425 int direction = object_mapping[tile].direction;
8426 int move_dir = (action_falling ? MV_DOWN : direction);
8431 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
8432 if (g->double_movement && frame_em == 0)
8436 // printf("::: resetting... [%d]\n", tile);
8440 if (move_dir == MV_LEFT)
8441 GfxFrame[x - 1][y] = GfxFrame[x][y];
8442 else if (move_dir == MV_RIGHT)
8443 GfxFrame[x + 1][y] = GfxFrame[x][y];
8444 else if (move_dir == MV_UP)
8445 GfxFrame[x][y - 1] = GfxFrame[x][y];
8446 else if (move_dir == MV_DOWN)
8447 GfxFrame[x][y + 1] = GfxFrame[x][y];
8454 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
8455 if (tile == Xsand_stonesand_quickout_1 ||
8456 tile == Xsand_stonesand_quickout_2)
8461 if (tile == Xsand_stonesand_1 ||
8462 tile == Xsand_stonesand_2 ||
8463 tile == Xsand_stonesand_3 ||
8464 tile == Xsand_stonesand_4)
8465 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
8469 if (graphic_info[graphic].anim_global_sync)
8470 sync_frame = FrameCounter;
8471 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8472 sync_frame = GfxFrame[x][y];
8474 sync_frame = 0; /* playfield border (pseudo steel) */
8476 SetRandomAnimationValue(x, y);
8478 int frame = getAnimationFrame(g->anim_frames,
8481 g->anim_start_frame,
8484 g_em->unique_identifier =
8485 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
8489 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
8490 int tile, int frame_em, int x, int y)
8492 int action = object_mapping[tile].action;
8493 int direction = object_mapping[tile].direction;
8494 boolean is_backside = object_mapping[tile].is_backside;
8495 int effective_element = get_effective_element_EM(tile, frame_em);
8497 int effective_action = action;
8499 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
8501 int graphic = (direction == MV_NONE ?
8502 el_act2img(effective_element, effective_action) :
8503 el_act_dir2img(effective_element, effective_action,
8505 int crumbled = (direction == MV_NONE ?
8506 el_act2crm(effective_element, effective_action) :
8507 el_act_dir2crm(effective_element, effective_action,
8509 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8510 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8511 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8512 struct GraphicInfo *g = &graphic_info[graphic];
8514 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8518 /* special case: graphic uses "2nd movement tile" and has defined
8519 7 frames for movement animation (or less) => use default graphic
8520 for last (8th) frame which ends the movement animation */
8521 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8523 effective_action = ACTION_DEFAULT;
8524 graphic = (direction == MV_NONE ?
8525 el_act2img(effective_element, effective_action) :
8526 el_act_dir2img(effective_element, effective_action,
8528 crumbled = (direction == MV_NONE ?
8529 el_act2crm(effective_element, effective_action) :
8530 el_act_dir2crm(effective_element, effective_action,
8533 g = &graphic_info[graphic];
8543 if (frame_em == 0) /* reset animation frame for certain elements */
8545 if (check_linear_animation_EM(tile))
8550 if (graphic_info[graphic].anim_global_sync)
8551 sync_frame = FrameCounter;
8552 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8553 sync_frame = GfxFrame[x][y];
8555 sync_frame = 0; /* playfield border (pseudo steel) */
8557 SetRandomAnimationValue(x, y);
8562 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
8563 i == Xdrip_stretchB ? 7 :
8564 i == Ydrip_s2 ? j + 8 :
8565 i == Ydrip_s2B ? j + 8 :
8574 i == Xfake_acid_1 ? 0 :
8575 i == Xfake_acid_2 ? 10 :
8576 i == Xfake_acid_3 ? 20 :
8577 i == Xfake_acid_4 ? 30 :
8578 i == Xfake_acid_5 ? 40 :
8579 i == Xfake_acid_6 ? 50 :
8580 i == Xfake_acid_7 ? 60 :
8581 i == Xfake_acid_8 ? 70 :
8583 i == Xball_2B ? j + 8 :
8584 i == Yball_eat ? j + 1 :
8585 i == Ykey_1_eat ? j + 1 :
8586 i == Ykey_2_eat ? j + 1 :
8587 i == Ykey_3_eat ? j + 1 :
8588 i == Ykey_4_eat ? j + 1 :
8589 i == Ykey_5_eat ? j + 1 :
8590 i == Ykey_6_eat ? j + 1 :
8591 i == Ykey_7_eat ? j + 1 :
8592 i == Ykey_8_eat ? j + 1 :
8593 i == Ylenses_eat ? j + 1 :
8594 i == Ymagnify_eat ? j + 1 :
8595 i == Ygrass_eat ? j + 1 :
8596 i == Ydirt_eat ? j + 1 :
8597 i == Xamoeba_1 ? 0 :
8598 i == Xamoeba_2 ? 1 :
8599 i == Xamoeba_3 ? 2 :
8600 i == Xamoeba_4 ? 3 :
8601 i == Xamoeba_5 ? 0 :
8602 i == Xamoeba_6 ? 1 :
8603 i == Xamoeba_7 ? 2 :
8604 i == Xamoeba_8 ? 3 :
8605 i == Xexit_2 ? j + 8 :
8606 i == Xexit_3 ? j + 16 :
8607 i == Xdynamite_1 ? 0 :
8608 i == Xdynamite_2 ? 8 :
8609 i == Xdynamite_3 ? 16 :
8610 i == Xdynamite_4 ? 24 :
8611 i == Xsand_stonein_1 ? j + 1 :
8612 i == Xsand_stonein_2 ? j + 9 :
8613 i == Xsand_stonein_3 ? j + 17 :
8614 i == Xsand_stonein_4 ? j + 25 :
8615 i == Xsand_stoneout_1 && j == 0 ? 0 :
8616 i == Xsand_stoneout_1 && j == 1 ? 0 :
8617 i == Xsand_stoneout_1 && j == 2 ? 1 :
8618 i == Xsand_stoneout_1 && j == 3 ? 2 :
8619 i == Xsand_stoneout_1 && j == 4 ? 2 :
8620 i == Xsand_stoneout_1 && j == 5 ? 3 :
8621 i == Xsand_stoneout_1 && j == 6 ? 4 :
8622 i == Xsand_stoneout_1 && j == 7 ? 4 :
8623 i == Xsand_stoneout_2 && j == 0 ? 5 :
8624 i == Xsand_stoneout_2 && j == 1 ? 6 :
8625 i == Xsand_stoneout_2 && j == 2 ? 7 :
8626 i == Xsand_stoneout_2 && j == 3 ? 8 :
8627 i == Xsand_stoneout_2 && j == 4 ? 9 :
8628 i == Xsand_stoneout_2 && j == 5 ? 11 :
8629 i == Xsand_stoneout_2 && j == 6 ? 13 :
8630 i == Xsand_stoneout_2 && j == 7 ? 15 :
8631 i == Xboom_bug && j == 1 ? 2 :
8632 i == Xboom_bug && j == 2 ? 2 :
8633 i == Xboom_bug && j == 3 ? 4 :
8634 i == Xboom_bug && j == 4 ? 4 :
8635 i == Xboom_bug && j == 5 ? 2 :
8636 i == Xboom_bug && j == 6 ? 2 :
8637 i == Xboom_bug && j == 7 ? 0 :
8638 i == Xboom_bomb && j == 1 ? 2 :
8639 i == Xboom_bomb && j == 2 ? 2 :
8640 i == Xboom_bomb && j == 3 ? 4 :
8641 i == Xboom_bomb && j == 4 ? 4 :
8642 i == Xboom_bomb && j == 5 ? 2 :
8643 i == Xboom_bomb && j == 6 ? 2 :
8644 i == Xboom_bomb && j == 7 ? 0 :
8645 i == Xboom_android && j == 7 ? 6 :
8646 i == Xboom_1 && j == 1 ? 2 :
8647 i == Xboom_1 && j == 2 ? 2 :
8648 i == Xboom_1 && j == 3 ? 4 :
8649 i == Xboom_1 && j == 4 ? 4 :
8650 i == Xboom_1 && j == 5 ? 6 :
8651 i == Xboom_1 && j == 6 ? 6 :
8652 i == Xboom_1 && j == 7 ? 8 :
8653 i == Xboom_2 && j == 0 ? 8 :
8654 i == Xboom_2 && j == 1 ? 8 :
8655 i == Xboom_2 && j == 2 ? 10 :
8656 i == Xboom_2 && j == 3 ? 10 :
8657 i == Xboom_2 && j == 4 ? 10 :
8658 i == Xboom_2 && j == 5 ? 12 :
8659 i == Xboom_2 && j == 6 ? 12 :
8660 i == Xboom_2 && j == 7 ? 12 :
8662 special_animation && j == 4 ? 3 :
8663 effective_action != action ? 0 :
8669 int xxx_effective_action;
8670 int xxx_has_action_graphics;
8673 int element = object_mapping[i].element_rnd;
8674 int action = object_mapping[i].action;
8675 int direction = object_mapping[i].direction;
8676 boolean is_backside = object_mapping[i].is_backside;
8678 boolean action_removing = (action == ACTION_DIGGING ||
8679 action == ACTION_SNAPPING ||
8680 action == ACTION_COLLECTING);
8682 boolean action_exploding = ((action == ACTION_EXPLODING ||
8683 action == ACTION_SMASHED_BY_ROCK ||
8684 action == ACTION_SMASHED_BY_SPRING) &&
8685 element != EL_DIAMOND);
8686 boolean action_active = (action == ACTION_ACTIVE);
8687 boolean action_other = (action == ACTION_OTHER);
8691 int effective_element = get_effective_element_EM(i, j);
8693 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8694 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8696 i == Xdrip_stretch ? element :
8697 i == Xdrip_stretchB ? element :
8698 i == Ydrip_s1 ? element :
8699 i == Ydrip_s1B ? element :
8700 i == Xball_1B ? element :
8701 i == Xball_2 ? element :
8702 i == Xball_2B ? element :
8703 i == Yball_eat ? element :
8704 i == Ykey_1_eat ? element :
8705 i == Ykey_2_eat ? element :
8706 i == Ykey_3_eat ? element :
8707 i == Ykey_4_eat ? element :
8708 i == Ykey_5_eat ? element :
8709 i == Ykey_6_eat ? element :
8710 i == Ykey_7_eat ? element :
8711 i == Ykey_8_eat ? element :
8712 i == Ylenses_eat ? element :
8713 i == Ymagnify_eat ? element :
8714 i == Ygrass_eat ? element :
8715 i == Ydirt_eat ? element :
8716 i == Yemerald_stone ? EL_EMERALD :
8717 i == Ydiamond_stone ? EL_ROCK :
8718 i == Xsand_stonein_1 ? element :
8719 i == Xsand_stonein_2 ? element :
8720 i == Xsand_stonein_3 ? element :
8721 i == Xsand_stonein_4 ? element :
8722 is_backside ? EL_EMPTY :
8723 action_removing ? EL_EMPTY :
8726 int effective_action = (j < 7 ? action :
8727 i == Xdrip_stretch ? action :
8728 i == Xdrip_stretchB ? action :
8729 i == Ydrip_s1 ? action :
8730 i == Ydrip_s1B ? action :
8731 i == Xball_1B ? action :
8732 i == Xball_2 ? action :
8733 i == Xball_2B ? action :
8734 i == Yball_eat ? action :
8735 i == Ykey_1_eat ? action :
8736 i == Ykey_2_eat ? action :
8737 i == Ykey_3_eat ? action :
8738 i == Ykey_4_eat ? action :
8739 i == Ykey_5_eat ? action :
8740 i == Ykey_6_eat ? action :
8741 i == Ykey_7_eat ? action :
8742 i == Ykey_8_eat ? action :
8743 i == Ylenses_eat ? action :
8744 i == Ymagnify_eat ? action :
8745 i == Ygrass_eat ? action :
8746 i == Ydirt_eat ? action :
8747 i == Xsand_stonein_1 ? action :
8748 i == Xsand_stonein_2 ? action :
8749 i == Xsand_stonein_3 ? action :
8750 i == Xsand_stonein_4 ? action :
8751 i == Xsand_stoneout_1 ? action :
8752 i == Xsand_stoneout_2 ? action :
8753 i == Xboom_android ? ACTION_EXPLODING :
8754 action_exploding ? ACTION_EXPLODING :
8755 action_active ? action :
8756 action_other ? action :
8758 int graphic = (el_act_dir2img(effective_element, effective_action,
8760 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8762 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8763 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8764 boolean has_action_graphics = (graphic != base_graphic);
8765 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8766 struct GraphicInfo *g = &graphic_info[graphic];
8768 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8770 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8773 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8774 boolean special_animation = (action != ACTION_DEFAULT &&
8775 g->anim_frames == 3 &&
8776 g->anim_delay == 2 &&
8777 g->anim_mode & ANIM_LINEAR);
8778 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
8779 i == Xdrip_stretchB ? 7 :
8780 i == Ydrip_s2 ? j + 8 :
8781 i == Ydrip_s2B ? j + 8 :
8790 i == Xfake_acid_1 ? 0 :
8791 i == Xfake_acid_2 ? 10 :
8792 i == Xfake_acid_3 ? 20 :
8793 i == Xfake_acid_4 ? 30 :
8794 i == Xfake_acid_5 ? 40 :
8795 i == Xfake_acid_6 ? 50 :
8796 i == Xfake_acid_7 ? 60 :
8797 i == Xfake_acid_8 ? 70 :
8799 i == Xball_2B ? j + 8 :
8800 i == Yball_eat ? j + 1 :
8801 i == Ykey_1_eat ? j + 1 :
8802 i == Ykey_2_eat ? j + 1 :
8803 i == Ykey_3_eat ? j + 1 :
8804 i == Ykey_4_eat ? j + 1 :
8805 i == Ykey_5_eat ? j + 1 :
8806 i == Ykey_6_eat ? j + 1 :
8807 i == Ykey_7_eat ? j + 1 :
8808 i == Ykey_8_eat ? j + 1 :
8809 i == Ylenses_eat ? j + 1 :
8810 i == Ymagnify_eat ? j + 1 :
8811 i == Ygrass_eat ? j + 1 :
8812 i == Ydirt_eat ? j + 1 :
8813 i == Xamoeba_1 ? 0 :
8814 i == Xamoeba_2 ? 1 :
8815 i == Xamoeba_3 ? 2 :
8816 i == Xamoeba_4 ? 3 :
8817 i == Xamoeba_5 ? 0 :
8818 i == Xamoeba_6 ? 1 :
8819 i == Xamoeba_7 ? 2 :
8820 i == Xamoeba_8 ? 3 :
8821 i == Xexit_2 ? j + 8 :
8822 i == Xexit_3 ? j + 16 :
8823 i == Xdynamite_1 ? 0 :
8824 i == Xdynamite_2 ? 8 :
8825 i == Xdynamite_3 ? 16 :
8826 i == Xdynamite_4 ? 24 :
8827 i == Xsand_stonein_1 ? j + 1 :
8828 i == Xsand_stonein_2 ? j + 9 :
8829 i == Xsand_stonein_3 ? j + 17 :
8830 i == Xsand_stonein_4 ? j + 25 :
8831 i == Xsand_stoneout_1 && j == 0 ? 0 :
8832 i == Xsand_stoneout_1 && j == 1 ? 0 :
8833 i == Xsand_stoneout_1 && j == 2 ? 1 :
8834 i == Xsand_stoneout_1 && j == 3 ? 2 :
8835 i == Xsand_stoneout_1 && j == 4 ? 2 :
8836 i == Xsand_stoneout_1 && j == 5 ? 3 :
8837 i == Xsand_stoneout_1 && j == 6 ? 4 :
8838 i == Xsand_stoneout_1 && j == 7 ? 4 :
8839 i == Xsand_stoneout_2 && j == 0 ? 5 :
8840 i == Xsand_stoneout_2 && j == 1 ? 6 :
8841 i == Xsand_stoneout_2 && j == 2 ? 7 :
8842 i == Xsand_stoneout_2 && j == 3 ? 8 :
8843 i == Xsand_stoneout_2 && j == 4 ? 9 :
8844 i == Xsand_stoneout_2 && j == 5 ? 11 :
8845 i == Xsand_stoneout_2 && j == 6 ? 13 :
8846 i == Xsand_stoneout_2 && j == 7 ? 15 :
8847 i == Xboom_bug && j == 1 ? 2 :
8848 i == Xboom_bug && j == 2 ? 2 :
8849 i == Xboom_bug && j == 3 ? 4 :
8850 i == Xboom_bug && j == 4 ? 4 :
8851 i == Xboom_bug && j == 5 ? 2 :
8852 i == Xboom_bug && j == 6 ? 2 :
8853 i == Xboom_bug && j == 7 ? 0 :
8854 i == Xboom_bomb && j == 1 ? 2 :
8855 i == Xboom_bomb && j == 2 ? 2 :
8856 i == Xboom_bomb && j == 3 ? 4 :
8857 i == Xboom_bomb && j == 4 ? 4 :
8858 i == Xboom_bomb && j == 5 ? 2 :
8859 i == Xboom_bomb && j == 6 ? 2 :
8860 i == Xboom_bomb && j == 7 ? 0 :
8861 i == Xboom_android && j == 7 ? 6 :
8862 i == Xboom_1 && j == 1 ? 2 :
8863 i == Xboom_1 && j == 2 ? 2 :
8864 i == Xboom_1 && j == 3 ? 4 :
8865 i == Xboom_1 && j == 4 ? 4 :
8866 i == Xboom_1 && j == 5 ? 6 :
8867 i == Xboom_1 && j == 6 ? 6 :
8868 i == Xboom_1 && j == 7 ? 8 :
8869 i == Xboom_2 && j == 0 ? 8 :
8870 i == Xboom_2 && j == 1 ? 8 :
8871 i == Xboom_2 && j == 2 ? 10 :
8872 i == Xboom_2 && j == 3 ? 10 :
8873 i == Xboom_2 && j == 4 ? 10 :
8874 i == Xboom_2 && j == 5 ? 12 :
8875 i == Xboom_2 && j == 6 ? 12 :
8876 i == Xboom_2 && j == 7 ? 12 :
8877 special_animation && j == 4 ? 3 :
8878 effective_action != action ? 0 :
8881 xxx_effective_action = effective_action;
8882 xxx_has_action_graphics = has_action_graphics;
8887 int frame = getAnimationFrame(g->anim_frames,
8890 g->anim_start_frame,
8904 int old_src_x = g_em->src_x;
8905 int old_src_y = g_em->src_y;
8909 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
8910 g->double_movement && is_backside);
8912 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8913 &g_em->src_x, &g_em->src_y, FALSE);
8918 if (tile == Ydiamond_stone)
8919 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
8924 g->anim_start_frame,
8927 g_em->src_x, g_em->src_y,
8928 g_em->src_offset_x, g_em->src_offset_y,
8929 g_em->dst_offset_x, g_em->dst_offset_y,
8941 if (graphic == IMG_BUG_MOVING_RIGHT)
8942 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
8943 g->double_movement, is_backside,
8944 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
8952 g_em->src_offset_x = 0;
8953 g_em->src_offset_y = 0;
8954 g_em->dst_offset_x = 0;
8955 g_em->dst_offset_y = 0;
8956 g_em->width = TILEX;
8957 g_em->height = TILEY;
8959 g_em->preserve_background = FALSE;
8962 /* (updating the "crumbled" graphic definitions is probably not really needed,
8963 as animations for crumbled graphics can't be longer than one EMC cycle) */
8965 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8970 g_em->crumbled_bitmap = NULL;
8971 g_em->crumbled_src_x = 0;
8972 g_em->crumbled_src_y = 0;
8974 g_em->has_crumbled_graphics = FALSE;
8976 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8978 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8979 g_crumbled->anim_delay,
8980 g_crumbled->anim_mode,
8981 g_crumbled->anim_start_frame,
8984 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8985 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8987 g_em->has_crumbled_graphics = TRUE;
8993 int effective_action = xxx_effective_action;
8994 int has_action_graphics = xxx_has_action_graphics;
8996 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8997 effective_action == ACTION_MOVING ||
8998 effective_action == ACTION_PUSHING ||
8999 effective_action == ACTION_EATING)) ||
9000 (!has_action_graphics && (effective_action == ACTION_FILLING ||
9001 effective_action == ACTION_EMPTYING)))
9004 (effective_action == ACTION_FALLING ||
9005 effective_action == ACTION_FILLING ||
9006 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
9007 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
9008 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
9009 int num_steps = (i == Ydrip_s1 ? 16 :
9010 i == Ydrip_s1B ? 16 :
9011 i == Ydrip_s2 ? 16 :
9012 i == Ydrip_s2B ? 16 :
9013 i == Xsand_stonein_1 ? 32 :
9014 i == Xsand_stonein_2 ? 32 :
9015 i == Xsand_stonein_3 ? 32 :
9016 i == Xsand_stonein_4 ? 32 :
9017 i == Xsand_stoneout_1 ? 16 :
9018 i == Xsand_stoneout_2 ? 16 : 8);
9019 int cx = ABS(dx) * (TILEX / num_steps);
9020 int cy = ABS(dy) * (TILEY / num_steps);
9021 int step_frame = (i == Ydrip_s2 ? j + 8 :
9022 i == Ydrip_s2B ? j + 8 :
9023 i == Xsand_stonein_2 ? j + 8 :
9024 i == Xsand_stonein_3 ? j + 16 :
9025 i == Xsand_stonein_4 ? j + 24 :
9026 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
9027 int step = (is_backside ? step_frame : num_steps - step_frame);
9029 if (is_backside) /* tile where movement starts */
9031 if (dx < 0 || dy < 0)
9033 g_em->src_offset_x = cx * step;
9034 g_em->src_offset_y = cy * step;
9038 g_em->dst_offset_x = cx * step;
9039 g_em->dst_offset_y = cy * step;
9042 else /* tile where movement ends */
9044 if (dx < 0 || dy < 0)
9046 g_em->dst_offset_x = cx * step;
9047 g_em->dst_offset_y = cy * step;
9051 g_em->src_offset_x = cx * step;
9052 g_em->src_offset_y = cy * step;
9056 g_em->width = TILEX - cx * step;
9057 g_em->height = TILEY - cy * step;
9060 /* create unique graphic identifier to decide if tile must be redrawn */
9061 /* bit 31 - 16 (16 bit): EM style graphic
9062 bit 15 - 12 ( 4 bit): EM style frame
9063 bit 11 - 6 ( 6 bit): graphic width
9064 bit 5 - 0 ( 6 bit): graphic height */
9065 g_em->unique_identifier =
9066 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
9072 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
9073 int player_nr, int anim, int frame_em)
9075 int element = player_mapping[player_nr][anim].element_rnd;
9076 int action = player_mapping[player_nr][anim].action;
9077 int direction = player_mapping[player_nr][anim].direction;
9078 int graphic = (direction == MV_NONE ?
9079 el_act2img(element, action) :
9080 el_act_dir2img(element, action, direction));
9081 struct GraphicInfo *g = &graphic_info[graphic];
9084 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
9086 stored_player[player_nr].StepFrame = frame_em;
9088 sync_frame = stored_player[player_nr].Frame;
9090 int frame = getAnimationFrame(g->anim_frames,
9093 g->anim_start_frame,
9096 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
9097 &g_em->src_x, &g_em->src_y, FALSE);
9100 printf("::: %d: %d, %d [%d]\n",
9102 stored_player[player_nr].Frame,
9103 stored_player[player_nr].StepFrame,
9108 void InitGraphicInfo_EM(void)
9111 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9112 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9117 int num_em_gfx_errors = 0;
9119 if (graphic_info_em_object[0][0].bitmap == NULL)
9121 /* EM graphics not yet initialized in em_open_all() */
9126 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
9129 /* always start with reliable default values */
9130 for (i = 0; i < TILE_MAX; i++)
9132 object_mapping[i].element_rnd = EL_UNKNOWN;
9133 object_mapping[i].is_backside = FALSE;
9134 object_mapping[i].action = ACTION_DEFAULT;
9135 object_mapping[i].direction = MV_NONE;
9138 /* always start with reliable default values */
9139 for (p = 0; p < MAX_PLAYERS; p++)
9141 for (i = 0; i < SPR_MAX; i++)
9143 player_mapping[p][i].element_rnd = EL_UNKNOWN;
9144 player_mapping[p][i].action = ACTION_DEFAULT;
9145 player_mapping[p][i].direction = MV_NONE;
9149 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9151 int e = em_object_mapping_list[i].element_em;
9153 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
9154 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
9156 if (em_object_mapping_list[i].action != -1)
9157 object_mapping[e].action = em_object_mapping_list[i].action;
9159 if (em_object_mapping_list[i].direction != -1)
9160 object_mapping[e].direction =
9161 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
9164 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
9166 int a = em_player_mapping_list[i].action_em;
9167 int p = em_player_mapping_list[i].player_nr;
9169 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
9171 if (em_player_mapping_list[i].action != -1)
9172 player_mapping[p][a].action = em_player_mapping_list[i].action;
9174 if (em_player_mapping_list[i].direction != -1)
9175 player_mapping[p][a].direction =
9176 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
9179 for (i = 0; i < TILE_MAX; i++)
9181 int element = object_mapping[i].element_rnd;
9182 int action = object_mapping[i].action;
9183 int direction = object_mapping[i].direction;
9184 boolean is_backside = object_mapping[i].is_backside;
9186 boolean action_removing = (action == ACTION_DIGGING ||
9187 action == ACTION_SNAPPING ||
9188 action == ACTION_COLLECTING);
9190 boolean action_exploding = ((action == ACTION_EXPLODING ||
9191 action == ACTION_SMASHED_BY_ROCK ||
9192 action == ACTION_SMASHED_BY_SPRING) &&
9193 element != EL_DIAMOND);
9194 boolean action_active = (action == ACTION_ACTIVE);
9195 boolean action_other = (action == ACTION_OTHER);
9197 for (j = 0; j < 8; j++)
9200 int effective_element = get_effective_element_EM(i, j);
9202 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
9203 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
9205 i == Xdrip_stretch ? element :
9206 i == Xdrip_stretchB ? element :
9207 i == Ydrip_s1 ? element :
9208 i == Ydrip_s1B ? element :
9209 i == Xball_1B ? element :
9210 i == Xball_2 ? element :
9211 i == Xball_2B ? element :
9212 i == Yball_eat ? element :
9213 i == Ykey_1_eat ? element :
9214 i == Ykey_2_eat ? element :
9215 i == Ykey_3_eat ? element :
9216 i == Ykey_4_eat ? element :
9217 i == Ykey_5_eat ? element :
9218 i == Ykey_6_eat ? element :
9219 i == Ykey_7_eat ? element :
9220 i == Ykey_8_eat ? element :
9221 i == Ylenses_eat ? element :
9222 i == Ymagnify_eat ? element :
9223 i == Ygrass_eat ? element :
9224 i == Ydirt_eat ? element :
9225 i == Yemerald_stone ? EL_EMERALD :
9226 i == Ydiamond_stone ? EL_ROCK :
9227 i == Xsand_stonein_1 ? element :
9228 i == Xsand_stonein_2 ? element :
9229 i == Xsand_stonein_3 ? element :
9230 i == Xsand_stonein_4 ? element :
9231 is_backside ? EL_EMPTY :
9232 action_removing ? EL_EMPTY :
9235 int effective_action = (j < 7 ? action :
9236 i == Xdrip_stretch ? action :
9237 i == Xdrip_stretchB ? action :
9238 i == Ydrip_s1 ? action :
9239 i == Ydrip_s1B ? action :
9240 i == Xball_1B ? action :
9241 i == Xball_2 ? action :
9242 i == Xball_2B ? action :
9243 i == Yball_eat ? action :
9244 i == Ykey_1_eat ? action :
9245 i == Ykey_2_eat ? action :
9246 i == Ykey_3_eat ? action :
9247 i == Ykey_4_eat ? action :
9248 i == Ykey_5_eat ? action :
9249 i == Ykey_6_eat ? action :
9250 i == Ykey_7_eat ? action :
9251 i == Ykey_8_eat ? action :
9252 i == Ylenses_eat ? action :
9253 i == Ymagnify_eat ? action :
9254 i == Ygrass_eat ? action :
9255 i == Ydirt_eat ? action :
9256 i == Xsand_stonein_1 ? action :
9257 i == Xsand_stonein_2 ? action :
9258 i == Xsand_stonein_3 ? action :
9259 i == Xsand_stonein_4 ? action :
9260 i == Xsand_stoneout_1 ? action :
9261 i == Xsand_stoneout_2 ? action :
9262 i == Xboom_android ? ACTION_EXPLODING :
9263 action_exploding ? ACTION_EXPLODING :
9264 action_active ? action :
9265 action_other ? action :
9267 int graphic = (el_act_dir2img(effective_element, effective_action,
9269 int crumbled = (el_act_dir2crm(effective_element, effective_action,
9271 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9272 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9273 boolean has_action_graphics = (graphic != base_graphic);
9274 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9275 struct GraphicInfo *g = &graphic_info[graphic];
9277 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9279 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
9282 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
9283 boolean special_animation = (action != ACTION_DEFAULT &&
9284 g->anim_frames == 3 &&
9285 g->anim_delay == 2 &&
9286 g->anim_mode & ANIM_LINEAR);
9287 int sync_frame = (i == Xdrip_stretch ? 7 :
9288 i == Xdrip_stretchB ? 7 :
9289 i == Ydrip_s2 ? j + 8 :
9290 i == Ydrip_s2B ? j + 8 :
9299 i == Xfake_acid_1 ? 0 :
9300 i == Xfake_acid_2 ? 10 :
9301 i == Xfake_acid_3 ? 20 :
9302 i == Xfake_acid_4 ? 30 :
9303 i == Xfake_acid_5 ? 40 :
9304 i == Xfake_acid_6 ? 50 :
9305 i == Xfake_acid_7 ? 60 :
9306 i == Xfake_acid_8 ? 70 :
9308 i == Xball_2B ? j + 8 :
9309 i == Yball_eat ? j + 1 :
9310 i == Ykey_1_eat ? j + 1 :
9311 i == Ykey_2_eat ? j + 1 :
9312 i == Ykey_3_eat ? j + 1 :
9313 i == Ykey_4_eat ? j + 1 :
9314 i == Ykey_5_eat ? j + 1 :
9315 i == Ykey_6_eat ? j + 1 :
9316 i == Ykey_7_eat ? j + 1 :
9317 i == Ykey_8_eat ? j + 1 :
9318 i == Ylenses_eat ? j + 1 :
9319 i == Ymagnify_eat ? j + 1 :
9320 i == Ygrass_eat ? j + 1 :
9321 i == Ydirt_eat ? j + 1 :
9322 i == Xamoeba_1 ? 0 :
9323 i == Xamoeba_2 ? 1 :
9324 i == Xamoeba_3 ? 2 :
9325 i == Xamoeba_4 ? 3 :
9326 i == Xamoeba_5 ? 0 :
9327 i == Xamoeba_6 ? 1 :
9328 i == Xamoeba_7 ? 2 :
9329 i == Xamoeba_8 ? 3 :
9330 i == Xexit_2 ? j + 8 :
9331 i == Xexit_3 ? j + 16 :
9332 i == Xdynamite_1 ? 0 :
9333 i == Xdynamite_2 ? 8 :
9334 i == Xdynamite_3 ? 16 :
9335 i == Xdynamite_4 ? 24 :
9336 i == Xsand_stonein_1 ? j + 1 :
9337 i == Xsand_stonein_2 ? j + 9 :
9338 i == Xsand_stonein_3 ? j + 17 :
9339 i == Xsand_stonein_4 ? j + 25 :
9340 i == Xsand_stoneout_1 && j == 0 ? 0 :
9341 i == Xsand_stoneout_1 && j == 1 ? 0 :
9342 i == Xsand_stoneout_1 && j == 2 ? 1 :
9343 i == Xsand_stoneout_1 && j == 3 ? 2 :
9344 i == Xsand_stoneout_1 && j == 4 ? 2 :
9345 i == Xsand_stoneout_1 && j == 5 ? 3 :
9346 i == Xsand_stoneout_1 && j == 6 ? 4 :
9347 i == Xsand_stoneout_1 && j == 7 ? 4 :
9348 i == Xsand_stoneout_2 && j == 0 ? 5 :
9349 i == Xsand_stoneout_2 && j == 1 ? 6 :
9350 i == Xsand_stoneout_2 && j == 2 ? 7 :
9351 i == Xsand_stoneout_2 && j == 3 ? 8 :
9352 i == Xsand_stoneout_2 && j == 4 ? 9 :
9353 i == Xsand_stoneout_2 && j == 5 ? 11 :
9354 i == Xsand_stoneout_2 && j == 6 ? 13 :
9355 i == Xsand_stoneout_2 && j == 7 ? 15 :
9356 i == Xboom_bug && j == 1 ? 2 :
9357 i == Xboom_bug && j == 2 ? 2 :
9358 i == Xboom_bug && j == 3 ? 4 :
9359 i == Xboom_bug && j == 4 ? 4 :
9360 i == Xboom_bug && j == 5 ? 2 :
9361 i == Xboom_bug && j == 6 ? 2 :
9362 i == Xboom_bug && j == 7 ? 0 :
9363 i == Xboom_bomb && j == 1 ? 2 :
9364 i == Xboom_bomb && j == 2 ? 2 :
9365 i == Xboom_bomb && j == 3 ? 4 :
9366 i == Xboom_bomb && j == 4 ? 4 :
9367 i == Xboom_bomb && j == 5 ? 2 :
9368 i == Xboom_bomb && j == 6 ? 2 :
9369 i == Xboom_bomb && j == 7 ? 0 :
9370 i == Xboom_android && j == 7 ? 6 :
9371 i == Xboom_1 && j == 1 ? 2 :
9372 i == Xboom_1 && j == 2 ? 2 :
9373 i == Xboom_1 && j == 3 ? 4 :
9374 i == Xboom_1 && j == 4 ? 4 :
9375 i == Xboom_1 && j == 5 ? 6 :
9376 i == Xboom_1 && j == 6 ? 6 :
9377 i == Xboom_1 && j == 7 ? 8 :
9378 i == Xboom_2 && j == 0 ? 8 :
9379 i == Xboom_2 && j == 1 ? 8 :
9380 i == Xboom_2 && j == 2 ? 10 :
9381 i == Xboom_2 && j == 3 ? 10 :
9382 i == Xboom_2 && j == 4 ? 10 :
9383 i == Xboom_2 && j == 5 ? 12 :
9384 i == Xboom_2 && j == 6 ? 12 :
9385 i == Xboom_2 && j == 7 ? 12 :
9386 special_animation && j == 4 ? 3 :
9387 effective_action != action ? 0 :
9391 Bitmap *debug_bitmap = g_em->bitmap;
9392 int debug_src_x = g_em->src_x;
9393 int debug_src_y = g_em->src_y;
9396 int frame = getAnimationFrame(g->anim_frames,
9399 g->anim_start_frame,
9402 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
9403 g->double_movement && is_backside);
9405 g_em->bitmap = src_bitmap;
9406 g_em->src_x = src_x;
9407 g_em->src_y = src_y;
9408 g_em->src_offset_x = 0;
9409 g_em->src_offset_y = 0;
9410 g_em->dst_offset_x = 0;
9411 g_em->dst_offset_y = 0;
9412 g_em->width = TILEX;
9413 g_em->height = TILEY;
9415 g_em->preserve_background = FALSE;
9418 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
9423 g_em->crumbled_bitmap = NULL;
9424 g_em->crumbled_src_x = 0;
9425 g_em->crumbled_src_y = 0;
9426 g_em->crumbled_border_size = 0;
9428 g_em->has_crumbled_graphics = FALSE;
9431 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
9432 printf("::: empty crumbled: %d [%s], %d, %d\n",
9433 effective_element, element_info[effective_element].token_name,
9434 effective_action, direction);
9437 /* if element can be crumbled, but certain action graphics are just empty
9438 space (like instantly snapping sand to empty space in 1 frame), do not
9439 treat these empty space graphics as crumbled graphics in EMC engine */
9440 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
9442 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9443 g_crumbled->anim_delay,
9444 g_crumbled->anim_mode,
9445 g_crumbled->anim_start_frame,
9448 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
9450 g_em->has_crumbled_graphics = TRUE;
9451 g_em->crumbled_bitmap = src_bitmap;
9452 g_em->crumbled_src_x = src_x;
9453 g_em->crumbled_src_y = src_y;
9454 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9458 if (g_em == &graphic_info_em_object[207][0])
9459 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
9460 graphic_info_em_object[207][0].crumbled_src_x,
9461 graphic_info_em_object[207][0].crumbled_src_y,
9463 crumbled, frame, src_x, src_y,
9468 g->anim_start_frame,
9470 gfx.anim_random_frame,
9475 printf("::: EMC tile %d is crumbled\n", i);
9481 if (element == EL_ROCK &&
9482 effective_action == ACTION_FILLING)
9483 printf("::: has_action_graphics == %d\n", has_action_graphics);
9486 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
9487 effective_action == ACTION_MOVING ||
9488 effective_action == ACTION_PUSHING ||
9489 effective_action == ACTION_EATING)) ||
9490 (!has_action_graphics && (effective_action == ACTION_FILLING ||
9491 effective_action == ACTION_EMPTYING)))
9494 (effective_action == ACTION_FALLING ||
9495 effective_action == ACTION_FILLING ||
9496 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
9497 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
9498 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
9499 int num_steps = (i == Ydrip_s1 ? 16 :
9500 i == Ydrip_s1B ? 16 :
9501 i == Ydrip_s2 ? 16 :
9502 i == Ydrip_s2B ? 16 :
9503 i == Xsand_stonein_1 ? 32 :
9504 i == Xsand_stonein_2 ? 32 :
9505 i == Xsand_stonein_3 ? 32 :
9506 i == Xsand_stonein_4 ? 32 :
9507 i == Xsand_stoneout_1 ? 16 :
9508 i == Xsand_stoneout_2 ? 16 : 8);
9509 int cx = ABS(dx) * (TILEX / num_steps);
9510 int cy = ABS(dy) * (TILEY / num_steps);
9511 int step_frame = (i == Ydrip_s2 ? j + 8 :
9512 i == Ydrip_s2B ? j + 8 :
9513 i == Xsand_stonein_2 ? j + 8 :
9514 i == Xsand_stonein_3 ? j + 16 :
9515 i == Xsand_stonein_4 ? j + 24 :
9516 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
9517 int step = (is_backside ? step_frame : num_steps - step_frame);
9519 if (is_backside) /* tile where movement starts */
9521 if (dx < 0 || dy < 0)
9523 g_em->src_offset_x = cx * step;
9524 g_em->src_offset_y = cy * step;
9528 g_em->dst_offset_x = cx * step;
9529 g_em->dst_offset_y = cy * step;
9532 else /* tile where movement ends */
9534 if (dx < 0 || dy < 0)
9536 g_em->dst_offset_x = cx * step;
9537 g_em->dst_offset_y = cy * step;
9541 g_em->src_offset_x = cx * step;
9542 g_em->src_offset_y = cy * step;
9546 g_em->width = TILEX - cx * step;
9547 g_em->height = TILEY - cy * step;
9550 /* create unique graphic identifier to decide if tile must be redrawn */
9551 /* bit 31 - 16 (16 bit): EM style graphic
9552 bit 15 - 12 ( 4 bit): EM style frame
9553 bit 11 - 6 ( 6 bit): graphic width
9554 bit 5 - 0 ( 6 bit): graphic height */
9555 g_em->unique_identifier =
9556 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
9560 /* skip check for EMC elements not contained in original EMC artwork */
9561 if (element == EL_EMC_FAKE_ACID)
9564 if (g_em->bitmap != debug_bitmap ||
9565 g_em->src_x != debug_src_x ||
9566 g_em->src_y != debug_src_y ||
9567 g_em->src_offset_x != 0 ||
9568 g_em->src_offset_y != 0 ||
9569 g_em->dst_offset_x != 0 ||
9570 g_em->dst_offset_y != 0 ||
9571 g_em->width != TILEX ||
9572 g_em->height != TILEY)
9574 static int last_i = -1;
9582 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
9583 i, element, element_info[element].token_name,
9584 element_action_info[effective_action].suffix, direction);
9586 if (element != effective_element)
9587 printf(" [%d ('%s')]",
9589 element_info[effective_element].token_name);
9593 if (g_em->bitmap != debug_bitmap)
9594 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
9595 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
9597 if (g_em->src_x != debug_src_x ||
9598 g_em->src_y != debug_src_y)
9599 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
9600 j, (is_backside ? 'B' : 'F'),
9601 g_em->src_x, g_em->src_y,
9602 g_em->src_x / 32, g_em->src_y / 32,
9603 debug_src_x, debug_src_y,
9604 debug_src_x / 32, debug_src_y / 32);
9606 if (g_em->src_offset_x != 0 ||
9607 g_em->src_offset_y != 0 ||
9608 g_em->dst_offset_x != 0 ||
9609 g_em->dst_offset_y != 0)
9610 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
9612 g_em->src_offset_x, g_em->src_offset_y,
9613 g_em->dst_offset_x, g_em->dst_offset_y);
9615 if (g_em->width != TILEX ||
9616 g_em->height != TILEY)
9617 printf(" %d (%d): size %d,%d should be %d,%d\n",
9619 g_em->width, g_em->height, TILEX, TILEY);
9621 num_em_gfx_errors++;
9628 for (i = 0; i < TILE_MAX; i++)
9630 for (j = 0; j < 8; j++)
9632 int element = object_mapping[i].element_rnd;
9633 int action = object_mapping[i].action;
9634 int direction = object_mapping[i].direction;
9635 boolean is_backside = object_mapping[i].is_backside;
9636 int graphic_action = el_act_dir2img(element, action, direction);
9637 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
9639 if ((action == ACTION_SMASHED_BY_ROCK ||
9640 action == ACTION_SMASHED_BY_SPRING ||
9641 action == ACTION_EATING) &&
9642 graphic_action == graphic_default)
9644 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
9645 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
9646 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
9647 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
9650 /* no separate animation for "smashed by rock" -- use rock instead */
9651 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
9652 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
9654 g_em->bitmap = g_xx->bitmap;
9655 g_em->src_x = g_xx->src_x;
9656 g_em->src_y = g_xx->src_y;
9657 g_em->src_offset_x = g_xx->src_offset_x;
9658 g_em->src_offset_y = g_xx->src_offset_y;
9659 g_em->dst_offset_x = g_xx->dst_offset_x;
9660 g_em->dst_offset_y = g_xx->dst_offset_y;
9661 g_em->width = g_xx->width;
9662 g_em->height = g_xx->height;
9663 g_em->unique_identifier = g_xx->unique_identifier;
9666 g_em->preserve_background = TRUE;
9671 for (p = 0; p < MAX_PLAYERS; p++)
9673 for (i = 0; i < SPR_MAX; i++)
9675 int element = player_mapping[p][i].element_rnd;
9676 int action = player_mapping[p][i].action;
9677 int direction = player_mapping[p][i].direction;
9679 for (j = 0; j < 8; j++)
9681 int effective_element = element;
9682 int effective_action = action;
9683 int graphic = (direction == MV_NONE ?
9684 el_act2img(effective_element, effective_action) :
9685 el_act_dir2img(effective_element, effective_action,
9687 struct GraphicInfo *g = &graphic_info[graphic];
9688 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
9694 Bitmap *debug_bitmap = g_em->bitmap;
9695 int debug_src_x = g_em->src_x;
9696 int debug_src_y = g_em->src_y;
9699 int frame = getAnimationFrame(g->anim_frames,
9702 g->anim_start_frame,
9705 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
9707 g_em->bitmap = src_bitmap;
9708 g_em->src_x = src_x;
9709 g_em->src_y = src_y;
9710 g_em->src_offset_x = 0;
9711 g_em->src_offset_y = 0;
9712 g_em->dst_offset_x = 0;
9713 g_em->dst_offset_y = 0;
9714 g_em->width = TILEX;
9715 g_em->height = TILEY;
9719 /* skip check for EMC elements not contained in original EMC artwork */
9720 if (element == EL_PLAYER_3 ||
9721 element == EL_PLAYER_4)
9724 if (g_em->bitmap != debug_bitmap ||
9725 g_em->src_x != debug_src_x ||
9726 g_em->src_y != debug_src_y)
9728 static int last_i = -1;
9736 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
9737 p, i, element, element_info[element].token_name,
9738 element_action_info[effective_action].suffix, direction);
9740 if (element != effective_element)
9741 printf(" [%d ('%s')]",
9743 element_info[effective_element].token_name);
9747 if (g_em->bitmap != debug_bitmap)
9748 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
9749 j, (int)(g_em->bitmap), (int)(debug_bitmap));
9751 if (g_em->src_x != debug_src_x ||
9752 g_em->src_y != debug_src_y)
9753 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
9755 g_em->src_x, g_em->src_y,
9756 g_em->src_x / 32, g_em->src_y / 32,
9757 debug_src_x, debug_src_y,
9758 debug_src_x / 32, debug_src_y / 32);
9760 num_em_gfx_errors++;
9770 printf("::: [%d errors found]\n", num_em_gfx_errors);
9776 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
9777 boolean any_player_moving,
9778 boolean player_is_dropping)
9780 if (tape.single_step && tape.recording && !tape.pausing)
9783 boolean active_players = FALSE;
9786 for (i = 0; i < MAX_PLAYERS; i++)
9787 if (action[i] != JOY_NO_ACTION)
9788 active_players = TRUE;
9792 if (frame == 0 && !player_is_dropping)
9793 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
9797 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
9798 boolean murphy_is_dropping)
9801 printf("::: waiting: %d, dropping: %d\n",
9802 murphy_is_waiting, murphy_is_dropping);
9805 if (tape.single_step && tape.recording && !tape.pausing)
9807 // if (murphy_is_waiting || murphy_is_dropping)
9808 if (murphy_is_waiting)
9811 printf("::: murphy is waiting -> pause mode\n");
9814 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
9819 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
9820 int graphic, int sync_frame, int x, int y)
9822 int frame = getGraphicAnimationFrame(graphic, sync_frame);
9824 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
9827 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
9829 return (IS_NEXT_FRAME(sync_frame, graphic));
9832 int getGraphicInfo_Delay(int graphic)
9834 return graphic_info[graphic].anim_delay;
9837 void PlayMenuSoundExt(int sound)
9839 if (sound == SND_UNDEFINED)
9842 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9843 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9846 if (IS_LOOP_SOUND(sound))
9847 PlaySoundLoop(sound);
9852 void PlayMenuSound()
9854 PlayMenuSoundExt(menu.sound[game_status]);
9857 void PlayMenuSoundStereo(int sound, int stereo_position)
9859 if (sound == SND_UNDEFINED)
9862 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9863 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9866 if (IS_LOOP_SOUND(sound))
9867 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
9869 PlaySoundStereo(sound, stereo_position);
9872 void PlayMenuSoundIfLoopExt(int sound)
9874 if (sound == SND_UNDEFINED)
9877 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9878 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9881 if (IS_LOOP_SOUND(sound))
9882 PlaySoundLoop(sound);
9885 void PlayMenuSoundIfLoop()
9887 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
9890 void PlayMenuMusicExt(int music)
9892 if (music == MUS_UNDEFINED)
9895 if (!setup.sound_music)
9901 void PlayMenuMusic()
9903 PlayMenuMusicExt(menu.music[game_status]);
9906 void PlaySoundActivating()
9909 PlaySound(SND_MENU_ITEM_ACTIVATING);
9913 void PlaySoundSelecting()
9916 PlaySound(SND_MENU_ITEM_SELECTING);
9920 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
9922 boolean change_fullscreen = (setup.fullscreen !=
9923 video.fullscreen_enabled);
9924 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
9925 !strEqual(setup.fullscreen_mode,
9926 video.fullscreen_mode_current));
9927 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
9928 setup.window_scaling_percent !=
9929 video.window_scaling_percent);
9931 if (change_window_scaling_percent && video.fullscreen_enabled)
9934 if (!change_window_scaling_percent && !video.fullscreen_available)
9937 #if defined(TARGET_SDL2)
9938 if (change_window_scaling_percent)
9940 SDLSetWindowScaling(setup.window_scaling_percent);
9944 else if (change_fullscreen)
9946 SDLSetWindowFullscreen(setup.fullscreen);
9948 /* set setup value according to successfully changed fullscreen mode */
9949 setup.fullscreen = video.fullscreen_enabled;
9955 if (change_fullscreen ||
9956 change_fullscreen_mode ||
9957 change_window_scaling_percent)
9959 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
9961 /* save backbuffer content which gets lost when toggling fullscreen mode */
9962 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9964 if (change_fullscreen_mode)
9966 /* keep fullscreen, but change fullscreen mode (screen resolution) */
9967 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
9970 if (change_window_scaling_percent)
9972 /* keep window mode, but change window scaling */
9973 video.fullscreen_enabled = TRUE; /* force new window scaling */
9976 /* toggle fullscreen */
9977 ChangeVideoModeIfNeeded(setup.fullscreen);
9979 /* set setup value according to successfully changed fullscreen mode */
9980 setup.fullscreen = video.fullscreen_enabled;
9982 /* restore backbuffer content from temporary backbuffer backup bitmap */
9983 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9985 FreeBitmap(tmp_backbuffer);
9988 /* update visible window/screen */
9989 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9991 redraw_mask = REDRAW_ALL;
9996 void ChangeViewportPropertiesIfNeeded()
9998 int *door_1_x = &DX;
9999 int *door_1_y = &DY;
10000 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
10001 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
10002 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
10003 game_status == GAME_MODE_EDITOR ? game_status :
10005 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
10006 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
10007 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
10008 int border_size = vp_playfield->border_size;
10009 int new_sx = vp_playfield->x + border_size;
10010 int new_sy = vp_playfield->y + border_size;
10011 int new_sxsize = vp_playfield->width - 2 * border_size;
10012 int new_sysize = vp_playfield->height - 2 * border_size;
10013 int new_real_sx = vp_playfield->x;
10014 int new_real_sy = vp_playfield->y;
10015 int new_full_sxsize = vp_playfield->width;
10016 int new_full_sysize = vp_playfield->height;
10018 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
10019 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
10020 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
10021 int new_scr_fieldx = new_sxsize / tilesize;
10022 int new_scr_fieldy = new_sysize / tilesize;
10023 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
10024 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
10026 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
10027 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
10029 boolean init_gfx_buffers = FALSE;
10030 boolean init_video_buffer = FALSE;
10031 boolean init_gadgets_and_toons = FALSE;
10034 /* !!! TEST ONLY !!! */
10035 // InitGfxBuffers();
10039 if (viewport.window.width != WIN_XSIZE ||
10040 viewport.window.height != WIN_YSIZE)
10042 WIN_XSIZE = viewport.window.width;
10043 WIN_YSIZE = viewport.window.height;
10046 init_video_buffer = TRUE;
10047 init_gfx_buffers = TRUE;
10049 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
10053 SetDrawDeactivationMask(REDRAW_NONE);
10054 SetDrawBackgroundMask(REDRAW_FIELD);
10056 // RedrawBackground();
10060 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
10063 if (new_scr_fieldx != SCR_FIELDX ||
10064 new_scr_fieldy != SCR_FIELDY)
10066 /* this always toggles between MAIN and GAME when using small tile size */
10068 SCR_FIELDX = new_scr_fieldx;
10069 SCR_FIELDY = new_scr_fieldy;
10071 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
10075 if (new_tilesize_var != TILESIZE_VAR &&
10076 gfx_game_mode == GAME_MODE_PLAYING)
10078 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
10080 TILESIZE_VAR = new_tilesize_var;
10082 init_gfx_buffers = TRUE;
10084 // printf("::: tilesize: init_gfx_buffers\n");
10088 if (new_sx != SX ||
10090 new_sxsize != SXSIZE ||
10091 new_sysize != SYSIZE ||
10092 new_real_sx != REAL_SX ||
10093 new_real_sy != REAL_SY ||
10094 new_full_sxsize != FULL_SXSIZE ||
10095 new_full_sysize != FULL_SYSIZE ||
10096 new_tilesize_var != TILESIZE_VAR ||
10097 vp_door_1->x != *door_1_x ||
10098 vp_door_1->y != *door_1_y ||
10099 vp_door_2->x != *door_2_x ||
10100 vp_door_2->y != *door_2_y)
10104 SXSIZE = new_sxsize;
10105 SYSIZE = new_sysize;
10106 REAL_SX = new_real_sx;
10107 REAL_SY = new_real_sy;
10108 FULL_SXSIZE = new_full_sxsize;
10109 FULL_SYSIZE = new_full_sysize;
10110 TILESIZE_VAR = new_tilesize_var;
10113 printf("::: %d, %d, %d [%d]\n",
10114 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
10115 setup.small_game_graphics);
10118 *door_1_x = vp_door_1->x;
10119 *door_1_y = vp_door_1->y;
10120 *door_2_x = vp_door_2->x;
10121 *door_2_y = vp_door_2->y;
10124 init_gfx_buffers = TRUE;
10126 // printf("::: viewports: init_gfx_buffers\n");
10131 if (gfx_game_mode == GAME_MODE_MAIN)
10134 init_gadgets_and_toons = TRUE;
10136 // printf("::: viewports: init_gadgets_and_toons\n");
10144 if (init_gfx_buffers)
10146 // printf("::: init_gfx_buffers\n");
10148 SCR_FIELDX = new_scr_fieldx_buffers;
10149 SCR_FIELDY = new_scr_fieldy_buffers;
10153 SCR_FIELDX = new_scr_fieldx;
10154 SCR_FIELDY = new_scr_fieldy;
10157 if (init_video_buffer)
10159 // printf("::: init_video_buffer\n");
10161 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
10163 SetDrawDeactivationMask(REDRAW_NONE);
10164 SetDrawBackgroundMask(REDRAW_FIELD);
10167 if (init_gadgets_and_toons)
10169 // printf("::: init_gadgets_and_toons\n");
10176 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);