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 ***********************************************************/
16 #include "libgame/libgame.h"
28 /* select level set with EMC X11 graphics before activating EM GFX debugging */
29 #define DEBUG_EM_GFX 0
31 /* tool button identifiers */
32 #define TOOL_CTRL_ID_YES 0
33 #define TOOL_CTRL_ID_NO 1
34 #define TOOL_CTRL_ID_CONFIRM 2
35 #define TOOL_CTRL_ID_PLAYER_1 3
36 #define TOOL_CTRL_ID_PLAYER_2 4
37 #define TOOL_CTRL_ID_PLAYER_3 5
38 #define TOOL_CTRL_ID_PLAYER_4 6
40 #define NUM_TOOL_BUTTONS 7
42 /* constants for number of doors and door parts */
44 #define NUM_PANELS NUM_DOORS
45 // #define NUM_PANELS 0
46 #define MAX_PARTS_PER_DOOR 8
47 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
48 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
51 struct DoorPartOrderInfo
57 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
59 struct DoorPartControlInfo
63 struct DoorPartPosInfo *pos;
66 static struct DoorPartControlInfo door_part_controls[] =
70 IMG_DOOR_1_GFX_PART_1,
75 IMG_DOOR_1_GFX_PART_2,
80 IMG_DOOR_1_GFX_PART_3,
85 IMG_DOOR_1_GFX_PART_4,
90 IMG_DOOR_1_GFX_PART_5,
95 IMG_DOOR_1_GFX_PART_6,
100 IMG_DOOR_1_GFX_PART_7,
105 IMG_DOOR_1_GFX_PART_8,
111 IMG_DOOR_2_GFX_PART_1,
116 IMG_DOOR_2_GFX_PART_2,
121 IMG_DOOR_2_GFX_PART_3,
126 IMG_DOOR_2_GFX_PART_4,
131 IMG_DOOR_2_GFX_PART_5,
136 IMG_DOOR_2_GFX_PART_6,
141 IMG_DOOR_2_GFX_PART_7,
146 IMG_DOOR_2_GFX_PART_8,
152 IMG_BACKGROUND_PANEL,
169 /* forward declaration for internal use */
170 static void UnmapToolButtons();
171 static void HandleToolButtons(struct GadgetInfo *);
172 static int el_act_dir2crm(int, int, int);
173 static int el_act2crm(int, int);
175 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
176 static int request_gadget_id = -1;
178 static char *print_if_not_empty(int element)
180 static char *s = NULL;
181 char *token_name = element_info[element].token_name;
186 s = checked_malloc(strlen(token_name) + 10 + 1);
188 if (element != EL_EMPTY)
189 sprintf(s, "%d\t['%s']", element, token_name);
191 sprintf(s, "%d", element);
196 void DumpTile(int x, int y)
201 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
207 printf_line("-", 79);
208 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
209 printf_line("-", 79);
211 if (!IN_LEV_FIELD(x, y))
213 printf("(not in level field)\n");
219 printf(" Feld: %d\t['%s']\n", Feld[x][y],
220 element_info[Feld[x][y]].token_name);
221 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
222 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
223 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
224 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
225 printf(" MovPos: %d\n", MovPos[x][y]);
226 printf(" MovDir: %d\n", MovDir[x][y]);
227 printf(" MovDelay: %d\n", MovDelay[x][y]);
228 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
229 printf(" CustomValue: %d\n", CustomValue[x][y]);
230 printf(" GfxElement: %d\n", GfxElement[x][y]);
231 printf(" GfxAction: %d\n", GfxAction[x][y]);
232 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
236 void SetDrawtoField(int mode)
238 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
246 BX2 = SCR_FIELDX + 1;
247 BY2 = SCR_FIELDY + 1;
266 BX2 = SCR_FIELDX + 1;
267 BY2 = SCR_FIELDY + 1;
282 drawto_field = fieldbuffer;
284 else /* DRAW_BACKBUFFER */
290 BX2 = SCR_FIELDX - 1;
291 BY2 = SCR_FIELDY - 1;
295 drawto_field = backbuffer;
301 static void RedrawPlayfield_RND()
303 if (game.envelope_active)
307 DrawLevel(REDRAW_ALL);
311 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
312 // SetDrawBackgroundMask(REDRAW_FIELD); // !!! CHECK THIS !!!
313 SetDrawBackgroundMask(REDRAW_ALL); // !!! CHECK THIS !!!
315 for (x = BX1; x <= BX2; x++)
316 for (y = BY1; y <= BY2; y++)
317 DrawScreenField(x, y);
319 redraw_mask |= REDRAW_FIELD;
325 BlitScreenToBitmap(backbuffer);
327 /* blit playfield from scroll buffer to normal back buffer */
328 if (setup.soft_scrolling)
330 int fx = FX, fy = FY;
332 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
333 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
335 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
341 void RedrawPlayfield()
343 if (game_status != GAME_MODE_PLAYING)
346 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
347 RedrawPlayfield_EM(TRUE);
348 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
349 RedrawPlayfield_SP(TRUE);
350 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
351 RedrawPlayfield_RND();
353 BlitScreenToBitmap(backbuffer);
355 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
361 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
363 if (game_status == GAME_MODE_PLAYING &&
364 level.game_engine_type == GAME_ENGINE_TYPE_EM)
366 /* currently there is no partial redraw -- always redraw whole playfield */
367 RedrawPlayfield_EM(TRUE);
369 /* blit playfield from scroll buffer to normal back buffer for fading in */
370 BlitScreenToBitmap_EM(backbuffer);
372 else if (game_status == GAME_MODE_PLAYING &&
373 level.game_engine_type == GAME_ENGINE_TYPE_SP)
375 /* currently there is no partial redraw -- always redraw whole playfield */
376 RedrawPlayfield_SP(TRUE);
378 /* blit playfield from scroll buffer to normal back buffer for fading in */
379 BlitScreenToBitmap_SP(backbuffer);
381 else if (game_status == GAME_MODE_PLAYING &&
382 !game.envelope_active)
388 width = gfx.sxsize + 2 * TILEX;
389 height = gfx.sysize + 2 * TILEY;
395 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
396 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
398 for (xx = BX1; xx <= BX2; xx++)
399 for (yy = BY1; yy <= BY2; yy++)
400 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
401 DrawScreenField(xx, yy);
405 if (setup.soft_scrolling)
407 int fx = FX, fy = FY;
409 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
410 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
412 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
424 BlitBitmap(drawto, window, x, y, width, height, x, y);
429 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
431 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
433 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
434 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
437 void DrawMaskedBorder_FIELD()
439 if (global.border_status >= GAME_MODE_TITLE &&
440 global.border_status <= GAME_MODE_PLAYING &&
441 border.draw_masked[global.border_status])
442 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
445 void DrawMaskedBorder_DOOR_1()
447 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
448 (global.border_status != GAME_MODE_EDITOR ||
449 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
450 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
453 void DrawMaskedBorder_DOOR_2()
455 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
456 global.border_status != GAME_MODE_EDITOR)
457 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
460 void DrawMaskedBorder_DOOR_3()
462 /* currently not available */
465 void DrawMaskedBorder_ALL()
467 DrawMaskedBorder_FIELD();
468 DrawMaskedBorder_DOOR_1();
469 DrawMaskedBorder_DOOR_2();
470 DrawMaskedBorder_DOOR_3();
473 void DrawMaskedBorder(int redraw_mask)
475 /* never draw masked screen borders on borderless screens */
476 if (effectiveGameStatus() == GAME_MODE_LOADING ||
477 effectiveGameStatus() == GAME_MODE_TITLE)
480 /* never draw masked screen borders when displaying request outside door */
481 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
482 global.use_envelope_request)
485 if (redraw_mask & REDRAW_ALL)
486 DrawMaskedBorder_ALL();
489 if (redraw_mask & REDRAW_FIELD)
490 DrawMaskedBorder_FIELD();
491 if (redraw_mask & REDRAW_DOOR_1)
492 DrawMaskedBorder_DOOR_1();
493 if (redraw_mask & REDRAW_DOOR_2)
494 DrawMaskedBorder_DOOR_2();
495 if (redraw_mask & REDRAW_DOOR_3)
496 DrawMaskedBorder_DOOR_3();
500 static void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
502 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
503 int fx = FX, fy = FY;
504 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
505 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
508 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
509 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
510 int dx_var = dx * TILESIZE_VAR / TILESIZE;
511 int dy_var = dy * TILESIZE_VAR / TILESIZE;
514 // fx += dx * TILESIZE_VAR / TILESIZE;
515 // fy += dy * TILESIZE_VAR / TILESIZE;
517 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
518 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
521 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
522 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
524 if (EVEN(SCR_FIELDX))
526 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
527 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
529 fx += (dx_var > 0 ? TILEX_VAR : 0);
536 if (EVEN(SCR_FIELDY))
538 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
539 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
541 fy += (dy_var > 0 ? TILEY_VAR : 0);
549 printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
552 SBY_Upper, SBY_Lower,
557 if (full_lev_fieldx <= SCR_FIELDX)
559 // printf(":1: PLAYFIELD FITS TO SCREEN [%d, %d, %d]\n", fx, ffx, dx_var);
561 if (EVEN(SCR_FIELDX))
562 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
564 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
566 // printf(":2: PLAYFIELD FITS TO SCREEN [%d, %d, %d]\n", fx, ffx, dx_var);
569 if (full_lev_fieldy <= SCR_FIELDY)
571 if (EVEN(SCR_FIELDY))
572 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
574 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
578 if (border.draw_masked[GAME_MODE_PLAYING])
580 if (buffer != backbuffer)
582 /* copy playfield buffer to backbuffer to add masked border */
583 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
584 DrawMaskedBorder(REDRAW_FIELD);
587 BlitBitmap(backbuffer, target_bitmap,
588 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
593 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
597 void BlitScreenToBitmap(Bitmap *target_bitmap)
599 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
600 BlitScreenToBitmap_EM(target_bitmap);
601 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
602 BlitScreenToBitmap_SP(target_bitmap);
603 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
604 BlitScreenToBitmap_RND(target_bitmap);
610 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
613 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
614 for (x = 0; x < SCR_FIELDX; x++)
615 for (y = 0 ; y < SCR_FIELDY; y++)
616 if (redraw[redraw_x1 + x][redraw_y1 + y])
617 printf("::: - %d, %d [%s]\n",
618 LEVELX(x), LEVELY(y),
619 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
622 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
623 redraw_mask |= REDRAW_FIELD;
626 // never redraw single tiles, always redraw the whole field
627 // (redrawing single tiles up to a certain threshold was faster on old,
628 // now legacy graphics, but slows things down on modern graphics now)
629 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
630 if (redraw_mask & REDRAW_TILES)
631 redraw_mask |= REDRAW_FIELD;
635 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
636 /* (force full redraw) */
637 if (game_status == GAME_MODE_PLAYING)
638 redraw_mask |= REDRAW_FIELD;
641 if (redraw_mask & REDRAW_FIELD)
642 redraw_mask &= ~REDRAW_TILES;
644 if (redraw_mask == REDRAW_NONE)
649 if (redraw_mask & REDRAW_ALL)
650 printf("[REDRAW_ALL]");
651 if (redraw_mask & REDRAW_FIELD)
652 printf("[REDRAW_FIELD]");
653 if (redraw_mask & REDRAW_TILES)
654 printf("[REDRAW_TILES]");
655 if (redraw_mask & REDRAW_DOOR_1)
656 printf("[REDRAW_DOOR_1]");
657 if (redraw_mask & REDRAW_DOOR_2)
658 printf("[REDRAW_DOOR_2]");
659 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
660 printf("[REDRAW_FROM_BACKBUFFER]");
661 printf(" [%d]\n", FrameCounter);
664 if (redraw_mask & REDRAW_TILES &&
665 game_status == GAME_MODE_PLAYING &&
666 border.draw_masked[GAME_MODE_PLAYING])
667 redraw_mask |= REDRAW_FIELD;
669 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
671 static boolean last_frame_skipped = FALSE;
672 boolean skip_even_when_not_scrolling = TRUE;
673 boolean just_scrolling = (ScreenMovDir != 0);
674 boolean verbose = FALSE;
676 if (global.fps_slowdown_factor > 1 &&
677 (FrameCounter % global.fps_slowdown_factor) &&
678 (just_scrolling || skip_even_when_not_scrolling))
680 redraw_mask &= ~REDRAW_MAIN;
682 last_frame_skipped = TRUE;
685 printf("FRAME SKIPPED\n");
689 if (last_frame_skipped)
690 redraw_mask |= REDRAW_FIELD;
692 last_frame_skipped = FALSE;
695 printf("frame not skipped\n");
699 /* synchronize X11 graphics at this point; if we would synchronize the
700 display immediately after the buffer switching (after the XFlush),
701 this could mean that we have to wait for the graphics to complete,
702 although we could go on doing calculations for the next frame */
706 /* never draw masked border to backbuffer when using playfield buffer */
707 if (game_status != GAME_MODE_PLAYING ||
708 redraw_mask & REDRAW_FROM_BACKBUFFER ||
709 buffer == backbuffer)
710 DrawMaskedBorder(redraw_mask);
712 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
714 if (redraw_mask & REDRAW_ALL)
717 if (game_status != GAME_MODE_PLAYING ||
718 redraw_mask & REDRAW_FROM_BACKBUFFER)
721 printf("::: REDRAW_ALL [%d]\n", FrameCounter);
724 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
726 redraw_mask = REDRAW_NONE;
730 redraw_mask &= ~REDRAW_ALL;
734 printf("::: REDRAW_ALL [%d]\n", FrameCounter);
737 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
739 redraw_mask = REDRAW_NONE;
743 if (redraw_mask & REDRAW_FIELD)
746 printf("::: REDRAW_FIELD [%d]\n", FrameCounter);
749 if (game_status != GAME_MODE_PLAYING ||
750 redraw_mask & REDRAW_FROM_BACKBUFFER)
752 BlitBitmap(backbuffer, window,
753 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
758 BlitScreenToBitmap_RND(window);
760 int fx = FX, fy = FY;
763 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
764 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
765 int dx_var = dx * TILESIZE_VAR / TILESIZE;
766 int dy_var = dy * TILESIZE_VAR / TILESIZE;
769 // fx += dx * TILESIZE_VAR / TILESIZE;
770 // fy += dy * TILESIZE_VAR / TILESIZE;
772 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
773 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
776 /* !!! THIS WORKS !!! */
778 printf("::: %d, %d\n", scroll_x, scroll_y);
780 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
781 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
783 if (EVEN(SCR_FIELDX))
785 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
786 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
788 fx += (dx > 0 ? TILEX_VAR : 0);
795 if (EVEN(SCR_FIELDY))
797 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
798 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
800 fy += (dy > 0 ? TILEY_VAR : 0);
807 if (border.draw_masked[GAME_MODE_PLAYING])
809 if (buffer != backbuffer)
811 /* copy playfield buffer to backbuffer to add masked border */
812 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
813 DrawMaskedBorder(REDRAW_FIELD);
816 BlitBitmap(backbuffer, window,
817 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
822 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
828 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
830 (setup.soft_scrolling ?
831 "setup.soft_scrolling" :
832 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
833 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
834 ABS(ScreenGfxPos) == ScrollStepSize ?
835 "ABS(ScreenGfxPos) == ScrollStepSize" :
836 "redraw_tiles > REDRAWTILES_THRESHOLD"));
841 redraw_mask &= ~REDRAW_MAIN;
844 if (redraw_mask & REDRAW_DOORS)
846 if (redraw_mask & REDRAW_DOOR_1)
847 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
849 if (redraw_mask & REDRAW_DOOR_2)
850 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
852 if (redraw_mask & REDRAW_DOOR_3)
853 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
855 redraw_mask &= ~REDRAW_DOORS;
858 if (redraw_mask & REDRAW_MICROLEVEL)
860 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
861 SX, SY + 10 * TILEY);
863 redraw_mask &= ~REDRAW_MICROLEVEL;
866 if (redraw_mask & REDRAW_TILES)
869 printf("::: REDRAW_TILES\n");
875 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
878 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
879 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
882 int dx_var = dx * TILESIZE_VAR / TILESIZE;
883 int dy_var = dy * TILESIZE_VAR / TILESIZE;
885 int fx = FX, fy = FY;
887 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
888 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
890 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
891 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
893 if (EVEN(SCR_FIELDX))
895 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
897 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
906 fx += (dx_var > 0 ? TILEX_VAR : 0);
910 if (EVEN(SCR_FIELDY))
912 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
914 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
923 fy += (dy_var > 0 ? TILEY_VAR : 0);
928 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
931 for (x = 0; x < scr_fieldx; x++)
932 for (y = 0 ; y < scr_fieldy; y++)
933 if (redraw[redraw_x1 + x][redraw_y1 + y])
934 BlitBitmap(buffer, window,
935 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
936 TILEX_VAR, TILEY_VAR,
937 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
940 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
942 for (x = 0; x < SCR_FIELDX; x++)
943 for (y = 0 ; y < SCR_FIELDY; y++)
944 if (redraw[redraw_x1 + x][redraw_y1 + y])
945 BlitBitmap(buffer, window,
946 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
947 TILEX_VAR, TILEY_VAR,
948 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
952 for (x = 0; x < SCR_FIELDX; x++)
953 for (y = 0 ; y < SCR_FIELDY; y++)
954 if (redraw[redraw_x1 + x][redraw_y1 + y])
955 BlitBitmap(buffer, window,
956 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
957 SX + x * TILEX, SY + y * TILEY);
961 if (redraw_mask & REDRAW_FPS) /* display frames per second */
966 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
967 if (!global.fps_slowdown)
970 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
972 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
974 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
980 for (x = 0; x < MAX_BUF_XSIZE; x++)
981 for (y = 0; y < MAX_BUF_YSIZE; y++)
984 redraw_mask = REDRAW_NONE;
987 static void FadeCrossSaveBackbuffer()
989 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
992 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
994 static int fade_type_skip = FADE_TYPE_NONE;
995 void (*draw_border_function)(void) = NULL;
996 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
997 int x, y, width, height;
998 int fade_delay, post_delay;
1000 if (fade_type == FADE_TYPE_FADE_OUT)
1002 if (fade_type_skip != FADE_TYPE_NONE)
1005 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
1008 /* skip all fade operations until specified fade operation */
1009 if (fade_type & fade_type_skip)
1010 fade_type_skip = FADE_TYPE_NONE;
1015 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1017 FadeCrossSaveBackbuffer();
1023 redraw_mask |= fade_mask;
1025 if (fade_type == FADE_TYPE_SKIP)
1028 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
1031 fade_type_skip = fade_mode;
1037 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
1042 fade_delay = fading.fade_delay;
1043 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1046 if (fade_type_skip != FADE_TYPE_NONE)
1049 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
1052 /* skip all fade operations until specified fade operation */
1053 if (fade_type & fade_type_skip)
1054 fade_type_skip = FADE_TYPE_NONE;
1064 if (global.autoplay_leveldir)
1066 // fading.fade_mode = FADE_MODE_NONE;
1073 if (fading.fade_mode == FADE_MODE_NONE)
1081 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
1084 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
1088 if (fade_mask == REDRAW_NONE)
1089 fade_mask = REDRAW_FIELD;
1092 // if (fade_mask & REDRAW_FIELD)
1093 if (fade_mask == REDRAW_FIELD)
1097 width = FULL_SXSIZE;
1098 height = FULL_SYSIZE;
1101 fade_delay = fading.fade_delay;
1102 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1105 if (border.draw_masked_when_fading)
1106 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
1108 DrawMaskedBorder_FIELD(); /* draw once */
1110 else /* REDRAW_ALL */
1118 fade_delay = fading.fade_delay;
1119 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1124 if (!setup.fade_screens ||
1126 fading.fade_mode == FADE_MODE_NONE)
1128 if (!setup.fade_screens || fade_delay == 0)
1131 if (fade_mode == FADE_MODE_FADE_OUT)
1135 if (fade_mode == FADE_MODE_FADE_OUT &&
1136 fading.fade_mode != FADE_MODE_NONE)
1137 ClearRectangle(backbuffer, x, y, width, height);
1143 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1145 redraw_mask &= ~fade_mask;
1147 /* always redraw area that was explicitly marked to fade */
1148 redraw_mask |= fade_mask;
1156 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1157 redraw_mask = REDRAW_NONE;
1158 // (^^^ WRONG; should be "redraw_mask &= ~fade_mask" if done this way)
1167 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
1168 draw_border_function);
1170 redraw_mask &= ~fade_mask;
1173 void FadeIn(int fade_mask)
1175 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1176 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1178 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1181 void FadeOut(int fade_mask)
1183 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1184 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1186 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1188 global.border_status = game_status;
1191 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1193 static struct TitleFadingInfo fading_leave_stored;
1196 fading_leave_stored = fading_leave;
1198 fading = fading_leave_stored;
1201 void FadeSetEnterMenu()
1203 fading = menu.enter_menu;
1206 printf("::: storing enter_menu\n");
1209 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1212 void FadeSetLeaveMenu()
1214 fading = menu.leave_menu;
1217 printf("::: storing leave_menu\n");
1220 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1223 void FadeSetEnterScreen()
1225 fading = menu.enter_screen[game_status];
1228 printf("::: storing leave_screen[%d]\n", game_status);
1231 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1234 void FadeSetNextScreen()
1236 fading = menu.next_screen;
1239 printf("::: storing next_screen\n");
1242 // (do not overwrite fade mode set by FadeSetEnterScreen)
1243 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1246 void FadeSetLeaveScreen()
1249 printf("::: recalling last stored value\n");
1252 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1255 void FadeSetFromType(int type)
1257 if (type & TYPE_ENTER_SCREEN)
1258 FadeSetEnterScreen();
1259 else if (type & TYPE_ENTER)
1261 else if (type & TYPE_LEAVE)
1265 void FadeSetDisabled()
1267 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1269 fading = fading_none;
1272 void FadeSkipNextFadeIn()
1274 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1277 void FadeSkipNextFadeOut()
1279 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1282 void SetWindowBackgroundImageIfDefined(int graphic)
1284 if (graphic_info[graphic].bitmap)
1285 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1288 void SetMainBackgroundImageIfDefined(int graphic)
1290 if (graphic_info[graphic].bitmap)
1291 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1294 void SetDoorBackgroundImageIfDefined(int graphic)
1296 if (graphic_info[graphic].bitmap)
1297 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1300 void SetWindowBackgroundImage(int graphic)
1302 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1303 graphic_info[graphic].bitmap ?
1304 graphic_info[graphic].bitmap :
1305 graphic_info[IMG_BACKGROUND].bitmap);
1308 void SetMainBackgroundImage(int graphic)
1310 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1311 graphic_info[graphic].bitmap ?
1312 graphic_info[graphic].bitmap :
1313 graphic_info[IMG_BACKGROUND].bitmap);
1316 void SetDoorBackgroundImage(int graphic)
1318 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1319 graphic_info[graphic].bitmap ?
1320 graphic_info[graphic].bitmap :
1321 graphic_info[IMG_BACKGROUND].bitmap);
1324 void SetPanelBackground()
1327 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1330 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1331 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1333 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1334 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1335 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1336 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1339 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1340 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1343 SetDoorBackgroundBitmap(bitmap_db_panel);
1346 void DrawBackground(int x, int y, int width, int height)
1348 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1349 /* (when entering hall of fame after playing) */
1351 ClearRectangleOnBackground(drawto, x, y, width, height);
1353 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1359 if (IN_GFX_FIELD_FULL(x, y))
1360 redraw_mask |= REDRAW_FIELD;
1361 else if (IN_GFX_DOOR_1(x, y))
1362 redraw_mask |= REDRAW_DOOR_1;
1363 else if (IN_GFX_DOOR_2(x, y))
1364 redraw_mask |= REDRAW_DOOR_2;
1365 else if (IN_GFX_DOOR_3(x, y))
1366 redraw_mask |= REDRAW_DOOR_3;
1368 /* (this only works for the current arrangement of playfield and panels) */
1370 redraw_mask |= REDRAW_FIELD;
1371 else if (y < gfx.vy)
1372 redraw_mask |= REDRAW_DOOR_1;
1374 redraw_mask |= REDRAW_DOOR_2;
1378 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1379 redraw_mask |= REDRAW_FIELD;
1383 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1385 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1387 if (font->bitmap == NULL)
1390 DrawBackground(x, y, width, height);
1393 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1395 struct GraphicInfo *g = &graphic_info[graphic];
1397 if (g->bitmap == NULL)
1400 DrawBackground(x, y, width, height);
1405 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1406 /* (when entering hall of fame after playing) */
1407 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1409 /* !!! maybe this should be done before clearing the background !!! */
1410 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1412 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1413 SetDrawtoField(DRAW_BUFFERED);
1416 SetDrawtoField(DRAW_BACKBUFFER);
1419 void MarkTileDirty(int x, int y)
1421 int xx = redraw_x1 + x;
1422 int yy = redraw_y1 + y;
1424 if (!redraw[xx][yy])
1427 redraw[xx][yy] = TRUE;
1428 redraw_mask |= REDRAW_TILES;
1431 void SetBorderElement()
1435 BorderElement = EL_EMPTY;
1437 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1439 for (x = 0; x < lev_fieldx; x++)
1441 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1442 BorderElement = EL_STEELWALL;
1444 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1450 void FloodFillLevel(int from_x, int from_y, int fill_element,
1451 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1452 int max_fieldx, int max_fieldy)
1456 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1457 static int safety = 0;
1459 /* check if starting field still has the desired content */
1460 if (field[from_x][from_y] == fill_element)
1465 if (safety > max_fieldx * max_fieldy)
1466 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1468 old_element = field[from_x][from_y];
1469 field[from_x][from_y] = fill_element;
1471 for (i = 0; i < 4; i++)
1473 x = from_x + check[i][0];
1474 y = from_y + check[i][1];
1476 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1477 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1483 void SetRandomAnimationValue(int x, int y)
1485 gfx.anim_random_frame = GfxRandom[x][y];
1488 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1490 /* animation synchronized with global frame counter, not move position */
1491 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1492 sync_frame = FrameCounter;
1494 return getAnimationFrame(graphic_info[graphic].anim_frames,
1495 graphic_info[graphic].anim_delay,
1496 graphic_info[graphic].anim_mode,
1497 graphic_info[graphic].anim_start_frame,
1501 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1502 Bitmap **bitmap, int *x, int *y,
1503 boolean get_backside)
1507 int width_mult, width_div;
1508 int height_mult, height_div;
1512 { 15, 16, 2, 3 }, /* 1 x 1 */
1513 { 7, 8, 2, 3 }, /* 2 x 2 */
1514 { 3, 4, 2, 3 }, /* 4 x 4 */
1515 { 1, 2, 2, 3 }, /* 8 x 8 */
1516 { 0, 1, 2, 3 }, /* 16 x 16 */
1517 { 0, 1, 0, 1 }, /* 32 x 32 */
1519 struct GraphicInfo *g = &graphic_info[graphic];
1520 Bitmap *src_bitmap = g->bitmap;
1521 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1522 int offset_calc_pos = log_2(tilesize);
1523 int width_mult = offset_calc[offset_calc_pos].width_mult;
1524 int width_div = offset_calc[offset_calc_pos].width_div;
1525 int height_mult = offset_calc[offset_calc_pos].height_mult;
1526 int height_div = offset_calc[offset_calc_pos].height_div;
1527 int startx = src_bitmap->width * width_mult / width_div;
1528 int starty = src_bitmap->height * height_mult / height_div;
1530 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1531 tilesize / TILESIZE;
1532 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1533 tilesize / TILESIZE;
1535 int src_x = g->src_x * tilesize / TILESIZE;
1536 int src_y = g->src_y * tilesize / TILESIZE;
1538 int width = g->width * tilesize / TILESIZE;
1539 int height = g->height * tilesize / TILESIZE;
1540 int offset_x = g->offset_x * tilesize / TILESIZE;
1541 int offset_y = g->offset_y * tilesize / TILESIZE;
1543 if (g->offset_y == 0) /* frames are ordered horizontally */
1545 int max_width = g->anim_frames_per_line * width;
1546 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1548 src_x = pos % max_width;
1549 src_y = src_y % height + pos / max_width * height;
1551 else if (g->offset_x == 0) /* frames are ordered vertically */
1553 int max_height = g->anim_frames_per_line * height;
1554 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1556 src_x = src_x % width + pos / max_height * width;
1557 src_y = pos % max_height;
1559 else /* frames are ordered diagonally */
1561 src_x = src_x + frame * offset_x;
1562 src_y = src_y + frame * offset_y;
1565 *bitmap = src_bitmap;
1566 *x = startx + src_x;
1567 *y = starty + src_y;
1570 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1571 int *x, int *y, boolean get_backside)
1573 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1577 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1578 Bitmap **bitmap, int *x, int *y)
1580 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1583 void getFixedGraphicSource(int graphic, int frame,
1584 Bitmap **bitmap, int *x, int *y)
1586 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1589 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1592 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1594 struct GraphicInfo *g = &graphic_info[graphic];
1595 int mini_startx = 0;
1596 int mini_starty = g->bitmap->height * 2 / 3;
1598 *bitmap = g->bitmap;
1599 *x = mini_startx + g->src_x / 2;
1600 *y = mini_starty + g->src_y / 2;
1604 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1605 int *x, int *y, boolean get_backside)
1607 struct GraphicInfo *g = &graphic_info[graphic];
1608 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1609 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1613 if (TILESIZE_VAR != TILESIZE)
1614 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1618 *bitmap = g->bitmap;
1620 if (g->offset_y == 0) /* frames are ordered horizontally */
1622 int max_width = g->anim_frames_per_line * g->width;
1623 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1625 *x = pos % max_width;
1626 *y = src_y % g->height + pos / max_width * g->height;
1628 else if (g->offset_x == 0) /* frames are ordered vertically */
1630 int max_height = g->anim_frames_per_line * g->height;
1631 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1633 *x = src_x % g->width + pos / max_height * g->width;
1634 *y = pos % max_height;
1636 else /* frames are ordered diagonally */
1638 *x = src_x + frame * g->offset_x;
1639 *y = src_y + frame * g->offset_y;
1643 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1645 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1648 void DrawGraphic(int x, int y, int graphic, int frame)
1651 if (!IN_SCR_FIELD(x, y))
1653 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1654 printf("DrawGraphic(): This should never happen!\n");
1660 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1663 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1665 MarkTileDirty(x, y);
1668 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1671 if (!IN_SCR_FIELD(x, y))
1673 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1674 printf("DrawGraphic(): This should never happen!\n");
1679 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1681 MarkTileDirty(x, y);
1684 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1690 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1692 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1694 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1698 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1704 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1705 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1708 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1711 if (!IN_SCR_FIELD(x, y))
1713 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1714 printf("DrawGraphicThruMask(): This should never happen!\n");
1720 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1723 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1726 MarkTileDirty(x, y);
1729 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1732 if (!IN_SCR_FIELD(x, y))
1734 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1735 printf("DrawGraphicThruMask(): This should never happen!\n");
1740 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1742 MarkTileDirty(x, y);
1745 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1751 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1753 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1754 dst_x - src_x, dst_y - src_y);
1756 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1759 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1763 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1764 int graphic, int frame)
1769 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1771 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1772 dst_x - src_x, dst_y - src_y);
1773 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1776 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1778 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1780 MarkTileDirty(x / tilesize, y / tilesize);
1783 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1789 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1790 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1793 void DrawMiniGraphic(int x, int y, int graphic)
1795 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1796 MarkTileDirty(x / 2, y / 2);
1799 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1804 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1805 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1808 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1809 int graphic, int frame,
1810 int cut_mode, int mask_mode)
1815 int width = TILEX, height = TILEY;
1818 if (dx || dy) /* shifted graphic */
1820 if (x < BX1) /* object enters playfield from the left */
1827 else if (x > BX2) /* object enters playfield from the right */
1833 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1839 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1841 else if (dx) /* general horizontal movement */
1842 MarkTileDirty(x + SIGN(dx), y);
1844 if (y < BY1) /* object enters playfield from the top */
1846 if (cut_mode==CUT_BELOW) /* object completely above top border */
1854 else if (y > BY2) /* object enters playfield from the bottom */
1860 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1866 else if (dy > 0 && cut_mode == CUT_ABOVE)
1868 if (y == BY2) /* object completely above bottom border */
1874 MarkTileDirty(x, y + 1);
1875 } /* object leaves playfield to the bottom */
1876 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1878 else if (dy) /* general vertical movement */
1879 MarkTileDirty(x, y + SIGN(dy));
1883 if (!IN_SCR_FIELD(x, y))
1885 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1886 printf("DrawGraphicShifted(): This should never happen!\n");
1892 width = width * TILESIZE_VAR / TILESIZE;
1893 height = height * TILESIZE_VAR / TILESIZE;
1894 cx = cx * TILESIZE_VAR / TILESIZE;
1895 cy = cy * TILESIZE_VAR / TILESIZE;
1896 dx = dx * TILESIZE_VAR / TILESIZE;
1897 dy = dy * TILESIZE_VAR / TILESIZE;
1900 if (width > 0 && height > 0)
1902 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1908 dst_x = FX + x * TILEX_VAR + dx;
1909 dst_y = FY + y * TILEY_VAR + dy;
1911 dst_x = FX + x * TILEX + dx;
1912 dst_y = FY + y * TILEY + dy;
1915 if (mask_mode == USE_MASKING)
1917 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1918 dst_x - src_x, dst_y - src_y);
1919 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1923 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1926 MarkTileDirty(x, y);
1930 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1931 int graphic, int frame,
1932 int cut_mode, int mask_mode)
1938 int width = TILEX_VAR, height = TILEY_VAR;
1940 int width = TILEX, height = TILEY;
1944 int x2 = x + SIGN(dx);
1945 int y2 = y + SIGN(dy);
1947 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1948 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1950 /* movement with two-tile animations must be sync'ed with movement position,
1951 not with current GfxFrame (which can be higher when using slow movement) */
1952 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1953 int anim_frames = graphic_info[graphic].anim_frames;
1955 /* (we also need anim_delay here for movement animations with less frames) */
1956 int anim_delay = graphic_info[graphic].anim_delay;
1957 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1959 int sync_frame = anim_pos * anim_frames / TILESIZE;
1962 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1963 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1965 /* re-calculate animation frame for two-tile movement animation */
1966 frame = getGraphicAnimationFrame(graphic, sync_frame);
1970 printf("::: %d, %d, %d => %d [%d]\n",
1971 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1973 printf("::: %d, %d => %d\n",
1974 anim_pos, anim_frames, sync_frame);
1979 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1980 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1983 /* check if movement start graphic inside screen area and should be drawn */
1984 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1986 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1989 dst_x = FX + x1 * TILEX_VAR;
1990 dst_y = FY + y1 * TILEY_VAR;
1992 dst_x = FX + x1 * TILEX;
1993 dst_y = FY + y1 * TILEY;
1996 if (mask_mode == USE_MASKING)
1998 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1999 dst_x - src_x, dst_y - src_y);
2000 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
2004 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2007 MarkTileDirty(x1, y1);
2010 /* check if movement end graphic inside screen area and should be drawn */
2011 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
2013 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
2016 dst_x = FX + x2 * TILEX_VAR;
2017 dst_y = FY + y2 * TILEY_VAR;
2019 dst_x = FX + x2 * TILEX;
2020 dst_y = FY + y2 * TILEY;
2023 if (mask_mode == USE_MASKING)
2025 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2026 dst_x - src_x, dst_y - src_y);
2027 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
2031 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2034 MarkTileDirty(x2, y2);
2038 static void DrawGraphicShifted(int x, int y, int dx, int dy,
2039 int graphic, int frame,
2040 int cut_mode, int mask_mode)
2044 DrawGraphic(x, y, graphic, frame);
2049 if (graphic_info[graphic].double_movement) /* EM style movement images */
2050 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2052 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2055 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
2056 int frame, int cut_mode)
2058 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
2061 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
2062 int cut_mode, int mask_mode)
2064 int lx = LEVELX(x), ly = LEVELY(y);
2068 if (IN_LEV_FIELD(lx, ly))
2070 SetRandomAnimationValue(lx, ly);
2072 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
2073 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2075 /* do not use double (EM style) movement graphic when not moving */
2076 if (graphic_info[graphic].double_movement && !dx && !dy)
2078 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
2079 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2082 else /* border element */
2084 graphic = el2img(element);
2085 frame = getGraphicAnimationFrame(graphic, -1);
2088 if (element == EL_EXPANDABLE_WALL)
2090 boolean left_stopped = FALSE, right_stopped = FALSE;
2092 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
2093 left_stopped = TRUE;
2094 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
2095 right_stopped = TRUE;
2097 if (left_stopped && right_stopped)
2099 else if (left_stopped)
2101 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
2102 frame = graphic_info[graphic].anim_frames - 1;
2104 else if (right_stopped)
2106 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
2107 frame = graphic_info[graphic].anim_frames - 1;
2112 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
2113 else if (mask_mode == USE_MASKING)
2114 DrawGraphicThruMask(x, y, graphic, frame);
2116 DrawGraphic(x, y, graphic, frame);
2119 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2120 int cut_mode, int mask_mode)
2122 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2123 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2124 cut_mode, mask_mode);
2127 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2130 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2133 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2136 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2139 void DrawLevelElementThruMask(int x, int y, int element)
2141 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2144 void DrawLevelFieldThruMask(int x, int y)
2146 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2149 /* !!! implementation of quicksand is totally broken !!! */
2150 #define IS_CRUMBLED_TILE(x, y, e) \
2151 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2152 !IS_MOVING(x, y) || \
2153 (e) == EL_QUICKSAND_EMPTYING || \
2154 (e) == EL_QUICKSAND_FAST_EMPTYING))
2156 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2161 int width, height, cx, cy;
2162 int sx = SCREENX(x), sy = SCREENY(y);
2163 int crumbled_border_size = graphic_info[graphic].border_size;
2166 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2168 for (i = 1; i < 4; i++)
2170 int dxx = (i & 1 ? dx : 0);
2171 int dyy = (i & 2 ? dy : 0);
2174 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2177 /* check if neighbour field is of same crumble type */
2178 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2179 graphic_info[graphic].class ==
2180 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2182 /* return if check prevents inner corner */
2183 if (same == (dxx == dx && dyy == dy))
2187 /* if we reach this point, we have an inner corner */
2189 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2192 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2193 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2194 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2195 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2197 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2198 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2200 width = crumbled_border_size;
2201 height = crumbled_border_size;
2202 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2203 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2205 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2206 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2210 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2215 int width, height, bx, by, cx, cy;
2216 int sx = SCREENX(x), sy = SCREENY(y);
2217 int crumbled_border_size = graphic_info[graphic].border_size;
2220 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2222 /* draw simple, sloppy, non-corner-accurate crumbled border */
2225 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
2226 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
2227 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2228 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2230 if (dir == 1 || dir == 2) /* left or right crumbled border */
2232 width = crumbled_border_size;
2234 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2237 else /* top or bottom crumbled border */
2240 height = crumbled_border_size;
2242 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2247 BlitBitmap(src_bitmap, drawto_field,
2248 src_x + cx * TILESIZE_VAR / TILESIZE,
2249 src_y + cy * TILESIZE_VAR / TILESIZE,
2250 width * TILESIZE_VAR / TILESIZE,
2251 height * TILESIZE_VAR / TILESIZE,
2252 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2253 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2255 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2256 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2259 /* (remaining middle border part must be at least as big as corner part) */
2260 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2261 crumbled_border_size >= TILESIZE / 3)
2264 /* correct corners of crumbled border, if needed */
2267 for (i = -1; i <= 1; i+=2)
2269 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2270 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2271 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2274 /* check if neighbour field is of same crumble type */
2275 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2276 graphic_info[graphic].class ==
2277 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2279 /* no crumbled corner, but continued crumbled border */
2281 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2282 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2283 int b1 = (i == 1 ? crumbled_border_size :
2284 TILESIZE - 2 * crumbled_border_size);
2286 width = crumbled_border_size;
2287 height = crumbled_border_size;
2289 if (dir == 1 || dir == 2)
2305 BlitBitmap(src_bitmap, drawto_field,
2306 src_x + bx * TILESIZE_VAR / TILESIZE,
2307 src_y + by * TILESIZE_VAR / TILESIZE,
2308 width * TILESIZE_VAR / TILESIZE,
2309 height * TILESIZE_VAR / TILESIZE,
2310 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2311 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2313 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2314 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2319 if (dir == 1 || dir == 2) /* left or right crumbled border */
2321 for (i = -1; i <= 1; i+=2)
2325 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2328 /* check if neighbour field is of same crumble type */
2329 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2330 graphic_info[graphic].class ==
2331 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2333 /* no crumbled corner, but continued crumbled border */
2335 width = crumbled_border_size;
2336 height = crumbled_border_size;
2337 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2338 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2340 by = (i == 1 ? crumbled_border_size :
2341 TILEY - 2 * crumbled_border_size);
2343 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2344 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2348 else /* top or bottom crumbled border */
2350 for (i = -1; i <= 1; i+=2)
2354 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2357 /* check if neighbour field is of same crumble type */
2358 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2359 graphic_info[graphic].class ==
2360 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2362 /* no crumbled corner, but continued crumbled border */
2364 width = crumbled_border_size;
2365 height = crumbled_border_size;
2366 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2367 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2368 bx = (i == 1 ? crumbled_border_size :
2369 TILEX - 2 * crumbled_border_size);
2372 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2373 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2380 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2382 int sx = SCREENX(x), sy = SCREENY(y);
2385 static int xy[4][2] =
2393 if (!IN_LEV_FIELD(x, y))
2396 element = TILE_GFX_ELEMENT(x, y);
2398 /* crumble field itself */
2399 if (IS_CRUMBLED_TILE(x, y, element))
2401 if (!IN_SCR_FIELD(sx, sy))
2404 for (i = 0; i < 4; i++)
2406 int xx = x + xy[i][0];
2407 int yy = y + xy[i][1];
2409 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2412 /* check if neighbour field is of same crumble type */
2414 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2415 graphic_info[graphic].class ==
2416 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2419 if (IS_CRUMBLED_TILE(xx, yy, element))
2423 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2426 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2427 graphic_info[graphic].anim_frames == 2)
2429 for (i = 0; i < 4; i++)
2431 int dx = (i & 1 ? +1 : -1);
2432 int dy = (i & 2 ? +1 : -1);
2434 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2438 MarkTileDirty(sx, sy);
2440 else /* center field not crumbled -- crumble neighbour fields */
2442 for (i = 0; i < 4; i++)
2444 int xx = x + xy[i][0];
2445 int yy = y + xy[i][1];
2446 int sxx = sx + xy[i][0];
2447 int syy = sy + xy[i][1];
2449 if (!IN_LEV_FIELD(xx, yy) ||
2450 !IN_SCR_FIELD(sxx, syy))
2453 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2456 element = TILE_GFX_ELEMENT(xx, yy);
2458 if (!IS_CRUMBLED_TILE(xx, yy, element))
2461 graphic = el_act2crm(element, ACTION_DEFAULT);
2463 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2465 MarkTileDirty(sxx, syy);
2470 void DrawLevelFieldCrumbled(int x, int y)
2474 if (!IN_LEV_FIELD(x, y))
2478 /* !!! CHECK THIS !!! */
2481 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2482 GFX_CRUMBLED(GfxElement[x][y]))
2485 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2486 GfxElement[x][y] != EL_UNDEFINED &&
2487 GFX_CRUMBLED(GfxElement[x][y]))
2489 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2496 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2498 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2501 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2504 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2507 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2508 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2509 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2510 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2511 int sx = SCREENX(x), sy = SCREENY(y);
2513 DrawGraphic(sx, sy, graphic1, frame1);
2514 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2517 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2519 int sx = SCREENX(x), sy = SCREENY(y);
2520 static int xy[4][2] =
2529 for (i = 0; i < 4; i++)
2531 int xx = x + xy[i][0];
2532 int yy = y + xy[i][1];
2533 int sxx = sx + xy[i][0];
2534 int syy = sy + xy[i][1];
2536 if (!IN_LEV_FIELD(xx, yy) ||
2537 !IN_SCR_FIELD(sxx, syy) ||
2538 !GFX_CRUMBLED(Feld[xx][yy]) ||
2542 DrawLevelField(xx, yy);
2546 static int getBorderElement(int x, int y)
2550 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2551 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2552 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2553 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2554 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2555 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2556 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2558 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2559 int steel_position = (x == -1 && y == -1 ? 0 :
2560 x == lev_fieldx && y == -1 ? 1 :
2561 x == -1 && y == lev_fieldy ? 2 :
2562 x == lev_fieldx && y == lev_fieldy ? 3 :
2563 x == -1 || x == lev_fieldx ? 4 :
2564 y == -1 || y == lev_fieldy ? 5 : 6);
2566 return border[steel_position][steel_type];
2569 void DrawScreenElement(int x, int y, int element)
2571 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2572 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2575 void DrawLevelElement(int x, int y, int element)
2577 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2578 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2581 void DrawScreenField(int x, int y)
2583 int lx = LEVELX(x), ly = LEVELY(y);
2584 int element, content;
2586 if (!IN_LEV_FIELD(lx, ly))
2588 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2591 element = getBorderElement(lx, ly);
2593 DrawScreenElement(x, y, element);
2598 element = Feld[lx][ly];
2599 content = Store[lx][ly];
2601 if (IS_MOVING(lx, ly))
2603 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2604 boolean cut_mode = NO_CUTTING;
2606 if (element == EL_QUICKSAND_EMPTYING ||
2607 element == EL_QUICKSAND_FAST_EMPTYING ||
2608 element == EL_MAGIC_WALL_EMPTYING ||
2609 element == EL_BD_MAGIC_WALL_EMPTYING ||
2610 element == EL_DC_MAGIC_WALL_EMPTYING ||
2611 element == EL_AMOEBA_DROPPING)
2612 cut_mode = CUT_ABOVE;
2613 else if (element == EL_QUICKSAND_FILLING ||
2614 element == EL_QUICKSAND_FAST_FILLING ||
2615 element == EL_MAGIC_WALL_FILLING ||
2616 element == EL_BD_MAGIC_WALL_FILLING ||
2617 element == EL_DC_MAGIC_WALL_FILLING)
2618 cut_mode = CUT_BELOW;
2621 if (lx == 9 && ly == 1)
2622 printf("::: %s [%d] [%d, %d] [%d]\n",
2623 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2624 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2625 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2626 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2627 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2630 if (cut_mode == CUT_ABOVE)
2632 DrawScreenElement(x, y, element);
2634 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2637 DrawScreenElement(x, y, EL_EMPTY);
2640 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2641 else if (cut_mode == NO_CUTTING)
2642 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2645 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2648 if (cut_mode == CUT_BELOW &&
2649 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2650 DrawLevelElement(lx, ly + 1, element);
2654 if (content == EL_ACID)
2656 int dir = MovDir[lx][ly];
2657 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2658 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2660 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2663 else if (IS_BLOCKED(lx, ly))
2668 boolean cut_mode = NO_CUTTING;
2669 int element_old, content_old;
2671 Blocked2Moving(lx, ly, &oldx, &oldy);
2674 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2675 MovDir[oldx][oldy] == MV_RIGHT);
2677 element_old = Feld[oldx][oldy];
2678 content_old = Store[oldx][oldy];
2680 if (element_old == EL_QUICKSAND_EMPTYING ||
2681 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2682 element_old == EL_MAGIC_WALL_EMPTYING ||
2683 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2684 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2685 element_old == EL_AMOEBA_DROPPING)
2686 cut_mode = CUT_ABOVE;
2688 DrawScreenElement(x, y, EL_EMPTY);
2691 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2693 else if (cut_mode == NO_CUTTING)
2694 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2697 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2700 else if (IS_DRAWABLE(element))
2701 DrawScreenElement(x, y, element);
2703 DrawScreenElement(x, y, EL_EMPTY);
2706 void DrawLevelField(int x, int y)
2708 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2709 DrawScreenField(SCREENX(x), SCREENY(y));
2710 else if (IS_MOVING(x, y))
2714 Moving2Blocked(x, y, &newx, &newy);
2715 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2716 DrawScreenField(SCREENX(newx), SCREENY(newy));
2718 else if (IS_BLOCKED(x, y))
2722 Blocked2Moving(x, y, &oldx, &oldy);
2723 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2724 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2728 void DrawMiniElement(int x, int y, int element)
2732 graphic = el2edimg(element);
2733 DrawMiniGraphic(x, y, graphic);
2736 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2738 int x = sx + scroll_x, y = sy + scroll_y;
2740 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2741 DrawMiniElement(sx, sy, EL_EMPTY);
2742 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2743 DrawMiniElement(sx, sy, Feld[x][y]);
2745 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2748 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2749 int x, int y, int xsize, int ysize,
2750 int tile_width, int tile_height)
2754 int dst_x = startx + x * tile_width;
2755 int dst_y = starty + y * tile_height;
2756 int width = graphic_info[graphic].width;
2757 int height = graphic_info[graphic].height;
2758 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2759 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2760 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2761 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2762 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2763 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2764 boolean draw_masked = graphic_info[graphic].draw_masked;
2766 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2768 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2770 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2774 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2775 inner_sx + (x - 1) * tile_width % inner_width);
2776 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2777 inner_sy + (y - 1) * tile_height % inner_height);
2781 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2782 dst_x - src_x, dst_y - src_y);
2783 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2787 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2791 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2792 int x, int y, int xsize, int ysize, int font_nr)
2794 int font_width = getFontWidth(font_nr);
2795 int font_height = getFontHeight(font_nr);
2797 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2798 font_width, font_height);
2801 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2803 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2804 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2805 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2806 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2807 boolean no_delay = (tape.warp_forward);
2808 unsigned int anim_delay = 0;
2809 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2810 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2811 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2812 int font_width = getFontWidth(font_nr);
2813 int font_height = getFontHeight(font_nr);
2814 int max_xsize = level.envelope[envelope_nr].xsize;
2815 int max_ysize = level.envelope[envelope_nr].ysize;
2816 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2817 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2818 int xend = max_xsize;
2819 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2820 int xstep = (xstart < xend ? 1 : 0);
2821 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2824 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2826 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2827 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2828 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2829 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2832 SetDrawtoField(DRAW_BUFFERED);
2835 BlitScreenToBitmap(backbuffer);
2837 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2840 SetDrawtoField(DRAW_BACKBUFFER);
2842 for (yy = 0; yy < ysize; yy++)
2843 for (xx = 0; xx < xsize; xx++)
2844 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2847 DrawTextBuffer(sx + font_width, sy + font_height,
2848 level.envelope[envelope_nr].text, font_nr, max_xsize,
2849 xsize - 2, ysize - 2, 0, mask_mode,
2850 level.envelope[envelope_nr].autowrap,
2851 level.envelope[envelope_nr].centered, FALSE);
2853 DrawTextToTextArea(sx + font_width, sy + font_height,
2854 level.envelope[envelope_nr].text, font_nr, max_xsize,
2855 xsize - 2, ysize - 2, mask_mode);
2858 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2861 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2865 void ShowEnvelope(int envelope_nr)
2867 int element = EL_ENVELOPE_1 + envelope_nr;
2868 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2869 int sound_opening = element_info[element].sound[ACTION_OPENING];
2870 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2871 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2872 boolean no_delay = (tape.warp_forward);
2873 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2874 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2875 int anim_mode = graphic_info[graphic].anim_mode;
2876 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2877 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2879 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2881 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2883 if (anim_mode == ANIM_DEFAULT)
2884 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2886 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2889 Delay(wait_delay_value);
2891 WaitForEventToContinue();
2893 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2895 if (anim_mode != ANIM_NONE)
2896 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2898 if (anim_mode == ANIM_DEFAULT)
2899 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2901 game.envelope_active = FALSE;
2903 SetDrawtoField(DRAW_BUFFERED);
2905 redraw_mask |= REDRAW_FIELD;
2909 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2911 int border_size = request.border_size;
2912 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2913 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2914 int sx = sx_center - request.width / 2;
2915 int sy = sy_center - request.height / 2;
2917 if (add_border_size)
2927 void DrawEnvelopeRequest(char *text)
2929 char *text_final = text;
2930 char *text_door_style = NULL;
2931 int graphic = IMG_BACKGROUND_REQUEST;
2932 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2933 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2934 int font_nr = FONT_REQUEST;
2935 int font_width = getFontWidth(font_nr);
2936 int font_height = getFontHeight(font_nr);
2937 int border_size = request.border_size;
2938 int line_spacing = request.line_spacing;
2939 int line_height = font_height + line_spacing;
2940 int text_width = request.width - 2 * border_size;
2941 int text_height = request.height - 2 * border_size;
2942 int line_length = text_width / font_width;
2943 int max_lines = text_height / line_height;
2944 int width = request.width;
2945 int height = request.height;
2946 int tile_size = request.step_offset;
2947 int x_steps = width / tile_size;
2948 int y_steps = height / tile_size;
2952 if (request.wrap_single_words)
2954 char *src_text_ptr, *dst_text_ptr;
2956 text_door_style = checked_malloc(2 * strlen(text) + 1);
2958 src_text_ptr = text;
2959 dst_text_ptr = text_door_style;
2961 while (*src_text_ptr)
2963 if (*src_text_ptr == ' ' ||
2964 *src_text_ptr == '?' ||
2965 *src_text_ptr == '!')
2966 *dst_text_ptr++ = '\n';
2968 if (*src_text_ptr != ' ')
2969 *dst_text_ptr++ = *src_text_ptr;
2974 *dst_text_ptr = '\0';
2976 text_final = text_door_style;
2979 setRequestPosition(&sx, &sy, FALSE);
2981 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2983 for (y = 0; y < y_steps; y++)
2984 for (x = 0; x < x_steps; x++)
2985 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2986 x, y, x_steps, y_steps,
2987 tile_size, tile_size);
2989 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2990 line_length, -1, max_lines, line_spacing, mask_mode,
2991 request.autowrap, request.centered, FALSE);
2993 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2994 RedrawGadget(tool_gadget[i]);
2996 // store readily prepared envelope request for later use when animating
2997 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3001 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3002 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
3004 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3009 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3011 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3017 if (text_door_style)
3018 free(text_door_style);
3023 void AnimateEnvelopeRequest(int anim_mode, int action)
3025 int graphic = IMG_BACKGROUND_REQUEST;
3026 boolean draw_masked = graphic_info[graphic].draw_masked;
3028 int delay_value_normal = request.step_delay;
3029 int delay_value_fast = delay_value_normal / 2;
3031 int delay_value_normal = GameFrameDelay;
3032 int delay_value_fast = FfwdFrameDelay;
3034 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3035 boolean no_delay = (tape.warp_forward);
3036 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
3037 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
3038 unsigned int anim_delay = 0;
3040 int width = request.width;
3041 int height = request.height;
3042 int tile_size = request.step_offset;
3043 int max_xsize = width / tile_size;
3044 int max_ysize = height / tile_size;
3045 int max_xsize_inner = max_xsize - 2;
3046 int max_ysize_inner = max_ysize - 2;
3048 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
3049 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
3050 int xend = max_xsize_inner;
3051 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
3052 int xstep = (xstart < xend ? 1 : 0);
3053 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3056 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3058 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3059 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3060 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
3061 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
3062 int src_x = sx_center - width / 2;
3063 int src_y = sy_center - height / 2;
3064 int dst_x = sx_center - xsize * tile_size / 2;
3065 int dst_y = sy_center - ysize * tile_size / 2;
3066 int xsize_size_left = (xsize - 1) * tile_size;
3067 int ysize_size_top = (ysize - 1) * tile_size;
3068 int max_xsize_pos = (max_xsize - 1) * tile_size;
3069 int max_ysize_pos = (max_ysize - 1) * tile_size;
3072 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3075 for (yy = 0; yy < 2; yy++)
3077 for (xx = 0; xx < 2; xx++)
3079 int src_xx = src_x + xx * max_xsize_pos;
3080 int src_yy = src_y + yy * max_ysize_pos;
3081 int dst_xx = dst_x + xx * xsize_size_left;
3082 int dst_yy = dst_y + yy * ysize_size_top;
3083 int xx_size = (xx ? tile_size : xsize_size_left);
3084 int yy_size = (yy ? tile_size : ysize_size_top);
3087 BlitBitmapMasked(bitmap_db_cross, backbuffer,
3088 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3090 BlitBitmap(bitmap_db_cross, backbuffer,
3091 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3095 BlitBitmap(bitmap_db_cross, backbuffer,
3097 xsize_size_left, ysize_size_top,
3099 BlitBitmap(bitmap_db_cross, backbuffer,
3100 src_x + max_xsize_pos, src_y,
3101 tile_size, ysize_size_top,
3102 dst_x + xsize_size_left, dst_y);
3103 BlitBitmap(bitmap_db_cross, backbuffer,
3104 src_x, src_y + max_ysize_pos,
3105 xsize_size_left, tile_size,
3106 dst_x, dst_y + ysize_size_top);
3107 BlitBitmap(bitmap_db_cross, backbuffer,
3108 src_x + max_xsize_pos, src_y + max_ysize_pos,
3109 tile_size, tile_size,
3110 dst_x + xsize_size_left, dst_y + ysize_size_top);
3114 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3115 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3117 /* CHECK AGAIN (previous code reactivated) */
3118 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3128 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3134 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
3137 int envelope_nr = 0;
3140 int graphic = IMG_BACKGROUND_REQUEST;
3142 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3144 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
3145 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
3146 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3147 boolean no_delay = (tape.warp_forward);
3148 unsigned int anim_delay = 0;
3149 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
3150 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
3152 int max_word_len = maxWordLengthInString(text);
3153 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3155 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3157 int font_width = getFontWidth(font_nr);
3158 int font_height = getFontHeight(font_nr);
3159 int line_spacing = 2 * 1;
3163 int max_xsize = DXSIZE / font_width;
3164 // int max_ysize = DYSIZE / font_height;
3165 int max_ysize = DYSIZE / (font_height + line_spacing);
3167 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3168 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
3172 int max_xsize = level.envelope[envelope_nr].xsize;
3173 int max_ysize = level.envelope[envelope_nr].ysize;
3175 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3176 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3177 int xend = max_xsize;
3178 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3179 int xstep = (xstart < xend ? 1 : 0);
3180 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3185 char *text_copy = getStringCopy(text);
3188 font_nr = FONT_TEXT_2;
3190 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3192 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3193 font_nr = FONT_TEXT_1;
3196 int max_word_len = 0;
3198 char *text_copy = getStringCopy(text);
3200 font_nr = FONT_TEXT_2;
3202 for (text_ptr = text; *text_ptr; text_ptr++)
3204 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3206 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3208 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3209 font_nr = FONT_TEXT_1;
3218 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3219 if (*text_ptr == ' ')
3224 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3225 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3227 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
3228 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3231 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3233 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3234 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3235 int sx = SX + (SXSIZE - xsize * font_width) / 2;
3236 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3237 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3241 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3243 SetDrawtoField(DRAW_BUFFERED);
3246 BlitScreenToBitmap(backbuffer);
3248 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3251 SetDrawtoField(DRAW_BACKBUFFER);
3254 for (yy = 0; yy < ysize; yy++)
3255 for (xx = 0; xx < xsize; xx++)
3256 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3257 getFontWidth(font_nr),
3258 getFontHeight(font_nr) + line_spacing);
3263 DrawTextBuffer(sx + font_width, sy + font_height + 8,
3264 text_copy, font_nr, max_xsize,
3265 xsize - 2, ysize - 2, line_spacing, mask_mode,
3266 FALSE, TRUE, FALSE);
3268 DrawTextBuffer(sx + font_width, sy + font_height,
3269 level.envelope[envelope_nr].text, font_nr, max_xsize,
3270 xsize - 2, ysize - 2, 0, mask_mode,
3271 level.envelope[envelope_nr].autowrap,
3272 level.envelope[envelope_nr].centered, FALSE);
3276 DrawTextToTextArea(sx + font_width, sy + font_height,
3277 level.envelope[envelope_nr].text, font_nr, max_xsize,
3278 xsize - 2, ysize - 2, mask_mode);
3281 /* copy request gadgets to door backbuffer */
3284 if ((ysize - 2) > 13)
3285 BlitBitmap(bitmap_db_door, drawto,
3286 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3287 DOOR_GFX_PAGEY1 + 13 * font_height,
3288 (xsize - 2) * font_width,
3289 (ysize - 2 - 13) * font_height,
3291 sy + font_height * (1 + 13));
3293 if ((ysize - 2) > 13)
3294 BlitBitmap(bitmap_db_door, drawto,
3295 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3296 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3297 (xsize - 2) * font_width,
3298 (ysize - 2 - 13) * (font_height + line_spacing),
3300 sy + (font_height + line_spacing) * (1 + 13));
3302 if ((ysize - 2) > 13)
3303 BlitBitmap(bitmap_db_door, drawto,
3304 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3305 DOOR_GFX_PAGEY1 + 13 * font_height,
3306 (xsize - 2) * font_width,
3307 (ysize - 2 - 13) * font_height,
3309 sy + font_height * (1 + 13));
3313 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3314 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3316 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3326 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3336 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3339 int last_game_status = game_status; /* save current game status */
3340 // int last_draw_background_mask = gfx.draw_background_mask;
3343 int graphic = IMG_BACKGROUND_REQUEST;
3344 int sound_opening = SND_REQUEST_OPENING;
3345 int sound_closing = SND_REQUEST_CLOSING;
3347 int envelope_nr = 0;
3348 int element = EL_ENVELOPE_1 + envelope_nr;
3349 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3350 int sound_opening = element_info[element].sound[ACTION_OPENING];
3351 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3354 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3355 boolean no_delay = (tape.warp_forward);
3356 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3357 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3359 int anim_mode = graphic_info[graphic].anim_mode;
3360 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3361 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3363 char *text_copy = getStringCopy(text);
3366 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3367 if (*text_ptr == ' ')
3372 if (game_status == GAME_MODE_PLAYING)
3376 BlitScreenToBitmap(backbuffer);
3378 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3379 BlitScreenToBitmap_EM(backbuffer);
3380 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3381 BlitScreenToBitmap_SP(backbuffer);
3383 BlitScreenToBitmap_RND(backbuffer);
3386 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3387 BlitScreenToBitmap_EM(backbuffer);
3388 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3389 BlitScreenToBitmap_SP(backbuffer);
3392 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3397 SetDrawtoField(DRAW_BACKBUFFER);
3399 // SetDrawBackgroundMask(REDRAW_NONE);
3401 if (action == ACTION_OPENING)
3403 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3406 if (req_state & REQ_ASK)
3408 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3409 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3411 else if (req_state & REQ_CONFIRM)
3413 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3415 else if (req_state & REQ_PLAYER)
3417 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3418 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3419 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3420 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3425 DrawEnvelopeRequest(text);
3427 DrawEnvelopeRequest(text_copy);
3430 if (game_status != GAME_MODE_MAIN)
3434 /* force DOOR font inside door area */
3435 game_status = GAME_MODE_PSEUDO_DOOR;
3438 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3440 if (action == ACTION_OPENING)
3442 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3444 if (anim_mode == ANIM_DEFAULT)
3445 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3447 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3451 Delay(wait_delay_value);
3453 WaitForEventToContinue();
3458 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3460 if (anim_mode != ANIM_NONE)
3461 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3463 if (anim_mode == ANIM_DEFAULT)
3464 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3467 game.envelope_active = FALSE;
3470 // game_status = last_game_status; /* restore current game status */
3473 /* !!! CHECK AGAIN (SEE BELOW) !!! */
3474 game_status = last_game_status; /* restore current game status */
3477 if (action == ACTION_CLOSING)
3479 if (game_status != GAME_MODE_MAIN)
3482 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3485 SetDrawtoField(DRAW_BUFFERED);
3488 // SetDrawBackgroundMask(last_draw_background_mask);
3491 redraw_mask = REDRAW_FIELD;
3492 // redraw_mask |= REDRAW_ALL;
3494 /* CHECK AGAIN (previous code reactivated) */
3495 redraw_mask |= REDRAW_FIELD;
3499 if (game_status == GAME_MODE_MAIN)
3505 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3506 game_status = last_game_status; /* restore current game status */
3510 if (action == ACTION_CLOSING &&
3511 game_status == GAME_MODE_PLAYING &&
3512 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3513 SetDrawtoField(DRAW_BUFFERED);
3515 if (game_status == GAME_MODE_PLAYING &&
3516 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3517 SetDrawtoField(DRAW_BUFFERED);
3529 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3533 int graphic = el2preimg(element);
3535 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3536 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3539 void DrawLevel(int draw_background_mask)
3544 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3545 SetDrawBackgroundMask(draw_background_mask);
3548 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3549 SetDrawBackgroundMask(REDRAW_FIELD);
3551 SetDrawBackgroundMask(REDRAW_NONE);
3557 for (x = BX1; x <= BX2; x++)
3558 for (y = BY1; y <= BY2; y++)
3559 DrawScreenField(x, y);
3561 redraw_mask |= REDRAW_FIELD;
3564 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3568 for (x = 0; x < size_x; x++)
3569 for (y = 0; y < size_y; y++)
3570 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3572 redraw_mask |= REDRAW_FIELD;
3575 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3577 boolean show_level_border = (BorderElement != EL_EMPTY);
3578 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3579 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3580 int tile_size = preview.tile_size;
3581 int preview_width = preview.xsize * tile_size;
3582 int preview_height = preview.ysize * tile_size;
3583 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3584 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3585 int real_preview_width = real_preview_xsize * tile_size;
3586 int real_preview_height = real_preview_ysize * tile_size;
3587 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3588 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3592 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3597 dst_x += (preview_width - real_preview_width) / 2;
3598 dst_y += (preview_height - real_preview_height) / 2;
3600 DrawBackground(dst_x, dst_y, real_preview_width, real_preview_height);
3602 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3604 dst_x += (preview_width - real_preview_width) / 2;
3605 dst_y += (preview_height - real_preview_height) / 2;
3608 for (x = 0; x < real_preview_xsize; x++)
3610 for (y = 0; y < real_preview_ysize; y++)
3612 int lx = from_x + x + (show_level_border ? -1 : 0);
3613 int ly = from_y + y + (show_level_border ? -1 : 0);
3614 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3615 getBorderElement(lx, ly));
3617 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3618 element, tile_size);
3622 redraw_mask |= REDRAW_MICROLEVEL;
3625 #define MICROLABEL_EMPTY 0
3626 #define MICROLABEL_LEVEL_NAME 1
3627 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3628 #define MICROLABEL_LEVEL_AUTHOR 3
3629 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3630 #define MICROLABEL_IMPORTED_FROM 5
3631 #define MICROLABEL_IMPORTED_BY_HEAD 6
3632 #define MICROLABEL_IMPORTED_BY 7
3634 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3636 int max_text_width = SXSIZE;
3637 int font_width = getFontWidth(font_nr);
3639 if (pos->align == ALIGN_CENTER)
3640 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3641 else if (pos->align == ALIGN_RIGHT)
3642 max_text_width = pos->x;
3644 max_text_width = SXSIZE - pos->x;
3646 return max_text_width / font_width;
3649 static void DrawPreviewLevelLabelExt(int mode)
3651 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3652 char label_text[MAX_OUTPUT_LINESIZE + 1];
3653 int max_len_label_text;
3655 int font_nr = pos->font;
3658 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3661 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3662 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3663 mode == MICROLABEL_IMPORTED_BY_HEAD)
3664 font_nr = pos->font_alt;
3666 int font_nr = FONT_TEXT_2;
3669 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3670 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3671 mode == MICROLABEL_IMPORTED_BY_HEAD)
3672 font_nr = FONT_TEXT_3;
3676 max_len_label_text = getMaxTextLength(pos, font_nr);
3678 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3682 if (pos->size != -1)
3683 max_len_label_text = pos->size;
3686 for (i = 0; i < max_len_label_text; i++)
3687 label_text[i] = ' ';
3688 label_text[max_len_label_text] = '\0';
3690 if (strlen(label_text) > 0)
3693 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3695 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3696 int lypos = MICROLABEL2_YPOS;
3698 DrawText(lxpos, lypos, label_text, font_nr);
3703 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3704 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3705 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3706 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3707 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3708 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3709 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3710 max_len_label_text);
3711 label_text[max_len_label_text] = '\0';
3713 if (strlen(label_text) > 0)
3716 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3718 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3719 int lypos = MICROLABEL2_YPOS;
3721 DrawText(lxpos, lypos, label_text, font_nr);
3725 redraw_mask |= REDRAW_MICROLEVEL;
3728 static void DrawPreviewLevelExt(boolean restart)
3730 static unsigned int scroll_delay = 0;
3731 static unsigned int label_delay = 0;
3732 static int from_x, from_y, scroll_direction;
3733 static int label_state, label_counter;
3734 unsigned int scroll_delay_value = preview.step_delay;
3735 boolean show_level_border = (BorderElement != EL_EMPTY);
3736 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3737 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3738 int last_game_status = game_status; /* save current game status */
3741 /* force PREVIEW font on preview level */
3742 game_status = GAME_MODE_PSEUDO_PREVIEW;
3750 if (preview.anim_mode == ANIM_CENTERED)
3752 if (level_xsize > preview.xsize)
3753 from_x = (level_xsize - preview.xsize) / 2;
3754 if (level_ysize > preview.ysize)
3755 from_y = (level_ysize - preview.ysize) / 2;
3758 from_x += preview.xoffset;
3759 from_y += preview.yoffset;
3761 scroll_direction = MV_RIGHT;
3765 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3766 DrawPreviewLevelLabelExt(label_state);
3768 /* initialize delay counters */
3769 DelayReached(&scroll_delay, 0);
3770 DelayReached(&label_delay, 0);
3772 if (leveldir_current->name)
3774 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3775 char label_text[MAX_OUTPUT_LINESIZE + 1];
3777 int font_nr = pos->font;
3779 int font_nr = FONT_TEXT_1;
3782 int max_len_label_text = getMaxTextLength(pos, font_nr);
3784 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3792 if (pos->size != -1)
3793 max_len_label_text = pos->size;
3796 strncpy(label_text, leveldir_current->name, max_len_label_text);
3797 label_text[max_len_label_text] = '\0';
3800 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3801 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3803 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3804 lypos = SY + MICROLABEL1_YPOS;
3806 DrawText(lxpos, lypos, label_text, font_nr);
3810 game_status = last_game_status; /* restore current game status */
3815 /* scroll preview level, if needed */
3816 if (preview.anim_mode != ANIM_NONE &&
3817 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3818 DelayReached(&scroll_delay, scroll_delay_value))
3820 switch (scroll_direction)
3825 from_x -= preview.step_offset;
3826 from_x = (from_x < 0 ? 0 : from_x);
3829 scroll_direction = MV_UP;
3833 if (from_x < level_xsize - preview.xsize)
3835 from_x += preview.step_offset;
3836 from_x = (from_x > level_xsize - preview.xsize ?
3837 level_xsize - preview.xsize : from_x);
3840 scroll_direction = MV_DOWN;
3846 from_y -= preview.step_offset;
3847 from_y = (from_y < 0 ? 0 : from_y);
3850 scroll_direction = MV_RIGHT;
3854 if (from_y < level_ysize - preview.ysize)
3856 from_y += preview.step_offset;
3857 from_y = (from_y > level_ysize - preview.ysize ?
3858 level_ysize - preview.ysize : from_y);
3861 scroll_direction = MV_LEFT;
3868 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3871 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3872 /* redraw micro level label, if needed */
3873 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3874 !strEqual(level.author, ANONYMOUS_NAME) &&
3875 !strEqual(level.author, leveldir_current->name) &&
3876 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3878 int max_label_counter = 23;
3880 if (leveldir_current->imported_from != NULL &&
3881 strlen(leveldir_current->imported_from) > 0)
3882 max_label_counter += 14;
3883 if (leveldir_current->imported_by != NULL &&
3884 strlen(leveldir_current->imported_by) > 0)
3885 max_label_counter += 14;
3887 label_counter = (label_counter + 1) % max_label_counter;
3888 label_state = (label_counter >= 0 && label_counter <= 7 ?
3889 MICROLABEL_LEVEL_NAME :
3890 label_counter >= 9 && label_counter <= 12 ?
3891 MICROLABEL_LEVEL_AUTHOR_HEAD :
3892 label_counter >= 14 && label_counter <= 21 ?
3893 MICROLABEL_LEVEL_AUTHOR :
3894 label_counter >= 23 && label_counter <= 26 ?
3895 MICROLABEL_IMPORTED_FROM_HEAD :
3896 label_counter >= 28 && label_counter <= 35 ?
3897 MICROLABEL_IMPORTED_FROM :
3898 label_counter >= 37 && label_counter <= 40 ?
3899 MICROLABEL_IMPORTED_BY_HEAD :
3900 label_counter >= 42 && label_counter <= 49 ?
3901 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3903 if (leveldir_current->imported_from == NULL &&
3904 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3905 label_state == MICROLABEL_IMPORTED_FROM))
3906 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3907 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3909 DrawPreviewLevelLabelExt(label_state);
3912 game_status = last_game_status; /* restore current game status */
3915 void DrawPreviewLevelInitial()
3917 DrawPreviewLevelExt(TRUE);
3920 void DrawPreviewLevelAnimation()
3922 DrawPreviewLevelExt(FALSE);
3925 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3926 int graphic, int sync_frame, int mask_mode)
3928 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3930 if (mask_mode == USE_MASKING)
3931 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3933 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3936 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3937 int graphic, int sync_frame,
3940 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3942 if (mask_mode == USE_MASKING)
3943 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3945 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3948 inline void DrawGraphicAnimation(int x, int y, int graphic)
3950 int lx = LEVELX(x), ly = LEVELY(y);
3952 if (!IN_SCR_FIELD(x, y))
3956 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3957 graphic, GfxFrame[lx][ly], NO_MASKING);
3959 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3960 graphic, GfxFrame[lx][ly], NO_MASKING);
3962 MarkTileDirty(x, y);
3965 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3967 int lx = LEVELX(x), ly = LEVELY(y);
3969 if (!IN_SCR_FIELD(x, y))
3972 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3973 graphic, GfxFrame[lx][ly], NO_MASKING);
3974 MarkTileDirty(x, y);
3977 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3979 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3982 void DrawLevelElementAnimation(int x, int y, int element)
3984 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3986 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3989 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3991 int sx = SCREENX(x), sy = SCREENY(y);
3993 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3996 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3999 DrawGraphicAnimation(sx, sy, graphic);
4002 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
4003 DrawLevelFieldCrumbled(x, y);
4005 if (GFX_CRUMBLED(Feld[x][y]))
4006 DrawLevelFieldCrumbled(x, y);
4010 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
4012 int sx = SCREENX(x), sy = SCREENY(y);
4015 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
4018 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
4020 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
4023 DrawGraphicAnimation(sx, sy, graphic);
4025 if (GFX_CRUMBLED(element))
4026 DrawLevelFieldCrumbled(x, y);
4029 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
4031 if (player->use_murphy)
4033 /* this works only because currently only one player can be "murphy" ... */
4034 static int last_horizontal_dir = MV_LEFT;
4035 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
4037 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4038 last_horizontal_dir = move_dir;
4040 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
4042 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
4044 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
4050 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
4053 static boolean equalGraphics(int graphic1, int graphic2)
4055 struct GraphicInfo *g1 = &graphic_info[graphic1];
4056 struct GraphicInfo *g2 = &graphic_info[graphic2];
4058 return (g1->bitmap == g2->bitmap &&
4059 g1->src_x == g2->src_x &&
4060 g1->src_y == g2->src_y &&
4061 g1->anim_frames == g2->anim_frames &&
4062 g1->anim_delay == g2->anim_delay &&
4063 g1->anim_mode == g2->anim_mode);
4066 void DrawAllPlayers()
4070 for (i = 0; i < MAX_PLAYERS; i++)
4071 if (stored_player[i].active)
4072 DrawPlayer(&stored_player[i]);
4075 void DrawPlayerField(int x, int y)
4077 if (!IS_PLAYER(x, y))
4080 DrawPlayer(PLAYERINFO(x, y));
4083 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
4085 void DrawPlayer(struct PlayerInfo *player)
4087 int jx = player->jx;
4088 int jy = player->jy;
4089 int move_dir = player->MovDir;
4090 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
4091 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
4092 int last_jx = (player->is_moving ? jx - dx : jx);
4093 int last_jy = (player->is_moving ? jy - dy : jy);
4094 int next_jx = jx + dx;
4095 int next_jy = jy + dy;
4096 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
4097 boolean player_is_opaque = FALSE;
4098 int sx = SCREENX(jx), sy = SCREENY(jy);
4099 int sxx = 0, syy = 0;
4100 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
4102 int action = ACTION_DEFAULT;
4103 int last_player_graphic = getPlayerGraphic(player, move_dir);
4104 int last_player_frame = player->Frame;
4107 /* GfxElement[][] is set to the element the player is digging or collecting;
4108 remove also for off-screen player if the player is not moving anymore */
4109 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
4110 GfxElement[jx][jy] = EL_UNDEFINED;
4112 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
4116 if (!IN_LEV_FIELD(jx, jy))
4118 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
4119 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
4120 printf("DrawPlayerField(): This should never happen!\n");
4125 if (element == EL_EXPLOSION)
4128 action = (player->is_pushing ? ACTION_PUSHING :
4129 player->is_digging ? ACTION_DIGGING :
4130 player->is_collecting ? ACTION_COLLECTING :
4131 player->is_moving ? ACTION_MOVING :
4132 player->is_snapping ? ACTION_SNAPPING :
4133 player->is_dropping ? ACTION_DROPPING :
4134 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
4136 if (player->is_waiting)
4137 move_dir = player->dir_waiting;
4139 InitPlayerGfxAnimation(player, action, move_dir);
4141 /* ----------------------------------------------------------------------- */
4142 /* draw things in the field the player is leaving, if needed */
4143 /* ----------------------------------------------------------------------- */
4145 if (player->is_moving)
4147 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
4149 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
4151 if (last_element == EL_DYNAMITE_ACTIVE ||
4152 last_element == EL_EM_DYNAMITE_ACTIVE ||
4153 last_element == EL_SP_DISK_RED_ACTIVE)
4154 DrawDynamite(last_jx, last_jy);
4156 DrawLevelFieldThruMask(last_jx, last_jy);
4158 else if (last_element == EL_DYNAMITE_ACTIVE ||
4159 last_element == EL_EM_DYNAMITE_ACTIVE ||
4160 last_element == EL_SP_DISK_RED_ACTIVE)
4161 DrawDynamite(last_jx, last_jy);
4163 /* !!! this is not enough to prevent flickering of players which are
4164 moving next to each others without a free tile between them -- this
4165 can only be solved by drawing all players layer by layer (first the
4166 background, then the foreground etc.) !!! => TODO */
4167 else if (!IS_PLAYER(last_jx, last_jy))
4168 DrawLevelField(last_jx, last_jy);
4171 DrawLevelField(last_jx, last_jy);
4174 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
4175 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4178 if (!IN_SCR_FIELD(sx, sy))
4181 /* ----------------------------------------------------------------------- */
4182 /* draw things behind the player, if needed */
4183 /* ----------------------------------------------------------------------- */
4186 DrawLevelElement(jx, jy, Back[jx][jy]);
4187 else if (IS_ACTIVE_BOMB(element))
4188 DrawLevelElement(jx, jy, EL_EMPTY);
4191 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
4193 int old_element = GfxElement[jx][jy];
4194 int old_graphic = el_act_dir2img(old_element, action, move_dir);
4195 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
4197 if (GFX_CRUMBLED(old_element))
4198 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4200 DrawGraphic(sx, sy, old_graphic, frame);
4202 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4203 player_is_opaque = TRUE;
4207 GfxElement[jx][jy] = EL_UNDEFINED;
4209 /* make sure that pushed elements are drawn with correct frame rate */
4211 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4213 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4214 GfxFrame[jx][jy] = player->StepFrame;
4216 if (player->is_pushing && player->is_moving)
4217 GfxFrame[jx][jy] = player->StepFrame;
4220 DrawLevelField(jx, jy);
4224 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4225 /* ----------------------------------------------------------------------- */
4226 /* draw player himself */
4227 /* ----------------------------------------------------------------------- */
4229 graphic = getPlayerGraphic(player, move_dir);
4231 /* in the case of changed player action or direction, prevent the current
4232 animation frame from being restarted for identical animations */
4233 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4234 player->Frame = last_player_frame;
4236 frame = getGraphicAnimationFrame(graphic, player->Frame);
4240 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4241 sxx = player->GfxPos;
4243 syy = player->GfxPos;
4246 if (!setup.soft_scrolling && ScreenMovPos)
4249 if (player_is_opaque)
4250 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4252 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4254 if (SHIELD_ON(player))
4256 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4257 IMG_SHIELD_NORMAL_ACTIVE);
4258 int frame = getGraphicAnimationFrame(graphic, -1);
4260 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4264 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4267 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4268 sxx = player->GfxPos;
4270 syy = player->GfxPos;
4274 /* ----------------------------------------------------------------------- */
4275 /* draw things the player is pushing, if needed */
4276 /* ----------------------------------------------------------------------- */
4279 printf("::: %d, %d [%d, %d] [%d]\n",
4280 player->is_pushing, player_is_moving, player->GfxAction,
4281 player->is_moving, player_is_moving);
4285 if (player->is_pushing && player->is_moving)
4287 int px = SCREENX(jx), py = SCREENY(jy);
4288 int pxx = (TILEX - ABS(sxx)) * dx;
4289 int pyy = (TILEY - ABS(syy)) * dy;
4290 int gfx_frame = GfxFrame[jx][jy];
4296 if (!IS_MOVING(jx, jy)) /* push movement already finished */
4298 element = Feld[next_jx][next_jy];
4299 gfx_frame = GfxFrame[next_jx][next_jy];
4302 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4305 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4306 frame = getGraphicAnimationFrame(graphic, sync_frame);
4308 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4311 /* draw background element under pushed element (like the Sokoban field) */
4313 if (game.use_masked_pushing && IS_MOVING(jx, jy))
4315 /* this allows transparent pushing animation over non-black background */
4318 DrawLevelElement(jx, jy, Back[jx][jy]);
4320 DrawLevelElement(jx, jy, EL_EMPTY);
4322 if (Back[next_jx][next_jy])
4323 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4325 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4327 else if (Back[next_jx][next_jy])
4328 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4330 if (Back[next_jx][next_jy])
4331 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4335 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4336 jx, px, player->GfxPos, player->StepFrame,
4341 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4345 /* do not draw (EM style) pushing animation when pushing is finished */
4346 /* (two-tile animations usually do not contain start and end frame) */
4347 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4348 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4350 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4352 /* masked drawing is needed for EMC style (double) movement graphics */
4353 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4354 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4359 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4360 /* ----------------------------------------------------------------------- */
4361 /* draw player himself */
4362 /* ----------------------------------------------------------------------- */
4364 graphic = getPlayerGraphic(player, move_dir);
4366 /* in the case of changed player action or direction, prevent the current
4367 animation frame from being restarted for identical animations */
4368 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4369 player->Frame = last_player_frame;
4371 frame = getGraphicAnimationFrame(graphic, player->Frame);
4375 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4376 sxx = player->GfxPos;
4378 syy = player->GfxPos;
4381 if (!setup.soft_scrolling && ScreenMovPos)
4384 if (player_is_opaque)
4385 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4387 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4389 if (SHIELD_ON(player))
4391 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4392 IMG_SHIELD_NORMAL_ACTIVE);
4393 int frame = getGraphicAnimationFrame(graphic, -1);
4395 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4399 /* ----------------------------------------------------------------------- */
4400 /* draw things in front of player (active dynamite or dynabombs) */
4401 /* ----------------------------------------------------------------------- */
4403 if (IS_ACTIVE_BOMB(element))
4405 graphic = el2img(element);
4406 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4408 if (game.emulation == EMU_SUPAPLEX)
4409 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4411 DrawGraphicThruMask(sx, sy, graphic, frame);
4414 if (player_is_moving && last_element == EL_EXPLOSION)
4416 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4417 GfxElement[last_jx][last_jy] : EL_EMPTY);
4418 int graphic = el_act2img(element, ACTION_EXPLODING);
4419 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4420 int phase = ExplodePhase[last_jx][last_jy] - 1;
4421 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4424 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4427 /* ----------------------------------------------------------------------- */
4428 /* draw elements the player is just walking/passing through/under */
4429 /* ----------------------------------------------------------------------- */
4431 if (player_is_moving)
4433 /* handle the field the player is leaving ... */
4434 if (IS_ACCESSIBLE_INSIDE(last_element))
4435 DrawLevelField(last_jx, last_jy);
4436 else if (IS_ACCESSIBLE_UNDER(last_element))
4437 DrawLevelFieldThruMask(last_jx, last_jy);
4440 /* do not redraw accessible elements if the player is just pushing them */
4441 if (!player_is_moving || !player->is_pushing)
4443 /* ... and the field the player is entering */
4444 if (IS_ACCESSIBLE_INSIDE(element))
4445 DrawLevelField(jx, jy);
4446 else if (IS_ACCESSIBLE_UNDER(element))
4447 DrawLevelFieldThruMask(jx, jy);
4450 MarkTileDirty(sx, sy);
4453 /* ------------------------------------------------------------------------- */
4455 void WaitForEventToContinue()
4457 boolean still_wait = TRUE;
4459 /* simulate releasing mouse button over last gadget, if still pressed */
4461 HandleGadgets(-1, -1, 0);
4463 button_status = MB_RELEASED;
4479 case EVENT_BUTTONPRESS:
4480 case EVENT_KEYPRESS:
4484 case EVENT_KEYRELEASE:
4485 ClearPlayerAction();
4489 HandleOtherEvents(&event);
4493 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4500 /* don't eat all CPU time */
4505 #define MAX_REQUEST_LINES 13
4506 #define MAX_REQUEST_LINE_FONT1_LEN 7
4507 #define MAX_REQUEST_LINE_FONT2_LEN 10
4511 static int RequestHandleEvents(unsigned int req_state)
4513 int last_game_status = game_status; /* save current game status */
4517 button_status = MB_RELEASED;
4519 request_gadget_id = -1;
4532 case EVENT_BUTTONPRESS:
4533 case EVENT_BUTTONRELEASE:
4534 case EVENT_MOTIONNOTIFY:
4536 if (event.type == EVENT_MOTIONNOTIFY)
4538 if (!PointerInWindow(window))
4539 continue; /* window and pointer are on different screens */
4544 motion_status = TRUE;
4545 mx = ((MotionEvent *) &event)->x;
4546 my = ((MotionEvent *) &event)->y;
4550 motion_status = FALSE;
4551 mx = ((ButtonEvent *) &event)->x;
4552 my = ((ButtonEvent *) &event)->y;
4553 if (event.type == EVENT_BUTTONPRESS)
4554 button_status = ((ButtonEvent *) &event)->button;
4556 button_status = MB_RELEASED;
4559 /* this sets 'request_gadget_id' */
4560 HandleGadgets(mx, my, button_status);
4562 switch (request_gadget_id)
4564 case TOOL_CTRL_ID_YES:
4567 case TOOL_CTRL_ID_NO:
4570 case TOOL_CTRL_ID_CONFIRM:
4571 result = TRUE | FALSE;
4574 case TOOL_CTRL_ID_PLAYER_1:
4577 case TOOL_CTRL_ID_PLAYER_2:
4580 case TOOL_CTRL_ID_PLAYER_3:
4583 case TOOL_CTRL_ID_PLAYER_4:
4594 case EVENT_KEYPRESS:
4595 switch (GetEventKey((KeyEvent *)&event, TRUE))
4598 if (req_state & REQ_CONFIRM)
4607 #if defined(TARGET_SDL2)
4617 if (req_state & REQ_PLAYER)
4621 case EVENT_KEYRELEASE:
4622 ClearPlayerAction();
4626 HandleOtherEvents(&event);
4630 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4632 int joy = AnyJoystick();
4634 if (joy & JOY_BUTTON_1)
4636 else if (joy & JOY_BUTTON_2)
4642 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4644 HandleGameActions();
4650 if (!PendingEvent()) /* delay only if no pending events */
4655 game_status = GAME_MODE_PSEUDO_DOOR;
4661 game_status = last_game_status; /* restore current game status */
4669 if (!PendingEvent()) /* delay only if no pending events */
4672 /* don't eat all CPU time */
4682 static boolean RequestDoor(char *text, unsigned int req_state)
4684 unsigned int old_door_state;
4685 int last_game_status = game_status; /* save current game status */
4686 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4687 int font_nr = FONT_TEXT_2;
4692 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4694 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4695 font_nr = FONT_TEXT_1;
4698 if (game_status == GAME_MODE_PLAYING)
4701 BlitScreenToBitmap(backbuffer);
4703 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4704 BlitScreenToBitmap_EM(backbuffer);
4705 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4706 BlitScreenToBitmap_SP(backbuffer);
4710 /* disable deactivated drawing when quick-loading level tape recording */
4711 if (tape.playing && tape.deactivate_display)
4712 TapeDeactivateDisplayOff(TRUE);
4714 SetMouseCursor(CURSOR_DEFAULT);
4716 #if defined(NETWORK_AVALIABLE)
4717 /* pause network game while waiting for request to answer */
4718 if (options.network &&
4719 game_status == GAME_MODE_PLAYING &&
4720 req_state & REQUEST_WAIT_FOR_INPUT)
4721 SendToServer_PausePlaying();
4724 old_door_state = GetDoorState();
4726 /* simulate releasing mouse button over last gadget, if still pressed */
4728 HandleGadgets(-1, -1, 0);
4732 /* draw released gadget before proceeding */
4735 if (old_door_state & DOOR_OPEN_1)
4737 CloseDoor(DOOR_CLOSE_1);
4739 /* save old door content */
4741 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4742 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4744 BlitBitmap(bitmap_db_door, bitmap_db_door,
4745 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4746 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4750 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4751 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4753 /* clear door drawing field */
4754 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4756 /* force DOOR font inside door area */
4757 game_status = GAME_MODE_PSEUDO_DOOR;
4759 /* write text for request */
4760 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4762 char text_line[max_request_line_len + 1];
4768 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4770 tc = *(text_ptr + tx);
4771 // if (!tc || tc == ' ')
4772 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4776 if ((tc == '?' || tc == '!') && tl == 0)
4786 strncpy(text_line, text_ptr, tl);
4789 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4790 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4791 text_line, font_nr);
4793 text_ptr += tl + (tc == ' ' ? 1 : 0);
4794 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4797 game_status = last_game_status; /* restore current game status */
4799 if (req_state & REQ_ASK)
4801 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4802 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4804 else if (req_state & REQ_CONFIRM)
4806 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4808 else if (req_state & REQ_PLAYER)
4810 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4811 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4812 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4813 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4816 /* copy request gadgets to door backbuffer */
4818 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4820 BlitBitmap(drawto, bitmap_db_door,
4821 DX, DY, DXSIZE, DYSIZE,
4822 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4825 OpenDoor(DOOR_OPEN_1);
4827 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4829 if (game_status == GAME_MODE_PLAYING)
4831 SetPanelBackground();
4832 SetDrawBackgroundMask(REDRAW_DOOR_1);
4836 SetDrawBackgroundMask(REDRAW_FIELD);
4842 if (game_status != GAME_MODE_MAIN)
4845 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4847 // ---------- handle request buttons ----------
4848 result = RequestHandleEvents(req_state);
4850 if (game_status != GAME_MODE_MAIN)
4855 if (!(req_state & REQ_STAY_OPEN))
4857 CloseDoor(DOOR_CLOSE_1);
4859 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4860 (req_state & REQ_REOPEN))
4861 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4866 if (game_status == GAME_MODE_PLAYING)
4868 SetPanelBackground();
4869 SetDrawBackgroundMask(REDRAW_DOOR_1);
4873 SetDrawBackgroundMask(REDRAW_FIELD);
4876 #if defined(NETWORK_AVALIABLE)
4877 /* continue network game after request */
4878 if (options.network &&
4879 game_status == GAME_MODE_PLAYING &&
4880 req_state & REQUEST_WAIT_FOR_INPUT)
4881 SendToServer_ContinuePlaying();
4884 /* restore deactivated drawing when quick-loading level tape recording */
4885 if (tape.playing && tape.deactivate_display)
4886 TapeDeactivateDisplayOn();
4891 static boolean RequestEnvelope(char *text, unsigned int req_state)
4898 if (game_status == GAME_MODE_PLAYING)
4902 BlitScreenToBitmap(backbuffer);
4904 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4905 BlitScreenToBitmap_EM(backbuffer);
4906 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4907 BlitScreenToBitmap_SP(backbuffer);
4909 BlitScreenToBitmap_RND(backbuffer);
4912 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4913 BlitScreenToBitmap_EM(backbuffer);
4914 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4915 BlitScreenToBitmap_SP(backbuffer);
4919 /* disable deactivated drawing when quick-loading level tape recording */
4920 if (tape.playing && tape.deactivate_display)
4921 TapeDeactivateDisplayOff(TRUE);
4923 SetMouseCursor(CURSOR_DEFAULT);
4925 #if defined(NETWORK_AVALIABLE)
4926 /* pause network game while waiting for request to answer */
4927 if (options.network &&
4928 game_status == GAME_MODE_PLAYING &&
4929 req_state & REQUEST_WAIT_FOR_INPUT)
4930 SendToServer_PausePlaying();
4933 /* simulate releasing mouse button over last gadget, if still pressed */
4935 HandleGadgets(-1, -1, 0);
4939 // (replace with setting corresponding request background)
4940 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4941 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4943 /* clear door drawing field */
4944 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4947 if (global.use_envelope_request)
4951 CreateToolButtons();
4957 if (req_state & REQ_ASK)
4959 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4960 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4962 else if (req_state & REQ_CONFIRM)
4964 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4966 else if (req_state & REQ_PLAYER)
4968 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4969 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4970 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4971 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4974 if (req_state & REQ_ASK)
4976 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4977 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4979 else if (req_state & REQ_CONFIRM)
4981 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4983 else if (req_state & REQ_PLAYER)
4985 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4986 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4987 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4988 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4993 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4996 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4998 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4999 i == TOOL_CTRL_ID_NO)) ||
5000 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5001 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5002 i == TOOL_CTRL_ID_PLAYER_2 &&
5003 i == TOOL_CTRL_ID_PLAYER_3 &&
5004 i == TOOL_CTRL_ID_PLAYER_4)))
5006 int x = tool_gadget[i]->x + dDX;
5007 int y = tool_gadget[i]->y + dDY;
5009 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5014 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5016 if (game_status == GAME_MODE_PLAYING)
5018 SetPanelBackground();
5019 SetDrawBackgroundMask(REDRAW_DOOR_1);
5023 SetDrawBackgroundMask(REDRAW_FIELD);
5030 if (game_status != GAME_MODE_MAIN)
5034 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5036 // ---------- handle request buttons ----------
5037 result = RequestHandleEvents(req_state);
5039 if (game_status != GAME_MODE_MAIN)
5044 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
5048 if (game_status == GAME_MODE_PLAYING)
5050 SetPanelBackground();
5051 SetDrawBackgroundMask(REDRAW_DOOR_1);
5055 SetDrawBackgroundMask(REDRAW_FIELD);
5058 #if defined(NETWORK_AVALIABLE)
5059 /* continue network game after request */
5060 if (options.network &&
5061 game_status == GAME_MODE_PLAYING &&
5062 req_state & REQUEST_WAIT_FOR_INPUT)
5063 SendToServer_ContinuePlaying();
5066 /* restore deactivated drawing when quick-loading level tape recording */
5067 if (tape.playing && tape.deactivate_display)
5068 TapeDeactivateDisplayOn();
5073 boolean Request(char *text, unsigned int req_state)
5075 if (global.use_envelope_request)
5076 return RequestEnvelope(text, req_state);
5078 return RequestDoor(text, req_state);
5081 #else // =====================================================================
5083 boolean Request(char *text, unsigned int req_state)
5085 int mx, my, ty, result = -1;
5086 unsigned int old_door_state;
5087 int last_game_status = game_status; /* save current game status */
5088 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
5089 int font_nr = FONT_TEXT_2;
5091 int max_word_len = 0;
5097 global.use_envelope_request = 1;
5101 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
5103 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5104 font_nr = FONT_TEXT_1;
5107 for (text_ptr = text; *text_ptr; text_ptr++)
5109 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
5111 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
5113 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5115 font_nr = FONT_TEXT_1;
5117 font_nr = FONT_LEVEL_NUMBER;
5125 if (game_status == GAME_MODE_PLAYING)
5128 BlitScreenToBitmap(backbuffer);
5130 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5131 BlitScreenToBitmap_EM(backbuffer);
5132 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
5133 BlitScreenToBitmap_SP(backbuffer);
5137 /* disable deactivated drawing when quick-loading level tape recording */
5138 if (tape.playing && tape.deactivate_display)
5139 TapeDeactivateDisplayOff(TRUE);
5141 SetMouseCursor(CURSOR_DEFAULT);
5143 #if defined(NETWORK_AVALIABLE)
5144 /* pause network game while waiting for request to answer */
5145 if (options.network &&
5146 game_status == GAME_MODE_PLAYING &&
5147 req_state & REQUEST_WAIT_FOR_INPUT)
5148 SendToServer_PausePlaying();
5151 old_door_state = GetDoorState();
5153 /* simulate releasing mouse button over last gadget, if still pressed */
5155 HandleGadgets(-1, -1, 0);
5159 /* draw released gadget before proceeding */
5163 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
5165 if (old_door_state & DOOR_OPEN_1)
5169 if (!global.use_envelope_request)
5170 CloseDoor(DOOR_CLOSE_1);
5172 CloseDoor(DOOR_CLOSE_1);
5175 /* save old door content */
5176 BlitBitmap(bitmap_db_door, bitmap_db_door,
5177 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5178 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
5182 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
5185 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5187 /* clear door drawing field */
5188 DrawBackground(DX, DY, DXSIZE, DYSIZE);
5190 /* force DOOR font inside door area */
5191 game_status = GAME_MODE_PSEUDO_DOOR;
5193 /* write text for request */
5194 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
5196 char text_line[max_request_line_len + 1];
5202 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
5204 tc = *(text_ptr + tx);
5205 if (!tc || tc == ' ')
5216 strncpy(text_line, text_ptr, tl);
5219 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5220 DY + 8 + ty * (getFontHeight(font_nr) + 2),
5221 text_line, font_nr);
5223 text_ptr += tl + (tc == ' ' ? 1 : 0);
5226 game_status = last_game_status; /* restore current game status */
5229 if (global.use_envelope_request)
5233 CreateToolButtons();
5237 if (req_state & REQ_ASK)
5239 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5240 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5242 else if (req_state & REQ_CONFIRM)
5244 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5246 else if (req_state & REQ_PLAYER)
5248 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5249 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5250 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5251 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5254 /* copy request gadgets to door backbuffer */
5255 BlitBitmap(drawto, bitmap_db_door,
5256 DX, DY, DXSIZE, DYSIZE,
5257 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5260 if (global.use_envelope_request)
5262 ShowEnvelopeRequest(text, ACTION_OPENING);
5264 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5266 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5267 i == TOOL_CTRL_ID_NO)) ||
5268 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5269 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5270 i == TOOL_CTRL_ID_PLAYER_2 &&
5271 i == TOOL_CTRL_ID_PLAYER_3 &&
5272 i == TOOL_CTRL_ID_PLAYER_4)))
5274 int x = tool_gadget[i]->x + dDX;
5275 int y = tool_gadget[i]->y + dDY;
5277 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5284 if (!global.use_envelope_request)
5285 OpenDoor(DOOR_OPEN_1);
5287 OpenDoor(DOOR_OPEN_1);
5290 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5292 if (game_status == GAME_MODE_PLAYING)
5294 SetPanelBackground();
5295 SetDrawBackgroundMask(REDRAW_DOOR_1);
5299 SetDrawBackgroundMask(REDRAW_FIELD);
5306 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5309 if (game_status != GAME_MODE_MAIN)
5313 button_status = MB_RELEASED;
5315 request_gadget_id = -1;
5317 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5329 case EVENT_BUTTONPRESS:
5330 case EVENT_BUTTONRELEASE:
5331 case EVENT_MOTIONNOTIFY:
5333 if (event.type == EVENT_MOTIONNOTIFY)
5335 if (!PointerInWindow(window))
5336 continue; /* window and pointer are on different screens */
5341 motion_status = TRUE;
5342 mx = ((MotionEvent *) &event)->x;
5343 my = ((MotionEvent *) &event)->y;
5347 motion_status = FALSE;
5348 mx = ((ButtonEvent *) &event)->x;
5349 my = ((ButtonEvent *) &event)->y;
5350 if (event.type == EVENT_BUTTONPRESS)
5351 button_status = ((ButtonEvent *) &event)->button;
5353 button_status = MB_RELEASED;
5356 /* this sets 'request_gadget_id' */
5357 HandleGadgets(mx, my, button_status);
5359 switch (request_gadget_id)
5361 case TOOL_CTRL_ID_YES:
5364 case TOOL_CTRL_ID_NO:
5367 case TOOL_CTRL_ID_CONFIRM:
5368 result = TRUE | FALSE;
5371 case TOOL_CTRL_ID_PLAYER_1:
5374 case TOOL_CTRL_ID_PLAYER_2:
5377 case TOOL_CTRL_ID_PLAYER_3:
5380 case TOOL_CTRL_ID_PLAYER_4:
5391 case EVENT_KEYPRESS:
5392 switch (GetEventKey((KeyEvent *)&event, TRUE))
5395 if (req_state & REQ_CONFIRM)
5404 #if defined(TARGET_SDL2)
5414 if (req_state & REQ_PLAYER)
5418 case EVENT_KEYRELEASE:
5419 ClearPlayerAction();
5423 HandleOtherEvents(&event);
5427 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5429 int joy = AnyJoystick();
5431 if (joy & JOY_BUTTON_1)
5433 else if (joy & JOY_BUTTON_2)
5439 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5441 HandleGameActions();
5447 if (!PendingEvent()) /* delay only if no pending events */
5452 game_status = GAME_MODE_PSEUDO_DOOR;
5458 game_status = last_game_status; /* restore current game status */
5466 if (!PendingEvent()) /* delay only if no pending events */
5469 /* don't eat all CPU time */
5476 if (game_status != GAME_MODE_MAIN)
5482 if (global.use_envelope_request)
5483 ShowEnvelopeRequest(text, ACTION_CLOSING);
5487 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5489 if (!(req_state & REQ_STAY_OPEN))
5492 CloseDoor(DOOR_CLOSE_1);
5494 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5495 (req_state & REQ_REOPEN))
5496 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5501 if (game_status == GAME_MODE_PLAYING)
5503 SetPanelBackground();
5504 SetDrawBackgroundMask(REDRAW_DOOR_1);
5508 SetDrawBackgroundMask(REDRAW_FIELD);
5511 #if defined(NETWORK_AVALIABLE)
5512 /* continue network game after request */
5513 if (options.network &&
5514 game_status == GAME_MODE_PLAYING &&
5515 req_state & REQUEST_WAIT_FOR_INPUT)
5516 SendToServer_ContinuePlaying();
5519 /* restore deactivated drawing when quick-loading level tape recording */
5520 if (tape.playing && tape.deactivate_display)
5521 TapeDeactivateDisplayOn();
5528 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5530 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5531 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5534 if (dpo1->sort_priority != dpo2->sort_priority)
5535 compare_result = dpo1->sort_priority - dpo2->sort_priority;
5537 compare_result = dpo1->nr - dpo2->nr;
5539 return compare_result;
5542 void InitGraphicCompatibilityInfo_Doors()
5548 struct DoorInfo *door;
5552 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
5553 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
5555 { -1, -1, -1, NULL }
5557 struct Rect door_rect_list[] =
5559 { DX, DY, DXSIZE, DYSIZE },
5560 { VX, VY, VXSIZE, VYSIZE }
5564 for (i = 0; doors[i].door_token != -1; i++)
5566 int door_token = doors[i].door_token;
5567 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5568 int part_1 = doors[i].part_1;
5569 int part_8 = doors[i].part_8;
5570 int part_2 = part_1 + 1;
5571 int part_3 = part_1 + 2;
5572 struct DoorInfo *door = doors[i].door;
5573 struct Rect *door_rect = &door_rect_list[door_index];
5574 boolean door_gfx_redefined = FALSE;
5576 /* check if any door part graphic definitions have been redefined */
5578 for (j = 0; door_part_controls[j].door_token != -1; j++)
5580 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5581 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
5583 if (dpc->door_token == door_token && fi->redefined)
5584 door_gfx_redefined = TRUE;
5587 /* check for old-style door graphic/animation modifications */
5589 if (!door_gfx_redefined)
5591 if (door->anim_mode & ANIM_STATIC_PANEL)
5593 door->panel.step_xoffset = 0;
5594 door->panel.step_yoffset = 0;
5597 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
5599 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
5600 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
5601 int num_door_steps, num_panel_steps;
5603 /* remove door part graphics other than the two default wings */
5605 for (j = 0; door_part_controls[j].door_token != -1; j++)
5607 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5608 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5610 if (dpc->graphic >= part_3 &&
5611 dpc->graphic <= part_8)
5615 /* set graphics and screen positions of the default wings */
5617 g_part_1->width = door_rect->width;
5618 g_part_1->height = door_rect->height;
5619 g_part_2->width = door_rect->width;
5620 g_part_2->height = door_rect->height;
5621 g_part_2->src_x = door_rect->width;
5622 g_part_2->src_y = g_part_1->src_y;
5624 door->part_2.x = door->part_1.x;
5625 door->part_2.y = door->part_1.y;
5627 if (door->width != -1)
5629 g_part_1->width = door->width;
5630 g_part_2->width = door->width;
5632 // special treatment for graphics and screen position of right wing
5633 g_part_2->src_x += door_rect->width - door->width;
5634 door->part_2.x += door_rect->width - door->width;
5637 if (door->height != -1)
5639 g_part_1->height = door->height;
5640 g_part_2->height = door->height;
5642 // special treatment for graphics and screen position of bottom wing
5643 g_part_2->src_y += door_rect->height - door->height;
5644 door->part_2.y += door_rect->height - door->height;
5647 /* set animation delays for the default wings and panels */
5649 door->part_1.step_delay = door->step_delay;
5650 door->part_2.step_delay = door->step_delay;
5651 door->panel.step_delay = door->step_delay;
5653 /* set animation draw order for the default wings */
5655 door->part_1.sort_priority = 2; /* draw left wing over ... */
5656 door->part_2.sort_priority = 1; /* ... right wing */
5658 /* set animation draw offset for the default wings */
5660 if (door->anim_mode & ANIM_HORIZONTAL)
5662 door->part_1.step_xoffset = door->step_offset;
5663 door->part_1.step_yoffset = 0;
5664 door->part_2.step_xoffset = door->step_offset * -1;
5665 door->part_2.step_yoffset = 0;
5667 num_door_steps = g_part_1->width / door->step_offset;
5669 else // ANIM_VERTICAL
5671 door->part_1.step_xoffset = 0;
5672 door->part_1.step_yoffset = door->step_offset;
5673 door->part_2.step_xoffset = 0;
5674 door->part_2.step_yoffset = door->step_offset * -1;
5676 num_door_steps = g_part_1->height / door->step_offset;
5679 /* set animation draw offset for the default panels */
5681 if (door->step_offset > 1)
5683 num_panel_steps = 2 * door_rect->height / door->step_offset;
5684 door->panel.start_step = num_panel_steps - num_door_steps;
5688 num_panel_steps = door_rect->height / door->step_offset;
5689 door->panel.start_step = num_panel_steps - num_door_steps / 2;
5690 door->panel.step_delay *= 2;
5701 for (i = 0; door_part_controls[i].door_token != -1; i++)
5703 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5704 struct DoorPartOrderInfo *dpo = &door_part_order[i];
5706 /* initialize "start_step_opening" and "start_step_closing", if needed */
5707 if (dpc->pos->start_step_opening == 0 &&
5708 dpc->pos->start_step_closing == 0)
5710 // dpc->pos->start_step_opening = dpc->pos->start_step;
5711 dpc->pos->start_step_closing = dpc->pos->start_step;
5714 /* fill structure for door part draw order (sorted below) */
5716 dpo->sort_priority = dpc->pos->sort_priority;
5719 struct DoorPartPosInfo *pos = dpc->pos;
5721 printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5722 pos->step_xoffset, pos->step_yoffset);
5726 /* sort door part controls according to sort_priority and graphic number */
5727 qsort(door_part_order, MAX_DOOR_PARTS,
5728 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5731 unsigned int OpenDoor(unsigned int door_state)
5733 if (door_state & DOOR_COPY_BACK)
5736 if (door_state & DOOR_OPEN_1)
5737 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5738 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5740 if (door_state & DOOR_OPEN_2)
5741 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5742 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5744 if (door_state & DOOR_OPEN_1)
5745 BlitBitmap(bitmap_db_door, bitmap_db_door,
5746 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5747 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5749 if (door_state & DOOR_OPEN_2)
5750 BlitBitmap(bitmap_db_door, bitmap_db_door,
5751 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5752 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5755 door_state &= ~DOOR_COPY_BACK;
5758 return MoveDoor(door_state);
5761 unsigned int CloseDoor(unsigned int door_state)
5763 unsigned int old_door_state = GetDoorState();
5765 if (!(door_state & DOOR_NO_COPY_BACK))
5768 if (old_door_state & DOOR_OPEN_1)
5769 BlitBitmap(backbuffer, bitmap_db_door_1,
5770 DX, DY, DXSIZE, DYSIZE, 0, 0);
5772 if (old_door_state & DOOR_OPEN_2)
5773 BlitBitmap(backbuffer, bitmap_db_door_2,
5774 VX, VY, VXSIZE, VYSIZE, 0, 0);
5776 if (old_door_state & DOOR_OPEN_1)
5777 BlitBitmap(backbuffer, bitmap_db_door,
5778 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5780 if (old_door_state & DOOR_OPEN_2)
5781 BlitBitmap(backbuffer, bitmap_db_door,
5782 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5785 door_state &= ~DOOR_NO_COPY_BACK;
5788 return MoveDoor(door_state);
5791 unsigned int GetDoorState()
5793 return MoveDoor(DOOR_GET_STATE);
5796 unsigned int SetDoorState(unsigned int door_state)
5798 return MoveDoor(door_state | DOOR_SET_STATE);
5803 // ========== TEST 1 ===========================================================
5805 int euclid(int a, int b)
5807 return (b ? euclid(b, a % b) : a);
5810 unsigned int MoveDoor(unsigned int door_state)
5813 struct XY panel_pos_list[] =
5815 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5816 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5819 struct Rect door_rect_list[] =
5821 { DX, DY, DXSIZE, DYSIZE },
5822 { VX, VY, VXSIZE, VYSIZE }
5824 static int door1 = DOOR_OPEN_1;
5825 static int door2 = DOOR_CLOSE_2;
5826 unsigned int door_delay = 0;
5827 unsigned int door_delay_value;
5831 if (door_1.width < 0 || door_1.width > DXSIZE)
5832 door_1.width = DXSIZE;
5833 if (door_1.height < 0 || door_1.height > DYSIZE)
5834 door_1.height = DYSIZE;
5835 if (door_2.width < 0 || door_2.width > VXSIZE)
5836 door_2.width = VXSIZE;
5837 if (door_2.height < 0 || door_2.height > VYSIZE)
5838 door_2.height = VYSIZE;
5841 if (door_state == DOOR_GET_STATE)
5842 return (door1 | door2);
5844 if (door_state & DOOR_SET_STATE)
5846 if (door_state & DOOR_ACTION_1)
5847 door1 = door_state & DOOR_ACTION_1;
5848 if (door_state & DOOR_ACTION_2)
5849 door2 = door_state & DOOR_ACTION_2;
5851 return (door1 | door2);
5854 if (!(door_state & DOOR_FORCE_REDRAW))
5856 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5857 door_state &= ~DOOR_OPEN_1;
5858 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5859 door_state &= ~DOOR_CLOSE_1;
5860 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5861 door_state &= ~DOOR_OPEN_2;
5862 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5863 door_state &= ~DOOR_CLOSE_2;
5867 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5870 if (setup.quick_doors)
5872 stepsize = 20; /* must be chosen to always draw last frame */
5873 door_delay_value = 0;
5877 if (global.autoplay_leveldir)
5879 door_state |= DOOR_NO_DELAY;
5880 door_state &= ~DOOR_CLOSE_ALL;
5884 if (game_status == GAME_MODE_EDITOR)
5885 door_state |= DOOR_NO_DELAY;
5888 if (door_state & DOOR_ACTION)
5890 boolean door_panel_drawn[NUM_DOORS];
5891 boolean panel_has_doors[NUM_DOORS];
5892 boolean door_part_skip[MAX_DOOR_PARTS];
5893 boolean door_part_done[MAX_DOOR_PARTS];
5894 boolean door_part_done_all;
5895 int num_steps[MAX_DOOR_PARTS];
5896 int max_move_delay = 0; // delay for complete animations of all doors
5897 int max_step_delay = 0; // delay (ms) between two animation frames
5898 int num_move_steps = 0; // number of animation steps for all doors
5899 int current_move_delay = 0;
5902 for (i = 0; i < NUM_DOORS; i++)
5903 panel_has_doors[i] = FALSE;
5905 for (i = 0; i < MAX_DOOR_PARTS; i++)
5907 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5908 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5909 int door_token = dpc->door_token;
5911 door_part_done[i] = FALSE;
5912 door_part_skip[i] = (!(door_state & door_token) ||
5917 for (i = 0; i < MAX_DOOR_PARTS; i++)
5919 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5920 struct DoorPartPosInfo *pos = dpc->pos;
5921 int start_step = pos->start_step;
5923 printf("::: ---> %d: start_step == %d [%d]\n",
5924 i, start_step, door_part_done[i]);
5928 for (i = 0; i < MAX_DOOR_PARTS; i++)
5930 int nr = door_part_order[i].nr;
5931 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5932 struct DoorPartPosInfo *pos = dpc->pos;
5933 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5934 int door_token = dpc->door_token;
5935 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5936 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5937 int step_xoffset = ABS(pos->step_xoffset);
5938 int step_yoffset = ABS(pos->step_yoffset);
5939 int step_delay = pos->step_delay;
5940 int current_door_state = door_state & door_token;
5941 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5942 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5943 boolean part_opening = (is_panel ? door_closing : door_opening);
5944 int start_step = (part_opening ? pos->start_step_opening :
5945 pos->start_step_closing);
5946 float move_xsize = (step_xoffset ? g->width : 0);
5947 float move_ysize = (step_yoffset ? g->height : 0);
5948 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5949 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5950 int move_steps = (move_xsteps && move_ysteps ?
5951 MIN(move_xsteps, move_ysteps) :
5952 move_xsteps ? move_xsteps : move_ysteps) - start_step;
5953 int move_delay = move_steps * step_delay;
5955 if (door_part_skip[nr])
5959 panel_has_doors[door_index] = TRUE;
5961 max_move_delay = MAX(max_move_delay, move_delay);
5962 max_step_delay = (max_step_delay == 0 ? step_delay :
5963 euclid(max_step_delay, step_delay));
5964 num_steps[nr] = move_steps;
5968 printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
5969 i, move_delay, start_step, door_part_order[i].nr);
5971 if (DOOR_PART_IS_PANEL(i))
5972 printf("::: %d: move_delay == %d, start_step == %d\n",
5973 i, move_delay, start_step);
5978 num_move_steps = max_move_delay / max_step_delay;
5980 door_delay_value = max_step_delay;
5983 door_delay_value *= 10;
5987 printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
5990 for (k = 0; k < num_move_steps; k++)
5992 door_part_done_all = TRUE;
5994 for (i = 0; i < NUM_DOORS; i++)
5995 door_panel_drawn[i] = FALSE;
5997 for (i = 0; i < MAX_DOOR_PARTS; i++)
5999 int nr = door_part_order[i].nr;
6000 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
6001 struct DoorPartPosInfo *pos = dpc->pos;
6002 struct GraphicInfo *g = &graphic_info[dpc->graphic];
6003 int door_token = dpc->door_token;
6004 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
6005 boolean is_panel = DOOR_PART_IS_PANEL(nr);
6007 struct XY *panel_pos = &panel_pos_list[door_index];
6009 struct Rect *door_rect = &door_rect_list[door_index];
6010 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
6012 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
6013 int current_door_state = door_state & door_token;
6014 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
6015 boolean door_closing = !door_opening;
6016 boolean part_opening = (is_panel ? door_closing : door_opening);
6017 boolean part_closing = !part_opening;
6018 int start_step = (part_opening ? pos->start_step_opening :
6019 pos->start_step_closing);
6020 int step_delay = pos->step_delay;
6021 int step_factor = step_delay / max_step_delay;
6022 int k1 = (step_factor ? k / step_factor + 1 : k);
6023 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
6024 int kk = (k2 < 0 ? 0 : k2);
6025 int src_x, src_y, src_xx, src_yy;
6026 int dst_x, dst_y, dst_xx, dst_yy;
6030 if (k == 0 && is_panel && door_token == DOOR_2)
6031 printf("::: %d, %d\n", g->width, g->height);
6035 if (DOOR_PART_IS_PANEL(nr))
6037 int start_step = pos->start_step;
6039 k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
6040 kk = (k2 < 0 ? 0 : k2);
6046 if (nr != 16 && nr != 0)
6057 if (door_part_skip[nr])
6061 if (!(door_state & door_token))
6068 if (current_move_delay % step_delay)
6074 if (!door_panel_drawn[door_index])
6077 ClearRectangle(drawto, door_rect->x, door_rect->y,
6078 door_rect->width, door_rect->height);
6080 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
6081 door_rect->width, door_rect->height,
6082 door_rect->x, door_rect->y);
6085 door_panel_drawn[door_index] = TRUE;
6088 // draw opening or closing door parts
6090 if (pos->step_xoffset < 0) // door part on right side
6093 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
6096 if (dst_xx + width > door_rect->width)
6097 width = door_rect->width - dst_xx;
6099 else // door part on left side
6102 dst_xx = pos->x - kk * pos->step_xoffset;
6106 src_xx = ABS(dst_xx);
6110 width = g->width - src_xx;
6112 // printf("::: k == %d [%d] \n", k, start_step);
6115 if (pos->step_yoffset < 0) // door part on bottom side
6118 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
6121 if (dst_yy + height > door_rect->height)
6122 height = door_rect->height - dst_yy;
6124 else // door part on top side
6127 dst_yy = pos->y - kk * pos->step_yoffset;
6131 src_yy = ABS(dst_yy);
6135 height = g->height - src_yy;
6144 src_x = panel_pos->x + src_xx;
6145 src_y = panel_pos->y + src_yy;
6150 src_x = g->src_x + src_xx;
6151 src_y = g->src_y + src_yy;
6154 dst_x = door_rect->x + dst_xx;
6155 dst_y = door_rect->y + dst_yy;
6158 if (DOOR_PART_IS_PANEL(nr))
6160 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6161 width, height, g->width, g->height, src_x, src_y);
6165 if (width >= 0 && width <= g->width &&
6166 height >= 0 && height <= g->height)
6168 if (is_panel || !pos->draw_masked)
6169 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
6172 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
6177 if (DOOR_PART_IS_PANEL(nr))
6179 bitmap = bitmap_db_door;
6180 src_x = panel_pos->x + src_xx;
6181 src_y = panel_pos->y + src_yy;
6183 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6184 width, height, g->width, g->height, src_x, src_y);
6186 if (width >= 0 && width <= g->width &&
6187 height >= 0 && height <= g->height)
6188 BlitBitmap(bitmap, drawto, src_x, src_y,
6194 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
6197 if ((part_opening && (width < 0 || height < 0)) ||
6198 (part_closing && (width >= g->width && height >= g->height)))
6199 door_part_done[nr] = TRUE;
6201 if ((door_opening && (width < 0 || height < 0)) ||
6202 (door_closing && (width >= g->width && height >= g->height)))
6203 door_part_done[nr] = TRUE;
6207 // continue door part animations, but not panel after door has closed
6208 if (!door_part_done[nr] &&
6209 !(is_panel && door_closing && panel_has_doors[door_index]))
6210 door_part_done_all = FALSE;
6212 // continue door part animations, but not panel after door has closed
6213 if (!door_part_done[nr] && !(is_panel && door_closing))
6214 door_part_done_all = FALSE;
6218 if (!door_part_done[nr])
6219 printf("::: k == %d, nr == %d\n", k, nr);
6223 if (!(door_state & DOOR_NO_DELAY))
6227 if (game_status == GAME_MODE_MAIN)
6230 WaitUntilDelayReached(&door_delay, door_delay_value);
6232 current_move_delay += max_step_delay;
6236 door_part_done_all = TRUE;
6238 for (i = 0; i < MAX_DOOR_PARTS; i++)
6239 if (!door_part_done[i] &&
6240 !(DOOR_PART_IS_PANEL(i) && door_closing))
6241 door_part_done_all = FALSE;
6244 if (door_part_done_all)
6250 if (door_state & DOOR_ACTION_1)
6251 door1 = door_state & DOOR_ACTION_1;
6252 if (door_state & DOOR_ACTION_2)
6253 door2 = door_state & DOOR_ACTION_2;
6256 printf("::: DOORS DONE %08x\n", door_state);
6258 printf("::: GO!\n");
6261 return (door1 | door2);
6266 // ========== OLD ==============================================================
6268 unsigned int MoveDoor(unsigned int door_state)
6270 static int door1 = DOOR_OPEN_1;
6271 static int door2 = DOOR_CLOSE_2;
6272 unsigned int door_delay = 0;
6273 unsigned int door_delay_value;
6277 if (door_1.width < 0 || door_1.width > DXSIZE)
6278 door_1.width = DXSIZE;
6279 if (door_1.height < 0 || door_1.height > DYSIZE)
6280 door_1.height = DYSIZE;
6281 if (door_2.width < 0 || door_2.width > VXSIZE)
6282 door_2.width = VXSIZE;
6283 if (door_2.height < 0 || door_2.height > VYSIZE)
6284 door_2.height = VYSIZE;
6287 if (door_state == DOOR_GET_STATE)
6288 return (door1 | door2);
6290 if (door_state & DOOR_SET_STATE)
6292 if (door_state & DOOR_ACTION_1)
6293 door1 = door_state & DOOR_ACTION_1;
6294 if (door_state & DOOR_ACTION_2)
6295 door2 = door_state & DOOR_ACTION_2;
6297 return (door1 | door2);
6300 if (!(door_state & DOOR_FORCE_REDRAW))
6302 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
6303 door_state &= ~DOOR_OPEN_1;
6304 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
6305 door_state &= ~DOOR_CLOSE_1;
6306 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
6307 door_state &= ~DOOR_OPEN_2;
6308 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
6309 door_state &= ~DOOR_CLOSE_2;
6312 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
6315 // door_delay_value *= 4; // !!! TEST ONLY !!!
6317 if (setup.quick_doors)
6319 stepsize = 20; /* must be chosen to always draw last frame */
6320 door_delay_value = 0;
6323 if (global.autoplay_leveldir)
6325 door_state |= DOOR_NO_DELAY;
6326 door_state &= ~DOOR_CLOSE_ALL;
6330 if (game_status == GAME_MODE_EDITOR)
6331 door_state |= DOOR_NO_DELAY;
6334 if (door_state & DOOR_ACTION)
6337 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6338 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6339 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6340 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6341 int door_1_left_width = g1_left->width;
6342 int door_1_left_height = g1_left->height;
6343 int door_1_right_width = g1_right->width;
6344 int door_1_right_height = g1_right->height;
6345 int door_2_left_width = g2_left->width;
6346 int door_2_left_height = g2_left->height;
6347 int door_2_right_width = g2_right->width;
6348 int door_2_right_height = g2_right->height;
6349 int door_1_width = MAX(door_1_left_width, door_1_right_width);
6350 int door_1_height = MAX(door_1_left_height, door_1_right_height);
6351 int door_2_width = MAX(door_2_left_width, door_2_right_width);
6352 int door_2_height = MAX(door_2_left_height, door_2_right_height);
6354 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
6355 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
6356 boolean door_1_done = (!handle_door_1);
6357 boolean door_2_done = (!handle_door_2);
6358 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
6359 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
6362 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
6363 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
6365 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6366 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6369 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
6370 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
6372 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6373 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6374 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
6375 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
6376 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
6377 int door_skip = max_door_size - door_size;
6378 int end = door_size;
6379 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
6382 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
6384 /* opening door sound has priority over simultaneously closing door */
6385 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
6386 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
6387 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
6388 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
6391 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
6395 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6396 GC gc = bitmap->stored_clip_gc;
6399 if (door_state & DOOR_ACTION_1 &&
6400 x * door_1.step_offset <= door_size_1)
6402 int a = MIN(x * door_1.step_offset, end);
6403 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6407 int i = p + door_skip;
6411 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6412 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6413 Bitmap *bm_left = g_left->bitmap;
6414 Bitmap *bm_right = g_right->bitmap;
6415 GC gc_left = bm_left->stored_clip_gc;
6416 GC gc_right = bm_right->stored_clip_gc;
6419 int classic_dxsize = 100;
6420 int classic_dysize = 280;
6421 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6422 DYSIZE == classic_dysize);
6424 if (door_1.anim_mode & ANIM_STATIC_PANEL)
6426 BlitBitmap(bitmap_db_door, drawto,
6427 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6428 DXSIZE, DYSIZE, DX, DY);
6432 BlitBitmap(bitmap_db_door, drawto,
6433 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6434 DXSIZE, DYSIZE - p / 2, DX, DY);
6437 // printf("::: p == %d\n", p);
6438 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6442 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6445 int src1_x = g_right->src_x;
6446 int src1_y = g_right->src_y;
6447 int src2_x = g_left->src_x + g_left->width - i;
6448 int src2_y = g_left->src_y;
6449 int dst1_x = DX + DXSIZE - i;
6454 int height = DYSIZE;
6456 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6457 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6460 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6461 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6464 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6465 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6466 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6467 int dst2_x = DX, dst2_y = DY;
6468 int width = i, height = DYSIZE;
6470 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6471 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6474 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6475 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6479 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6482 int src1_x = g_right->src_x;
6483 int src1_y = g_right->src_y;
6484 int src2_x = g_left->src_x;
6485 int src2_y = g_left->src_y + g_left->height - i;
6487 int dst1_y = DY + DYSIZE - i;
6493 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6494 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6497 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6498 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6501 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6502 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6503 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
6504 int dst2_x = DX, dst2_y = DY;
6505 int width = DXSIZE, height = i;
6507 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6508 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6511 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6512 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6516 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
6518 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6521 int src1_x = g_right->src_x;
6522 int src1_y = g_right->src_y;
6523 int src2_x = g_left->src_x + g_left->width - i;
6524 int src2_y = g_left->src_y;
6525 int dst1_x = DX + DXSIZE - i;
6530 int height1 = 63, height2 = DYSIZE / 2 - height1;
6531 int ypos1 = 0, ypos2 = height2;
6532 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6534 SetClipOrigin(bm_right, gc_right,
6535 dst1_x - src1_x, dst1_y - src1_y + j);
6536 BlitBitmapMasked(bm_right, drawto,
6537 src1_x, src1_y + ypos1, width, height2,
6538 dst1_x, dst1_y + ypos1 + j);
6539 BlitBitmapMasked(bm_right, drawto,
6540 src1_x, src1_y + ypos3, width, height1,
6541 dst1_x, dst1_y + ypos3 + j);
6542 SetClipOrigin(bm_left, gc_left,
6543 dst2_x - src2_x, dst2_y - src2_y - j);
6544 BlitBitmapMasked(bm_left, drawto,
6545 src2_x, src2_y + ypos1 + j, width, height2 - j,
6546 dst2_x, dst2_y + ypos1);
6547 BlitBitmapMasked(bm_left, drawto,
6548 src2_x, src2_y + ypos3, width, height1,
6549 dst2_x, dst2_y + ypos3 - j);
6551 SetClipOrigin(bm_left, gc_left,
6552 dst2_x - src2_x, dst2_y - src2_y - j);
6553 BlitBitmapMasked(bm_left, drawto,
6554 src2_x, src2_y + ypos2, width, height1,
6555 dst2_x, dst2_y + ypos2 - j);
6556 BlitBitmapMasked(bm_left, drawto,
6557 src2_x, src2_y + ypos4, width, height2,
6558 dst2_x, dst2_y + ypos4 - j);
6559 SetClipOrigin(bm_right, gc_right,
6560 dst1_x - src1_x, dst1_y - src1_y + j);
6561 BlitBitmapMasked(bm_right, drawto,
6562 src1_x, src1_y + ypos2, width, height1,
6563 dst1_x, dst1_y + ypos2 + j);
6564 BlitBitmapMasked(bm_right, drawto,
6565 src1_x, src1_y + ypos4, width, height2 - j,
6566 dst1_x, dst1_y + ypos4 + j);
6569 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6570 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6571 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6572 int dst2_x = DX, dst2_y = DY;
6573 int width = i, height = DYSIZE;
6574 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6576 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6577 BlitBitmapMasked(bitmap, drawto,
6578 src1_x, src1_y, width, ypos2,
6579 dst1_x, dst1_y + j);
6580 BlitBitmapMasked(bitmap, drawto,
6581 src1_x, src1_y + ypos3, width, ypos1,
6582 dst1_x, dst1_y + ypos3 + j);
6583 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6584 BlitBitmapMasked(bitmap, drawto,
6585 src2_x, src2_y + j, width, ypos2 - j,
6587 BlitBitmapMasked(bitmap, drawto,
6588 src2_x, src2_y + ypos3, width, ypos1,
6589 dst2_x, dst2_y + ypos3 - j);
6591 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6592 BlitBitmapMasked(bitmap, drawto,
6593 src2_x, src2_y + ypos2, width, ypos1,
6594 dst2_x, dst2_y + ypos2 - j);
6595 BlitBitmapMasked(bitmap, drawto,
6596 src2_x, src2_y + ypos4, width, ypos2,
6597 dst2_x, dst2_y + ypos4 - j);
6598 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6599 BlitBitmapMasked(bitmap, drawto,
6600 src1_x, src1_y + ypos2, width, ypos1,
6601 dst1_x, dst1_y + ypos2 + j);
6602 BlitBitmapMasked(bitmap, drawto,
6603 src1_x, src1_y + ypos4, width, ypos2 - j,
6604 dst1_x, dst1_y + ypos4 + j);
6607 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6608 BlitBitmapMasked(bitmap, drawto,
6609 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6610 DX + DXSIZE - i, DY + j);
6611 BlitBitmapMasked(bitmap, drawto,
6612 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6613 DX + DXSIZE - i, DY + 140 + j);
6614 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6615 DY - (DOOR_GFX_PAGEY1 + j));
6616 BlitBitmapMasked(bitmap, drawto,
6617 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6619 BlitBitmapMasked(bitmap, drawto,
6620 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6623 BlitBitmapMasked(bitmap, drawto,
6624 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6626 BlitBitmapMasked(bitmap, drawto,
6627 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6629 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6630 BlitBitmapMasked(bitmap, drawto,
6631 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6632 DX + DXSIZE - i, DY + 77 + j);
6633 BlitBitmapMasked(bitmap, drawto,
6634 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6635 DX + DXSIZE - i, DY + 203 + j);
6640 redraw_mask |= REDRAW_DOOR_1;
6641 door_1_done = (a == end);
6644 if (door_state & DOOR_ACTION_2 &&
6645 x * door_2.step_offset <= door_size_2)
6647 int a = MIN(x * door_2.step_offset, door_size);
6648 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6649 int i = p + door_skip;
6652 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6653 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6654 Bitmap *bm_left = g_left->bitmap;
6655 Bitmap *bm_right = g_right->bitmap;
6656 GC gc_left = bm_left->stored_clip_gc;
6657 GC gc_right = bm_right->stored_clip_gc;
6660 int classic_vxsize = 100;
6661 int classic_vysize = 100;
6662 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6663 VYSIZE == classic_vysize);
6665 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6667 BlitBitmap(bitmap_db_door, drawto,
6668 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6669 VXSIZE, VYSIZE, VX, VY);
6671 else if (x <= VYSIZE)
6673 BlitBitmap(bitmap_db_door, drawto,
6674 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6675 VXSIZE, VYSIZE - p / 2, VX, VY);
6677 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6680 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6683 int src1_x = g_right->src_x;
6684 int src1_y = g_right->src_y;
6685 int src2_x = g_left->src_x + g_left->width - i;
6686 int src2_y = g_left->src_y;
6687 int dst1_x = VX + VXSIZE - i;
6692 int height = VYSIZE;
6694 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6695 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6698 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6699 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6702 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6703 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6704 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6705 int dst2_x = VX, dst2_y = VY;
6706 int width = i, height = VYSIZE;
6708 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6709 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6712 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6713 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6717 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6720 int src1_x = g_right->src_x;
6721 int src1_y = g_right->src_y;
6722 int src2_x = g_left->src_x;
6723 int src2_y = g_left->src_y + g_left->height - i;
6725 int dst1_y = VY + VYSIZE - i;
6731 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6732 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6735 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6736 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6739 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6740 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6741 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6742 int dst2_x = VX, dst2_y = VY;
6743 int width = VXSIZE, height = i;
6745 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6746 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6749 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6750 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6754 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6756 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6759 int src1_x = g_right->src_x;
6760 int src1_y = g_right->src_y;
6761 int src2_x = g_left->src_x + g_left->width - i;
6762 int src2_y = g_left->src_y;
6763 int dst1_x = VX + VXSIZE - i;
6768 int height = VYSIZE / 2;
6769 int ypos1 = 0, ypos2 = VYSIZE / 2;
6771 SetClipOrigin(bm_right, gc_right,
6772 dst1_x - src1_x, dst1_y - src1_y + j);
6773 BlitBitmapMasked(bm_right, drawto,
6774 src1_x, src1_y + ypos1, width, height,
6775 dst1_x, dst1_y + ypos1 + j);
6776 SetClipOrigin(bm_left, gc_left,
6777 dst2_x - src2_x, dst2_y - src2_y - j);
6778 BlitBitmapMasked(bm_left, drawto,
6779 src2_x, src2_y + ypos1 + j, width, height - j,
6780 dst2_x, dst2_y + ypos1);
6782 SetClipOrigin(bm_left, gc_left,
6783 dst2_x - src2_x, dst2_y - src2_y - j);
6784 BlitBitmapMasked(bm_left, drawto,
6785 src2_x, src2_y + ypos2, width, height,
6786 dst2_x, dst2_y + ypos2 - j);
6787 SetClipOrigin(bm_right, gc_right,
6788 dst1_x - src1_x, dst1_y - src1_y + j);
6789 BlitBitmapMasked(bm_right, drawto,
6790 src1_x, src1_y + ypos2, width, height - j,
6791 dst1_x, dst1_y + ypos2 + j);
6793 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6794 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6795 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6796 int dst2_x = VX, dst2_y = VY;
6797 int width = i, height = VYSIZE;
6798 int ypos = VYSIZE / 2;
6800 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6801 BlitBitmapMasked(bitmap, drawto,
6802 src1_x, src1_y, width, ypos,
6803 dst1_x, dst1_y + j);
6804 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6805 BlitBitmapMasked(bitmap, drawto,
6806 src2_x, src2_y + j, width, ypos - j,
6809 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6810 BlitBitmapMasked(bitmap, drawto,
6811 src2_x, src2_y + ypos, width, ypos,
6812 dst2_x, dst2_y + ypos - j);
6813 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6814 BlitBitmapMasked(bitmap, drawto,
6815 src1_x, src1_y + ypos, width, ypos - j,
6816 dst1_x, dst1_y + ypos + j);
6819 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6820 BlitBitmapMasked(bitmap, drawto,
6821 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6822 VX + VXSIZE - i, VY + j);
6823 SetClipOrigin(bitmap, gc,
6824 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6825 BlitBitmapMasked(bitmap, drawto,
6826 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6829 BlitBitmapMasked(bitmap, drawto,
6830 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6831 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6832 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6833 BlitBitmapMasked(bitmap, drawto,
6834 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6836 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6841 redraw_mask |= REDRAW_DOOR_2;
6842 door_2_done = (a == VXSIZE);
6845 if (!(door_state & DOOR_NO_DELAY))
6849 if (game_status == GAME_MODE_MAIN)
6852 WaitUntilDelayReached(&door_delay, door_delay_value);
6857 if (door_state & DOOR_ACTION_1)
6858 door1 = door_state & DOOR_ACTION_1;
6859 if (door_state & DOOR_ACTION_2)
6860 door2 = door_state & DOOR_ACTION_2;
6862 return (door1 | door2);
6867 void DrawSpecialEditorDoor()
6870 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6871 int top_border_width = gfx1->width;
6872 int top_border_height = gfx1->height;
6873 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6874 int ex = EX - outer_border;
6875 int ey = EY - outer_border;
6876 int vy = VY - outer_border;
6877 int exsize = EXSIZE + 2 * outer_border;
6879 CloseDoor(DOOR_CLOSE_2);
6881 /* draw bigger level editor toolbox window */
6882 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6883 top_border_width, top_border_height, ex, ey - top_border_height);
6884 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6885 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6887 /* draw bigger level editor toolbox window */
6888 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6889 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6891 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6892 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6896 redraw_mask |= REDRAW_ALL;
6899 void UndrawSpecialEditorDoor()
6902 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6903 int top_border_width = gfx1->width;
6904 int top_border_height = gfx1->height;
6905 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6906 int ex = EX - outer_border;
6907 int ey = EY - outer_border;
6908 int ey_top = ey - top_border_height;
6909 int exsize = EXSIZE + 2 * outer_border;
6910 int eysize = EYSIZE + 2 * outer_border;
6912 /* draw normal tape recorder window */
6913 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6915 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6916 ex, ey_top, top_border_width, top_border_height,
6918 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6919 ex, ey, exsize, eysize, ex, ey);
6923 // if screen background is set to "[NONE]", clear editor toolbox window
6924 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6925 ClearRectangle(drawto, ex, ey, exsize, eysize);
6928 /* draw normal tape recorder window */
6929 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6930 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6934 redraw_mask |= REDRAW_ALL;
6938 /* ---------- new tool button stuff ---------------------------------------- */
6945 struct TextPosInfo *pos;
6948 } toolbutton_info[NUM_TOOL_BUTTONS] =
6951 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
6952 TOOL_CTRL_ID_YES, "yes"
6955 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
6956 TOOL_CTRL_ID_NO, "no"
6959 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
6960 TOOL_CTRL_ID_CONFIRM, "confirm"
6963 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
6964 TOOL_CTRL_ID_PLAYER_1, "player 1"
6967 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
6968 TOOL_CTRL_ID_PLAYER_2, "player 2"
6971 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
6972 TOOL_CTRL_ID_PLAYER_3, "player 3"
6975 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
6976 TOOL_CTRL_ID_PLAYER_4, "player 4"
6980 void CreateToolButtons()
6984 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6986 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6987 struct TextPosInfo *pos = toolbutton_info[i].pos;
6988 struct GadgetInfo *gi;
6989 Bitmap *deco_bitmap = None;
6990 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6991 unsigned int event_mask = GD_EVENT_RELEASED;
6994 int gd_x = gfx->src_x;
6995 int gd_y = gfx->src_y;
6996 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6997 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
7000 if (global.use_envelope_request)
7001 setRequestPosition(&dx, &dy, TRUE);
7003 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7005 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7007 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
7008 pos->size, &deco_bitmap, &deco_x, &deco_y);
7009 deco_xpos = (gfx->width - pos->size) / 2;
7010 deco_ypos = (gfx->height - pos->size) / 2;
7013 gi = CreateGadget(GDI_CUSTOM_ID, id,
7014 GDI_INFO_TEXT, toolbutton_info[i].infotext,
7015 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
7016 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
7017 GDI_WIDTH, gfx->width,
7018 GDI_HEIGHT, gfx->height,
7019 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7020 GDI_STATE, GD_BUTTON_UNPRESSED,
7021 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
7022 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
7023 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7024 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7025 GDI_DECORATION_SIZE, pos->size, pos->size,
7026 GDI_DECORATION_SHIFTING, 1, 1,
7027 GDI_DIRECT_DRAW, FALSE,
7028 GDI_EVENT_MASK, event_mask,
7029 GDI_CALLBACK_ACTION, HandleToolButtons,
7033 Error(ERR_EXIT, "cannot create gadget");
7035 tool_gadget[id] = gi;
7041 /* graphic position values for tool buttons */
7042 #define TOOL_BUTTON_YES_XPOS 2
7043 #define TOOL_BUTTON_YES_YPOS 250
7044 #define TOOL_BUTTON_YES_GFX_YPOS 0
7045 #define TOOL_BUTTON_YES_XSIZE 46
7046 #define TOOL_BUTTON_YES_YSIZE 28
7047 #define TOOL_BUTTON_NO_XPOS 52
7048 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
7049 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
7050 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
7051 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
7052 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
7053 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
7054 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
7055 #define TOOL_BUTTON_CONFIRM_XSIZE 96
7056 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
7057 #define TOOL_BUTTON_PLAYER_XSIZE 30
7058 #define TOOL_BUTTON_PLAYER_YSIZE 30
7059 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
7060 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
7061 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
7062 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
7063 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7064 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7065 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7066 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7067 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7068 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7069 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7070 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7071 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7072 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7073 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7074 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7075 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7076 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7077 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7078 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7087 } toolbutton_info[NUM_TOOL_BUTTONS] =
7090 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
7091 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
7092 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
7097 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
7098 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
7099 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
7104 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
7105 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
7106 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
7107 TOOL_CTRL_ID_CONFIRM,
7111 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7112 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
7113 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7114 TOOL_CTRL_ID_PLAYER_1,
7118 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7119 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
7120 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7121 TOOL_CTRL_ID_PLAYER_2,
7125 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7126 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
7127 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7128 TOOL_CTRL_ID_PLAYER_3,
7132 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7133 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
7134 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7135 TOOL_CTRL_ID_PLAYER_4,
7140 void CreateToolButtons()
7144 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7146 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
7147 Bitmap *deco_bitmap = None;
7148 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7149 struct GadgetInfo *gi;
7150 unsigned int event_mask;
7151 int gd_xoffset, gd_yoffset;
7152 int gd_x1, gd_x2, gd_y;
7155 event_mask = GD_EVENT_RELEASED;
7157 gd_xoffset = toolbutton_info[i].xpos;
7158 gd_yoffset = toolbutton_info[i].ypos;
7159 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
7160 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
7161 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
7163 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7165 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7167 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
7168 &deco_bitmap, &deco_x, &deco_y);
7169 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
7170 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
7173 gi = CreateGadget(GDI_CUSTOM_ID, id,
7174 GDI_INFO_TEXT, toolbutton_info[i].infotext,
7175 GDI_X, DX + GDI_ACTIVE_POS(toolbutton_info[i].x),
7176 GDI_Y, DY + GDI_ACTIVE_POS(toolbutton_info[i].y),
7177 GDI_WIDTH, toolbutton_info[i].width,
7178 GDI_HEIGHT, toolbutton_info[i].height,
7179 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7180 GDI_STATE, GD_BUTTON_UNPRESSED,
7181 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
7182 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
7183 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7184 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7185 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
7186 GDI_DECORATION_SHIFTING, 1, 1,
7187 GDI_DIRECT_DRAW, FALSE,
7188 GDI_EVENT_MASK, event_mask,
7189 GDI_CALLBACK_ACTION, HandleToolButtons,
7193 Error(ERR_EXIT, "cannot create gadget");
7195 tool_gadget[id] = gi;
7201 void FreeToolButtons()
7205 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7206 FreeGadget(tool_gadget[i]);
7209 static void UnmapToolButtons()
7213 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7214 UnmapGadget(tool_gadget[i]);
7217 static void HandleToolButtons(struct GadgetInfo *gi)
7219 request_gadget_id = gi->custom_id;
7222 static struct Mapping_EM_to_RND_object
7225 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
7226 boolean is_backside; /* backside of moving element */
7232 em_object_mapping_list[] =
7235 Xblank, TRUE, FALSE,
7239 Yacid_splash_eB, FALSE, FALSE,
7240 EL_ACID_SPLASH_RIGHT, -1, -1
7243 Yacid_splash_wB, FALSE, FALSE,
7244 EL_ACID_SPLASH_LEFT, -1, -1
7247 #ifdef EM_ENGINE_BAD_ROLL
7249 Xstone_force_e, FALSE, FALSE,
7250 EL_ROCK, -1, MV_BIT_RIGHT
7253 Xstone_force_w, FALSE, FALSE,
7254 EL_ROCK, -1, MV_BIT_LEFT
7257 Xnut_force_e, FALSE, FALSE,
7258 EL_NUT, -1, MV_BIT_RIGHT
7261 Xnut_force_w, FALSE, FALSE,
7262 EL_NUT, -1, MV_BIT_LEFT
7265 Xspring_force_e, FALSE, FALSE,
7266 EL_SPRING, -1, MV_BIT_RIGHT
7269 Xspring_force_w, FALSE, FALSE,
7270 EL_SPRING, -1, MV_BIT_LEFT
7273 Xemerald_force_e, FALSE, FALSE,
7274 EL_EMERALD, -1, MV_BIT_RIGHT
7277 Xemerald_force_w, FALSE, FALSE,
7278 EL_EMERALD, -1, MV_BIT_LEFT
7281 Xdiamond_force_e, FALSE, FALSE,
7282 EL_DIAMOND, -1, MV_BIT_RIGHT
7285 Xdiamond_force_w, FALSE, FALSE,
7286 EL_DIAMOND, -1, MV_BIT_LEFT
7289 Xbomb_force_e, FALSE, FALSE,
7290 EL_BOMB, -1, MV_BIT_RIGHT
7293 Xbomb_force_w, FALSE, FALSE,
7294 EL_BOMB, -1, MV_BIT_LEFT
7296 #endif /* EM_ENGINE_BAD_ROLL */
7299 Xstone, TRUE, FALSE,
7303 Xstone_pause, FALSE, FALSE,
7307 Xstone_fall, FALSE, FALSE,
7311 Ystone_s, FALSE, FALSE,
7312 EL_ROCK, ACTION_FALLING, -1
7315 Ystone_sB, FALSE, TRUE,
7316 EL_ROCK, ACTION_FALLING, -1
7319 Ystone_e, FALSE, FALSE,
7320 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7323 Ystone_eB, FALSE, TRUE,
7324 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7327 Ystone_w, FALSE, FALSE,
7328 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7331 Ystone_wB, FALSE, TRUE,
7332 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7339 Xnut_pause, FALSE, FALSE,
7343 Xnut_fall, FALSE, FALSE,
7347 Ynut_s, FALSE, FALSE,
7348 EL_NUT, ACTION_FALLING, -1
7351 Ynut_sB, FALSE, TRUE,
7352 EL_NUT, ACTION_FALLING, -1
7355 Ynut_e, FALSE, FALSE,
7356 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7359 Ynut_eB, FALSE, TRUE,
7360 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7363 Ynut_w, FALSE, FALSE,
7364 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7367 Ynut_wB, FALSE, TRUE,
7368 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7371 Xbug_n, TRUE, FALSE,
7375 Xbug_e, TRUE, FALSE,
7376 EL_BUG_RIGHT, -1, -1
7379 Xbug_s, TRUE, FALSE,
7383 Xbug_w, TRUE, FALSE,
7387 Xbug_gon, FALSE, FALSE,
7391 Xbug_goe, FALSE, FALSE,
7392 EL_BUG_RIGHT, -1, -1
7395 Xbug_gos, FALSE, FALSE,
7399 Xbug_gow, FALSE, FALSE,
7403 Ybug_n, FALSE, FALSE,
7404 EL_BUG, ACTION_MOVING, MV_BIT_UP
7407 Ybug_nB, FALSE, TRUE,
7408 EL_BUG, ACTION_MOVING, MV_BIT_UP
7411 Ybug_e, FALSE, FALSE,
7412 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7415 Ybug_eB, FALSE, TRUE,
7416 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7419 Ybug_s, FALSE, FALSE,
7420 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7423 Ybug_sB, FALSE, TRUE,
7424 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7427 Ybug_w, FALSE, FALSE,
7428 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7431 Ybug_wB, FALSE, TRUE,
7432 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7435 Ybug_w_n, FALSE, FALSE,
7436 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7439 Ybug_n_e, FALSE, FALSE,
7440 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7443 Ybug_e_s, FALSE, FALSE,
7444 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7447 Ybug_s_w, FALSE, FALSE,
7448 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7451 Ybug_e_n, FALSE, FALSE,
7452 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7455 Ybug_s_e, FALSE, FALSE,
7456 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7459 Ybug_w_s, FALSE, FALSE,
7460 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7463 Ybug_n_w, FALSE, FALSE,
7464 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7467 Ybug_stone, FALSE, FALSE,
7468 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
7471 Ybug_spring, FALSE, FALSE,
7472 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
7475 Xtank_n, TRUE, FALSE,
7476 EL_SPACESHIP_UP, -1, -1
7479 Xtank_e, TRUE, FALSE,
7480 EL_SPACESHIP_RIGHT, -1, -1
7483 Xtank_s, TRUE, FALSE,
7484 EL_SPACESHIP_DOWN, -1, -1
7487 Xtank_w, TRUE, FALSE,
7488 EL_SPACESHIP_LEFT, -1, -1
7491 Xtank_gon, FALSE, FALSE,
7492 EL_SPACESHIP_UP, -1, -1
7495 Xtank_goe, FALSE, FALSE,
7496 EL_SPACESHIP_RIGHT, -1, -1
7499 Xtank_gos, FALSE, FALSE,
7500 EL_SPACESHIP_DOWN, -1, -1
7503 Xtank_gow, FALSE, FALSE,
7504 EL_SPACESHIP_LEFT, -1, -1
7507 Ytank_n, FALSE, FALSE,
7508 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7511 Ytank_nB, FALSE, TRUE,
7512 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7515 Ytank_e, FALSE, FALSE,
7516 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7519 Ytank_eB, FALSE, TRUE,
7520 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7523 Ytank_s, FALSE, FALSE,
7524 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7527 Ytank_sB, FALSE, TRUE,
7528 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7531 Ytank_w, FALSE, FALSE,
7532 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7535 Ytank_wB, FALSE, TRUE,
7536 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7539 Ytank_w_n, FALSE, FALSE,
7540 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7543 Ytank_n_e, FALSE, FALSE,
7544 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7547 Ytank_e_s, FALSE, FALSE,
7548 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7551 Ytank_s_w, FALSE, FALSE,
7552 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7555 Ytank_e_n, FALSE, FALSE,
7556 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7559 Ytank_s_e, FALSE, FALSE,
7560 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7563 Ytank_w_s, FALSE, FALSE,
7564 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7567 Ytank_n_w, FALSE, FALSE,
7568 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7571 Ytank_stone, FALSE, FALSE,
7572 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
7575 Ytank_spring, FALSE, FALSE,
7576 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
7579 Xandroid, TRUE, FALSE,
7580 EL_EMC_ANDROID, ACTION_ACTIVE, -1
7583 Xandroid_1_n, FALSE, FALSE,
7584 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7587 Xandroid_2_n, FALSE, FALSE,
7588 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7591 Xandroid_1_e, FALSE, FALSE,
7592 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7595 Xandroid_2_e, FALSE, FALSE,
7596 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7599 Xandroid_1_w, FALSE, FALSE,
7600 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7603 Xandroid_2_w, FALSE, FALSE,
7604 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7607 Xandroid_1_s, FALSE, FALSE,
7608 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7611 Xandroid_2_s, FALSE, FALSE,
7612 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7615 Yandroid_n, FALSE, FALSE,
7616 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7619 Yandroid_nB, FALSE, TRUE,
7620 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7623 Yandroid_ne, FALSE, FALSE,
7624 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7627 Yandroid_neB, FALSE, TRUE,
7628 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7631 Yandroid_e, FALSE, FALSE,
7632 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7635 Yandroid_eB, FALSE, TRUE,
7636 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7639 Yandroid_se, FALSE, FALSE,
7640 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7643 Yandroid_seB, FALSE, TRUE,
7644 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7647 Yandroid_s, FALSE, FALSE,
7648 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7651 Yandroid_sB, FALSE, TRUE,
7652 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7655 Yandroid_sw, FALSE, FALSE,
7656 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7659 Yandroid_swB, FALSE, TRUE,
7660 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7663 Yandroid_w, FALSE, FALSE,
7664 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7667 Yandroid_wB, FALSE, TRUE,
7668 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7671 Yandroid_nw, FALSE, FALSE,
7672 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7675 Yandroid_nwB, FALSE, TRUE,
7676 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7679 Xspring, TRUE, FALSE,
7683 Xspring_pause, FALSE, FALSE,
7687 Xspring_e, FALSE, FALSE,
7691 Xspring_w, FALSE, FALSE,
7695 Xspring_fall, FALSE, FALSE,
7699 Yspring_s, FALSE, FALSE,
7700 EL_SPRING, ACTION_FALLING, -1
7703 Yspring_sB, FALSE, TRUE,
7704 EL_SPRING, ACTION_FALLING, -1
7707 Yspring_e, FALSE, FALSE,
7708 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7711 Yspring_eB, FALSE, TRUE,
7712 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7715 Yspring_w, FALSE, FALSE,
7716 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7719 Yspring_wB, FALSE, TRUE,
7720 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7723 Yspring_kill_e, FALSE, FALSE,
7724 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7727 Yspring_kill_eB, FALSE, TRUE,
7728 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7731 Yspring_kill_w, FALSE, FALSE,
7732 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7735 Yspring_kill_wB, FALSE, TRUE,
7736 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7739 Xeater_n, TRUE, FALSE,
7740 EL_YAMYAM_UP, -1, -1
7743 Xeater_e, TRUE, FALSE,
7744 EL_YAMYAM_RIGHT, -1, -1
7747 Xeater_w, TRUE, FALSE,
7748 EL_YAMYAM_LEFT, -1, -1
7751 Xeater_s, TRUE, FALSE,
7752 EL_YAMYAM_DOWN, -1, -1
7755 Yeater_n, FALSE, FALSE,
7756 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7759 Yeater_nB, FALSE, TRUE,
7760 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7763 Yeater_e, FALSE, FALSE,
7764 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7767 Yeater_eB, FALSE, TRUE,
7768 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7771 Yeater_s, FALSE, FALSE,
7772 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7775 Yeater_sB, FALSE, TRUE,
7776 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7779 Yeater_w, FALSE, FALSE,
7780 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7783 Yeater_wB, FALSE, TRUE,
7784 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7787 Yeater_stone, FALSE, FALSE,
7788 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7791 Yeater_spring, FALSE, FALSE,
7792 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7795 Xalien, TRUE, FALSE,
7799 Xalien_pause, FALSE, FALSE,
7803 Yalien_n, FALSE, FALSE,
7804 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7807 Yalien_nB, FALSE, TRUE,
7808 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7811 Yalien_e, FALSE, FALSE,
7812 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7815 Yalien_eB, FALSE, TRUE,
7816 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7819 Yalien_s, FALSE, FALSE,
7820 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7823 Yalien_sB, FALSE, TRUE,
7824 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7827 Yalien_w, FALSE, FALSE,
7828 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7831 Yalien_wB, FALSE, TRUE,
7832 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7835 Yalien_stone, FALSE, FALSE,
7836 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7839 Yalien_spring, FALSE, FALSE,
7840 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7843 Xemerald, TRUE, FALSE,
7847 Xemerald_pause, FALSE, FALSE,
7851 Xemerald_fall, FALSE, FALSE,
7855 Xemerald_shine, FALSE, FALSE,
7856 EL_EMERALD, ACTION_TWINKLING, -1
7859 Yemerald_s, FALSE, FALSE,
7860 EL_EMERALD, ACTION_FALLING, -1
7863 Yemerald_sB, FALSE, TRUE,
7864 EL_EMERALD, ACTION_FALLING, -1
7867 Yemerald_e, FALSE, FALSE,
7868 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7871 Yemerald_eB, FALSE, TRUE,
7872 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7875 Yemerald_w, FALSE, FALSE,
7876 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7879 Yemerald_wB, FALSE, TRUE,
7880 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7883 Yemerald_eat, FALSE, FALSE,
7884 EL_EMERALD, ACTION_COLLECTING, -1
7887 Yemerald_stone, FALSE, FALSE,
7888 EL_NUT, ACTION_BREAKING, -1
7891 Xdiamond, TRUE, FALSE,
7895 Xdiamond_pause, FALSE, FALSE,
7899 Xdiamond_fall, FALSE, FALSE,
7903 Xdiamond_shine, FALSE, FALSE,
7904 EL_DIAMOND, ACTION_TWINKLING, -1
7907 Ydiamond_s, FALSE, FALSE,
7908 EL_DIAMOND, ACTION_FALLING, -1
7911 Ydiamond_sB, FALSE, TRUE,
7912 EL_DIAMOND, ACTION_FALLING, -1
7915 Ydiamond_e, FALSE, FALSE,
7916 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7919 Ydiamond_eB, FALSE, TRUE,
7920 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7923 Ydiamond_w, FALSE, FALSE,
7924 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7927 Ydiamond_wB, FALSE, TRUE,
7928 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7931 Ydiamond_eat, FALSE, FALSE,
7932 EL_DIAMOND, ACTION_COLLECTING, -1
7935 Ydiamond_stone, FALSE, FALSE,
7936 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7939 Xdrip_fall, TRUE, FALSE,
7940 EL_AMOEBA_DROP, -1, -1
7943 Xdrip_stretch, FALSE, FALSE,
7944 EL_AMOEBA_DROP, ACTION_FALLING, -1
7947 Xdrip_stretchB, FALSE, TRUE,
7948 EL_AMOEBA_DROP, ACTION_FALLING, -1
7951 Xdrip_eat, FALSE, FALSE,
7952 EL_AMOEBA_DROP, ACTION_GROWING, -1
7955 Ydrip_s1, FALSE, FALSE,
7956 EL_AMOEBA_DROP, ACTION_FALLING, -1
7959 Ydrip_s1B, FALSE, TRUE,
7960 EL_AMOEBA_DROP, ACTION_FALLING, -1
7963 Ydrip_s2, FALSE, FALSE,
7964 EL_AMOEBA_DROP, ACTION_FALLING, -1
7967 Ydrip_s2B, FALSE, TRUE,
7968 EL_AMOEBA_DROP, ACTION_FALLING, -1
7975 Xbomb_pause, FALSE, FALSE,
7979 Xbomb_fall, FALSE, FALSE,
7983 Ybomb_s, FALSE, FALSE,
7984 EL_BOMB, ACTION_FALLING, -1
7987 Ybomb_sB, FALSE, TRUE,
7988 EL_BOMB, ACTION_FALLING, -1
7991 Ybomb_e, FALSE, FALSE,
7992 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7995 Ybomb_eB, FALSE, TRUE,
7996 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7999 Ybomb_w, FALSE, FALSE,
8000 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
8003 Ybomb_wB, FALSE, TRUE,
8004 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
8007 Ybomb_eat, FALSE, FALSE,
8008 EL_BOMB, ACTION_ACTIVATING, -1
8011 Xballoon, TRUE, FALSE,
8015 Yballoon_n, FALSE, FALSE,
8016 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
8019 Yballoon_nB, FALSE, TRUE,
8020 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
8023 Yballoon_e, FALSE, FALSE,
8024 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8027 Yballoon_eB, FALSE, TRUE,
8028 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8031 Yballoon_s, FALSE, FALSE,
8032 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8035 Yballoon_sB, FALSE, TRUE,
8036 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8039 Yballoon_w, FALSE, FALSE,
8040 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8043 Yballoon_wB, FALSE, TRUE,
8044 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8047 Xgrass, TRUE, FALSE,
8048 EL_EMC_GRASS, -1, -1
8051 Ygrass_nB, FALSE, FALSE,
8052 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
8055 Ygrass_eB, FALSE, FALSE,
8056 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
8059 Ygrass_sB, FALSE, FALSE,
8060 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
8063 Ygrass_wB, FALSE, FALSE,
8064 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
8071 Ydirt_nB, FALSE, FALSE,
8072 EL_SAND, ACTION_DIGGING, MV_BIT_UP
8075 Ydirt_eB, FALSE, FALSE,
8076 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
8079 Ydirt_sB, FALSE, FALSE,
8080 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
8083 Ydirt_wB, FALSE, FALSE,
8084 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
8087 Xacid_ne, TRUE, FALSE,
8088 EL_ACID_POOL_TOPRIGHT, -1, -1
8091 Xacid_se, TRUE, FALSE,
8092 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
8095 Xacid_s, TRUE, FALSE,
8096 EL_ACID_POOL_BOTTOM, -1, -1
8099 Xacid_sw, TRUE, FALSE,
8100 EL_ACID_POOL_BOTTOMLEFT, -1, -1
8103 Xacid_nw, TRUE, FALSE,
8104 EL_ACID_POOL_TOPLEFT, -1, -1
8107 Xacid_1, TRUE, FALSE,
8111 Xacid_2, FALSE, FALSE,
8115 Xacid_3, FALSE, FALSE,
8119 Xacid_4, FALSE, FALSE,
8123 Xacid_5, FALSE, FALSE,
8127 Xacid_6, FALSE, FALSE,
8131 Xacid_7, FALSE, FALSE,
8135 Xacid_8, FALSE, FALSE,
8139 Xball_1, TRUE, FALSE,
8140 EL_EMC_MAGIC_BALL, -1, -1
8143 Xball_1B, FALSE, FALSE,
8144 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8147 Xball_2, FALSE, FALSE,
8148 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8151 Xball_2B, FALSE, FALSE,
8152 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8155 Yball_eat, FALSE, FALSE,
8156 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
8159 Ykey_1_eat, FALSE, FALSE,
8160 EL_EM_KEY_1, ACTION_COLLECTING, -1
8163 Ykey_2_eat, FALSE, FALSE,
8164 EL_EM_KEY_2, ACTION_COLLECTING, -1
8167 Ykey_3_eat, FALSE, FALSE,
8168 EL_EM_KEY_3, ACTION_COLLECTING, -1
8171 Ykey_4_eat, FALSE, FALSE,
8172 EL_EM_KEY_4, ACTION_COLLECTING, -1
8175 Ykey_5_eat, FALSE, FALSE,
8176 EL_EMC_KEY_5, ACTION_COLLECTING, -1
8179 Ykey_6_eat, FALSE, FALSE,
8180 EL_EMC_KEY_6, ACTION_COLLECTING, -1
8183 Ykey_7_eat, FALSE, FALSE,
8184 EL_EMC_KEY_7, ACTION_COLLECTING, -1
8187 Ykey_8_eat, FALSE, FALSE,
8188 EL_EMC_KEY_8, ACTION_COLLECTING, -1
8191 Ylenses_eat, FALSE, FALSE,
8192 EL_EMC_LENSES, ACTION_COLLECTING, -1
8195 Ymagnify_eat, FALSE, FALSE,
8196 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
8199 Ygrass_eat, FALSE, FALSE,
8200 EL_EMC_GRASS, ACTION_SNAPPING, -1
8203 Ydirt_eat, FALSE, FALSE,
8204 EL_SAND, ACTION_SNAPPING, -1
8207 Xgrow_ns, TRUE, FALSE,
8208 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
8211 Ygrow_ns_eat, FALSE, FALSE,
8212 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
8215 Xgrow_ew, TRUE, FALSE,
8216 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
8219 Ygrow_ew_eat, FALSE, FALSE,
8220 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
8223 Xwonderwall, TRUE, FALSE,
8224 EL_MAGIC_WALL, -1, -1
8227 XwonderwallB, FALSE, FALSE,
8228 EL_MAGIC_WALL, ACTION_ACTIVE, -1
8231 Xamoeba_1, TRUE, FALSE,
8232 EL_AMOEBA_DRY, ACTION_OTHER, -1
8235 Xamoeba_2, FALSE, FALSE,
8236 EL_AMOEBA_DRY, ACTION_OTHER, -1
8239 Xamoeba_3, FALSE, FALSE,
8240 EL_AMOEBA_DRY, ACTION_OTHER, -1
8243 Xamoeba_4, FALSE, FALSE,
8244 EL_AMOEBA_DRY, ACTION_OTHER, -1
8247 Xamoeba_5, TRUE, FALSE,
8248 EL_AMOEBA_WET, ACTION_OTHER, -1
8251 Xamoeba_6, FALSE, FALSE,
8252 EL_AMOEBA_WET, ACTION_OTHER, -1
8255 Xamoeba_7, FALSE, FALSE,
8256 EL_AMOEBA_WET, ACTION_OTHER, -1
8259 Xamoeba_8, FALSE, FALSE,
8260 EL_AMOEBA_WET, ACTION_OTHER, -1
8263 Xdoor_1, TRUE, FALSE,
8264 EL_EM_GATE_1, -1, -1
8267 Xdoor_2, TRUE, FALSE,
8268 EL_EM_GATE_2, -1, -1
8271 Xdoor_3, TRUE, FALSE,
8272 EL_EM_GATE_3, -1, -1
8275 Xdoor_4, TRUE, FALSE,
8276 EL_EM_GATE_4, -1, -1
8279 Xdoor_5, TRUE, FALSE,
8280 EL_EMC_GATE_5, -1, -1
8283 Xdoor_6, TRUE, FALSE,
8284 EL_EMC_GATE_6, -1, -1
8287 Xdoor_7, TRUE, FALSE,
8288 EL_EMC_GATE_7, -1, -1
8291 Xdoor_8, TRUE, FALSE,
8292 EL_EMC_GATE_8, -1, -1
8295 Xkey_1, TRUE, FALSE,
8299 Xkey_2, TRUE, FALSE,
8303 Xkey_3, TRUE, FALSE,
8307 Xkey_4, TRUE, FALSE,
8311 Xkey_5, TRUE, FALSE,
8312 EL_EMC_KEY_5, -1, -1
8315 Xkey_6, TRUE, FALSE,
8316 EL_EMC_KEY_6, -1, -1
8319 Xkey_7, TRUE, FALSE,
8320 EL_EMC_KEY_7, -1, -1
8323 Xkey_8, TRUE, FALSE,
8324 EL_EMC_KEY_8, -1, -1
8327 Xwind_n, TRUE, FALSE,
8328 EL_BALLOON_SWITCH_UP, -1, -1
8331 Xwind_e, TRUE, FALSE,
8332 EL_BALLOON_SWITCH_RIGHT, -1, -1
8335 Xwind_s, TRUE, FALSE,
8336 EL_BALLOON_SWITCH_DOWN, -1, -1
8339 Xwind_w, TRUE, FALSE,
8340 EL_BALLOON_SWITCH_LEFT, -1, -1
8343 Xwind_nesw, TRUE, FALSE,
8344 EL_BALLOON_SWITCH_ANY, -1, -1
8347 Xwind_stop, TRUE, FALSE,
8348 EL_BALLOON_SWITCH_NONE, -1, -1
8352 EL_EM_EXIT_CLOSED, -1, -1
8355 Xexit_1, TRUE, FALSE,
8356 EL_EM_EXIT_OPEN, -1, -1
8359 Xexit_2, FALSE, FALSE,
8360 EL_EM_EXIT_OPEN, -1, -1
8363 Xexit_3, FALSE, FALSE,
8364 EL_EM_EXIT_OPEN, -1, -1
8367 Xdynamite, TRUE, FALSE,
8368 EL_EM_DYNAMITE, -1, -1
8371 Ydynamite_eat, FALSE, FALSE,
8372 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
8375 Xdynamite_1, TRUE, FALSE,
8376 EL_EM_DYNAMITE_ACTIVE, -1, -1
8379 Xdynamite_2, FALSE, FALSE,
8380 EL_EM_DYNAMITE_ACTIVE, -1, -1
8383 Xdynamite_3, FALSE, FALSE,
8384 EL_EM_DYNAMITE_ACTIVE, -1, -1
8387 Xdynamite_4, FALSE, FALSE,
8388 EL_EM_DYNAMITE_ACTIVE, -1, -1
8391 Xbumper, TRUE, FALSE,
8392 EL_EMC_SPRING_BUMPER, -1, -1
8395 XbumperB, FALSE, FALSE,
8396 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
8399 Xwheel, TRUE, FALSE,
8400 EL_ROBOT_WHEEL, -1, -1
8403 XwheelB, FALSE, FALSE,
8404 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
8407 Xswitch, TRUE, FALSE,
8408 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
8411 XswitchB, FALSE, FALSE,
8412 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
8416 EL_QUICKSAND_EMPTY, -1, -1
8419 Xsand_stone, TRUE, FALSE,
8420 EL_QUICKSAND_FULL, -1, -1
8423 Xsand_stonein_1, FALSE, TRUE,
8424 EL_ROCK, ACTION_FILLING, -1
8427 Xsand_stonein_2, FALSE, TRUE,
8428 EL_ROCK, ACTION_FILLING, -1
8431 Xsand_stonein_3, FALSE, TRUE,
8432 EL_ROCK, ACTION_FILLING, -1
8435 Xsand_stonein_4, FALSE, TRUE,
8436 EL_ROCK, ACTION_FILLING, -1
8440 Xsand_stonesand_1, FALSE, FALSE,
8441 EL_QUICKSAND_EMPTYING, -1, -1
8444 Xsand_stonesand_2, FALSE, FALSE,
8445 EL_QUICKSAND_EMPTYING, -1, -1
8448 Xsand_stonesand_3, FALSE, FALSE,
8449 EL_QUICKSAND_EMPTYING, -1, -1
8452 Xsand_stonesand_4, FALSE, FALSE,
8453 EL_QUICKSAND_EMPTYING, -1, -1
8456 Xsand_stonesand_quickout_1, FALSE, FALSE,
8457 EL_QUICKSAND_EMPTYING, -1, -1
8460 Xsand_stonesand_quickout_2, FALSE, FALSE,
8461 EL_QUICKSAND_EMPTYING, -1, -1
8465 Xsand_stonesand_1, FALSE, FALSE,
8466 EL_QUICKSAND_FULL, -1, -1
8469 Xsand_stonesand_2, FALSE, FALSE,
8470 EL_QUICKSAND_FULL, -1, -1
8473 Xsand_stonesand_3, FALSE, FALSE,
8474 EL_QUICKSAND_FULL, -1, -1
8477 Xsand_stonesand_4, FALSE, FALSE,
8478 EL_QUICKSAND_FULL, -1, -1
8482 Xsand_stoneout_1, FALSE, FALSE,
8483 EL_ROCK, ACTION_EMPTYING, -1
8486 Xsand_stoneout_2, FALSE, FALSE,
8487 EL_ROCK, ACTION_EMPTYING, -1
8491 Xsand_sandstone_1, FALSE, FALSE,
8492 EL_QUICKSAND_FILLING, -1, -1
8495 Xsand_sandstone_2, FALSE, FALSE,
8496 EL_QUICKSAND_FILLING, -1, -1
8499 Xsand_sandstone_3, FALSE, FALSE,
8500 EL_QUICKSAND_FILLING, -1, -1
8503 Xsand_sandstone_4, FALSE, FALSE,
8504 EL_QUICKSAND_FILLING, -1, -1
8508 Xsand_sandstone_1, FALSE, FALSE,
8509 EL_QUICKSAND_FULL, -1, -1
8512 Xsand_sandstone_2, FALSE, FALSE,
8513 EL_QUICKSAND_FULL, -1, -1
8516 Xsand_sandstone_3, FALSE, FALSE,
8517 EL_QUICKSAND_FULL, -1, -1
8520 Xsand_sandstone_4, FALSE, FALSE,
8521 EL_QUICKSAND_FULL, -1, -1
8525 Xplant, TRUE, FALSE,
8526 EL_EMC_PLANT, -1, -1
8529 Yplant, FALSE, FALSE,
8530 EL_EMC_PLANT, -1, -1
8533 Xlenses, TRUE, FALSE,
8534 EL_EMC_LENSES, -1, -1
8537 Xmagnify, TRUE, FALSE,
8538 EL_EMC_MAGNIFIER, -1, -1
8541 Xdripper, TRUE, FALSE,
8542 EL_EMC_DRIPPER, -1, -1
8545 XdripperB, FALSE, FALSE,
8546 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
8549 Xfake_blank, TRUE, FALSE,
8550 EL_INVISIBLE_WALL, -1, -1
8553 Xfake_blankB, FALSE, FALSE,
8554 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
8557 Xfake_grass, TRUE, FALSE,
8558 EL_EMC_FAKE_GRASS, -1, -1
8561 Xfake_grassB, FALSE, FALSE,
8562 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
8565 Xfake_door_1, TRUE, FALSE,
8566 EL_EM_GATE_1_GRAY, -1, -1
8569 Xfake_door_2, TRUE, FALSE,
8570 EL_EM_GATE_2_GRAY, -1, -1
8573 Xfake_door_3, TRUE, FALSE,
8574 EL_EM_GATE_3_GRAY, -1, -1
8577 Xfake_door_4, TRUE, FALSE,
8578 EL_EM_GATE_4_GRAY, -1, -1
8581 Xfake_door_5, TRUE, FALSE,
8582 EL_EMC_GATE_5_GRAY, -1, -1
8585 Xfake_door_6, TRUE, FALSE,
8586 EL_EMC_GATE_6_GRAY, -1, -1
8589 Xfake_door_7, TRUE, FALSE,
8590 EL_EMC_GATE_7_GRAY, -1, -1
8593 Xfake_door_8, TRUE, FALSE,
8594 EL_EMC_GATE_8_GRAY, -1, -1
8597 Xfake_acid_1, TRUE, FALSE,
8598 EL_EMC_FAKE_ACID, -1, -1
8601 Xfake_acid_2, FALSE, FALSE,
8602 EL_EMC_FAKE_ACID, -1, -1
8605 Xfake_acid_3, FALSE, FALSE,
8606 EL_EMC_FAKE_ACID, -1, -1
8609 Xfake_acid_4, FALSE, FALSE,
8610 EL_EMC_FAKE_ACID, -1, -1
8613 Xfake_acid_5, FALSE, FALSE,
8614 EL_EMC_FAKE_ACID, -1, -1
8617 Xfake_acid_6, FALSE, FALSE,
8618 EL_EMC_FAKE_ACID, -1, -1
8621 Xfake_acid_7, FALSE, FALSE,
8622 EL_EMC_FAKE_ACID, -1, -1
8625 Xfake_acid_8, FALSE, FALSE,
8626 EL_EMC_FAKE_ACID, -1, -1
8629 Xsteel_1, TRUE, FALSE,
8630 EL_STEELWALL, -1, -1
8633 Xsteel_2, TRUE, FALSE,
8634 EL_EMC_STEELWALL_2, -1, -1
8637 Xsteel_3, TRUE, FALSE,
8638 EL_EMC_STEELWALL_3, -1, -1
8641 Xsteel_4, TRUE, FALSE,
8642 EL_EMC_STEELWALL_4, -1, -1
8645 Xwall_1, TRUE, FALSE,
8649 Xwall_2, TRUE, FALSE,
8650 EL_EMC_WALL_14, -1, -1
8653 Xwall_3, TRUE, FALSE,
8654 EL_EMC_WALL_15, -1, -1
8657 Xwall_4, TRUE, FALSE,
8658 EL_EMC_WALL_16, -1, -1
8661 Xround_wall_1, TRUE, FALSE,
8662 EL_WALL_SLIPPERY, -1, -1
8665 Xround_wall_2, TRUE, FALSE,
8666 EL_EMC_WALL_SLIPPERY_2, -1, -1
8669 Xround_wall_3, TRUE, FALSE,
8670 EL_EMC_WALL_SLIPPERY_3, -1, -1
8673 Xround_wall_4, TRUE, FALSE,
8674 EL_EMC_WALL_SLIPPERY_4, -1, -1
8677 Xdecor_1, TRUE, FALSE,
8678 EL_EMC_WALL_8, -1, -1
8681 Xdecor_2, TRUE, FALSE,
8682 EL_EMC_WALL_6, -1, -1
8685 Xdecor_3, TRUE, FALSE,
8686 EL_EMC_WALL_4, -1, -1
8689 Xdecor_4, TRUE, FALSE,
8690 EL_EMC_WALL_7, -1, -1
8693 Xdecor_5, TRUE, FALSE,
8694 EL_EMC_WALL_5, -1, -1
8697 Xdecor_6, TRUE, FALSE,
8698 EL_EMC_WALL_9, -1, -1
8701 Xdecor_7, TRUE, FALSE,
8702 EL_EMC_WALL_10, -1, -1
8705 Xdecor_8, TRUE, FALSE,
8706 EL_EMC_WALL_1, -1, -1
8709 Xdecor_9, TRUE, FALSE,
8710 EL_EMC_WALL_2, -1, -1
8713 Xdecor_10, TRUE, FALSE,
8714 EL_EMC_WALL_3, -1, -1
8717 Xdecor_11, TRUE, FALSE,
8718 EL_EMC_WALL_11, -1, -1
8721 Xdecor_12, TRUE, FALSE,
8722 EL_EMC_WALL_12, -1, -1
8725 Xalpha_0, TRUE, FALSE,
8726 EL_CHAR('0'), -1, -1
8729 Xalpha_1, TRUE, FALSE,
8730 EL_CHAR('1'), -1, -1
8733 Xalpha_2, TRUE, FALSE,
8734 EL_CHAR('2'), -1, -1
8737 Xalpha_3, TRUE, FALSE,
8738 EL_CHAR('3'), -1, -1
8741 Xalpha_4, TRUE, FALSE,
8742 EL_CHAR('4'), -1, -1
8745 Xalpha_5, TRUE, FALSE,
8746 EL_CHAR('5'), -1, -1
8749 Xalpha_6, TRUE, FALSE,
8750 EL_CHAR('6'), -1, -1
8753 Xalpha_7, TRUE, FALSE,
8754 EL_CHAR('7'), -1, -1
8757 Xalpha_8, TRUE, FALSE,
8758 EL_CHAR('8'), -1, -1
8761 Xalpha_9, TRUE, FALSE,
8762 EL_CHAR('9'), -1, -1
8765 Xalpha_excla, TRUE, FALSE,
8766 EL_CHAR('!'), -1, -1
8769 Xalpha_quote, TRUE, FALSE,
8770 EL_CHAR('"'), -1, -1
8773 Xalpha_comma, TRUE, FALSE,
8774 EL_CHAR(','), -1, -1
8777 Xalpha_minus, TRUE, FALSE,
8778 EL_CHAR('-'), -1, -1
8781 Xalpha_perio, TRUE, FALSE,
8782 EL_CHAR('.'), -1, -1
8785 Xalpha_colon, TRUE, FALSE,
8786 EL_CHAR(':'), -1, -1
8789 Xalpha_quest, TRUE, FALSE,
8790 EL_CHAR('?'), -1, -1
8793 Xalpha_a, TRUE, FALSE,
8794 EL_CHAR('A'), -1, -1
8797 Xalpha_b, TRUE, FALSE,
8798 EL_CHAR('B'), -1, -1
8801 Xalpha_c, TRUE, FALSE,
8802 EL_CHAR('C'), -1, -1
8805 Xalpha_d, TRUE, FALSE,
8806 EL_CHAR('D'), -1, -1
8809 Xalpha_e, TRUE, FALSE,
8810 EL_CHAR('E'), -1, -1
8813 Xalpha_f, TRUE, FALSE,
8814 EL_CHAR('F'), -1, -1
8817 Xalpha_g, TRUE, FALSE,
8818 EL_CHAR('G'), -1, -1
8821 Xalpha_h, TRUE, FALSE,
8822 EL_CHAR('H'), -1, -1
8825 Xalpha_i, TRUE, FALSE,
8826 EL_CHAR('I'), -1, -1
8829 Xalpha_j, TRUE, FALSE,
8830 EL_CHAR('J'), -1, -1
8833 Xalpha_k, TRUE, FALSE,
8834 EL_CHAR('K'), -1, -1
8837 Xalpha_l, TRUE, FALSE,
8838 EL_CHAR('L'), -1, -1
8841 Xalpha_m, TRUE, FALSE,
8842 EL_CHAR('M'), -1, -1
8845 Xalpha_n, TRUE, FALSE,
8846 EL_CHAR('N'), -1, -1
8849 Xalpha_o, TRUE, FALSE,
8850 EL_CHAR('O'), -1, -1
8853 Xalpha_p, TRUE, FALSE,
8854 EL_CHAR('P'), -1, -1
8857 Xalpha_q, TRUE, FALSE,
8858 EL_CHAR('Q'), -1, -1
8861 Xalpha_r, TRUE, FALSE,
8862 EL_CHAR('R'), -1, -1
8865 Xalpha_s, TRUE, FALSE,
8866 EL_CHAR('S'), -1, -1
8869 Xalpha_t, TRUE, FALSE,
8870 EL_CHAR('T'), -1, -1
8873 Xalpha_u, TRUE, FALSE,
8874 EL_CHAR('U'), -1, -1
8877 Xalpha_v, TRUE, FALSE,
8878 EL_CHAR('V'), -1, -1
8881 Xalpha_w, TRUE, FALSE,
8882 EL_CHAR('W'), -1, -1
8885 Xalpha_x, TRUE, FALSE,
8886 EL_CHAR('X'), -1, -1
8889 Xalpha_y, TRUE, FALSE,
8890 EL_CHAR('Y'), -1, -1
8893 Xalpha_z, TRUE, FALSE,
8894 EL_CHAR('Z'), -1, -1
8897 Xalpha_arrow_e, TRUE, FALSE,
8898 EL_CHAR('>'), -1, -1
8901 Xalpha_arrow_w, TRUE, FALSE,
8902 EL_CHAR('<'), -1, -1
8905 Xalpha_copyr, TRUE, FALSE,
8906 EL_CHAR('©'), -1, -1
8910 Xboom_bug, FALSE, FALSE,
8911 EL_BUG, ACTION_EXPLODING, -1
8914 Xboom_bomb, FALSE, FALSE,
8915 EL_BOMB, ACTION_EXPLODING, -1
8918 Xboom_android, FALSE, FALSE,
8919 EL_EMC_ANDROID, ACTION_OTHER, -1
8922 Xboom_1, FALSE, FALSE,
8923 EL_DEFAULT, ACTION_EXPLODING, -1
8926 Xboom_2, FALSE, FALSE,
8927 EL_DEFAULT, ACTION_EXPLODING, -1
8930 Znormal, FALSE, FALSE,
8934 Zdynamite, FALSE, FALSE,
8938 Zplayer, FALSE, FALSE,
8942 ZBORDER, FALSE, FALSE,
8952 static struct Mapping_EM_to_RND_player
8961 em_player_mapping_list[] =
8965 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
8969 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
8973 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
8977 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
8981 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
8985 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
8989 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
8993 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
8997 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
9001 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
9005 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
9009 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
9013 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
9017 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
9021 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
9025 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
9029 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
9033 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
9037 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
9041 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
9045 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
9049 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
9053 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
9057 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
9061 EL_PLAYER_1, ACTION_DEFAULT, -1,
9065 EL_PLAYER_2, ACTION_DEFAULT, -1,
9069 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
9073 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
9077 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
9081 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
9085 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
9089 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
9093 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
9097 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
9101 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
9105 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
9109 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
9113 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
9117 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
9121 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
9125 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
9129 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
9133 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
9137 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
9141 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
9145 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
9149 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
9153 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
9157 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
9161 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
9165 EL_PLAYER_3, ACTION_DEFAULT, -1,
9169 EL_PLAYER_4, ACTION_DEFAULT, -1,
9178 int map_element_RND_to_EM(int element_rnd)
9180 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
9181 static boolean mapping_initialized = FALSE;
9183 if (!mapping_initialized)
9187 /* return "Xalpha_quest" for all undefined elements in mapping array */
9188 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9189 mapping_RND_to_EM[i] = Xalpha_quest;
9191 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9192 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
9193 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
9194 em_object_mapping_list[i].element_em;
9196 mapping_initialized = TRUE;
9199 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
9200 return mapping_RND_to_EM[element_rnd];
9202 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
9207 int map_element_EM_to_RND(int element_em)
9209 static unsigned short mapping_EM_to_RND[TILE_MAX];
9210 static boolean mapping_initialized = FALSE;
9212 if (!mapping_initialized)
9216 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
9217 for (i = 0; i < TILE_MAX; i++)
9218 mapping_EM_to_RND[i] = EL_UNKNOWN;
9220 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9221 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
9222 em_object_mapping_list[i].element_rnd;
9224 mapping_initialized = TRUE;
9227 if (element_em >= 0 && element_em < TILE_MAX)
9228 return mapping_EM_to_RND[element_em];
9230 Error(ERR_WARN, "invalid EM level element %d", element_em);
9235 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
9237 struct LevelInfo_EM *level_em = level->native_em_level;
9238 struct LEVEL *lev = level_em->lev;
9241 for (i = 0; i < TILE_MAX; i++)
9242 lev->android_array[i] = Xblank;
9244 for (i = 0; i < level->num_android_clone_elements; i++)
9246 int element_rnd = level->android_clone_element[i];
9247 int element_em = map_element_RND_to_EM(element_rnd);
9249 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
9250 if (em_object_mapping_list[j].element_rnd == element_rnd)
9251 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
9255 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
9257 struct LevelInfo_EM *level_em = level->native_em_level;
9258 struct LEVEL *lev = level_em->lev;
9261 level->num_android_clone_elements = 0;
9263 for (i = 0; i < TILE_MAX; i++)
9265 int element_em = lev->android_array[i];
9267 boolean element_found = FALSE;
9269 if (element_em == Xblank)
9272 element_rnd = map_element_EM_to_RND(element_em);
9274 for (j = 0; j < level->num_android_clone_elements; j++)
9275 if (level->android_clone_element[j] == element_rnd)
9276 element_found = TRUE;
9280 level->android_clone_element[level->num_android_clone_elements++] =
9283 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
9288 if (level->num_android_clone_elements == 0)
9290 level->num_android_clone_elements = 1;
9291 level->android_clone_element[0] = EL_EMPTY;
9295 int map_direction_RND_to_EM(int direction)
9297 return (direction == MV_UP ? 0 :
9298 direction == MV_RIGHT ? 1 :
9299 direction == MV_DOWN ? 2 :
9300 direction == MV_LEFT ? 3 :
9304 int map_direction_EM_to_RND(int direction)
9306 return (direction == 0 ? MV_UP :
9307 direction == 1 ? MV_RIGHT :
9308 direction == 2 ? MV_DOWN :
9309 direction == 3 ? MV_LEFT :
9313 int map_element_RND_to_SP(int element_rnd)
9315 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
9317 if (element_rnd >= EL_SP_START &&
9318 element_rnd <= EL_SP_END)
9319 element_sp = element_rnd - EL_SP_START;
9320 else if (element_rnd == EL_EMPTY_SPACE)
9322 else if (element_rnd == EL_INVISIBLE_WALL)
9328 int map_element_SP_to_RND(int element_sp)
9330 int element_rnd = EL_UNKNOWN;
9332 if (element_sp >= 0x00 &&
9334 element_rnd = EL_SP_START + element_sp;
9335 else if (element_sp == 0x28)
9336 element_rnd = EL_INVISIBLE_WALL;
9341 int map_action_SP_to_RND(int action_sp)
9345 case actActive: return ACTION_ACTIVE;
9346 case actImpact: return ACTION_IMPACT;
9347 case actExploding: return ACTION_EXPLODING;
9348 case actDigging: return ACTION_DIGGING;
9349 case actSnapping: return ACTION_SNAPPING;
9350 case actCollecting: return ACTION_COLLECTING;
9351 case actPassing: return ACTION_PASSING;
9352 case actPushing: return ACTION_PUSHING;
9353 case actDropping: return ACTION_DROPPING;
9355 default: return ACTION_DEFAULT;
9359 int get_next_element(int element)
9363 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
9364 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
9365 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
9366 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
9367 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
9368 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
9369 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
9370 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
9371 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
9372 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
9373 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
9375 default: return element;
9380 int el_act_dir2img(int element, int action, int direction)
9382 element = GFX_ELEMENT(element);
9384 if (direction == MV_NONE)
9385 return element_info[element].graphic[action];
9387 direction = MV_DIR_TO_BIT(direction);
9389 return element_info[element].direction_graphic[action][direction];
9392 int el_act_dir2img(int element, int action, int direction)
9394 element = GFX_ELEMENT(element);
9395 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9397 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9398 return element_info[element].direction_graphic[action][direction];
9403 static int el_act_dir2crm(int element, int action, int direction)
9405 element = GFX_ELEMENT(element);
9407 if (direction == MV_NONE)
9408 return element_info[element].crumbled[action];
9410 direction = MV_DIR_TO_BIT(direction);
9412 return element_info[element].direction_crumbled[action][direction];
9415 static int el_act_dir2crm(int element, int action, int direction)
9417 element = GFX_ELEMENT(element);
9418 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9420 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9421 return element_info[element].direction_crumbled[action][direction];
9425 int el_act2img(int element, int action)
9427 element = GFX_ELEMENT(element);
9429 return element_info[element].graphic[action];
9432 int el_act2crm(int element, int action)
9434 element = GFX_ELEMENT(element);
9436 return element_info[element].crumbled[action];
9439 int el_dir2img(int element, int direction)
9441 element = GFX_ELEMENT(element);
9443 return el_act_dir2img(element, ACTION_DEFAULT, direction);
9446 int el2baseimg(int element)
9448 return element_info[element].graphic[ACTION_DEFAULT];
9451 int el2img(int element)
9453 element = GFX_ELEMENT(element);
9455 return element_info[element].graphic[ACTION_DEFAULT];
9458 int el2edimg(int element)
9460 element = GFX_ELEMENT(element);
9462 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9465 int el2preimg(int element)
9467 element = GFX_ELEMENT(element);
9469 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9472 int el2panelimg(int element)
9474 element = GFX_ELEMENT(element);
9476 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9479 int font2baseimg(int font_nr)
9481 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9484 int getBeltNrFromBeltElement(int element)
9486 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9487 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9488 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9491 int getBeltNrFromBeltActiveElement(int element)
9493 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9494 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9495 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9498 int getBeltNrFromBeltSwitchElement(int element)
9500 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9501 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9502 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9505 int getBeltDirNrFromBeltElement(int element)
9507 static int belt_base_element[4] =
9509 EL_CONVEYOR_BELT_1_LEFT,
9510 EL_CONVEYOR_BELT_2_LEFT,
9511 EL_CONVEYOR_BELT_3_LEFT,
9512 EL_CONVEYOR_BELT_4_LEFT
9515 int belt_nr = getBeltNrFromBeltElement(element);
9516 int belt_dir_nr = element - belt_base_element[belt_nr];
9518 return (belt_dir_nr % 3);
9521 int getBeltDirNrFromBeltSwitchElement(int element)
9523 static int belt_base_element[4] =
9525 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9526 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9527 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9528 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9531 int belt_nr = getBeltNrFromBeltSwitchElement(element);
9532 int belt_dir_nr = element - belt_base_element[belt_nr];
9534 return (belt_dir_nr % 3);
9537 int getBeltDirFromBeltElement(int element)
9539 static int belt_move_dir[3] =
9546 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9548 return belt_move_dir[belt_dir_nr];
9551 int getBeltDirFromBeltSwitchElement(int element)
9553 static int belt_move_dir[3] =
9560 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9562 return belt_move_dir[belt_dir_nr];
9565 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9567 static int belt_base_element[4] =
9569 EL_CONVEYOR_BELT_1_LEFT,
9570 EL_CONVEYOR_BELT_2_LEFT,
9571 EL_CONVEYOR_BELT_3_LEFT,
9572 EL_CONVEYOR_BELT_4_LEFT
9575 return belt_base_element[belt_nr] + belt_dir_nr;
9578 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9580 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9582 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9585 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9587 static int belt_base_element[4] =
9589 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9590 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9591 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9592 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9595 return belt_base_element[belt_nr] + belt_dir_nr;
9598 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9600 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9602 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9606 boolean getTeamMode_EM()
9608 return game.team_mode;
9611 int getNumActivePlayers_EM()
9614 int num_players = 0;
9618 return (setup.team_mode ? MAX_PLAYERS : 1);
9620 for (i = 0; i < MAX_PLAYERS; i++)
9621 if (tape.player_participates[i])
9624 return (num_players > 1 ? MAX_PLAYERS : 1);
9628 int num_players = 0;
9631 /* when recording game, activate all connected players */
9635 for (i = 0; i < MAX_PLAYERS; i++)
9636 if (tape.player_participates[i])
9644 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9646 int game_frame_delay_value;
9648 game_frame_delay_value =
9649 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9650 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9653 if (tape.playing && tape.warp_forward && !tape.pausing)
9654 game_frame_delay_value = 0;
9656 return game_frame_delay_value;
9659 unsigned int InitRND(int seed)
9661 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9662 return InitEngineRandom_EM(seed);
9663 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9664 return InitEngineRandom_SP(seed);
9666 return InitEngineRandom_RND(seed);
9670 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9671 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9674 inline static int get_effective_element_EM(int tile, int frame_em)
9676 int element = object_mapping[tile].element_rnd;
9677 int action = object_mapping[tile].action;
9678 boolean is_backside = object_mapping[tile].is_backside;
9679 boolean action_removing = (action == ACTION_DIGGING ||
9680 action == ACTION_SNAPPING ||
9681 action == ACTION_COLLECTING);
9687 case Yacid_splash_eB:
9688 case Yacid_splash_wB:
9689 return (frame_em > 5 ? EL_EMPTY : element);
9693 case Ydiamond_stone:
9694 // if (!game.use_native_emc_graphics_engine)
9702 else /* frame_em == 7 */
9706 case Yacid_splash_eB:
9707 case Yacid_splash_wB:
9710 case Yemerald_stone:
9713 case Ydiamond_stone:
9717 case Xdrip_stretchB:
9736 case Xsand_stonein_1:
9737 case Xsand_stonein_2:
9738 case Xsand_stonein_3:
9739 case Xsand_stonein_4:
9743 return (is_backside || action_removing ? EL_EMPTY : element);
9748 inline static boolean check_linear_animation_EM(int tile)
9752 case Xsand_stonesand_1:
9753 case Xsand_stonesand_quickout_1:
9754 case Xsand_sandstone_1:
9755 case Xsand_stonein_1:
9756 case Xsand_stoneout_1:
9776 case Yacid_splash_eB:
9777 case Yacid_splash_wB:
9778 case Yemerald_stone:
9786 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9787 boolean has_crumbled_graphics,
9788 int crumbled, int sync_frame)
9790 /* if element can be crumbled, but certain action graphics are just empty
9791 space (like instantly snapping sand to empty space in 1 frame), do not
9792 treat these empty space graphics as crumbled graphics in EMC engine */
9793 if (crumbled == IMG_EMPTY_SPACE)
9794 has_crumbled_graphics = FALSE;
9796 if (has_crumbled_graphics)
9798 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9799 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9800 g_crumbled->anim_delay,
9801 g_crumbled->anim_mode,
9802 g_crumbled->anim_start_frame,
9805 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9806 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9808 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9810 g_em->has_crumbled_graphics = TRUE;
9814 g_em->crumbled_bitmap = NULL;
9815 g_em->crumbled_src_x = 0;
9816 g_em->crumbled_src_y = 0;
9817 g_em->crumbled_border_size = 0;
9819 g_em->has_crumbled_graphics = FALSE;
9823 void ResetGfxAnimation_EM(int x, int y, int tile)
9828 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9829 int tile, int frame_em, int x, int y)
9831 int action = object_mapping[tile].action;
9833 int direction = object_mapping[tile].direction;
9834 int effective_element = get_effective_element_EM(tile, frame_em);
9835 int graphic = (direction == MV_NONE ?
9836 el_act2img(effective_element, action) :
9837 el_act_dir2img(effective_element, action, direction));
9838 struct GraphicInfo *g = &graphic_info[graphic];
9841 boolean action_removing = (action == ACTION_DIGGING ||
9842 action == ACTION_SNAPPING ||
9843 action == ACTION_COLLECTING);
9844 boolean action_moving = (action == ACTION_FALLING ||
9845 action == ACTION_MOVING ||
9846 action == ACTION_PUSHING ||
9847 action == ACTION_EATING ||
9848 action == ACTION_FILLING ||
9849 action == ACTION_EMPTYING);
9850 boolean action_falling = (action == ACTION_FALLING ||
9851 action == ACTION_FILLING ||
9852 action == ACTION_EMPTYING);
9854 /* special case: graphic uses "2nd movement tile" and has defined
9855 7 frames for movement animation (or less) => use default graphic
9856 for last (8th) frame which ends the movement animation */
9857 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9859 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9860 graphic = (direction == MV_NONE ?
9861 el_act2img(effective_element, action) :
9862 el_act_dir2img(effective_element, action, direction));
9864 g = &graphic_info[graphic];
9868 if (tile == Xsand_stonesand_1 ||
9869 tile == Xsand_stonesand_2 ||
9870 tile == Xsand_stonesand_3 ||
9871 tile == Xsand_stonesand_4)
9872 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9876 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9880 // printf("::: resetting... [%d]\n", tile);
9883 if (action_removing || check_linear_animation_EM(tile))
9885 GfxFrame[x][y] = frame_em;
9887 // printf("::: resetting... [%d]\n", tile);
9890 else if (action_moving)
9892 boolean is_backside = object_mapping[tile].is_backside;
9896 int direction = object_mapping[tile].direction;
9897 int move_dir = (action_falling ? MV_DOWN : direction);
9902 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9903 if (g->double_movement && frame_em == 0)
9907 // printf("::: resetting... [%d]\n", tile);
9911 if (move_dir == MV_LEFT)
9912 GfxFrame[x - 1][y] = GfxFrame[x][y];
9913 else if (move_dir == MV_RIGHT)
9914 GfxFrame[x + 1][y] = GfxFrame[x][y];
9915 else if (move_dir == MV_UP)
9916 GfxFrame[x][y - 1] = GfxFrame[x][y];
9917 else if (move_dir == MV_DOWN)
9918 GfxFrame[x][y + 1] = GfxFrame[x][y];
9925 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9926 if (tile == Xsand_stonesand_quickout_1 ||
9927 tile == Xsand_stonesand_quickout_2)
9932 if (tile == Xsand_stonesand_1 ||
9933 tile == Xsand_stonesand_2 ||
9934 tile == Xsand_stonesand_3 ||
9935 tile == Xsand_stonesand_4)
9936 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9940 if (graphic_info[graphic].anim_global_sync)
9941 sync_frame = FrameCounter;
9942 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9943 sync_frame = GfxFrame[x][y];
9945 sync_frame = 0; /* playfield border (pseudo steel) */
9947 SetRandomAnimationValue(x, y);
9949 int frame = getAnimationFrame(g->anim_frames,
9952 g->anim_start_frame,
9955 g_em->unique_identifier =
9956 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9960 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9961 int tile, int frame_em, int x, int y)
9963 int action = object_mapping[tile].action;
9964 int direction = object_mapping[tile].direction;
9965 boolean is_backside = object_mapping[tile].is_backside;
9966 int effective_element = get_effective_element_EM(tile, frame_em);
9968 int effective_action = action;
9970 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9972 int graphic = (direction == MV_NONE ?
9973 el_act2img(effective_element, effective_action) :
9974 el_act_dir2img(effective_element, effective_action,
9976 int crumbled = (direction == MV_NONE ?
9977 el_act2crm(effective_element, effective_action) :
9978 el_act_dir2crm(effective_element, effective_action,
9980 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9981 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9982 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9983 struct GraphicInfo *g = &graphic_info[graphic];
9985 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9989 /* special case: graphic uses "2nd movement tile" and has defined
9990 7 frames for movement animation (or less) => use default graphic
9991 for last (8th) frame which ends the movement animation */
9992 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9994 effective_action = ACTION_DEFAULT;
9995 graphic = (direction == MV_NONE ?
9996 el_act2img(effective_element, effective_action) :
9997 el_act_dir2img(effective_element, effective_action,
9999 crumbled = (direction == MV_NONE ?
10000 el_act2crm(effective_element, effective_action) :
10001 el_act_dir2crm(effective_element, effective_action,
10004 g = &graphic_info[graphic];
10014 if (frame_em == 0) /* reset animation frame for certain elements */
10016 if (check_linear_animation_EM(tile))
10017 GfxFrame[x][y] = 0;
10021 if (graphic_info[graphic].anim_global_sync)
10022 sync_frame = FrameCounter;
10023 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
10024 sync_frame = GfxFrame[x][y];
10026 sync_frame = 0; /* playfield border (pseudo steel) */
10028 SetRandomAnimationValue(x, y);
10033 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10034 i == Xdrip_stretchB ? 7 :
10035 i == Ydrip_s2 ? j + 8 :
10036 i == Ydrip_s2B ? j + 8 :
10038 i == Xacid_2 ? 10 :
10039 i == Xacid_3 ? 20 :
10040 i == Xacid_4 ? 30 :
10041 i == Xacid_5 ? 40 :
10042 i == Xacid_6 ? 50 :
10043 i == Xacid_7 ? 60 :
10044 i == Xacid_8 ? 70 :
10045 i == Xfake_acid_1 ? 0 :
10046 i == Xfake_acid_2 ? 10 :
10047 i == Xfake_acid_3 ? 20 :
10048 i == Xfake_acid_4 ? 30 :
10049 i == Xfake_acid_5 ? 40 :
10050 i == Xfake_acid_6 ? 50 :
10051 i == Xfake_acid_7 ? 60 :
10052 i == Xfake_acid_8 ? 70 :
10054 i == Xball_2B ? j + 8 :
10055 i == Yball_eat ? j + 1 :
10056 i == Ykey_1_eat ? j + 1 :
10057 i == Ykey_2_eat ? j + 1 :
10058 i == Ykey_3_eat ? j + 1 :
10059 i == Ykey_4_eat ? j + 1 :
10060 i == Ykey_5_eat ? j + 1 :
10061 i == Ykey_6_eat ? j + 1 :
10062 i == Ykey_7_eat ? j + 1 :
10063 i == Ykey_8_eat ? j + 1 :
10064 i == Ylenses_eat ? j + 1 :
10065 i == Ymagnify_eat ? j + 1 :
10066 i == Ygrass_eat ? j + 1 :
10067 i == Ydirt_eat ? j + 1 :
10068 i == Xamoeba_1 ? 0 :
10069 i == Xamoeba_2 ? 1 :
10070 i == Xamoeba_3 ? 2 :
10071 i == Xamoeba_4 ? 3 :
10072 i == Xamoeba_5 ? 0 :
10073 i == Xamoeba_6 ? 1 :
10074 i == Xamoeba_7 ? 2 :
10075 i == Xamoeba_8 ? 3 :
10076 i == Xexit_2 ? j + 8 :
10077 i == Xexit_3 ? j + 16 :
10078 i == Xdynamite_1 ? 0 :
10079 i == Xdynamite_2 ? 8 :
10080 i == Xdynamite_3 ? 16 :
10081 i == Xdynamite_4 ? 24 :
10082 i == Xsand_stonein_1 ? j + 1 :
10083 i == Xsand_stonein_2 ? j + 9 :
10084 i == Xsand_stonein_3 ? j + 17 :
10085 i == Xsand_stonein_4 ? j + 25 :
10086 i == Xsand_stoneout_1 && j == 0 ? 0 :
10087 i == Xsand_stoneout_1 && j == 1 ? 0 :
10088 i == Xsand_stoneout_1 && j == 2 ? 1 :
10089 i == Xsand_stoneout_1 && j == 3 ? 2 :
10090 i == Xsand_stoneout_1 && j == 4 ? 2 :
10091 i == Xsand_stoneout_1 && j == 5 ? 3 :
10092 i == Xsand_stoneout_1 && j == 6 ? 4 :
10093 i == Xsand_stoneout_1 && j == 7 ? 4 :
10094 i == Xsand_stoneout_2 && j == 0 ? 5 :
10095 i == Xsand_stoneout_2 && j == 1 ? 6 :
10096 i == Xsand_stoneout_2 && j == 2 ? 7 :
10097 i == Xsand_stoneout_2 && j == 3 ? 8 :
10098 i == Xsand_stoneout_2 && j == 4 ? 9 :
10099 i == Xsand_stoneout_2 && j == 5 ? 11 :
10100 i == Xsand_stoneout_2 && j == 6 ? 13 :
10101 i == Xsand_stoneout_2 && j == 7 ? 15 :
10102 i == Xboom_bug && j == 1 ? 2 :
10103 i == Xboom_bug && j == 2 ? 2 :
10104 i == Xboom_bug && j == 3 ? 4 :
10105 i == Xboom_bug && j == 4 ? 4 :
10106 i == Xboom_bug && j == 5 ? 2 :
10107 i == Xboom_bug && j == 6 ? 2 :
10108 i == Xboom_bug && j == 7 ? 0 :
10109 i == Xboom_bomb && j == 1 ? 2 :
10110 i == Xboom_bomb && j == 2 ? 2 :
10111 i == Xboom_bomb && j == 3 ? 4 :
10112 i == Xboom_bomb && j == 4 ? 4 :
10113 i == Xboom_bomb && j == 5 ? 2 :
10114 i == Xboom_bomb && j == 6 ? 2 :
10115 i == Xboom_bomb && j == 7 ? 0 :
10116 i == Xboom_android && j == 7 ? 6 :
10117 i == Xboom_1 && j == 1 ? 2 :
10118 i == Xboom_1 && j == 2 ? 2 :
10119 i == Xboom_1 && j == 3 ? 4 :
10120 i == Xboom_1 && j == 4 ? 4 :
10121 i == Xboom_1 && j == 5 ? 6 :
10122 i == Xboom_1 && j == 6 ? 6 :
10123 i == Xboom_1 && j == 7 ? 8 :
10124 i == Xboom_2 && j == 0 ? 8 :
10125 i == Xboom_2 && j == 1 ? 8 :
10126 i == Xboom_2 && j == 2 ? 10 :
10127 i == Xboom_2 && j == 3 ? 10 :
10128 i == Xboom_2 && j == 4 ? 10 :
10129 i == Xboom_2 && j == 5 ? 12 :
10130 i == Xboom_2 && j == 6 ? 12 :
10131 i == Xboom_2 && j == 7 ? 12 :
10133 special_animation && j == 4 ? 3 :
10134 effective_action != action ? 0 :
10140 int xxx_effective_action;
10141 int xxx_has_action_graphics;
10144 int element = object_mapping[i].element_rnd;
10145 int action = object_mapping[i].action;
10146 int direction = object_mapping[i].direction;
10147 boolean is_backside = object_mapping[i].is_backside;
10149 boolean action_removing = (action == ACTION_DIGGING ||
10150 action == ACTION_SNAPPING ||
10151 action == ACTION_COLLECTING);
10153 boolean action_exploding = ((action == ACTION_EXPLODING ||
10154 action == ACTION_SMASHED_BY_ROCK ||
10155 action == ACTION_SMASHED_BY_SPRING) &&
10156 element != EL_DIAMOND);
10157 boolean action_active = (action == ACTION_ACTIVE);
10158 boolean action_other = (action == ACTION_OTHER);
10162 int effective_element = get_effective_element_EM(i, j);
10164 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10165 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10167 i == Xdrip_stretch ? element :
10168 i == Xdrip_stretchB ? element :
10169 i == Ydrip_s1 ? element :
10170 i == Ydrip_s1B ? element :
10171 i == Xball_1B ? element :
10172 i == Xball_2 ? element :
10173 i == Xball_2B ? element :
10174 i == Yball_eat ? element :
10175 i == Ykey_1_eat ? element :
10176 i == Ykey_2_eat ? element :
10177 i == Ykey_3_eat ? element :
10178 i == Ykey_4_eat ? element :
10179 i == Ykey_5_eat ? element :
10180 i == Ykey_6_eat ? element :
10181 i == Ykey_7_eat ? element :
10182 i == Ykey_8_eat ? element :
10183 i == Ylenses_eat ? element :
10184 i == Ymagnify_eat ? element :
10185 i == Ygrass_eat ? element :
10186 i == Ydirt_eat ? element :
10187 i == Yemerald_stone ? EL_EMERALD :
10188 i == Ydiamond_stone ? EL_ROCK :
10189 i == Xsand_stonein_1 ? element :
10190 i == Xsand_stonein_2 ? element :
10191 i == Xsand_stonein_3 ? element :
10192 i == Xsand_stonein_4 ? element :
10193 is_backside ? EL_EMPTY :
10194 action_removing ? EL_EMPTY :
10197 int effective_action = (j < 7 ? action :
10198 i == Xdrip_stretch ? action :
10199 i == Xdrip_stretchB ? action :
10200 i == Ydrip_s1 ? action :
10201 i == Ydrip_s1B ? action :
10202 i == Xball_1B ? action :
10203 i == Xball_2 ? action :
10204 i == Xball_2B ? action :
10205 i == Yball_eat ? action :
10206 i == Ykey_1_eat ? action :
10207 i == Ykey_2_eat ? action :
10208 i == Ykey_3_eat ? action :
10209 i == Ykey_4_eat ? action :
10210 i == Ykey_5_eat ? action :
10211 i == Ykey_6_eat ? action :
10212 i == Ykey_7_eat ? action :
10213 i == Ykey_8_eat ? action :
10214 i == Ylenses_eat ? action :
10215 i == Ymagnify_eat ? action :
10216 i == Ygrass_eat ? action :
10217 i == Ydirt_eat ? action :
10218 i == Xsand_stonein_1 ? action :
10219 i == Xsand_stonein_2 ? action :
10220 i == Xsand_stonein_3 ? action :
10221 i == Xsand_stonein_4 ? action :
10222 i == Xsand_stoneout_1 ? action :
10223 i == Xsand_stoneout_2 ? action :
10224 i == Xboom_android ? ACTION_EXPLODING :
10225 action_exploding ? ACTION_EXPLODING :
10226 action_active ? action :
10227 action_other ? action :
10229 int graphic = (el_act_dir2img(effective_element, effective_action,
10231 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10233 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10234 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10235 boolean has_action_graphics = (graphic != base_graphic);
10236 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10237 struct GraphicInfo *g = &graphic_info[graphic];
10239 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10241 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10242 Bitmap *src_bitmap;
10244 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10245 boolean special_animation = (action != ACTION_DEFAULT &&
10246 g->anim_frames == 3 &&
10247 g->anim_delay == 2 &&
10248 g->anim_mode & ANIM_LINEAR);
10249 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10250 i == Xdrip_stretchB ? 7 :
10251 i == Ydrip_s2 ? j + 8 :
10252 i == Ydrip_s2B ? j + 8 :
10254 i == Xacid_2 ? 10 :
10255 i == Xacid_3 ? 20 :
10256 i == Xacid_4 ? 30 :
10257 i == Xacid_5 ? 40 :
10258 i == Xacid_6 ? 50 :
10259 i == Xacid_7 ? 60 :
10260 i == Xacid_8 ? 70 :
10261 i == Xfake_acid_1 ? 0 :
10262 i == Xfake_acid_2 ? 10 :
10263 i == Xfake_acid_3 ? 20 :
10264 i == Xfake_acid_4 ? 30 :
10265 i == Xfake_acid_5 ? 40 :
10266 i == Xfake_acid_6 ? 50 :
10267 i == Xfake_acid_7 ? 60 :
10268 i == Xfake_acid_8 ? 70 :
10270 i == Xball_2B ? j + 8 :
10271 i == Yball_eat ? j + 1 :
10272 i == Ykey_1_eat ? j + 1 :
10273 i == Ykey_2_eat ? j + 1 :
10274 i == Ykey_3_eat ? j + 1 :
10275 i == Ykey_4_eat ? j + 1 :
10276 i == Ykey_5_eat ? j + 1 :
10277 i == Ykey_6_eat ? j + 1 :
10278 i == Ykey_7_eat ? j + 1 :
10279 i == Ykey_8_eat ? j + 1 :
10280 i == Ylenses_eat ? j + 1 :
10281 i == Ymagnify_eat ? j + 1 :
10282 i == Ygrass_eat ? j + 1 :
10283 i == Ydirt_eat ? j + 1 :
10284 i == Xamoeba_1 ? 0 :
10285 i == Xamoeba_2 ? 1 :
10286 i == Xamoeba_3 ? 2 :
10287 i == Xamoeba_4 ? 3 :
10288 i == Xamoeba_5 ? 0 :
10289 i == Xamoeba_6 ? 1 :
10290 i == Xamoeba_7 ? 2 :
10291 i == Xamoeba_8 ? 3 :
10292 i == Xexit_2 ? j + 8 :
10293 i == Xexit_3 ? j + 16 :
10294 i == Xdynamite_1 ? 0 :
10295 i == Xdynamite_2 ? 8 :
10296 i == Xdynamite_3 ? 16 :
10297 i == Xdynamite_4 ? 24 :
10298 i == Xsand_stonein_1 ? j + 1 :
10299 i == Xsand_stonein_2 ? j + 9 :
10300 i == Xsand_stonein_3 ? j + 17 :
10301 i == Xsand_stonein_4 ? j + 25 :
10302 i == Xsand_stoneout_1 && j == 0 ? 0 :
10303 i == Xsand_stoneout_1 && j == 1 ? 0 :
10304 i == Xsand_stoneout_1 && j == 2 ? 1 :
10305 i == Xsand_stoneout_1 && j == 3 ? 2 :
10306 i == Xsand_stoneout_1 && j == 4 ? 2 :
10307 i == Xsand_stoneout_1 && j == 5 ? 3 :
10308 i == Xsand_stoneout_1 && j == 6 ? 4 :
10309 i == Xsand_stoneout_1 && j == 7 ? 4 :
10310 i == Xsand_stoneout_2 && j == 0 ? 5 :
10311 i == Xsand_stoneout_2 && j == 1 ? 6 :
10312 i == Xsand_stoneout_2 && j == 2 ? 7 :
10313 i == Xsand_stoneout_2 && j == 3 ? 8 :
10314 i == Xsand_stoneout_2 && j == 4 ? 9 :
10315 i == Xsand_stoneout_2 && j == 5 ? 11 :
10316 i == Xsand_stoneout_2 && j == 6 ? 13 :
10317 i == Xsand_stoneout_2 && j == 7 ? 15 :
10318 i == Xboom_bug && j == 1 ? 2 :
10319 i == Xboom_bug && j == 2 ? 2 :
10320 i == Xboom_bug && j == 3 ? 4 :
10321 i == Xboom_bug && j == 4 ? 4 :
10322 i == Xboom_bug && j == 5 ? 2 :
10323 i == Xboom_bug && j == 6 ? 2 :
10324 i == Xboom_bug && j == 7 ? 0 :
10325 i == Xboom_bomb && j == 1 ? 2 :
10326 i == Xboom_bomb && j == 2 ? 2 :
10327 i == Xboom_bomb && j == 3 ? 4 :
10328 i == Xboom_bomb && j == 4 ? 4 :
10329 i == Xboom_bomb && j == 5 ? 2 :
10330 i == Xboom_bomb && j == 6 ? 2 :
10331 i == Xboom_bomb && j == 7 ? 0 :
10332 i == Xboom_android && j == 7 ? 6 :
10333 i == Xboom_1 && j == 1 ? 2 :
10334 i == Xboom_1 && j == 2 ? 2 :
10335 i == Xboom_1 && j == 3 ? 4 :
10336 i == Xboom_1 && j == 4 ? 4 :
10337 i == Xboom_1 && j == 5 ? 6 :
10338 i == Xboom_1 && j == 6 ? 6 :
10339 i == Xboom_1 && j == 7 ? 8 :
10340 i == Xboom_2 && j == 0 ? 8 :
10341 i == Xboom_2 && j == 1 ? 8 :
10342 i == Xboom_2 && j == 2 ? 10 :
10343 i == Xboom_2 && j == 3 ? 10 :
10344 i == Xboom_2 && j == 4 ? 10 :
10345 i == Xboom_2 && j == 5 ? 12 :
10346 i == Xboom_2 && j == 6 ? 12 :
10347 i == Xboom_2 && j == 7 ? 12 :
10348 special_animation && j == 4 ? 3 :
10349 effective_action != action ? 0 :
10352 xxx_effective_action = effective_action;
10353 xxx_has_action_graphics = has_action_graphics;
10358 int frame = getAnimationFrame(g->anim_frames,
10361 g->anim_start_frame,
10375 int old_src_x = g_em->src_x;
10376 int old_src_y = g_em->src_y;
10380 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
10381 g->double_movement && is_backside);
10383 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10384 &g_em->src_x, &g_em->src_y, FALSE);
10389 if (tile == Ydiamond_stone)
10390 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
10395 g->anim_start_frame,
10398 g_em->src_x, g_em->src_y,
10399 g_em->src_offset_x, g_em->src_offset_y,
10400 g_em->dst_offset_x, g_em->dst_offset_y,
10412 if (graphic == IMG_BUG_MOVING_RIGHT)
10413 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10414 g->double_movement, is_backside,
10415 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10423 g_em->src_offset_x = 0;
10424 g_em->src_offset_y = 0;
10425 g_em->dst_offset_x = 0;
10426 g_em->dst_offset_y = 0;
10427 g_em->width = TILEX;
10428 g_em->height = TILEY;
10430 g_em->preserve_background = FALSE;
10433 /* (updating the "crumbled" graphic definitions is probably not really needed,
10434 as animations for crumbled graphics can't be longer than one EMC cycle) */
10436 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10441 g_em->crumbled_bitmap = NULL;
10442 g_em->crumbled_src_x = 0;
10443 g_em->crumbled_src_y = 0;
10445 g_em->has_crumbled_graphics = FALSE;
10447 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10449 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10450 g_crumbled->anim_delay,
10451 g_crumbled->anim_mode,
10452 g_crumbled->anim_start_frame,
10455 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10456 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10458 g_em->has_crumbled_graphics = TRUE;
10464 int effective_action = xxx_effective_action;
10465 int has_action_graphics = xxx_has_action_graphics;
10467 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10468 effective_action == ACTION_MOVING ||
10469 effective_action == ACTION_PUSHING ||
10470 effective_action == ACTION_EATING)) ||
10471 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10472 effective_action == ACTION_EMPTYING)))
10475 (effective_action == ACTION_FALLING ||
10476 effective_action == ACTION_FILLING ||
10477 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10478 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10479 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10480 int num_steps = (i == Ydrip_s1 ? 16 :
10481 i == Ydrip_s1B ? 16 :
10482 i == Ydrip_s2 ? 16 :
10483 i == Ydrip_s2B ? 16 :
10484 i == Xsand_stonein_1 ? 32 :
10485 i == Xsand_stonein_2 ? 32 :
10486 i == Xsand_stonein_3 ? 32 :
10487 i == Xsand_stonein_4 ? 32 :
10488 i == Xsand_stoneout_1 ? 16 :
10489 i == Xsand_stoneout_2 ? 16 : 8);
10490 int cx = ABS(dx) * (TILEX / num_steps);
10491 int cy = ABS(dy) * (TILEY / num_steps);
10492 int step_frame = (i == Ydrip_s2 ? j + 8 :
10493 i == Ydrip_s2B ? j + 8 :
10494 i == Xsand_stonein_2 ? j + 8 :
10495 i == Xsand_stonein_3 ? j + 16 :
10496 i == Xsand_stonein_4 ? j + 24 :
10497 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10498 int step = (is_backside ? step_frame : num_steps - step_frame);
10500 if (is_backside) /* tile where movement starts */
10502 if (dx < 0 || dy < 0)
10504 g_em->src_offset_x = cx * step;
10505 g_em->src_offset_y = cy * step;
10509 g_em->dst_offset_x = cx * step;
10510 g_em->dst_offset_y = cy * step;
10513 else /* tile where movement ends */
10515 if (dx < 0 || dy < 0)
10517 g_em->dst_offset_x = cx * step;
10518 g_em->dst_offset_y = cy * step;
10522 g_em->src_offset_x = cx * step;
10523 g_em->src_offset_y = cy * step;
10527 g_em->width = TILEX - cx * step;
10528 g_em->height = TILEY - cy * step;
10531 /* create unique graphic identifier to decide if tile must be redrawn */
10532 /* bit 31 - 16 (16 bit): EM style graphic
10533 bit 15 - 12 ( 4 bit): EM style frame
10534 bit 11 - 6 ( 6 bit): graphic width
10535 bit 5 - 0 ( 6 bit): graphic height */
10536 g_em->unique_identifier =
10537 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10543 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10544 int player_nr, int anim, int frame_em)
10546 int element = player_mapping[player_nr][anim].element_rnd;
10547 int action = player_mapping[player_nr][anim].action;
10548 int direction = player_mapping[player_nr][anim].direction;
10549 int graphic = (direction == MV_NONE ?
10550 el_act2img(element, action) :
10551 el_act_dir2img(element, action, direction));
10552 struct GraphicInfo *g = &graphic_info[graphic];
10555 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10557 stored_player[player_nr].StepFrame = frame_em;
10559 sync_frame = stored_player[player_nr].Frame;
10561 int frame = getAnimationFrame(g->anim_frames,
10564 g->anim_start_frame,
10567 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10568 &g_em->src_x, &g_em->src_y, FALSE);
10571 printf("::: %d: %d, %d [%d]\n",
10573 stored_player[player_nr].Frame,
10574 stored_player[player_nr].StepFrame,
10579 void InitGraphicInfo_EM(void)
10582 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10583 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10588 int num_em_gfx_errors = 0;
10590 if (graphic_info_em_object[0][0].bitmap == NULL)
10592 /* EM graphics not yet initialized in em_open_all() */
10597 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10600 /* always start with reliable default values */
10601 for (i = 0; i < TILE_MAX; i++)
10603 object_mapping[i].element_rnd = EL_UNKNOWN;
10604 object_mapping[i].is_backside = FALSE;
10605 object_mapping[i].action = ACTION_DEFAULT;
10606 object_mapping[i].direction = MV_NONE;
10609 /* always start with reliable default values */
10610 for (p = 0; p < MAX_PLAYERS; p++)
10612 for (i = 0; i < SPR_MAX; i++)
10614 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10615 player_mapping[p][i].action = ACTION_DEFAULT;
10616 player_mapping[p][i].direction = MV_NONE;
10620 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10622 int e = em_object_mapping_list[i].element_em;
10624 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10625 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10627 if (em_object_mapping_list[i].action != -1)
10628 object_mapping[e].action = em_object_mapping_list[i].action;
10630 if (em_object_mapping_list[i].direction != -1)
10631 object_mapping[e].direction =
10632 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10635 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10637 int a = em_player_mapping_list[i].action_em;
10638 int p = em_player_mapping_list[i].player_nr;
10640 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10642 if (em_player_mapping_list[i].action != -1)
10643 player_mapping[p][a].action = em_player_mapping_list[i].action;
10645 if (em_player_mapping_list[i].direction != -1)
10646 player_mapping[p][a].direction =
10647 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10650 for (i = 0; i < TILE_MAX; i++)
10652 int element = object_mapping[i].element_rnd;
10653 int action = object_mapping[i].action;
10654 int direction = object_mapping[i].direction;
10655 boolean is_backside = object_mapping[i].is_backside;
10657 boolean action_removing = (action == ACTION_DIGGING ||
10658 action == ACTION_SNAPPING ||
10659 action == ACTION_COLLECTING);
10661 boolean action_exploding = ((action == ACTION_EXPLODING ||
10662 action == ACTION_SMASHED_BY_ROCK ||
10663 action == ACTION_SMASHED_BY_SPRING) &&
10664 element != EL_DIAMOND);
10665 boolean action_active = (action == ACTION_ACTIVE);
10666 boolean action_other = (action == ACTION_OTHER);
10668 for (j = 0; j < 8; j++)
10671 int effective_element = get_effective_element_EM(i, j);
10673 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10674 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10676 i == Xdrip_stretch ? element :
10677 i == Xdrip_stretchB ? element :
10678 i == Ydrip_s1 ? element :
10679 i == Ydrip_s1B ? element :
10680 i == Xball_1B ? element :
10681 i == Xball_2 ? element :
10682 i == Xball_2B ? element :
10683 i == Yball_eat ? element :
10684 i == Ykey_1_eat ? element :
10685 i == Ykey_2_eat ? element :
10686 i == Ykey_3_eat ? element :
10687 i == Ykey_4_eat ? element :
10688 i == Ykey_5_eat ? element :
10689 i == Ykey_6_eat ? element :
10690 i == Ykey_7_eat ? element :
10691 i == Ykey_8_eat ? element :
10692 i == Ylenses_eat ? element :
10693 i == Ymagnify_eat ? element :
10694 i == Ygrass_eat ? element :
10695 i == Ydirt_eat ? element :
10696 i == Yemerald_stone ? EL_EMERALD :
10697 i == Ydiamond_stone ? EL_ROCK :
10698 i == Xsand_stonein_1 ? element :
10699 i == Xsand_stonein_2 ? element :
10700 i == Xsand_stonein_3 ? element :
10701 i == Xsand_stonein_4 ? element :
10702 is_backside ? EL_EMPTY :
10703 action_removing ? EL_EMPTY :
10706 int effective_action = (j < 7 ? action :
10707 i == Xdrip_stretch ? action :
10708 i == Xdrip_stretchB ? action :
10709 i == Ydrip_s1 ? action :
10710 i == Ydrip_s1B ? action :
10711 i == Xball_1B ? action :
10712 i == Xball_2 ? action :
10713 i == Xball_2B ? action :
10714 i == Yball_eat ? action :
10715 i == Ykey_1_eat ? action :
10716 i == Ykey_2_eat ? action :
10717 i == Ykey_3_eat ? action :
10718 i == Ykey_4_eat ? action :
10719 i == Ykey_5_eat ? action :
10720 i == Ykey_6_eat ? action :
10721 i == Ykey_7_eat ? action :
10722 i == Ykey_8_eat ? action :
10723 i == Ylenses_eat ? action :
10724 i == Ymagnify_eat ? action :
10725 i == Ygrass_eat ? action :
10726 i == Ydirt_eat ? action :
10727 i == Xsand_stonein_1 ? action :
10728 i == Xsand_stonein_2 ? action :
10729 i == Xsand_stonein_3 ? action :
10730 i == Xsand_stonein_4 ? action :
10731 i == Xsand_stoneout_1 ? action :
10732 i == Xsand_stoneout_2 ? action :
10733 i == Xboom_android ? ACTION_EXPLODING :
10734 action_exploding ? ACTION_EXPLODING :
10735 action_active ? action :
10736 action_other ? action :
10738 int graphic = (el_act_dir2img(effective_element, effective_action,
10740 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10742 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10743 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10744 boolean has_action_graphics = (graphic != base_graphic);
10745 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10746 struct GraphicInfo *g = &graphic_info[graphic];
10748 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10750 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10751 Bitmap *src_bitmap;
10753 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10754 boolean special_animation = (action != ACTION_DEFAULT &&
10755 g->anim_frames == 3 &&
10756 g->anim_delay == 2 &&
10757 g->anim_mode & ANIM_LINEAR);
10758 int sync_frame = (i == Xdrip_stretch ? 7 :
10759 i == Xdrip_stretchB ? 7 :
10760 i == Ydrip_s2 ? j + 8 :
10761 i == Ydrip_s2B ? j + 8 :
10763 i == Xacid_2 ? 10 :
10764 i == Xacid_3 ? 20 :
10765 i == Xacid_4 ? 30 :
10766 i == Xacid_5 ? 40 :
10767 i == Xacid_6 ? 50 :
10768 i == Xacid_7 ? 60 :
10769 i == Xacid_8 ? 70 :
10770 i == Xfake_acid_1 ? 0 :
10771 i == Xfake_acid_2 ? 10 :
10772 i == Xfake_acid_3 ? 20 :
10773 i == Xfake_acid_4 ? 30 :
10774 i == Xfake_acid_5 ? 40 :
10775 i == Xfake_acid_6 ? 50 :
10776 i == Xfake_acid_7 ? 60 :
10777 i == Xfake_acid_8 ? 70 :
10779 i == Xball_2B ? j + 8 :
10780 i == Yball_eat ? j + 1 :
10781 i == Ykey_1_eat ? j + 1 :
10782 i == Ykey_2_eat ? j + 1 :
10783 i == Ykey_3_eat ? j + 1 :
10784 i == Ykey_4_eat ? j + 1 :
10785 i == Ykey_5_eat ? j + 1 :
10786 i == Ykey_6_eat ? j + 1 :
10787 i == Ykey_7_eat ? j + 1 :
10788 i == Ykey_8_eat ? j + 1 :
10789 i == Ylenses_eat ? j + 1 :
10790 i == Ymagnify_eat ? j + 1 :
10791 i == Ygrass_eat ? j + 1 :
10792 i == Ydirt_eat ? j + 1 :
10793 i == Xamoeba_1 ? 0 :
10794 i == Xamoeba_2 ? 1 :
10795 i == Xamoeba_3 ? 2 :
10796 i == Xamoeba_4 ? 3 :
10797 i == Xamoeba_5 ? 0 :
10798 i == Xamoeba_6 ? 1 :
10799 i == Xamoeba_7 ? 2 :
10800 i == Xamoeba_8 ? 3 :
10801 i == Xexit_2 ? j + 8 :
10802 i == Xexit_3 ? j + 16 :
10803 i == Xdynamite_1 ? 0 :
10804 i == Xdynamite_2 ? 8 :
10805 i == Xdynamite_3 ? 16 :
10806 i == Xdynamite_4 ? 24 :
10807 i == Xsand_stonein_1 ? j + 1 :
10808 i == Xsand_stonein_2 ? j + 9 :
10809 i == Xsand_stonein_3 ? j + 17 :
10810 i == Xsand_stonein_4 ? j + 25 :
10811 i == Xsand_stoneout_1 && j == 0 ? 0 :
10812 i == Xsand_stoneout_1 && j == 1 ? 0 :
10813 i == Xsand_stoneout_1 && j == 2 ? 1 :
10814 i == Xsand_stoneout_1 && j == 3 ? 2 :
10815 i == Xsand_stoneout_1 && j == 4 ? 2 :
10816 i == Xsand_stoneout_1 && j == 5 ? 3 :
10817 i == Xsand_stoneout_1 && j == 6 ? 4 :
10818 i == Xsand_stoneout_1 && j == 7 ? 4 :
10819 i == Xsand_stoneout_2 && j == 0 ? 5 :
10820 i == Xsand_stoneout_2 && j == 1 ? 6 :
10821 i == Xsand_stoneout_2 && j == 2 ? 7 :
10822 i == Xsand_stoneout_2 && j == 3 ? 8 :
10823 i == Xsand_stoneout_2 && j == 4 ? 9 :
10824 i == Xsand_stoneout_2 && j == 5 ? 11 :
10825 i == Xsand_stoneout_2 && j == 6 ? 13 :
10826 i == Xsand_stoneout_2 && j == 7 ? 15 :
10827 i == Xboom_bug && j == 1 ? 2 :
10828 i == Xboom_bug && j == 2 ? 2 :
10829 i == Xboom_bug && j == 3 ? 4 :
10830 i == Xboom_bug && j == 4 ? 4 :
10831 i == Xboom_bug && j == 5 ? 2 :
10832 i == Xboom_bug && j == 6 ? 2 :
10833 i == Xboom_bug && j == 7 ? 0 :
10834 i == Xboom_bomb && j == 1 ? 2 :
10835 i == Xboom_bomb && j == 2 ? 2 :
10836 i == Xboom_bomb && j == 3 ? 4 :
10837 i == Xboom_bomb && j == 4 ? 4 :
10838 i == Xboom_bomb && j == 5 ? 2 :
10839 i == Xboom_bomb && j == 6 ? 2 :
10840 i == Xboom_bomb && j == 7 ? 0 :
10841 i == Xboom_android && j == 7 ? 6 :
10842 i == Xboom_1 && j == 1 ? 2 :
10843 i == Xboom_1 && j == 2 ? 2 :
10844 i == Xboom_1 && j == 3 ? 4 :
10845 i == Xboom_1 && j == 4 ? 4 :
10846 i == Xboom_1 && j == 5 ? 6 :
10847 i == Xboom_1 && j == 6 ? 6 :
10848 i == Xboom_1 && j == 7 ? 8 :
10849 i == Xboom_2 && j == 0 ? 8 :
10850 i == Xboom_2 && j == 1 ? 8 :
10851 i == Xboom_2 && j == 2 ? 10 :
10852 i == Xboom_2 && j == 3 ? 10 :
10853 i == Xboom_2 && j == 4 ? 10 :
10854 i == Xboom_2 && j == 5 ? 12 :
10855 i == Xboom_2 && j == 6 ? 12 :
10856 i == Xboom_2 && j == 7 ? 12 :
10857 special_animation && j == 4 ? 3 :
10858 effective_action != action ? 0 :
10862 Bitmap *debug_bitmap = g_em->bitmap;
10863 int debug_src_x = g_em->src_x;
10864 int debug_src_y = g_em->src_y;
10867 int frame = getAnimationFrame(g->anim_frames,
10870 g->anim_start_frame,
10873 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10874 g->double_movement && is_backside);
10876 g_em->bitmap = src_bitmap;
10877 g_em->src_x = src_x;
10878 g_em->src_y = src_y;
10879 g_em->src_offset_x = 0;
10880 g_em->src_offset_y = 0;
10881 g_em->dst_offset_x = 0;
10882 g_em->dst_offset_y = 0;
10883 g_em->width = TILEX;
10884 g_em->height = TILEY;
10886 g_em->preserve_background = FALSE;
10889 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10894 g_em->crumbled_bitmap = NULL;
10895 g_em->crumbled_src_x = 0;
10896 g_em->crumbled_src_y = 0;
10897 g_em->crumbled_border_size = 0;
10899 g_em->has_crumbled_graphics = FALSE;
10902 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10903 printf("::: empty crumbled: %d [%s], %d, %d\n",
10904 effective_element, element_info[effective_element].token_name,
10905 effective_action, direction);
10908 /* if element can be crumbled, but certain action graphics are just empty
10909 space (like instantly snapping sand to empty space in 1 frame), do not
10910 treat these empty space graphics as crumbled graphics in EMC engine */
10911 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10913 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10914 g_crumbled->anim_delay,
10915 g_crumbled->anim_mode,
10916 g_crumbled->anim_start_frame,
10919 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10921 g_em->has_crumbled_graphics = TRUE;
10922 g_em->crumbled_bitmap = src_bitmap;
10923 g_em->crumbled_src_x = src_x;
10924 g_em->crumbled_src_y = src_y;
10925 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10929 if (g_em == &graphic_info_em_object[207][0])
10930 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10931 graphic_info_em_object[207][0].crumbled_src_x,
10932 graphic_info_em_object[207][0].crumbled_src_y,
10934 crumbled, frame, src_x, src_y,
10939 g->anim_start_frame,
10941 gfx.anim_random_frame,
10946 printf("::: EMC tile %d is crumbled\n", i);
10952 if (element == EL_ROCK &&
10953 effective_action == ACTION_FILLING)
10954 printf("::: has_action_graphics == %d\n", has_action_graphics);
10957 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10958 effective_action == ACTION_MOVING ||
10959 effective_action == ACTION_PUSHING ||
10960 effective_action == ACTION_EATING)) ||
10961 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10962 effective_action == ACTION_EMPTYING)))
10965 (effective_action == ACTION_FALLING ||
10966 effective_action == ACTION_FILLING ||
10967 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10968 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10969 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10970 int num_steps = (i == Ydrip_s1 ? 16 :
10971 i == Ydrip_s1B ? 16 :
10972 i == Ydrip_s2 ? 16 :
10973 i == Ydrip_s2B ? 16 :
10974 i == Xsand_stonein_1 ? 32 :
10975 i == Xsand_stonein_2 ? 32 :
10976 i == Xsand_stonein_3 ? 32 :
10977 i == Xsand_stonein_4 ? 32 :
10978 i == Xsand_stoneout_1 ? 16 :
10979 i == Xsand_stoneout_2 ? 16 : 8);
10980 int cx = ABS(dx) * (TILEX / num_steps);
10981 int cy = ABS(dy) * (TILEY / num_steps);
10982 int step_frame = (i == Ydrip_s2 ? j + 8 :
10983 i == Ydrip_s2B ? j + 8 :
10984 i == Xsand_stonein_2 ? j + 8 :
10985 i == Xsand_stonein_3 ? j + 16 :
10986 i == Xsand_stonein_4 ? j + 24 :
10987 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10988 int step = (is_backside ? step_frame : num_steps - step_frame);
10990 if (is_backside) /* tile where movement starts */
10992 if (dx < 0 || dy < 0)
10994 g_em->src_offset_x = cx * step;
10995 g_em->src_offset_y = cy * step;
10999 g_em->dst_offset_x = cx * step;
11000 g_em->dst_offset_y = cy * step;
11003 else /* tile where movement ends */
11005 if (dx < 0 || dy < 0)
11007 g_em->dst_offset_x = cx * step;
11008 g_em->dst_offset_y = cy * step;
11012 g_em->src_offset_x = cx * step;
11013 g_em->src_offset_y = cy * step;
11017 g_em->width = TILEX - cx * step;
11018 g_em->height = TILEY - cy * step;
11021 /* create unique graphic identifier to decide if tile must be redrawn */
11022 /* bit 31 - 16 (16 bit): EM style graphic
11023 bit 15 - 12 ( 4 bit): EM style frame
11024 bit 11 - 6 ( 6 bit): graphic width
11025 bit 5 - 0 ( 6 bit): graphic height */
11026 g_em->unique_identifier =
11027 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
11031 /* skip check for EMC elements not contained in original EMC artwork */
11032 if (element == EL_EMC_FAKE_ACID)
11035 if (g_em->bitmap != debug_bitmap ||
11036 g_em->src_x != debug_src_x ||
11037 g_em->src_y != debug_src_y ||
11038 g_em->src_offset_x != 0 ||
11039 g_em->src_offset_y != 0 ||
11040 g_em->dst_offset_x != 0 ||
11041 g_em->dst_offset_y != 0 ||
11042 g_em->width != TILEX ||
11043 g_em->height != TILEY)
11045 static int last_i = -1;
11053 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
11054 i, element, element_info[element].token_name,
11055 element_action_info[effective_action].suffix, direction);
11057 if (element != effective_element)
11058 printf(" [%d ('%s')]",
11060 element_info[effective_element].token_name);
11064 if (g_em->bitmap != debug_bitmap)
11065 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
11066 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
11068 if (g_em->src_x != debug_src_x ||
11069 g_em->src_y != debug_src_y)
11070 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11071 j, (is_backside ? 'B' : 'F'),
11072 g_em->src_x, g_em->src_y,
11073 g_em->src_x / 32, g_em->src_y / 32,
11074 debug_src_x, debug_src_y,
11075 debug_src_x / 32, debug_src_y / 32);
11077 if (g_em->src_offset_x != 0 ||
11078 g_em->src_offset_y != 0 ||
11079 g_em->dst_offset_x != 0 ||
11080 g_em->dst_offset_y != 0)
11081 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
11083 g_em->src_offset_x, g_em->src_offset_y,
11084 g_em->dst_offset_x, g_em->dst_offset_y);
11086 if (g_em->width != TILEX ||
11087 g_em->height != TILEY)
11088 printf(" %d (%d): size %d,%d should be %d,%d\n",
11090 g_em->width, g_em->height, TILEX, TILEY);
11092 num_em_gfx_errors++;
11099 for (i = 0; i < TILE_MAX; i++)
11101 for (j = 0; j < 8; j++)
11103 int element = object_mapping[i].element_rnd;
11104 int action = object_mapping[i].action;
11105 int direction = object_mapping[i].direction;
11106 boolean is_backside = object_mapping[i].is_backside;
11107 int graphic_action = el_act_dir2img(element, action, direction);
11108 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
11110 if ((action == ACTION_SMASHED_BY_ROCK ||
11111 action == ACTION_SMASHED_BY_SPRING ||
11112 action == ACTION_EATING) &&
11113 graphic_action == graphic_default)
11115 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
11116 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
11117 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
11118 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
11121 /* no separate animation for "smashed by rock" -- use rock instead */
11122 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
11123 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
11125 g_em->bitmap = g_xx->bitmap;
11126 g_em->src_x = g_xx->src_x;
11127 g_em->src_y = g_xx->src_y;
11128 g_em->src_offset_x = g_xx->src_offset_x;
11129 g_em->src_offset_y = g_xx->src_offset_y;
11130 g_em->dst_offset_x = g_xx->dst_offset_x;
11131 g_em->dst_offset_y = g_xx->dst_offset_y;
11132 g_em->width = g_xx->width;
11133 g_em->height = g_xx->height;
11134 g_em->unique_identifier = g_xx->unique_identifier;
11137 g_em->preserve_background = TRUE;
11142 for (p = 0; p < MAX_PLAYERS; p++)
11144 for (i = 0; i < SPR_MAX; i++)
11146 int element = player_mapping[p][i].element_rnd;
11147 int action = player_mapping[p][i].action;
11148 int direction = player_mapping[p][i].direction;
11150 for (j = 0; j < 8; j++)
11152 int effective_element = element;
11153 int effective_action = action;
11154 int graphic = (direction == MV_NONE ?
11155 el_act2img(effective_element, effective_action) :
11156 el_act_dir2img(effective_element, effective_action,
11158 struct GraphicInfo *g = &graphic_info[graphic];
11159 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
11160 Bitmap *src_bitmap;
11162 int sync_frame = j;
11165 Bitmap *debug_bitmap = g_em->bitmap;
11166 int debug_src_x = g_em->src_x;
11167 int debug_src_y = g_em->src_y;
11170 int frame = getAnimationFrame(g->anim_frames,
11173 g->anim_start_frame,
11176 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
11178 g_em->bitmap = src_bitmap;
11179 g_em->src_x = src_x;
11180 g_em->src_y = src_y;
11181 g_em->src_offset_x = 0;
11182 g_em->src_offset_y = 0;
11183 g_em->dst_offset_x = 0;
11184 g_em->dst_offset_y = 0;
11185 g_em->width = TILEX;
11186 g_em->height = TILEY;
11190 /* skip check for EMC elements not contained in original EMC artwork */
11191 if (element == EL_PLAYER_3 ||
11192 element == EL_PLAYER_4)
11195 if (g_em->bitmap != debug_bitmap ||
11196 g_em->src_x != debug_src_x ||
11197 g_em->src_y != debug_src_y)
11199 static int last_i = -1;
11207 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
11208 p, i, element, element_info[element].token_name,
11209 element_action_info[effective_action].suffix, direction);
11211 if (element != effective_element)
11212 printf(" [%d ('%s')]",
11214 element_info[effective_element].token_name);
11218 if (g_em->bitmap != debug_bitmap)
11219 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
11220 j, (int)(g_em->bitmap), (int)(debug_bitmap));
11222 if (g_em->src_x != debug_src_x ||
11223 g_em->src_y != debug_src_y)
11224 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11226 g_em->src_x, g_em->src_y,
11227 g_em->src_x / 32, g_em->src_y / 32,
11228 debug_src_x, debug_src_y,
11229 debug_src_x / 32, debug_src_y / 32);
11231 num_em_gfx_errors++;
11241 printf("::: [%d errors found]\n", num_em_gfx_errors);
11247 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
11248 boolean any_player_moving,
11249 boolean player_is_dropping)
11251 if (tape.single_step && tape.recording && !tape.pausing)
11254 boolean active_players = FALSE;
11257 for (i = 0; i < MAX_PLAYERS; i++)
11258 if (action[i] != JOY_NO_ACTION)
11259 active_players = TRUE;
11263 if (frame == 0 && !player_is_dropping)
11264 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11268 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
11269 boolean murphy_is_dropping)
11272 printf("::: waiting: %d, dropping: %d\n",
11273 murphy_is_waiting, murphy_is_dropping);
11276 if (tape.single_step && tape.recording && !tape.pausing)
11278 // if (murphy_is_waiting || murphy_is_dropping)
11279 if (murphy_is_waiting)
11282 printf("::: murphy is waiting -> pause mode\n");
11285 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11290 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
11291 int graphic, int sync_frame, int x, int y)
11293 int frame = getGraphicAnimationFrame(graphic, sync_frame);
11295 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
11298 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
11300 return (IS_NEXT_FRAME(sync_frame, graphic));
11303 int getGraphicInfo_Delay(int graphic)
11305 return graphic_info[graphic].anim_delay;
11308 void PlayMenuSoundExt(int sound)
11310 if (sound == SND_UNDEFINED)
11313 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11314 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11317 if (IS_LOOP_SOUND(sound))
11318 PlaySoundLoop(sound);
11323 void PlayMenuSound()
11325 PlayMenuSoundExt(menu.sound[game_status]);
11328 void PlayMenuSoundStereo(int sound, int stereo_position)
11330 if (sound == SND_UNDEFINED)
11333 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11334 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11337 if (IS_LOOP_SOUND(sound))
11338 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
11340 PlaySoundStereo(sound, stereo_position);
11343 void PlayMenuSoundIfLoopExt(int sound)
11345 if (sound == SND_UNDEFINED)
11348 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11349 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11352 if (IS_LOOP_SOUND(sound))
11353 PlaySoundLoop(sound);
11356 void PlayMenuSoundIfLoop()
11358 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
11361 void PlayMenuMusicExt(int music)
11363 if (music == MUS_UNDEFINED)
11366 if (!setup.sound_music)
11372 void PlayMenuMusic()
11374 PlayMenuMusicExt(menu.music[game_status]);
11377 void PlaySoundActivating()
11380 PlaySound(SND_MENU_ITEM_ACTIVATING);
11384 void PlaySoundSelecting()
11387 PlaySound(SND_MENU_ITEM_SELECTING);
11391 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
11393 boolean change_fullscreen = (setup.fullscreen !=
11394 video.fullscreen_enabled);
11395 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
11396 !strEqual(setup.fullscreen_mode,
11397 video.fullscreen_mode_current));
11398 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
11399 setup.window_scaling_percent !=
11400 video.window_scaling_percent);
11402 if (change_window_scaling_percent && video.fullscreen_enabled)
11405 if (!change_window_scaling_percent && !video.fullscreen_available)
11408 #if defined(TARGET_SDL2)
11409 if (change_window_scaling_percent)
11411 SDLSetWindowScaling(setup.window_scaling_percent);
11415 else if (change_fullscreen)
11417 SDLSetWindowFullscreen(setup.fullscreen);
11419 /* set setup value according to successfully changed fullscreen mode */
11420 setup.fullscreen = video.fullscreen_enabled;
11426 if (change_fullscreen ||
11427 change_fullscreen_mode ||
11428 change_window_scaling_percent)
11430 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11432 /* save backbuffer content which gets lost when toggling fullscreen mode */
11433 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11435 if (change_fullscreen_mode)
11437 /* keep fullscreen, but change fullscreen mode (screen resolution) */
11438 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
11441 if (change_window_scaling_percent)
11443 /* keep window mode, but change window scaling */
11444 video.fullscreen_enabled = TRUE; /* force new window scaling */
11447 /* toggle fullscreen */
11448 ChangeVideoModeIfNeeded(setup.fullscreen);
11450 /* set setup value according to successfully changed fullscreen mode */
11451 setup.fullscreen = video.fullscreen_enabled;
11453 /* restore backbuffer content from temporary backbuffer backup bitmap */
11454 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11456 FreeBitmap(tmp_backbuffer);
11459 /* update visible window/screen */
11460 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11462 redraw_mask = REDRAW_ALL;
11467 void ChangeViewportPropertiesIfNeeded()
11470 int *door_1_x = &DX;
11471 int *door_1_y = &DY;
11472 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11473 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11476 int gfx_game_mode = game_status;
11478 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11479 game_status == GAME_MODE_EDITOR ? game_status :
11482 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11484 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11485 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11486 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11487 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11488 int border_size = vp_playfield->border_size;
11489 int new_sx = vp_playfield->x + border_size;
11490 int new_sy = vp_playfield->y + border_size;
11491 int new_sxsize = vp_playfield->width - 2 * border_size;
11492 int new_sysize = vp_playfield->height - 2 * border_size;
11493 int new_real_sx = vp_playfield->x;
11494 int new_real_sy = vp_playfield->y;
11495 int new_full_sxsize = vp_playfield->width;
11496 int new_full_sysize = vp_playfield->height;
11497 int new_dx = vp_door_1->x;
11498 int new_dy = vp_door_1->y;
11499 int new_dxsize = vp_door_1->width;
11500 int new_dysize = vp_door_1->height;
11501 int new_vx = vp_door_2->x;
11502 int new_vy = vp_door_2->y;
11503 int new_vxsize = vp_door_2->width;
11504 int new_vysize = vp_door_2->height;
11505 int new_ex = vp_door_3->x;
11506 int new_ey = vp_door_3->y;
11507 int new_exsize = vp_door_3->width;
11508 int new_eysize = vp_door_3->height;
11510 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11511 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11512 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11513 int new_scr_fieldx = new_sxsize / tilesize;
11514 int new_scr_fieldy = new_sysize / tilesize;
11515 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11516 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11518 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
11519 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11521 boolean init_gfx_buffers = FALSE;
11522 boolean init_video_buffer = FALSE;
11523 boolean init_gadgets_and_toons = FALSE;
11524 boolean init_em_graphics = FALSE;
11527 /* !!! TEST ONLY !!! */
11528 // InitGfxBuffers();
11532 if (viewport.window.width != WIN_XSIZE ||
11533 viewport.window.height != WIN_YSIZE)
11535 WIN_XSIZE = viewport.window.width;
11536 WIN_YSIZE = viewport.window.height;
11539 init_video_buffer = TRUE;
11540 init_gfx_buffers = TRUE;
11542 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11546 SetDrawDeactivationMask(REDRAW_NONE);
11547 SetDrawBackgroundMask(REDRAW_FIELD);
11549 // RedrawBackground();
11553 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11556 if (new_scr_fieldx != SCR_FIELDX ||
11557 new_scr_fieldy != SCR_FIELDY)
11559 /* this always toggles between MAIN and GAME when using small tile size */
11561 SCR_FIELDX = new_scr_fieldx;
11562 SCR_FIELDY = new_scr_fieldy;
11564 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11568 if (new_tilesize_var != TILESIZE_VAR &&
11569 gfx_game_mode == GAME_MODE_PLAYING)
11571 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11573 TILESIZE_VAR = new_tilesize_var;
11575 init_gfx_buffers = TRUE;
11577 // printf("::: tilesize: init_gfx_buffers\n");
11581 if (new_sx != SX ||
11589 new_sxsize != SXSIZE ||
11590 new_sysize != SYSIZE ||
11591 new_dxsize != DXSIZE ||
11592 new_dysize != DYSIZE ||
11593 new_vxsize != VXSIZE ||
11594 new_vysize != VYSIZE ||
11595 new_exsize != EXSIZE ||
11596 new_eysize != EYSIZE ||
11597 new_real_sx != REAL_SX ||
11598 new_real_sy != REAL_SY ||
11599 new_full_sxsize != FULL_SXSIZE ||
11600 new_full_sysize != FULL_SYSIZE ||
11601 new_tilesize_var != TILESIZE_VAR
11604 vp_door_1->x != *door_1_x ||
11605 vp_door_1->y != *door_1_y ||
11606 vp_door_2->x != *door_2_x ||
11607 vp_door_2->y != *door_2_y
11612 if (new_tilesize_var != TILESIZE_VAR)
11614 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
11616 // changing tile size invalidates scroll values of engine snapshots
11617 FreeEngineSnapshot();
11619 // changing tile size requires update of graphic mapping for EM engine
11620 init_em_graphics = TRUE;
11632 SXSIZE = new_sxsize;
11633 SYSIZE = new_sysize;
11634 DXSIZE = new_dxsize;
11635 DYSIZE = new_dysize;
11636 VXSIZE = new_vxsize;
11637 VYSIZE = new_vysize;
11638 EXSIZE = new_exsize;
11639 EYSIZE = new_eysize;
11640 REAL_SX = new_real_sx;
11641 REAL_SY = new_real_sy;
11642 FULL_SXSIZE = new_full_sxsize;
11643 FULL_SYSIZE = new_full_sysize;
11644 TILESIZE_VAR = new_tilesize_var;
11647 printf("::: %d, %d, %d [%d]\n",
11648 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11649 setup.small_game_graphics);
11653 *door_1_x = vp_door_1->x;
11654 *door_1_y = vp_door_1->y;
11655 *door_2_x = vp_door_2->x;
11656 *door_2_y = vp_door_2->y;
11660 init_gfx_buffers = TRUE;
11662 // printf("::: viewports: init_gfx_buffers\n");
11668 if (gfx_game_mode == GAME_MODE_MAIN)
11672 init_gadgets_and_toons = TRUE;
11674 // printf("::: viewports: init_gadgets_and_toons\n");
11682 if (init_gfx_buffers)
11684 // printf("::: init_gfx_buffers\n");
11686 SCR_FIELDX = new_scr_fieldx_buffers;
11687 SCR_FIELDY = new_scr_fieldy_buffers;
11691 SCR_FIELDX = new_scr_fieldx;
11692 SCR_FIELDY = new_scr_fieldy;
11695 if (init_video_buffer)
11697 // printf("::: init_video_buffer\n");
11699 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11701 SetDrawDeactivationMask(REDRAW_NONE);
11702 SetDrawBackgroundMask(REDRAW_FIELD);
11705 if (init_gadgets_and_toons)
11707 // printf("::: init_gadgets_and_toons\n");
11713 if (init_em_graphics)
11715 InitGraphicInfo_EM();
11719 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);