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 bitmap_width = src_bitmap->width;
1524 int bitmap_height = src_bitmap->height;
1525 int width_mult = offset_calc[offset_calc_pos].width_mult;
1526 int width_div = offset_calc[offset_calc_pos].width_div;
1527 int height_mult = offset_calc[offset_calc_pos].height_mult;
1528 int height_div = offset_calc[offset_calc_pos].height_div;
1529 int startx = bitmap_width * width_mult / width_div;
1530 int starty = bitmap_height * height_mult / height_div;
1532 #if NEW_GAME_TILESIZE
1534 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1535 tilesize_raw / TILESIZE;
1536 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1537 tilesize_raw / TILESIZE;
1538 int width = g->width * tilesize_raw / TILESIZE;
1539 int height = g->height * tilesize_raw / TILESIZE;
1540 int offset_x = g->offset_x * tilesize_raw / TILESIZE;
1541 int offset_y = g->offset_y * tilesize_raw / TILESIZE;
1546 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1547 tilesize / TILESIZE;
1548 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1549 tilesize / TILESIZE;
1551 int src_x = g->src_x * tilesize / TILESIZE;
1552 int src_y = g->src_y * tilesize / TILESIZE;
1554 int width = g->width * tilesize / TILESIZE;
1555 int height = g->height * tilesize / TILESIZE;
1556 int offset_x = g->offset_x * tilesize / TILESIZE;
1557 int offset_y = g->offset_y * tilesize / TILESIZE;
1561 #if NEW_GAME_TILESIZE
1562 if (game.tile_size != TILESIZE)
1564 int bitmap_width_std =
1565 bitmap_width * TILESIZE / (TILESIZE + game.tile_size);
1566 int bitmap_height_std =
1567 bitmap_height * TILESIZE / game.tile_size * 3 / 2;
1569 if (tilesize_raw == game.tile_size)
1571 startx = bitmap_width_std;
1576 bitmap_width = bitmap_width_std;
1578 if (game.tile_size > TILESIZE * 3 / 2)
1579 bitmap_height = bitmap_height_std;
1581 startx = bitmap_width * width_mult / width_div;
1582 starty = bitmap_height * height_mult / height_div;
1587 if (g->offset_y == 0) /* frames are ordered horizontally */
1589 int max_width = g->anim_frames_per_line * width;
1590 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1592 src_x = pos % max_width;
1593 src_y = src_y % height + pos / max_width * height;
1595 else if (g->offset_x == 0) /* frames are ordered vertically */
1597 int max_height = g->anim_frames_per_line * height;
1598 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1600 src_x = src_x % width + pos / max_height * width;
1601 src_y = pos % max_height;
1603 else /* frames are ordered diagonally */
1605 src_x = src_x + frame * offset_x;
1606 src_y = src_y + frame * offset_y;
1609 *bitmap = src_bitmap;
1610 *x = startx + src_x;
1611 *y = starty + src_y;
1614 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1615 int *x, int *y, boolean get_backside)
1617 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1621 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1622 Bitmap **bitmap, int *x, int *y)
1624 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1627 void getFixedGraphicSource(int graphic, int frame,
1628 Bitmap **bitmap, int *x, int *y)
1630 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1633 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1636 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1638 struct GraphicInfo *g = &graphic_info[graphic];
1639 int mini_startx = 0;
1640 int mini_starty = g->bitmap->height * 2 / 3;
1642 *bitmap = g->bitmap;
1643 *x = mini_startx + g->src_x / 2;
1644 *y = mini_starty + g->src_y / 2;
1648 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1649 int *x, int *y, boolean get_backside)
1651 struct GraphicInfo *g = &graphic_info[graphic];
1652 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1653 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1656 if (TILESIZE_VAR != TILESIZE)
1657 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1661 *bitmap = g->bitmap;
1663 if (g->offset_y == 0) /* frames are ordered horizontally */
1665 int max_width = g->anim_frames_per_line * g->width;
1666 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1668 *x = pos % max_width;
1669 *y = src_y % g->height + pos / max_width * g->height;
1671 else if (g->offset_x == 0) /* frames are ordered vertically */
1673 int max_height = g->anim_frames_per_line * g->height;
1674 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1676 *x = src_x % g->width + pos / max_height * g->width;
1677 *y = pos % max_height;
1679 else /* frames are ordered diagonally */
1681 *x = src_x + frame * g->offset_x;
1682 *y = src_y + frame * g->offset_y;
1686 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1688 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1691 void DrawGraphic(int x, int y, int graphic, int frame)
1694 if (!IN_SCR_FIELD(x, y))
1696 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1697 printf("DrawGraphic(): This should never happen!\n");
1703 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1706 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1708 MarkTileDirty(x, y);
1711 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1714 if (!IN_SCR_FIELD(x, y))
1716 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1717 printf("DrawGraphic(): This should never happen!\n");
1722 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1724 MarkTileDirty(x, y);
1727 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1733 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1735 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1737 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1741 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1747 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1748 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1751 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1754 if (!IN_SCR_FIELD(x, y))
1756 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1757 printf("DrawGraphicThruMask(): This should never happen!\n");
1763 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1766 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1769 MarkTileDirty(x, y);
1772 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1775 if (!IN_SCR_FIELD(x, y))
1777 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1778 printf("DrawGraphicThruMask(): This should never happen!\n");
1783 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1785 MarkTileDirty(x, y);
1788 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1794 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1796 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1797 dst_x - src_x, dst_y - src_y);
1799 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1802 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1806 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1807 int graphic, int frame)
1812 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1814 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1815 dst_x - src_x, dst_y - src_y);
1816 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1819 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1821 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1823 MarkTileDirty(x / tilesize, y / tilesize);
1826 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1832 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1833 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1836 void DrawMiniGraphic(int x, int y, int graphic)
1838 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1839 MarkTileDirty(x / 2, y / 2);
1842 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1847 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1848 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1851 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1852 int graphic, int frame,
1853 int cut_mode, int mask_mode)
1858 int width = TILEX, height = TILEY;
1861 if (dx || dy) /* shifted graphic */
1863 if (x < BX1) /* object enters playfield from the left */
1870 else if (x > BX2) /* object enters playfield from the right */
1876 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1882 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1884 else if (dx) /* general horizontal movement */
1885 MarkTileDirty(x + SIGN(dx), y);
1887 if (y < BY1) /* object enters playfield from the top */
1889 if (cut_mode==CUT_BELOW) /* object completely above top border */
1897 else if (y > BY2) /* object enters playfield from the bottom */
1903 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1909 else if (dy > 0 && cut_mode == CUT_ABOVE)
1911 if (y == BY2) /* object completely above bottom border */
1917 MarkTileDirty(x, y + 1);
1918 } /* object leaves playfield to the bottom */
1919 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1921 else if (dy) /* general vertical movement */
1922 MarkTileDirty(x, y + SIGN(dy));
1926 if (!IN_SCR_FIELD(x, y))
1928 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1929 printf("DrawGraphicShifted(): This should never happen!\n");
1935 width = width * TILESIZE_VAR / TILESIZE;
1936 height = height * TILESIZE_VAR / TILESIZE;
1937 cx = cx * TILESIZE_VAR / TILESIZE;
1938 cy = cy * TILESIZE_VAR / TILESIZE;
1939 dx = dx * TILESIZE_VAR / TILESIZE;
1940 dy = dy * TILESIZE_VAR / TILESIZE;
1943 if (width > 0 && height > 0)
1945 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1951 dst_x = FX + x * TILEX_VAR + dx;
1952 dst_y = FY + y * TILEY_VAR + dy;
1954 dst_x = FX + x * TILEX + dx;
1955 dst_y = FY + y * TILEY + dy;
1958 if (mask_mode == USE_MASKING)
1960 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1961 dst_x - src_x, dst_y - src_y);
1962 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1966 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1969 MarkTileDirty(x, y);
1973 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1974 int graphic, int frame,
1975 int cut_mode, int mask_mode)
1981 int width = TILEX_VAR, height = TILEY_VAR;
1983 int width = TILEX, height = TILEY;
1987 int x2 = x + SIGN(dx);
1988 int y2 = y + SIGN(dy);
1990 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1991 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1993 /* movement with two-tile animations must be sync'ed with movement position,
1994 not with current GfxFrame (which can be higher when using slow movement) */
1995 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1996 int anim_frames = graphic_info[graphic].anim_frames;
1998 /* (we also need anim_delay here for movement animations with less frames) */
1999 int anim_delay = graphic_info[graphic].anim_delay;
2000 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
2002 int sync_frame = anim_pos * anim_frames / TILESIZE;
2005 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
2006 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
2008 /* re-calculate animation frame for two-tile movement animation */
2009 frame = getGraphicAnimationFrame(graphic, sync_frame);
2013 printf("::: %d, %d, %d => %d [%d]\n",
2014 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
2016 printf("::: %d, %d => %d\n",
2017 anim_pos, anim_frames, sync_frame);
2022 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
2023 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
2026 /* check if movement start graphic inside screen area and should be drawn */
2027 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
2029 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
2032 dst_x = FX + x1 * TILEX_VAR;
2033 dst_y = FY + y1 * TILEY_VAR;
2035 dst_x = FX + x1 * TILEX;
2036 dst_y = FY + y1 * TILEY;
2039 if (mask_mode == USE_MASKING)
2041 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2042 dst_x - src_x, dst_y - src_y);
2043 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
2047 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2050 MarkTileDirty(x1, y1);
2053 /* check if movement end graphic inside screen area and should be drawn */
2054 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
2056 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
2059 dst_x = FX + x2 * TILEX_VAR;
2060 dst_y = FY + y2 * TILEY_VAR;
2062 dst_x = FX + x2 * TILEX;
2063 dst_y = FY + y2 * TILEY;
2066 if (mask_mode == USE_MASKING)
2068 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2069 dst_x - src_x, dst_y - src_y);
2070 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
2074 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2077 MarkTileDirty(x2, y2);
2081 static void DrawGraphicShifted(int x, int y, int dx, int dy,
2082 int graphic, int frame,
2083 int cut_mode, int mask_mode)
2087 DrawGraphic(x, y, graphic, frame);
2092 if (graphic_info[graphic].double_movement) /* EM style movement images */
2093 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2095 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2098 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
2099 int frame, int cut_mode)
2101 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
2104 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
2105 int cut_mode, int mask_mode)
2107 int lx = LEVELX(x), ly = LEVELY(y);
2111 if (IN_LEV_FIELD(lx, ly))
2113 SetRandomAnimationValue(lx, ly);
2115 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
2116 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2118 /* do not use double (EM style) movement graphic when not moving */
2119 if (graphic_info[graphic].double_movement && !dx && !dy)
2121 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
2122 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2125 else /* border element */
2127 graphic = el2img(element);
2128 frame = getGraphicAnimationFrame(graphic, -1);
2131 if (element == EL_EXPANDABLE_WALL)
2133 boolean left_stopped = FALSE, right_stopped = FALSE;
2135 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
2136 left_stopped = TRUE;
2137 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
2138 right_stopped = TRUE;
2140 if (left_stopped && right_stopped)
2142 else if (left_stopped)
2144 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
2145 frame = graphic_info[graphic].anim_frames - 1;
2147 else if (right_stopped)
2149 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
2150 frame = graphic_info[graphic].anim_frames - 1;
2155 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
2156 else if (mask_mode == USE_MASKING)
2157 DrawGraphicThruMask(x, y, graphic, frame);
2159 DrawGraphic(x, y, graphic, frame);
2162 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2163 int cut_mode, int mask_mode)
2165 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2166 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2167 cut_mode, mask_mode);
2170 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2173 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2176 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2179 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2182 void DrawLevelElementThruMask(int x, int y, int element)
2184 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2187 void DrawLevelFieldThruMask(int x, int y)
2189 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2192 /* !!! implementation of quicksand is totally broken !!! */
2193 #define IS_CRUMBLED_TILE(x, y, e) \
2194 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2195 !IS_MOVING(x, y) || \
2196 (e) == EL_QUICKSAND_EMPTYING || \
2197 (e) == EL_QUICKSAND_FAST_EMPTYING))
2199 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2204 int width, height, cx, cy;
2205 int sx = SCREENX(x), sy = SCREENY(y);
2206 int crumbled_border_size = graphic_info[graphic].border_size;
2209 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2211 for (i = 1; i < 4; i++)
2213 int dxx = (i & 1 ? dx : 0);
2214 int dyy = (i & 2 ? dy : 0);
2217 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2220 /* check if neighbour field is of same crumble type */
2221 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2222 graphic_info[graphic].class ==
2223 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2225 /* return if check prevents inner corner */
2226 if (same == (dxx == dx && dyy == dy))
2230 /* if we reach this point, we have an inner corner */
2232 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2235 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2236 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2237 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
2238 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
2240 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2241 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2243 width = crumbled_border_size;
2244 height = crumbled_border_size;
2245 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2246 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2248 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2249 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2253 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2258 int width, height, bx, by, cx, cy;
2259 int sx = SCREENX(x), sy = SCREENY(y);
2260 int crumbled_border_size = graphic_info[graphic].border_size;
2261 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2262 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
2265 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2267 /* draw simple, sloppy, non-corner-accurate crumbled border */
2270 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
2271 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
2272 cx = (dir == 2 ? crumbled_border_pos_var : 0);
2273 cy = (dir == 3 ? crumbled_border_pos_var : 0);
2275 if (dir == 1 || dir == 2) /* left or right crumbled border */
2277 width = crumbled_border_size;
2279 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2282 else /* top or bottom crumbled border */
2285 height = crumbled_border_size;
2287 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2292 BlitBitmap(src_bitmap, drawto_field,
2297 FX + sx * TILEX_VAR + cx,
2298 FY + sy * TILEY_VAR + cy);
2300 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2301 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2304 /* (remaining middle border part must be at least as big as corner part) */
2305 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2306 crumbled_border_size >= TILESIZE / 3)
2309 /* correct corners of crumbled border, if needed */
2312 for (i = -1; i <= 1; i += 2)
2314 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2315 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2316 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2319 /* check if neighbour field is of same crumble type */
2320 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2321 graphic_info[graphic].class ==
2322 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2324 /* no crumbled corner, but continued crumbled border */
2326 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
2327 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
2328 int b1 = (i == 1 ? crumbled_border_size_var :
2329 TILESIZE_VAR - 2 * crumbled_border_size_var);
2331 width = crumbled_border_size_var;
2332 height = crumbled_border_size_var;
2334 if (dir == 1 || dir == 2)
2350 BlitBitmap(src_bitmap, drawto_field,
2355 FX + sx * TILEX_VAR + cx,
2356 FY + sy * TILEY_VAR + cy);
2358 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2359 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2364 if (dir == 1 || dir == 2) /* left or right crumbled border */
2366 for (i = -1; i <= 1; i+=2)
2370 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2373 /* check if neighbour field is of same crumble type */
2374 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2375 graphic_info[graphic].class ==
2376 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2378 /* no crumbled corner, but continued crumbled border */
2380 width = crumbled_border_size;
2381 height = crumbled_border_size;
2382 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2383 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2385 by = (i == 1 ? crumbled_border_size :
2386 TILEY - 2 * crumbled_border_size);
2388 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2389 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2393 else /* top or bottom crumbled border */
2395 for (i = -1; i <= 1; i+=2)
2399 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2402 /* check if neighbour field is of same crumble type */
2403 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2404 graphic_info[graphic].class ==
2405 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2407 /* no crumbled corner, but continued crumbled border */
2409 width = crumbled_border_size;
2410 height = crumbled_border_size;
2411 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2412 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2413 bx = (i == 1 ? crumbled_border_size :
2414 TILEX - 2 * crumbled_border_size);
2417 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2418 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2425 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2427 int sx = SCREENX(x), sy = SCREENY(y);
2430 static int xy[4][2] =
2438 if (!IN_LEV_FIELD(x, y))
2441 element = TILE_GFX_ELEMENT(x, y);
2443 /* crumble field itself */
2444 if (IS_CRUMBLED_TILE(x, y, element))
2446 if (!IN_SCR_FIELD(sx, sy))
2449 for (i = 0; i < 4; i++)
2451 int xx = x + xy[i][0];
2452 int yy = y + xy[i][1];
2454 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2457 /* check if neighbour field is of same crumble type */
2459 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2460 graphic_info[graphic].class ==
2461 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2464 if (IS_CRUMBLED_TILE(xx, yy, element))
2468 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2471 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2472 graphic_info[graphic].anim_frames == 2)
2474 for (i = 0; i < 4; i++)
2476 int dx = (i & 1 ? +1 : -1);
2477 int dy = (i & 2 ? +1 : -1);
2479 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2483 MarkTileDirty(sx, sy);
2485 else /* center field not crumbled -- crumble neighbour fields */
2487 for (i = 0; i < 4; i++)
2489 int xx = x + xy[i][0];
2490 int yy = y + xy[i][1];
2491 int sxx = sx + xy[i][0];
2492 int syy = sy + xy[i][1];
2494 if (!IN_LEV_FIELD(xx, yy) ||
2495 !IN_SCR_FIELD(sxx, syy))
2498 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2501 element = TILE_GFX_ELEMENT(xx, yy);
2503 if (!IS_CRUMBLED_TILE(xx, yy, element))
2506 graphic = el_act2crm(element, ACTION_DEFAULT);
2508 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2510 MarkTileDirty(sxx, syy);
2515 void DrawLevelFieldCrumbled(int x, int y)
2519 if (!IN_LEV_FIELD(x, y))
2523 /* !!! CHECK THIS !!! */
2526 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2527 GFX_CRUMBLED(GfxElement[x][y]))
2530 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2531 GfxElement[x][y] != EL_UNDEFINED &&
2532 GFX_CRUMBLED(GfxElement[x][y]))
2534 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2541 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2543 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2546 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2549 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2552 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2553 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2554 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2555 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2556 int sx = SCREENX(x), sy = SCREENY(y);
2558 DrawGraphic(sx, sy, graphic1, frame1);
2559 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2562 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2564 int sx = SCREENX(x), sy = SCREENY(y);
2565 static int xy[4][2] =
2574 for (i = 0; i < 4; i++)
2576 int xx = x + xy[i][0];
2577 int yy = y + xy[i][1];
2578 int sxx = sx + xy[i][0];
2579 int syy = sy + xy[i][1];
2581 if (!IN_LEV_FIELD(xx, yy) ||
2582 !IN_SCR_FIELD(sxx, syy) ||
2583 !GFX_CRUMBLED(Feld[xx][yy]) ||
2587 DrawLevelField(xx, yy);
2591 static int getBorderElement(int x, int y)
2595 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2596 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2597 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2598 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2599 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2600 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2601 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2603 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2604 int steel_position = (x == -1 && y == -1 ? 0 :
2605 x == lev_fieldx && y == -1 ? 1 :
2606 x == -1 && y == lev_fieldy ? 2 :
2607 x == lev_fieldx && y == lev_fieldy ? 3 :
2608 x == -1 || x == lev_fieldx ? 4 :
2609 y == -1 || y == lev_fieldy ? 5 : 6);
2611 return border[steel_position][steel_type];
2614 void DrawScreenElement(int x, int y, int element)
2616 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2617 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2620 void DrawLevelElement(int x, int y, int element)
2622 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2623 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2626 void DrawScreenField(int x, int y)
2628 int lx = LEVELX(x), ly = LEVELY(y);
2629 int element, content;
2631 if (!IN_LEV_FIELD(lx, ly))
2633 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2636 element = getBorderElement(lx, ly);
2638 DrawScreenElement(x, y, element);
2643 element = Feld[lx][ly];
2644 content = Store[lx][ly];
2646 if (IS_MOVING(lx, ly))
2648 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2649 boolean cut_mode = NO_CUTTING;
2651 if (element == EL_QUICKSAND_EMPTYING ||
2652 element == EL_QUICKSAND_FAST_EMPTYING ||
2653 element == EL_MAGIC_WALL_EMPTYING ||
2654 element == EL_BD_MAGIC_WALL_EMPTYING ||
2655 element == EL_DC_MAGIC_WALL_EMPTYING ||
2656 element == EL_AMOEBA_DROPPING)
2657 cut_mode = CUT_ABOVE;
2658 else if (element == EL_QUICKSAND_FILLING ||
2659 element == EL_QUICKSAND_FAST_FILLING ||
2660 element == EL_MAGIC_WALL_FILLING ||
2661 element == EL_BD_MAGIC_WALL_FILLING ||
2662 element == EL_DC_MAGIC_WALL_FILLING)
2663 cut_mode = CUT_BELOW;
2666 if (lx == 9 && ly == 1)
2667 printf("::: %s [%d] [%d, %d] [%d]\n",
2668 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2669 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2670 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2671 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2672 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2675 if (cut_mode == CUT_ABOVE)
2677 DrawScreenElement(x, y, element);
2679 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2682 DrawScreenElement(x, y, EL_EMPTY);
2685 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2686 else if (cut_mode == NO_CUTTING)
2687 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2690 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2693 if (cut_mode == CUT_BELOW &&
2694 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2695 DrawLevelElement(lx, ly + 1, element);
2699 if (content == EL_ACID)
2701 int dir = MovDir[lx][ly];
2702 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2703 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2705 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2708 else if (IS_BLOCKED(lx, ly))
2713 boolean cut_mode = NO_CUTTING;
2714 int element_old, content_old;
2716 Blocked2Moving(lx, ly, &oldx, &oldy);
2719 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2720 MovDir[oldx][oldy] == MV_RIGHT);
2722 element_old = Feld[oldx][oldy];
2723 content_old = Store[oldx][oldy];
2725 if (element_old == EL_QUICKSAND_EMPTYING ||
2726 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2727 element_old == EL_MAGIC_WALL_EMPTYING ||
2728 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2729 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2730 element_old == EL_AMOEBA_DROPPING)
2731 cut_mode = CUT_ABOVE;
2733 DrawScreenElement(x, y, EL_EMPTY);
2736 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2738 else if (cut_mode == NO_CUTTING)
2739 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2742 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2745 else if (IS_DRAWABLE(element))
2746 DrawScreenElement(x, y, element);
2748 DrawScreenElement(x, y, EL_EMPTY);
2751 void DrawLevelField(int x, int y)
2753 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2754 DrawScreenField(SCREENX(x), SCREENY(y));
2755 else if (IS_MOVING(x, y))
2759 Moving2Blocked(x, y, &newx, &newy);
2760 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2761 DrawScreenField(SCREENX(newx), SCREENY(newy));
2763 else if (IS_BLOCKED(x, y))
2767 Blocked2Moving(x, y, &oldx, &oldy);
2768 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2769 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2773 void DrawMiniElement(int x, int y, int element)
2777 graphic = el2edimg(element);
2778 DrawMiniGraphic(x, y, graphic);
2781 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2783 int x = sx + scroll_x, y = sy + scroll_y;
2785 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2786 DrawMiniElement(sx, sy, EL_EMPTY);
2787 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2788 DrawMiniElement(sx, sy, Feld[x][y]);
2790 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2793 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2794 int x, int y, int xsize, int ysize,
2795 int tile_width, int tile_height)
2799 int dst_x = startx + x * tile_width;
2800 int dst_y = starty + y * tile_height;
2801 int width = graphic_info[graphic].width;
2802 int height = graphic_info[graphic].height;
2803 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2804 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2805 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2806 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2807 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2808 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2809 boolean draw_masked = graphic_info[graphic].draw_masked;
2811 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2813 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2815 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2819 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2820 inner_sx + (x - 1) * tile_width % inner_width);
2821 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2822 inner_sy + (y - 1) * tile_height % inner_height);
2826 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2827 dst_x - src_x, dst_y - src_y);
2828 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2832 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2836 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2837 int x, int y, int xsize, int ysize, int font_nr)
2839 int font_width = getFontWidth(font_nr);
2840 int font_height = getFontHeight(font_nr);
2842 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2843 font_width, font_height);
2846 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2848 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2849 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2850 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2851 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2852 boolean no_delay = (tape.warp_forward);
2853 unsigned int anim_delay = 0;
2854 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2855 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2856 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2857 int font_width = getFontWidth(font_nr);
2858 int font_height = getFontHeight(font_nr);
2859 int max_xsize = level.envelope[envelope_nr].xsize;
2860 int max_ysize = level.envelope[envelope_nr].ysize;
2861 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2862 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2863 int xend = max_xsize;
2864 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2865 int xstep = (xstart < xend ? 1 : 0);
2866 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2869 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2871 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2872 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2873 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2874 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2877 SetDrawtoField(DRAW_BUFFERED);
2880 BlitScreenToBitmap(backbuffer);
2882 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2885 SetDrawtoField(DRAW_BACKBUFFER);
2887 for (yy = 0; yy < ysize; yy++)
2888 for (xx = 0; xx < xsize; xx++)
2889 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2892 DrawTextBuffer(sx + font_width, sy + font_height,
2893 level.envelope[envelope_nr].text, font_nr, max_xsize,
2894 xsize - 2, ysize - 2, 0, mask_mode,
2895 level.envelope[envelope_nr].autowrap,
2896 level.envelope[envelope_nr].centered, FALSE);
2898 DrawTextToTextArea(sx + font_width, sy + font_height,
2899 level.envelope[envelope_nr].text, font_nr, max_xsize,
2900 xsize - 2, ysize - 2, mask_mode);
2903 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2906 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2910 void ShowEnvelope(int envelope_nr)
2912 int element = EL_ENVELOPE_1 + envelope_nr;
2913 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2914 int sound_opening = element_info[element].sound[ACTION_OPENING];
2915 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2916 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2917 boolean no_delay = (tape.warp_forward);
2918 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2919 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2920 int anim_mode = graphic_info[graphic].anim_mode;
2921 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2922 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2924 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2926 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2928 if (anim_mode == ANIM_DEFAULT)
2929 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2931 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2934 Delay(wait_delay_value);
2936 WaitForEventToContinue();
2938 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2940 if (anim_mode != ANIM_NONE)
2941 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2943 if (anim_mode == ANIM_DEFAULT)
2944 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2946 game.envelope_active = FALSE;
2948 SetDrawtoField(DRAW_BUFFERED);
2950 redraw_mask |= REDRAW_FIELD;
2954 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2956 int border_size = request.border_size;
2957 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2958 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2959 int sx = sx_center - request.width / 2;
2960 int sy = sy_center - request.height / 2;
2962 if (add_border_size)
2972 void DrawEnvelopeRequest(char *text)
2974 char *text_final = text;
2975 char *text_door_style = NULL;
2976 int graphic = IMG_BACKGROUND_REQUEST;
2977 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2978 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2979 int font_nr = FONT_REQUEST;
2980 int font_width = getFontWidth(font_nr);
2981 int font_height = getFontHeight(font_nr);
2982 int border_size = request.border_size;
2983 int line_spacing = request.line_spacing;
2984 int line_height = font_height + line_spacing;
2985 int text_width = request.width - 2 * border_size;
2986 int text_height = request.height - 2 * border_size;
2987 int line_length = text_width / font_width;
2988 int max_lines = text_height / line_height;
2989 int width = request.width;
2990 int height = request.height;
2991 int tile_size = request.step_offset;
2992 int x_steps = width / tile_size;
2993 int y_steps = height / tile_size;
2997 if (request.wrap_single_words)
2999 char *src_text_ptr, *dst_text_ptr;
3001 text_door_style = checked_malloc(2 * strlen(text) + 1);
3003 src_text_ptr = text;
3004 dst_text_ptr = text_door_style;
3006 while (*src_text_ptr)
3008 if (*src_text_ptr == ' ' ||
3009 *src_text_ptr == '?' ||
3010 *src_text_ptr == '!')
3011 *dst_text_ptr++ = '\n';
3013 if (*src_text_ptr != ' ')
3014 *dst_text_ptr++ = *src_text_ptr;
3019 *dst_text_ptr = '\0';
3021 text_final = text_door_style;
3024 setRequestPosition(&sx, &sy, FALSE);
3026 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
3028 for (y = 0; y < y_steps; y++)
3029 for (x = 0; x < x_steps; x++)
3030 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
3031 x, y, x_steps, y_steps,
3032 tile_size, tile_size);
3034 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
3035 line_length, -1, max_lines, line_spacing, mask_mode,
3036 request.autowrap, request.centered, FALSE);
3038 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3039 RedrawGadget(tool_gadget[i]);
3041 // store readily prepared envelope request for later use when animating
3042 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3046 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3047 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
3049 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3054 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3056 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3062 if (text_door_style)
3063 free(text_door_style);
3068 void AnimateEnvelopeRequest(int anim_mode, int action)
3070 int graphic = IMG_BACKGROUND_REQUEST;
3071 boolean draw_masked = graphic_info[graphic].draw_masked;
3073 int delay_value_normal = request.step_delay;
3074 int delay_value_fast = delay_value_normal / 2;
3076 int delay_value_normal = GameFrameDelay;
3077 int delay_value_fast = FfwdFrameDelay;
3079 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3080 boolean no_delay = (tape.warp_forward);
3081 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
3082 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
3083 unsigned int anim_delay = 0;
3085 int width = request.width;
3086 int height = request.height;
3087 int tile_size = request.step_offset;
3088 int max_xsize = width / tile_size;
3089 int max_ysize = height / tile_size;
3090 int max_xsize_inner = max_xsize - 2;
3091 int max_ysize_inner = max_ysize - 2;
3093 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
3094 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
3095 int xend = max_xsize_inner;
3096 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
3097 int xstep = (xstart < xend ? 1 : 0);
3098 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3101 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3103 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3104 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3105 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
3106 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
3107 int src_x = sx_center - width / 2;
3108 int src_y = sy_center - height / 2;
3109 int dst_x = sx_center - xsize * tile_size / 2;
3110 int dst_y = sy_center - ysize * tile_size / 2;
3111 int xsize_size_left = (xsize - 1) * tile_size;
3112 int ysize_size_top = (ysize - 1) * tile_size;
3113 int max_xsize_pos = (max_xsize - 1) * tile_size;
3114 int max_ysize_pos = (max_ysize - 1) * tile_size;
3117 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3120 for (yy = 0; yy < 2; yy++)
3122 for (xx = 0; xx < 2; xx++)
3124 int src_xx = src_x + xx * max_xsize_pos;
3125 int src_yy = src_y + yy * max_ysize_pos;
3126 int dst_xx = dst_x + xx * xsize_size_left;
3127 int dst_yy = dst_y + yy * ysize_size_top;
3128 int xx_size = (xx ? tile_size : xsize_size_left);
3129 int yy_size = (yy ? tile_size : ysize_size_top);
3132 BlitBitmapMasked(bitmap_db_cross, backbuffer,
3133 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3135 BlitBitmap(bitmap_db_cross, backbuffer,
3136 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3140 BlitBitmap(bitmap_db_cross, backbuffer,
3142 xsize_size_left, ysize_size_top,
3144 BlitBitmap(bitmap_db_cross, backbuffer,
3145 src_x + max_xsize_pos, src_y,
3146 tile_size, ysize_size_top,
3147 dst_x + xsize_size_left, dst_y);
3148 BlitBitmap(bitmap_db_cross, backbuffer,
3149 src_x, src_y + max_ysize_pos,
3150 xsize_size_left, tile_size,
3151 dst_x, dst_y + ysize_size_top);
3152 BlitBitmap(bitmap_db_cross, backbuffer,
3153 src_x + max_xsize_pos, src_y + max_ysize_pos,
3154 tile_size, tile_size,
3155 dst_x + xsize_size_left, dst_y + ysize_size_top);
3159 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3160 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3162 /* CHECK AGAIN (previous code reactivated) */
3163 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3173 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3179 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
3182 int envelope_nr = 0;
3185 int graphic = IMG_BACKGROUND_REQUEST;
3187 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3189 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
3190 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
3191 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3192 boolean no_delay = (tape.warp_forward);
3193 unsigned int anim_delay = 0;
3194 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
3195 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
3197 int max_word_len = maxWordLengthInString(text);
3198 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3200 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3202 int font_width = getFontWidth(font_nr);
3203 int font_height = getFontHeight(font_nr);
3204 int line_spacing = 2 * 1;
3208 int max_xsize = DXSIZE / font_width;
3209 // int max_ysize = DYSIZE / font_height;
3210 int max_ysize = DYSIZE / (font_height + line_spacing);
3212 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3213 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
3217 int max_xsize = level.envelope[envelope_nr].xsize;
3218 int max_ysize = level.envelope[envelope_nr].ysize;
3220 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3221 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3222 int xend = max_xsize;
3223 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3224 int xstep = (xstart < xend ? 1 : 0);
3225 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3230 char *text_copy = getStringCopy(text);
3233 font_nr = FONT_TEXT_2;
3235 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3237 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3238 font_nr = FONT_TEXT_1;
3241 int max_word_len = 0;
3243 char *text_copy = getStringCopy(text);
3245 font_nr = FONT_TEXT_2;
3247 for (text_ptr = text; *text_ptr; text_ptr++)
3249 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3251 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3253 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3254 font_nr = FONT_TEXT_1;
3263 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3264 if (*text_ptr == ' ')
3269 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3270 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3272 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
3273 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3276 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3278 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3279 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3280 int sx = SX + (SXSIZE - xsize * font_width) / 2;
3281 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3282 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3286 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3288 SetDrawtoField(DRAW_BUFFERED);
3291 BlitScreenToBitmap(backbuffer);
3293 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3296 SetDrawtoField(DRAW_BACKBUFFER);
3299 for (yy = 0; yy < ysize; yy++)
3300 for (xx = 0; xx < xsize; xx++)
3301 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3302 getFontWidth(font_nr),
3303 getFontHeight(font_nr) + line_spacing);
3308 DrawTextBuffer(sx + font_width, sy + font_height + 8,
3309 text_copy, font_nr, max_xsize,
3310 xsize - 2, ysize - 2, line_spacing, mask_mode,
3311 FALSE, TRUE, FALSE);
3313 DrawTextBuffer(sx + font_width, sy + font_height,
3314 level.envelope[envelope_nr].text, font_nr, max_xsize,
3315 xsize - 2, ysize - 2, 0, mask_mode,
3316 level.envelope[envelope_nr].autowrap,
3317 level.envelope[envelope_nr].centered, FALSE);
3321 DrawTextToTextArea(sx + font_width, sy + font_height,
3322 level.envelope[envelope_nr].text, font_nr, max_xsize,
3323 xsize - 2, ysize - 2, mask_mode);
3326 /* copy request gadgets to door backbuffer */
3329 if ((ysize - 2) > 13)
3330 BlitBitmap(bitmap_db_door, drawto,
3331 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3332 DOOR_GFX_PAGEY1 + 13 * font_height,
3333 (xsize - 2) * font_width,
3334 (ysize - 2 - 13) * font_height,
3336 sy + font_height * (1 + 13));
3338 if ((ysize - 2) > 13)
3339 BlitBitmap(bitmap_db_door, drawto,
3340 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3341 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3342 (xsize - 2) * font_width,
3343 (ysize - 2 - 13) * (font_height + line_spacing),
3345 sy + (font_height + line_spacing) * (1 + 13));
3347 if ((ysize - 2) > 13)
3348 BlitBitmap(bitmap_db_door, drawto,
3349 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3350 DOOR_GFX_PAGEY1 + 13 * font_height,
3351 (xsize - 2) * font_width,
3352 (ysize - 2 - 13) * font_height,
3354 sy + font_height * (1 + 13));
3358 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3359 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3361 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3371 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3381 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3384 int last_game_status = game_status; /* save current game status */
3385 // int last_draw_background_mask = gfx.draw_background_mask;
3388 int graphic = IMG_BACKGROUND_REQUEST;
3389 int sound_opening = SND_REQUEST_OPENING;
3390 int sound_closing = SND_REQUEST_CLOSING;
3392 int envelope_nr = 0;
3393 int element = EL_ENVELOPE_1 + envelope_nr;
3394 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3395 int sound_opening = element_info[element].sound[ACTION_OPENING];
3396 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3399 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3400 boolean no_delay = (tape.warp_forward);
3401 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3402 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3404 int anim_mode = graphic_info[graphic].anim_mode;
3405 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3406 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3408 char *text_copy = getStringCopy(text);
3411 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3412 if (*text_ptr == ' ')
3417 if (game_status == GAME_MODE_PLAYING)
3421 BlitScreenToBitmap(backbuffer);
3423 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3424 BlitScreenToBitmap_EM(backbuffer);
3425 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3426 BlitScreenToBitmap_SP(backbuffer);
3428 BlitScreenToBitmap_RND(backbuffer);
3431 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3432 BlitScreenToBitmap_EM(backbuffer);
3433 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3434 BlitScreenToBitmap_SP(backbuffer);
3437 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3442 SetDrawtoField(DRAW_BACKBUFFER);
3444 // SetDrawBackgroundMask(REDRAW_NONE);
3446 if (action == ACTION_OPENING)
3448 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3451 if (req_state & REQ_ASK)
3453 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3454 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3456 else if (req_state & REQ_CONFIRM)
3458 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3460 else if (req_state & REQ_PLAYER)
3462 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3463 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3464 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3465 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3470 DrawEnvelopeRequest(text);
3472 DrawEnvelopeRequest(text_copy);
3475 if (game_status != GAME_MODE_MAIN)
3479 /* force DOOR font inside door area */
3480 game_status = GAME_MODE_PSEUDO_DOOR;
3483 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3485 if (action == ACTION_OPENING)
3487 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3489 if (anim_mode == ANIM_DEFAULT)
3490 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3492 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3496 Delay(wait_delay_value);
3498 WaitForEventToContinue();
3503 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3505 if (anim_mode != ANIM_NONE)
3506 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3508 if (anim_mode == ANIM_DEFAULT)
3509 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3512 game.envelope_active = FALSE;
3515 // game_status = last_game_status; /* restore current game status */
3518 /* !!! CHECK AGAIN (SEE BELOW) !!! */
3519 game_status = last_game_status; /* restore current game status */
3522 if (action == ACTION_CLOSING)
3524 if (game_status != GAME_MODE_MAIN)
3527 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3530 SetDrawtoField(DRAW_BUFFERED);
3533 // SetDrawBackgroundMask(last_draw_background_mask);
3536 redraw_mask = REDRAW_FIELD;
3537 // redraw_mask |= REDRAW_ALL;
3539 /* CHECK AGAIN (previous code reactivated) */
3540 redraw_mask |= REDRAW_FIELD;
3544 if (game_status == GAME_MODE_MAIN)
3550 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3551 game_status = last_game_status; /* restore current game status */
3555 if (action == ACTION_CLOSING &&
3556 game_status == GAME_MODE_PLAYING &&
3557 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3558 SetDrawtoField(DRAW_BUFFERED);
3560 if (game_status == GAME_MODE_PLAYING &&
3561 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3562 SetDrawtoField(DRAW_BUFFERED);
3574 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3578 int graphic = el2preimg(element);
3580 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3581 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3584 void DrawLevel(int draw_background_mask)
3589 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3590 SetDrawBackgroundMask(draw_background_mask);
3593 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3594 SetDrawBackgroundMask(REDRAW_FIELD);
3596 SetDrawBackgroundMask(REDRAW_NONE);
3602 for (x = BX1; x <= BX2; x++)
3603 for (y = BY1; y <= BY2; y++)
3604 DrawScreenField(x, y);
3606 redraw_mask |= REDRAW_FIELD;
3609 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3613 for (x = 0; x < size_x; x++)
3614 for (y = 0; y < size_y; y++)
3615 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3617 redraw_mask |= REDRAW_FIELD;
3620 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3622 boolean show_level_border = (BorderElement != EL_EMPTY);
3623 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3624 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3625 int tile_size = preview.tile_size;
3626 int preview_width = preview.xsize * tile_size;
3627 int preview_height = preview.ysize * tile_size;
3628 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3629 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3630 int real_preview_width = real_preview_xsize * tile_size;
3631 int real_preview_height = real_preview_ysize * tile_size;
3632 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3633 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3637 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3642 dst_x += (preview_width - real_preview_width) / 2;
3643 dst_y += (preview_height - real_preview_height) / 2;
3645 DrawBackground(dst_x, dst_y, real_preview_width, real_preview_height);
3647 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3649 dst_x += (preview_width - real_preview_width) / 2;
3650 dst_y += (preview_height - real_preview_height) / 2;
3653 for (x = 0; x < real_preview_xsize; x++)
3655 for (y = 0; y < real_preview_ysize; y++)
3657 int lx = from_x + x + (show_level_border ? -1 : 0);
3658 int ly = from_y + y + (show_level_border ? -1 : 0);
3659 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3660 getBorderElement(lx, ly));
3662 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3663 element, tile_size);
3667 redraw_mask |= REDRAW_MICROLEVEL;
3670 #define MICROLABEL_EMPTY 0
3671 #define MICROLABEL_LEVEL_NAME 1
3672 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3673 #define MICROLABEL_LEVEL_AUTHOR 3
3674 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3675 #define MICROLABEL_IMPORTED_FROM 5
3676 #define MICROLABEL_IMPORTED_BY_HEAD 6
3677 #define MICROLABEL_IMPORTED_BY 7
3679 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3681 int max_text_width = SXSIZE;
3682 int font_width = getFontWidth(font_nr);
3684 if (pos->align == ALIGN_CENTER)
3685 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3686 else if (pos->align == ALIGN_RIGHT)
3687 max_text_width = pos->x;
3689 max_text_width = SXSIZE - pos->x;
3691 return max_text_width / font_width;
3694 static void DrawPreviewLevelLabelExt(int mode)
3696 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3697 char label_text[MAX_OUTPUT_LINESIZE + 1];
3698 int max_len_label_text;
3700 int font_nr = pos->font;
3703 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3706 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3707 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3708 mode == MICROLABEL_IMPORTED_BY_HEAD)
3709 font_nr = pos->font_alt;
3711 int font_nr = FONT_TEXT_2;
3714 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3715 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3716 mode == MICROLABEL_IMPORTED_BY_HEAD)
3717 font_nr = FONT_TEXT_3;
3721 max_len_label_text = getMaxTextLength(pos, font_nr);
3723 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3727 if (pos->size != -1)
3728 max_len_label_text = pos->size;
3731 for (i = 0; i < max_len_label_text; i++)
3732 label_text[i] = ' ';
3733 label_text[max_len_label_text] = '\0';
3735 if (strlen(label_text) > 0)
3738 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3740 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3741 int lypos = MICROLABEL2_YPOS;
3743 DrawText(lxpos, lypos, label_text, font_nr);
3748 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3749 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3750 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3751 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3752 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3753 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3754 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3755 max_len_label_text);
3756 label_text[max_len_label_text] = '\0';
3758 if (strlen(label_text) > 0)
3761 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3763 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3764 int lypos = MICROLABEL2_YPOS;
3766 DrawText(lxpos, lypos, label_text, font_nr);
3770 redraw_mask |= REDRAW_MICROLEVEL;
3773 static void DrawPreviewLevelExt(boolean restart)
3775 static unsigned int scroll_delay = 0;
3776 static unsigned int label_delay = 0;
3777 static int from_x, from_y, scroll_direction;
3778 static int label_state, label_counter;
3779 unsigned int scroll_delay_value = preview.step_delay;
3780 boolean show_level_border = (BorderElement != EL_EMPTY);
3781 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3782 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3783 int last_game_status = game_status; /* save current game status */
3786 /* force PREVIEW font on preview level */
3787 game_status = GAME_MODE_PSEUDO_PREVIEW;
3795 if (preview.anim_mode == ANIM_CENTERED)
3797 if (level_xsize > preview.xsize)
3798 from_x = (level_xsize - preview.xsize) / 2;
3799 if (level_ysize > preview.ysize)
3800 from_y = (level_ysize - preview.ysize) / 2;
3803 from_x += preview.xoffset;
3804 from_y += preview.yoffset;
3806 scroll_direction = MV_RIGHT;
3810 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3811 DrawPreviewLevelLabelExt(label_state);
3813 /* initialize delay counters */
3814 DelayReached(&scroll_delay, 0);
3815 DelayReached(&label_delay, 0);
3817 if (leveldir_current->name)
3819 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3820 char label_text[MAX_OUTPUT_LINESIZE + 1];
3822 int font_nr = pos->font;
3824 int font_nr = FONT_TEXT_1;
3827 int max_len_label_text = getMaxTextLength(pos, font_nr);
3829 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3837 if (pos->size != -1)
3838 max_len_label_text = pos->size;
3841 strncpy(label_text, leveldir_current->name, max_len_label_text);
3842 label_text[max_len_label_text] = '\0';
3845 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3846 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3848 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3849 lypos = SY + MICROLABEL1_YPOS;
3851 DrawText(lxpos, lypos, label_text, font_nr);
3855 game_status = last_game_status; /* restore current game status */
3860 /* scroll preview level, if needed */
3861 if (preview.anim_mode != ANIM_NONE &&
3862 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3863 DelayReached(&scroll_delay, scroll_delay_value))
3865 switch (scroll_direction)
3870 from_x -= preview.step_offset;
3871 from_x = (from_x < 0 ? 0 : from_x);
3874 scroll_direction = MV_UP;
3878 if (from_x < level_xsize - preview.xsize)
3880 from_x += preview.step_offset;
3881 from_x = (from_x > level_xsize - preview.xsize ?
3882 level_xsize - preview.xsize : from_x);
3885 scroll_direction = MV_DOWN;
3891 from_y -= preview.step_offset;
3892 from_y = (from_y < 0 ? 0 : from_y);
3895 scroll_direction = MV_RIGHT;
3899 if (from_y < level_ysize - preview.ysize)
3901 from_y += preview.step_offset;
3902 from_y = (from_y > level_ysize - preview.ysize ?
3903 level_ysize - preview.ysize : from_y);
3906 scroll_direction = MV_LEFT;
3913 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3916 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3917 /* redraw micro level label, if needed */
3918 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3919 !strEqual(level.author, ANONYMOUS_NAME) &&
3920 !strEqual(level.author, leveldir_current->name) &&
3921 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3923 int max_label_counter = 23;
3925 if (leveldir_current->imported_from != NULL &&
3926 strlen(leveldir_current->imported_from) > 0)
3927 max_label_counter += 14;
3928 if (leveldir_current->imported_by != NULL &&
3929 strlen(leveldir_current->imported_by) > 0)
3930 max_label_counter += 14;
3932 label_counter = (label_counter + 1) % max_label_counter;
3933 label_state = (label_counter >= 0 && label_counter <= 7 ?
3934 MICROLABEL_LEVEL_NAME :
3935 label_counter >= 9 && label_counter <= 12 ?
3936 MICROLABEL_LEVEL_AUTHOR_HEAD :
3937 label_counter >= 14 && label_counter <= 21 ?
3938 MICROLABEL_LEVEL_AUTHOR :
3939 label_counter >= 23 && label_counter <= 26 ?
3940 MICROLABEL_IMPORTED_FROM_HEAD :
3941 label_counter >= 28 && label_counter <= 35 ?
3942 MICROLABEL_IMPORTED_FROM :
3943 label_counter >= 37 && label_counter <= 40 ?
3944 MICROLABEL_IMPORTED_BY_HEAD :
3945 label_counter >= 42 && label_counter <= 49 ?
3946 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3948 if (leveldir_current->imported_from == NULL &&
3949 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3950 label_state == MICROLABEL_IMPORTED_FROM))
3951 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3952 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3954 DrawPreviewLevelLabelExt(label_state);
3957 game_status = last_game_status; /* restore current game status */
3960 void DrawPreviewLevelInitial()
3962 DrawPreviewLevelExt(TRUE);
3965 void DrawPreviewLevelAnimation()
3967 DrawPreviewLevelExt(FALSE);
3970 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3971 int graphic, int sync_frame, int mask_mode)
3973 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3975 if (mask_mode == USE_MASKING)
3976 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3978 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3981 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3982 int graphic, int sync_frame,
3985 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3987 if (mask_mode == USE_MASKING)
3988 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3990 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3993 inline void DrawGraphicAnimation(int x, int y, int graphic)
3995 int lx = LEVELX(x), ly = LEVELY(y);
3997 if (!IN_SCR_FIELD(x, y))
4001 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
4002 graphic, GfxFrame[lx][ly], NO_MASKING);
4004 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
4005 graphic, GfxFrame[lx][ly], NO_MASKING);
4007 MarkTileDirty(x, y);
4010 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
4012 int lx = LEVELX(x), ly = LEVELY(y);
4014 if (!IN_SCR_FIELD(x, y))
4017 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
4018 graphic, GfxFrame[lx][ly], NO_MASKING);
4019 MarkTileDirty(x, y);
4022 void DrawLevelGraphicAnimation(int x, int y, int graphic)
4024 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4027 void DrawLevelElementAnimation(int x, int y, int element)
4029 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
4031 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4034 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
4036 int sx = SCREENX(x), sy = SCREENY(y);
4038 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
4041 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
4044 DrawGraphicAnimation(sx, sy, graphic);
4047 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
4048 DrawLevelFieldCrumbled(x, y);
4050 if (GFX_CRUMBLED(Feld[x][y]))
4051 DrawLevelFieldCrumbled(x, y);
4055 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
4057 int sx = SCREENX(x), sy = SCREENY(y);
4060 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
4063 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
4065 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
4068 DrawGraphicAnimation(sx, sy, graphic);
4070 if (GFX_CRUMBLED(element))
4071 DrawLevelFieldCrumbled(x, y);
4074 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
4076 if (player->use_murphy)
4078 /* this works only because currently only one player can be "murphy" ... */
4079 static int last_horizontal_dir = MV_LEFT;
4080 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
4082 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4083 last_horizontal_dir = move_dir;
4085 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
4087 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
4089 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
4095 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
4098 static boolean equalGraphics(int graphic1, int graphic2)
4100 struct GraphicInfo *g1 = &graphic_info[graphic1];
4101 struct GraphicInfo *g2 = &graphic_info[graphic2];
4103 return (g1->bitmap == g2->bitmap &&
4104 g1->src_x == g2->src_x &&
4105 g1->src_y == g2->src_y &&
4106 g1->anim_frames == g2->anim_frames &&
4107 g1->anim_delay == g2->anim_delay &&
4108 g1->anim_mode == g2->anim_mode);
4111 void DrawAllPlayers()
4115 for (i = 0; i < MAX_PLAYERS; i++)
4116 if (stored_player[i].active)
4117 DrawPlayer(&stored_player[i]);
4120 void DrawPlayerField(int x, int y)
4122 if (!IS_PLAYER(x, y))
4125 DrawPlayer(PLAYERINFO(x, y));
4128 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
4130 void DrawPlayer(struct PlayerInfo *player)
4132 int jx = player->jx;
4133 int jy = player->jy;
4134 int move_dir = player->MovDir;
4135 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
4136 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
4137 int last_jx = (player->is_moving ? jx - dx : jx);
4138 int last_jy = (player->is_moving ? jy - dy : jy);
4139 int next_jx = jx + dx;
4140 int next_jy = jy + dy;
4141 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
4142 boolean player_is_opaque = FALSE;
4143 int sx = SCREENX(jx), sy = SCREENY(jy);
4144 int sxx = 0, syy = 0;
4145 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
4147 int action = ACTION_DEFAULT;
4148 int last_player_graphic = getPlayerGraphic(player, move_dir);
4149 int last_player_frame = player->Frame;
4152 /* GfxElement[][] is set to the element the player is digging or collecting;
4153 remove also for off-screen player if the player is not moving anymore */
4154 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
4155 GfxElement[jx][jy] = EL_UNDEFINED;
4157 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
4161 if (!IN_LEV_FIELD(jx, jy))
4163 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
4164 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
4165 printf("DrawPlayerField(): This should never happen!\n");
4170 if (element == EL_EXPLOSION)
4173 action = (player->is_pushing ? ACTION_PUSHING :
4174 player->is_digging ? ACTION_DIGGING :
4175 player->is_collecting ? ACTION_COLLECTING :
4176 player->is_moving ? ACTION_MOVING :
4177 player->is_snapping ? ACTION_SNAPPING :
4178 player->is_dropping ? ACTION_DROPPING :
4179 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
4181 if (player->is_waiting)
4182 move_dir = player->dir_waiting;
4184 InitPlayerGfxAnimation(player, action, move_dir);
4186 /* ----------------------------------------------------------------------- */
4187 /* draw things in the field the player is leaving, if needed */
4188 /* ----------------------------------------------------------------------- */
4190 if (player->is_moving)
4192 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
4194 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
4196 if (last_element == EL_DYNAMITE_ACTIVE ||
4197 last_element == EL_EM_DYNAMITE_ACTIVE ||
4198 last_element == EL_SP_DISK_RED_ACTIVE)
4199 DrawDynamite(last_jx, last_jy);
4201 DrawLevelFieldThruMask(last_jx, last_jy);
4203 else if (last_element == EL_DYNAMITE_ACTIVE ||
4204 last_element == EL_EM_DYNAMITE_ACTIVE ||
4205 last_element == EL_SP_DISK_RED_ACTIVE)
4206 DrawDynamite(last_jx, last_jy);
4208 /* !!! this is not enough to prevent flickering of players which are
4209 moving next to each others without a free tile between them -- this
4210 can only be solved by drawing all players layer by layer (first the
4211 background, then the foreground etc.) !!! => TODO */
4212 else if (!IS_PLAYER(last_jx, last_jy))
4213 DrawLevelField(last_jx, last_jy);
4216 DrawLevelField(last_jx, last_jy);
4219 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
4220 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4223 if (!IN_SCR_FIELD(sx, sy))
4226 /* ----------------------------------------------------------------------- */
4227 /* draw things behind the player, if needed */
4228 /* ----------------------------------------------------------------------- */
4231 DrawLevelElement(jx, jy, Back[jx][jy]);
4232 else if (IS_ACTIVE_BOMB(element))
4233 DrawLevelElement(jx, jy, EL_EMPTY);
4236 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
4238 int old_element = GfxElement[jx][jy];
4239 int old_graphic = el_act_dir2img(old_element, action, move_dir);
4240 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
4242 if (GFX_CRUMBLED(old_element))
4243 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4245 DrawGraphic(sx, sy, old_graphic, frame);
4247 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4248 player_is_opaque = TRUE;
4252 GfxElement[jx][jy] = EL_UNDEFINED;
4254 /* make sure that pushed elements are drawn with correct frame rate */
4256 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4258 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4259 GfxFrame[jx][jy] = player->StepFrame;
4261 if (player->is_pushing && player->is_moving)
4262 GfxFrame[jx][jy] = player->StepFrame;
4265 DrawLevelField(jx, jy);
4269 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4270 /* ----------------------------------------------------------------------- */
4271 /* draw player himself */
4272 /* ----------------------------------------------------------------------- */
4274 graphic = getPlayerGraphic(player, move_dir);
4276 /* in the case of changed player action or direction, prevent the current
4277 animation frame from being restarted for identical animations */
4278 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4279 player->Frame = last_player_frame;
4281 frame = getGraphicAnimationFrame(graphic, player->Frame);
4285 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4286 sxx = player->GfxPos;
4288 syy = player->GfxPos;
4291 if (!setup.soft_scrolling && ScreenMovPos)
4294 if (player_is_opaque)
4295 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4297 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4299 if (SHIELD_ON(player))
4301 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4302 IMG_SHIELD_NORMAL_ACTIVE);
4303 int frame = getGraphicAnimationFrame(graphic, -1);
4305 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4309 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4312 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4313 sxx = player->GfxPos;
4315 syy = player->GfxPos;
4319 /* ----------------------------------------------------------------------- */
4320 /* draw things the player is pushing, if needed */
4321 /* ----------------------------------------------------------------------- */
4324 printf("::: %d, %d [%d, %d] [%d]\n",
4325 player->is_pushing, player_is_moving, player->GfxAction,
4326 player->is_moving, player_is_moving);
4330 if (player->is_pushing && player->is_moving)
4332 int px = SCREENX(jx), py = SCREENY(jy);
4333 int pxx = (TILEX - ABS(sxx)) * dx;
4334 int pyy = (TILEY - ABS(syy)) * dy;
4335 int gfx_frame = GfxFrame[jx][jy];
4341 if (!IS_MOVING(jx, jy)) /* push movement already finished */
4343 element = Feld[next_jx][next_jy];
4344 gfx_frame = GfxFrame[next_jx][next_jy];
4347 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4350 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4351 frame = getGraphicAnimationFrame(graphic, sync_frame);
4353 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4356 /* draw background element under pushed element (like the Sokoban field) */
4358 if (game.use_masked_pushing && IS_MOVING(jx, jy))
4360 /* this allows transparent pushing animation over non-black background */
4363 DrawLevelElement(jx, jy, Back[jx][jy]);
4365 DrawLevelElement(jx, jy, EL_EMPTY);
4367 if (Back[next_jx][next_jy])
4368 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4370 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4372 else if (Back[next_jx][next_jy])
4373 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4375 if (Back[next_jx][next_jy])
4376 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4380 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4381 jx, px, player->GfxPos, player->StepFrame,
4386 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4390 /* do not draw (EM style) pushing animation when pushing is finished */
4391 /* (two-tile animations usually do not contain start and end frame) */
4392 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4393 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4395 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4397 /* masked drawing is needed for EMC style (double) movement graphics */
4398 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4399 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4404 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4405 /* ----------------------------------------------------------------------- */
4406 /* draw player himself */
4407 /* ----------------------------------------------------------------------- */
4409 graphic = getPlayerGraphic(player, move_dir);
4411 /* in the case of changed player action or direction, prevent the current
4412 animation frame from being restarted for identical animations */
4413 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4414 player->Frame = last_player_frame;
4416 frame = getGraphicAnimationFrame(graphic, player->Frame);
4420 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4421 sxx = player->GfxPos;
4423 syy = player->GfxPos;
4426 if (!setup.soft_scrolling && ScreenMovPos)
4429 if (player_is_opaque)
4430 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4432 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4434 if (SHIELD_ON(player))
4436 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4437 IMG_SHIELD_NORMAL_ACTIVE);
4438 int frame = getGraphicAnimationFrame(graphic, -1);
4440 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4444 /* ----------------------------------------------------------------------- */
4445 /* draw things in front of player (active dynamite or dynabombs) */
4446 /* ----------------------------------------------------------------------- */
4448 if (IS_ACTIVE_BOMB(element))
4450 graphic = el2img(element);
4451 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4453 if (game.emulation == EMU_SUPAPLEX)
4454 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4456 DrawGraphicThruMask(sx, sy, graphic, frame);
4459 if (player_is_moving && last_element == EL_EXPLOSION)
4461 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4462 GfxElement[last_jx][last_jy] : EL_EMPTY);
4463 int graphic = el_act2img(element, ACTION_EXPLODING);
4464 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4465 int phase = ExplodePhase[last_jx][last_jy] - 1;
4466 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4469 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4472 /* ----------------------------------------------------------------------- */
4473 /* draw elements the player is just walking/passing through/under */
4474 /* ----------------------------------------------------------------------- */
4476 if (player_is_moving)
4478 /* handle the field the player is leaving ... */
4479 if (IS_ACCESSIBLE_INSIDE(last_element))
4480 DrawLevelField(last_jx, last_jy);
4481 else if (IS_ACCESSIBLE_UNDER(last_element))
4482 DrawLevelFieldThruMask(last_jx, last_jy);
4485 /* do not redraw accessible elements if the player is just pushing them */
4486 if (!player_is_moving || !player->is_pushing)
4488 /* ... and the field the player is entering */
4489 if (IS_ACCESSIBLE_INSIDE(element))
4490 DrawLevelField(jx, jy);
4491 else if (IS_ACCESSIBLE_UNDER(element))
4492 DrawLevelFieldThruMask(jx, jy);
4495 MarkTileDirty(sx, sy);
4498 /* ------------------------------------------------------------------------- */
4500 void WaitForEventToContinue()
4502 boolean still_wait = TRUE;
4504 /* simulate releasing mouse button over last gadget, if still pressed */
4506 HandleGadgets(-1, -1, 0);
4508 button_status = MB_RELEASED;
4524 case EVENT_BUTTONPRESS:
4525 case EVENT_KEYPRESS:
4529 case EVENT_KEYRELEASE:
4530 ClearPlayerAction();
4534 HandleOtherEvents(&event);
4538 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4545 /* don't eat all CPU time */
4550 #define MAX_REQUEST_LINES 13
4551 #define MAX_REQUEST_LINE_FONT1_LEN 7
4552 #define MAX_REQUEST_LINE_FONT2_LEN 10
4556 static int RequestHandleEvents(unsigned int req_state)
4558 int last_game_status = game_status; /* save current game status */
4562 button_status = MB_RELEASED;
4564 request_gadget_id = -1;
4577 case EVENT_BUTTONPRESS:
4578 case EVENT_BUTTONRELEASE:
4579 case EVENT_MOTIONNOTIFY:
4581 if (event.type == EVENT_MOTIONNOTIFY)
4583 if (!PointerInWindow(window))
4584 continue; /* window and pointer are on different screens */
4589 motion_status = TRUE;
4590 mx = ((MotionEvent *) &event)->x;
4591 my = ((MotionEvent *) &event)->y;
4595 motion_status = FALSE;
4596 mx = ((ButtonEvent *) &event)->x;
4597 my = ((ButtonEvent *) &event)->y;
4598 if (event.type == EVENT_BUTTONPRESS)
4599 button_status = ((ButtonEvent *) &event)->button;
4601 button_status = MB_RELEASED;
4604 /* this sets 'request_gadget_id' */
4605 HandleGadgets(mx, my, button_status);
4607 switch (request_gadget_id)
4609 case TOOL_CTRL_ID_YES:
4612 case TOOL_CTRL_ID_NO:
4615 case TOOL_CTRL_ID_CONFIRM:
4616 result = TRUE | FALSE;
4619 case TOOL_CTRL_ID_PLAYER_1:
4622 case TOOL_CTRL_ID_PLAYER_2:
4625 case TOOL_CTRL_ID_PLAYER_3:
4628 case TOOL_CTRL_ID_PLAYER_4:
4639 case EVENT_KEYPRESS:
4640 switch (GetEventKey((KeyEvent *)&event, TRUE))
4643 if (req_state & REQ_CONFIRM)
4648 #if defined(TARGET_SDL2)
4655 #if defined(TARGET_SDL2)
4665 if (req_state & REQ_PLAYER)
4669 case EVENT_KEYRELEASE:
4670 ClearPlayerAction();
4674 HandleOtherEvents(&event);
4678 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4680 int joy = AnyJoystick();
4682 if (joy & JOY_BUTTON_1)
4684 else if (joy & JOY_BUTTON_2)
4690 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4692 HandleGameActions();
4698 if (!PendingEvent()) /* delay only if no pending events */
4703 game_status = GAME_MODE_PSEUDO_DOOR;
4709 game_status = last_game_status; /* restore current game status */
4717 if (!PendingEvent()) /* delay only if no pending events */
4720 /* don't eat all CPU time */
4730 static boolean RequestDoor(char *text, unsigned int req_state)
4732 unsigned int old_door_state;
4733 int last_game_status = game_status; /* save current game status */
4734 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4735 int font_nr = FONT_TEXT_2;
4740 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4742 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4743 font_nr = FONT_TEXT_1;
4746 if (game_status == GAME_MODE_PLAYING)
4749 BlitScreenToBitmap(backbuffer);
4751 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4752 BlitScreenToBitmap_EM(backbuffer);
4753 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4754 BlitScreenToBitmap_SP(backbuffer);
4758 /* disable deactivated drawing when quick-loading level tape recording */
4759 if (tape.playing && tape.deactivate_display)
4760 TapeDeactivateDisplayOff(TRUE);
4762 SetMouseCursor(CURSOR_DEFAULT);
4764 #if defined(NETWORK_AVALIABLE)
4765 /* pause network game while waiting for request to answer */
4766 if (options.network &&
4767 game_status == GAME_MODE_PLAYING &&
4768 req_state & REQUEST_WAIT_FOR_INPUT)
4769 SendToServer_PausePlaying();
4772 old_door_state = GetDoorState();
4774 /* simulate releasing mouse button over last gadget, if still pressed */
4776 HandleGadgets(-1, -1, 0);
4780 /* draw released gadget before proceeding */
4783 if (old_door_state & DOOR_OPEN_1)
4785 CloseDoor(DOOR_CLOSE_1);
4787 /* save old door content */
4789 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4790 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4792 BlitBitmap(bitmap_db_door, bitmap_db_door,
4793 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4794 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4798 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4799 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4801 /* clear door drawing field */
4802 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4804 /* force DOOR font inside door area */
4805 game_status = GAME_MODE_PSEUDO_DOOR;
4807 /* write text for request */
4808 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4810 char text_line[max_request_line_len + 1];
4816 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4818 tc = *(text_ptr + tx);
4819 // if (!tc || tc == ' ')
4820 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4824 if ((tc == '?' || tc == '!') && tl == 0)
4834 strncpy(text_line, text_ptr, tl);
4837 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4838 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4839 text_line, font_nr);
4841 text_ptr += tl + (tc == ' ' ? 1 : 0);
4842 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4845 game_status = last_game_status; /* restore current game status */
4847 if (req_state & REQ_ASK)
4849 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4850 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4852 else if (req_state & REQ_CONFIRM)
4854 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4856 else if (req_state & REQ_PLAYER)
4858 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4859 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4860 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4861 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4864 /* copy request gadgets to door backbuffer */
4866 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4868 BlitBitmap(drawto, bitmap_db_door,
4869 DX, DY, DXSIZE, DYSIZE,
4870 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4873 OpenDoor(DOOR_OPEN_1);
4875 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4877 if (game_status == GAME_MODE_PLAYING)
4879 SetPanelBackground();
4880 SetDrawBackgroundMask(REDRAW_DOOR_1);
4884 SetDrawBackgroundMask(REDRAW_FIELD);
4890 if (game_status != GAME_MODE_MAIN)
4893 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4895 // ---------- handle request buttons ----------
4896 result = RequestHandleEvents(req_state);
4898 if (game_status != GAME_MODE_MAIN)
4903 if (!(req_state & REQ_STAY_OPEN))
4905 CloseDoor(DOOR_CLOSE_1);
4907 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4908 (req_state & REQ_REOPEN))
4909 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4914 if (game_status == GAME_MODE_PLAYING)
4916 SetPanelBackground();
4917 SetDrawBackgroundMask(REDRAW_DOOR_1);
4921 SetDrawBackgroundMask(REDRAW_FIELD);
4924 #if defined(NETWORK_AVALIABLE)
4925 /* continue network game after request */
4926 if (options.network &&
4927 game_status == GAME_MODE_PLAYING &&
4928 req_state & REQUEST_WAIT_FOR_INPUT)
4929 SendToServer_ContinuePlaying();
4932 /* restore deactivated drawing when quick-loading level tape recording */
4933 if (tape.playing && tape.deactivate_display)
4934 TapeDeactivateDisplayOn();
4939 static boolean RequestEnvelope(char *text, unsigned int req_state)
4946 if (game_status == GAME_MODE_PLAYING)
4950 BlitScreenToBitmap(backbuffer);
4952 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4953 BlitScreenToBitmap_EM(backbuffer);
4954 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4955 BlitScreenToBitmap_SP(backbuffer);
4957 BlitScreenToBitmap_RND(backbuffer);
4960 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4961 BlitScreenToBitmap_EM(backbuffer);
4962 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4963 BlitScreenToBitmap_SP(backbuffer);
4967 /* disable deactivated drawing when quick-loading level tape recording */
4968 if (tape.playing && tape.deactivate_display)
4969 TapeDeactivateDisplayOff(TRUE);
4971 SetMouseCursor(CURSOR_DEFAULT);
4973 #if defined(NETWORK_AVALIABLE)
4974 /* pause network game while waiting for request to answer */
4975 if (options.network &&
4976 game_status == GAME_MODE_PLAYING &&
4977 req_state & REQUEST_WAIT_FOR_INPUT)
4978 SendToServer_PausePlaying();
4981 /* simulate releasing mouse button over last gadget, if still pressed */
4983 HandleGadgets(-1, -1, 0);
4987 // (replace with setting corresponding request background)
4988 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4989 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4991 /* clear door drawing field */
4992 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4995 if (global.use_envelope_request)
4999 CreateToolButtons();
5005 if (req_state & REQ_ASK)
5007 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
5008 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
5010 else if (req_state & REQ_CONFIRM)
5012 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
5014 else if (req_state & REQ_PLAYER)
5016 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
5017 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
5018 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
5019 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
5022 if (req_state & REQ_ASK)
5024 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5025 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5027 else if (req_state & REQ_CONFIRM)
5029 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5031 else if (req_state & REQ_PLAYER)
5033 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5034 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5035 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5036 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5041 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
5044 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5046 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5047 i == TOOL_CTRL_ID_NO)) ||
5048 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5049 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5050 i == TOOL_CTRL_ID_PLAYER_2 &&
5051 i == TOOL_CTRL_ID_PLAYER_3 &&
5052 i == TOOL_CTRL_ID_PLAYER_4)))
5054 int x = tool_gadget[i]->x + dDX;
5055 int y = tool_gadget[i]->y + dDY;
5057 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5062 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5064 if (game_status == GAME_MODE_PLAYING)
5066 SetPanelBackground();
5067 SetDrawBackgroundMask(REDRAW_DOOR_1);
5071 SetDrawBackgroundMask(REDRAW_FIELD);
5078 if (game_status != GAME_MODE_MAIN)
5082 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5084 // ---------- handle request buttons ----------
5085 result = RequestHandleEvents(req_state);
5087 if (game_status != GAME_MODE_MAIN)
5092 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
5096 if (game_status == GAME_MODE_PLAYING)
5098 SetPanelBackground();
5099 SetDrawBackgroundMask(REDRAW_DOOR_1);
5103 SetDrawBackgroundMask(REDRAW_FIELD);
5106 #if defined(NETWORK_AVALIABLE)
5107 /* continue network game after request */
5108 if (options.network &&
5109 game_status == GAME_MODE_PLAYING &&
5110 req_state & REQUEST_WAIT_FOR_INPUT)
5111 SendToServer_ContinuePlaying();
5114 /* restore deactivated drawing when quick-loading level tape recording */
5115 if (tape.playing && tape.deactivate_display)
5116 TapeDeactivateDisplayOn();
5121 boolean Request(char *text, unsigned int req_state)
5123 if (global.use_envelope_request)
5124 return RequestEnvelope(text, req_state);
5126 return RequestDoor(text, req_state);
5129 #else // =====================================================================
5131 boolean Request(char *text, unsigned int req_state)
5133 int mx, my, ty, result = -1;
5134 unsigned int old_door_state;
5135 int last_game_status = game_status; /* save current game status */
5136 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
5137 int font_nr = FONT_TEXT_2;
5139 int max_word_len = 0;
5145 global.use_envelope_request = 1;
5149 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
5151 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5152 font_nr = FONT_TEXT_1;
5155 for (text_ptr = text; *text_ptr; text_ptr++)
5157 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
5159 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
5161 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5163 font_nr = FONT_TEXT_1;
5165 font_nr = FONT_LEVEL_NUMBER;
5173 if (game_status == GAME_MODE_PLAYING)
5176 BlitScreenToBitmap(backbuffer);
5178 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5179 BlitScreenToBitmap_EM(backbuffer);
5180 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
5181 BlitScreenToBitmap_SP(backbuffer);
5185 /* disable deactivated drawing when quick-loading level tape recording */
5186 if (tape.playing && tape.deactivate_display)
5187 TapeDeactivateDisplayOff(TRUE);
5189 SetMouseCursor(CURSOR_DEFAULT);
5191 #if defined(NETWORK_AVALIABLE)
5192 /* pause network game while waiting for request to answer */
5193 if (options.network &&
5194 game_status == GAME_MODE_PLAYING &&
5195 req_state & REQUEST_WAIT_FOR_INPUT)
5196 SendToServer_PausePlaying();
5199 old_door_state = GetDoorState();
5201 /* simulate releasing mouse button over last gadget, if still pressed */
5203 HandleGadgets(-1, -1, 0);
5207 /* draw released gadget before proceeding */
5211 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
5213 if (old_door_state & DOOR_OPEN_1)
5217 if (!global.use_envelope_request)
5218 CloseDoor(DOOR_CLOSE_1);
5220 CloseDoor(DOOR_CLOSE_1);
5223 /* save old door content */
5224 BlitBitmap(bitmap_db_door, bitmap_db_door,
5225 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5226 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
5230 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
5233 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5235 /* clear door drawing field */
5236 DrawBackground(DX, DY, DXSIZE, DYSIZE);
5238 /* force DOOR font inside door area */
5239 game_status = GAME_MODE_PSEUDO_DOOR;
5241 /* write text for request */
5242 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
5244 char text_line[max_request_line_len + 1];
5250 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
5252 tc = *(text_ptr + tx);
5253 if (!tc || tc == ' ')
5264 strncpy(text_line, text_ptr, tl);
5267 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5268 DY + 8 + ty * (getFontHeight(font_nr) + 2),
5269 text_line, font_nr);
5271 text_ptr += tl + (tc == ' ' ? 1 : 0);
5274 game_status = last_game_status; /* restore current game status */
5277 if (global.use_envelope_request)
5281 CreateToolButtons();
5285 if (req_state & REQ_ASK)
5287 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5288 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5290 else if (req_state & REQ_CONFIRM)
5292 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5294 else if (req_state & REQ_PLAYER)
5296 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5297 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5298 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5299 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5302 /* copy request gadgets to door backbuffer */
5303 BlitBitmap(drawto, bitmap_db_door,
5304 DX, DY, DXSIZE, DYSIZE,
5305 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5308 if (global.use_envelope_request)
5310 ShowEnvelopeRequest(text, ACTION_OPENING);
5312 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5314 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5315 i == TOOL_CTRL_ID_NO)) ||
5316 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5317 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5318 i == TOOL_CTRL_ID_PLAYER_2 &&
5319 i == TOOL_CTRL_ID_PLAYER_3 &&
5320 i == TOOL_CTRL_ID_PLAYER_4)))
5322 int x = tool_gadget[i]->x + dDX;
5323 int y = tool_gadget[i]->y + dDY;
5325 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5332 if (!global.use_envelope_request)
5333 OpenDoor(DOOR_OPEN_1);
5335 OpenDoor(DOOR_OPEN_1);
5338 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5340 if (game_status == GAME_MODE_PLAYING)
5342 SetPanelBackground();
5343 SetDrawBackgroundMask(REDRAW_DOOR_1);
5347 SetDrawBackgroundMask(REDRAW_FIELD);
5354 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5357 if (game_status != GAME_MODE_MAIN)
5361 button_status = MB_RELEASED;
5363 request_gadget_id = -1;
5365 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5377 case EVENT_BUTTONPRESS:
5378 case EVENT_BUTTONRELEASE:
5379 case EVENT_MOTIONNOTIFY:
5381 if (event.type == EVENT_MOTIONNOTIFY)
5383 if (!PointerInWindow(window))
5384 continue; /* window and pointer are on different screens */
5389 motion_status = TRUE;
5390 mx = ((MotionEvent *) &event)->x;
5391 my = ((MotionEvent *) &event)->y;
5395 motion_status = FALSE;
5396 mx = ((ButtonEvent *) &event)->x;
5397 my = ((ButtonEvent *) &event)->y;
5398 if (event.type == EVENT_BUTTONPRESS)
5399 button_status = ((ButtonEvent *) &event)->button;
5401 button_status = MB_RELEASED;
5404 /* this sets 'request_gadget_id' */
5405 HandleGadgets(mx, my, button_status);
5407 switch (request_gadget_id)
5409 case TOOL_CTRL_ID_YES:
5412 case TOOL_CTRL_ID_NO:
5415 case TOOL_CTRL_ID_CONFIRM:
5416 result = TRUE | FALSE;
5419 case TOOL_CTRL_ID_PLAYER_1:
5422 case TOOL_CTRL_ID_PLAYER_2:
5425 case TOOL_CTRL_ID_PLAYER_3:
5428 case TOOL_CTRL_ID_PLAYER_4:
5439 case EVENT_KEYPRESS:
5440 switch (GetEventKey((KeyEvent *)&event, TRUE))
5443 if (req_state & REQ_CONFIRM)
5452 #if defined(TARGET_SDL2)
5462 if (req_state & REQ_PLAYER)
5466 case EVENT_KEYRELEASE:
5467 ClearPlayerAction();
5471 HandleOtherEvents(&event);
5475 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5477 int joy = AnyJoystick();
5479 if (joy & JOY_BUTTON_1)
5481 else if (joy & JOY_BUTTON_2)
5487 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5489 HandleGameActions();
5495 if (!PendingEvent()) /* delay only if no pending events */
5500 game_status = GAME_MODE_PSEUDO_DOOR;
5506 game_status = last_game_status; /* restore current game status */
5514 if (!PendingEvent()) /* delay only if no pending events */
5517 /* don't eat all CPU time */
5524 if (game_status != GAME_MODE_MAIN)
5530 if (global.use_envelope_request)
5531 ShowEnvelopeRequest(text, ACTION_CLOSING);
5535 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5537 if (!(req_state & REQ_STAY_OPEN))
5540 CloseDoor(DOOR_CLOSE_1);
5542 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5543 (req_state & REQ_REOPEN))
5544 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5549 if (game_status == GAME_MODE_PLAYING)
5551 SetPanelBackground();
5552 SetDrawBackgroundMask(REDRAW_DOOR_1);
5556 SetDrawBackgroundMask(REDRAW_FIELD);
5559 #if defined(NETWORK_AVALIABLE)
5560 /* continue network game after request */
5561 if (options.network &&
5562 game_status == GAME_MODE_PLAYING &&
5563 req_state & REQUEST_WAIT_FOR_INPUT)
5564 SendToServer_ContinuePlaying();
5567 /* restore deactivated drawing when quick-loading level tape recording */
5568 if (tape.playing && tape.deactivate_display)
5569 TapeDeactivateDisplayOn();
5576 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5578 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5579 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5582 if (dpo1->sort_priority != dpo2->sort_priority)
5583 compare_result = dpo1->sort_priority - dpo2->sort_priority;
5585 compare_result = dpo1->nr - dpo2->nr;
5587 return compare_result;
5590 void InitGraphicCompatibilityInfo_Doors()
5596 struct DoorInfo *door;
5600 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
5601 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
5603 { -1, -1, -1, NULL }
5605 struct Rect door_rect_list[] =
5607 { DX, DY, DXSIZE, DYSIZE },
5608 { VX, VY, VXSIZE, VYSIZE }
5612 for (i = 0; doors[i].door_token != -1; i++)
5614 int door_token = doors[i].door_token;
5615 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5616 int part_1 = doors[i].part_1;
5617 int part_8 = doors[i].part_8;
5618 int part_2 = part_1 + 1;
5619 int part_3 = part_1 + 2;
5620 struct DoorInfo *door = doors[i].door;
5621 struct Rect *door_rect = &door_rect_list[door_index];
5622 boolean door_gfx_redefined = FALSE;
5624 /* check if any door part graphic definitions have been redefined */
5626 for (j = 0; door_part_controls[j].door_token != -1; j++)
5628 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5629 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
5631 if (dpc->door_token == door_token && fi->redefined)
5632 door_gfx_redefined = TRUE;
5635 /* check for old-style door graphic/animation modifications */
5637 if (!door_gfx_redefined)
5639 if (door->anim_mode & ANIM_STATIC_PANEL)
5641 door->panel.step_xoffset = 0;
5642 door->panel.step_yoffset = 0;
5645 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
5647 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
5648 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
5649 int num_door_steps, num_panel_steps;
5651 /* remove door part graphics other than the two default wings */
5653 for (j = 0; door_part_controls[j].door_token != -1; j++)
5655 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5656 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5658 if (dpc->graphic >= part_3 &&
5659 dpc->graphic <= part_8)
5663 /* set graphics and screen positions of the default wings */
5665 g_part_1->width = door_rect->width;
5666 g_part_1->height = door_rect->height;
5667 g_part_2->width = door_rect->width;
5668 g_part_2->height = door_rect->height;
5669 g_part_2->src_x = door_rect->width;
5670 g_part_2->src_y = g_part_1->src_y;
5672 door->part_2.x = door->part_1.x;
5673 door->part_2.y = door->part_1.y;
5675 if (door->width != -1)
5677 g_part_1->width = door->width;
5678 g_part_2->width = door->width;
5680 // special treatment for graphics and screen position of right wing
5681 g_part_2->src_x += door_rect->width - door->width;
5682 door->part_2.x += door_rect->width - door->width;
5685 if (door->height != -1)
5687 g_part_1->height = door->height;
5688 g_part_2->height = door->height;
5690 // special treatment for graphics and screen position of bottom wing
5691 g_part_2->src_y += door_rect->height - door->height;
5692 door->part_2.y += door_rect->height - door->height;
5695 /* set animation delays for the default wings and panels */
5697 door->part_1.step_delay = door->step_delay;
5698 door->part_2.step_delay = door->step_delay;
5699 door->panel.step_delay = door->step_delay;
5701 /* set animation draw order for the default wings */
5703 door->part_1.sort_priority = 2; /* draw left wing over ... */
5704 door->part_2.sort_priority = 1; /* ... right wing */
5706 /* set animation draw offset for the default wings */
5708 if (door->anim_mode & ANIM_HORIZONTAL)
5710 door->part_1.step_xoffset = door->step_offset;
5711 door->part_1.step_yoffset = 0;
5712 door->part_2.step_xoffset = door->step_offset * -1;
5713 door->part_2.step_yoffset = 0;
5715 num_door_steps = g_part_1->width / door->step_offset;
5717 else // ANIM_VERTICAL
5719 door->part_1.step_xoffset = 0;
5720 door->part_1.step_yoffset = door->step_offset;
5721 door->part_2.step_xoffset = 0;
5722 door->part_2.step_yoffset = door->step_offset * -1;
5724 num_door_steps = g_part_1->height / door->step_offset;
5727 /* set animation draw offset for the default panels */
5729 if (door->step_offset > 1)
5731 num_panel_steps = 2 * door_rect->height / door->step_offset;
5732 door->panel.start_step = num_panel_steps - num_door_steps;
5736 num_panel_steps = door_rect->height / door->step_offset;
5737 door->panel.start_step = num_panel_steps - num_door_steps / 2;
5738 door->panel.step_delay *= 2;
5749 for (i = 0; door_part_controls[i].door_token != -1; i++)
5751 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5752 struct DoorPartOrderInfo *dpo = &door_part_order[i];
5754 /* initialize "start_step_opening" and "start_step_closing", if needed */
5755 if (dpc->pos->start_step_opening == 0 &&
5756 dpc->pos->start_step_closing == 0)
5758 // dpc->pos->start_step_opening = dpc->pos->start_step;
5759 dpc->pos->start_step_closing = dpc->pos->start_step;
5762 /* fill structure for door part draw order (sorted below) */
5764 dpo->sort_priority = dpc->pos->sort_priority;
5767 struct DoorPartPosInfo *pos = dpc->pos;
5769 printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5770 pos->step_xoffset, pos->step_yoffset);
5774 /* sort door part controls according to sort_priority and graphic number */
5775 qsort(door_part_order, MAX_DOOR_PARTS,
5776 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5779 unsigned int OpenDoor(unsigned int door_state)
5781 if (door_state & DOOR_COPY_BACK)
5784 if (door_state & DOOR_OPEN_1)
5785 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5786 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5788 if (door_state & DOOR_OPEN_2)
5789 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5790 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5792 if (door_state & DOOR_OPEN_1)
5793 BlitBitmap(bitmap_db_door, bitmap_db_door,
5794 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5795 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5797 if (door_state & DOOR_OPEN_2)
5798 BlitBitmap(bitmap_db_door, bitmap_db_door,
5799 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5800 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5803 door_state &= ~DOOR_COPY_BACK;
5806 return MoveDoor(door_state);
5809 unsigned int CloseDoor(unsigned int door_state)
5811 unsigned int old_door_state = GetDoorState();
5813 if (!(door_state & DOOR_NO_COPY_BACK))
5816 if (old_door_state & DOOR_OPEN_1)
5817 BlitBitmap(backbuffer, bitmap_db_door_1,
5818 DX, DY, DXSIZE, DYSIZE, 0, 0);
5820 if (old_door_state & DOOR_OPEN_2)
5821 BlitBitmap(backbuffer, bitmap_db_door_2,
5822 VX, VY, VXSIZE, VYSIZE, 0, 0);
5824 if (old_door_state & DOOR_OPEN_1)
5825 BlitBitmap(backbuffer, bitmap_db_door,
5826 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5828 if (old_door_state & DOOR_OPEN_2)
5829 BlitBitmap(backbuffer, bitmap_db_door,
5830 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5833 door_state &= ~DOOR_NO_COPY_BACK;
5836 return MoveDoor(door_state);
5839 unsigned int GetDoorState()
5841 return MoveDoor(DOOR_GET_STATE);
5844 unsigned int SetDoorState(unsigned int door_state)
5846 return MoveDoor(door_state | DOOR_SET_STATE);
5851 // ========== TEST 1 ===========================================================
5853 int euclid(int a, int b)
5855 return (b ? euclid(b, a % b) : a);
5858 unsigned int MoveDoor(unsigned int door_state)
5861 struct XY panel_pos_list[] =
5863 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5864 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5867 struct Rect door_rect_list[] =
5869 { DX, DY, DXSIZE, DYSIZE },
5870 { VX, VY, VXSIZE, VYSIZE }
5872 static int door1 = DOOR_OPEN_1;
5873 static int door2 = DOOR_CLOSE_2;
5874 unsigned int door_delay = 0;
5875 unsigned int door_delay_value;
5879 if (door_1.width < 0 || door_1.width > DXSIZE)
5880 door_1.width = DXSIZE;
5881 if (door_1.height < 0 || door_1.height > DYSIZE)
5882 door_1.height = DYSIZE;
5883 if (door_2.width < 0 || door_2.width > VXSIZE)
5884 door_2.width = VXSIZE;
5885 if (door_2.height < 0 || door_2.height > VYSIZE)
5886 door_2.height = VYSIZE;
5889 if (door_state == DOOR_GET_STATE)
5890 return (door1 | door2);
5892 if (door_state & DOOR_SET_STATE)
5894 if (door_state & DOOR_ACTION_1)
5895 door1 = door_state & DOOR_ACTION_1;
5896 if (door_state & DOOR_ACTION_2)
5897 door2 = door_state & DOOR_ACTION_2;
5899 return (door1 | door2);
5902 if (!(door_state & DOOR_FORCE_REDRAW))
5904 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5905 door_state &= ~DOOR_OPEN_1;
5906 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5907 door_state &= ~DOOR_CLOSE_1;
5908 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5909 door_state &= ~DOOR_OPEN_2;
5910 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5911 door_state &= ~DOOR_CLOSE_2;
5915 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5918 if (setup.quick_doors)
5920 stepsize = 20; /* must be chosen to always draw last frame */
5921 door_delay_value = 0;
5925 if (global.autoplay_leveldir)
5927 door_state |= DOOR_NO_DELAY;
5928 door_state &= ~DOOR_CLOSE_ALL;
5932 if (game_status == GAME_MODE_EDITOR)
5933 door_state |= DOOR_NO_DELAY;
5936 if (door_state & DOOR_ACTION)
5938 boolean door_panel_drawn[NUM_DOORS];
5939 boolean panel_has_doors[NUM_DOORS];
5940 boolean door_part_skip[MAX_DOOR_PARTS];
5941 boolean door_part_done[MAX_DOOR_PARTS];
5942 boolean door_part_done_all;
5943 int num_steps[MAX_DOOR_PARTS];
5944 int max_move_delay = 0; // delay for complete animations of all doors
5945 int max_step_delay = 0; // delay (ms) between two animation frames
5946 int num_move_steps = 0; // number of animation steps for all doors
5947 int current_move_delay = 0;
5950 for (i = 0; i < NUM_DOORS; i++)
5951 panel_has_doors[i] = FALSE;
5953 for (i = 0; i < MAX_DOOR_PARTS; i++)
5955 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5956 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5957 int door_token = dpc->door_token;
5959 door_part_done[i] = FALSE;
5960 door_part_skip[i] = (!(door_state & door_token) ||
5965 for (i = 0; i < MAX_DOOR_PARTS; i++)
5967 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5968 struct DoorPartPosInfo *pos = dpc->pos;
5969 int start_step = pos->start_step;
5971 printf("::: ---> %d: start_step == %d [%d]\n",
5972 i, start_step, door_part_done[i]);
5976 for (i = 0; i < MAX_DOOR_PARTS; i++)
5978 int nr = door_part_order[i].nr;
5979 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5980 struct DoorPartPosInfo *pos = dpc->pos;
5981 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5982 int door_token = dpc->door_token;
5983 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5984 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5985 int step_xoffset = ABS(pos->step_xoffset);
5986 int step_yoffset = ABS(pos->step_yoffset);
5987 int step_delay = pos->step_delay;
5988 int current_door_state = door_state & door_token;
5989 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5990 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5991 boolean part_opening = (is_panel ? door_closing : door_opening);
5992 int start_step = (part_opening ? pos->start_step_opening :
5993 pos->start_step_closing);
5994 float move_xsize = (step_xoffset ? g->width : 0);
5995 float move_ysize = (step_yoffset ? g->height : 0);
5996 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5997 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5998 int move_steps = (move_xsteps && move_ysteps ?
5999 MIN(move_xsteps, move_ysteps) :
6000 move_xsteps ? move_xsteps : move_ysteps) - start_step;
6001 int move_delay = move_steps * step_delay;
6003 if (door_part_skip[nr])
6007 panel_has_doors[door_index] = TRUE;
6009 max_move_delay = MAX(max_move_delay, move_delay);
6010 max_step_delay = (max_step_delay == 0 ? step_delay :
6011 euclid(max_step_delay, step_delay));
6012 num_steps[nr] = move_steps;
6016 printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
6017 i, move_delay, start_step, door_part_order[i].nr);
6019 if (DOOR_PART_IS_PANEL(i))
6020 printf("::: %d: move_delay == %d, start_step == %d\n",
6021 i, move_delay, start_step);
6026 num_move_steps = max_move_delay / max_step_delay;
6028 door_delay_value = max_step_delay;
6031 door_delay_value *= 10;
6035 printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
6038 for (k = 0; k < num_move_steps; k++)
6040 door_part_done_all = TRUE;
6042 for (i = 0; i < NUM_DOORS; i++)
6043 door_panel_drawn[i] = FALSE;
6045 for (i = 0; i < MAX_DOOR_PARTS; i++)
6047 int nr = door_part_order[i].nr;
6048 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
6049 struct DoorPartPosInfo *pos = dpc->pos;
6050 struct GraphicInfo *g = &graphic_info[dpc->graphic];
6051 int door_token = dpc->door_token;
6052 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
6053 boolean is_panel = DOOR_PART_IS_PANEL(nr);
6055 struct XY *panel_pos = &panel_pos_list[door_index];
6057 struct Rect *door_rect = &door_rect_list[door_index];
6058 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
6060 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
6061 int current_door_state = door_state & door_token;
6062 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
6063 boolean door_closing = !door_opening;
6064 boolean part_opening = (is_panel ? door_closing : door_opening);
6065 boolean part_closing = !part_opening;
6066 int start_step = (part_opening ? pos->start_step_opening :
6067 pos->start_step_closing);
6068 int step_delay = pos->step_delay;
6069 int step_factor = step_delay / max_step_delay;
6070 int k1 = (step_factor ? k / step_factor + 1 : k);
6071 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
6072 int kk = (k2 < 0 ? 0 : k2);
6073 int src_x, src_y, src_xx, src_yy;
6074 int dst_x, dst_y, dst_xx, dst_yy;
6078 if (k == 0 && is_panel && door_token == DOOR_2)
6079 printf("::: %d, %d\n", g->width, g->height);
6083 if (DOOR_PART_IS_PANEL(nr))
6085 int start_step = pos->start_step;
6087 k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
6088 kk = (k2 < 0 ? 0 : k2);
6094 if (nr != 16 && nr != 0)
6105 if (door_part_skip[nr])
6109 if (!(door_state & door_token))
6116 if (current_move_delay % step_delay)
6122 if (!door_panel_drawn[door_index])
6125 ClearRectangle(drawto, door_rect->x, door_rect->y,
6126 door_rect->width, door_rect->height);
6128 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
6129 door_rect->width, door_rect->height,
6130 door_rect->x, door_rect->y);
6133 door_panel_drawn[door_index] = TRUE;
6136 // draw opening or closing door parts
6138 if (pos->step_xoffset < 0) // door part on right side
6141 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
6144 if (dst_xx + width > door_rect->width)
6145 width = door_rect->width - dst_xx;
6147 else // door part on left side
6150 dst_xx = pos->x - kk * pos->step_xoffset;
6154 src_xx = ABS(dst_xx);
6158 width = g->width - src_xx;
6160 // printf("::: k == %d [%d] \n", k, start_step);
6163 if (pos->step_yoffset < 0) // door part on bottom side
6166 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
6169 if (dst_yy + height > door_rect->height)
6170 height = door_rect->height - dst_yy;
6172 else // door part on top side
6175 dst_yy = pos->y - kk * pos->step_yoffset;
6179 src_yy = ABS(dst_yy);
6183 height = g->height - src_yy;
6192 src_x = panel_pos->x + src_xx;
6193 src_y = panel_pos->y + src_yy;
6198 src_x = g->src_x + src_xx;
6199 src_y = g->src_y + src_yy;
6202 dst_x = door_rect->x + dst_xx;
6203 dst_y = door_rect->y + dst_yy;
6206 if (DOOR_PART_IS_PANEL(nr))
6208 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6209 width, height, g->width, g->height, src_x, src_y);
6213 if (width >= 0 && width <= g->width &&
6214 height >= 0 && height <= g->height)
6216 if (is_panel || !pos->draw_masked)
6217 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
6220 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
6225 if (DOOR_PART_IS_PANEL(nr))
6227 bitmap = bitmap_db_door;
6228 src_x = panel_pos->x + src_xx;
6229 src_y = panel_pos->y + src_yy;
6231 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6232 width, height, g->width, g->height, src_x, src_y);
6234 if (width >= 0 && width <= g->width &&
6235 height >= 0 && height <= g->height)
6236 BlitBitmap(bitmap, drawto, src_x, src_y,
6242 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
6245 if ((part_opening && (width < 0 || height < 0)) ||
6246 (part_closing && (width >= g->width && height >= g->height)))
6247 door_part_done[nr] = TRUE;
6249 if ((door_opening && (width < 0 || height < 0)) ||
6250 (door_closing && (width >= g->width && height >= g->height)))
6251 door_part_done[nr] = TRUE;
6255 // continue door part animations, but not panel after door has closed
6256 if (!door_part_done[nr] &&
6257 !(is_panel && door_closing && panel_has_doors[door_index]))
6258 door_part_done_all = FALSE;
6260 // continue door part animations, but not panel after door has closed
6261 if (!door_part_done[nr] && !(is_panel && door_closing))
6262 door_part_done_all = FALSE;
6266 if (!door_part_done[nr])
6267 printf("::: k == %d, nr == %d\n", k, nr);
6271 if (!(door_state & DOOR_NO_DELAY))
6275 if (game_status == GAME_MODE_MAIN)
6278 WaitUntilDelayReached(&door_delay, door_delay_value);
6280 current_move_delay += max_step_delay;
6284 door_part_done_all = TRUE;
6286 for (i = 0; i < MAX_DOOR_PARTS; i++)
6287 if (!door_part_done[i] &&
6288 !(DOOR_PART_IS_PANEL(i) && door_closing))
6289 door_part_done_all = FALSE;
6292 if (door_part_done_all)
6298 if (door_state & DOOR_ACTION_1)
6299 door1 = door_state & DOOR_ACTION_1;
6300 if (door_state & DOOR_ACTION_2)
6301 door2 = door_state & DOOR_ACTION_2;
6304 printf("::: DOORS DONE %08x\n", door_state);
6306 printf("::: GO!\n");
6309 return (door1 | door2);
6314 // ========== OLD ==============================================================
6316 unsigned int MoveDoor(unsigned int door_state)
6318 static int door1 = DOOR_OPEN_1;
6319 static int door2 = DOOR_CLOSE_2;
6320 unsigned int door_delay = 0;
6321 unsigned int door_delay_value;
6325 if (door_1.width < 0 || door_1.width > DXSIZE)
6326 door_1.width = DXSIZE;
6327 if (door_1.height < 0 || door_1.height > DYSIZE)
6328 door_1.height = DYSIZE;
6329 if (door_2.width < 0 || door_2.width > VXSIZE)
6330 door_2.width = VXSIZE;
6331 if (door_2.height < 0 || door_2.height > VYSIZE)
6332 door_2.height = VYSIZE;
6335 if (door_state == DOOR_GET_STATE)
6336 return (door1 | door2);
6338 if (door_state & DOOR_SET_STATE)
6340 if (door_state & DOOR_ACTION_1)
6341 door1 = door_state & DOOR_ACTION_1;
6342 if (door_state & DOOR_ACTION_2)
6343 door2 = door_state & DOOR_ACTION_2;
6345 return (door1 | door2);
6348 if (!(door_state & DOOR_FORCE_REDRAW))
6350 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
6351 door_state &= ~DOOR_OPEN_1;
6352 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
6353 door_state &= ~DOOR_CLOSE_1;
6354 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
6355 door_state &= ~DOOR_OPEN_2;
6356 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
6357 door_state &= ~DOOR_CLOSE_2;
6360 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
6363 // door_delay_value *= 4; // !!! TEST ONLY !!!
6365 if (setup.quick_doors)
6367 stepsize = 20; /* must be chosen to always draw last frame */
6368 door_delay_value = 0;
6371 if (global.autoplay_leveldir)
6373 door_state |= DOOR_NO_DELAY;
6374 door_state &= ~DOOR_CLOSE_ALL;
6378 if (game_status == GAME_MODE_EDITOR)
6379 door_state |= DOOR_NO_DELAY;
6382 if (door_state & DOOR_ACTION)
6385 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6386 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6387 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6388 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6389 int door_1_left_width = g1_left->width;
6390 int door_1_left_height = g1_left->height;
6391 int door_1_right_width = g1_right->width;
6392 int door_1_right_height = g1_right->height;
6393 int door_2_left_width = g2_left->width;
6394 int door_2_left_height = g2_left->height;
6395 int door_2_right_width = g2_right->width;
6396 int door_2_right_height = g2_right->height;
6397 int door_1_width = MAX(door_1_left_width, door_1_right_width);
6398 int door_1_height = MAX(door_1_left_height, door_1_right_height);
6399 int door_2_width = MAX(door_2_left_width, door_2_right_width);
6400 int door_2_height = MAX(door_2_left_height, door_2_right_height);
6402 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
6403 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
6404 boolean door_1_done = (!handle_door_1);
6405 boolean door_2_done = (!handle_door_2);
6406 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
6407 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
6410 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
6411 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
6413 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6414 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6417 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
6418 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
6420 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6421 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6422 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
6423 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
6424 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
6425 int door_skip = max_door_size - door_size;
6426 int end = door_size;
6427 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
6430 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
6432 /* opening door sound has priority over simultaneously closing door */
6433 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
6434 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
6435 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
6436 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
6439 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
6443 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6444 GC gc = bitmap->stored_clip_gc;
6447 if (door_state & DOOR_ACTION_1 &&
6448 x * door_1.step_offset <= door_size_1)
6450 int a = MIN(x * door_1.step_offset, end);
6451 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6455 int i = p + door_skip;
6459 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6460 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6461 Bitmap *bm_left = g_left->bitmap;
6462 Bitmap *bm_right = g_right->bitmap;
6463 GC gc_left = bm_left->stored_clip_gc;
6464 GC gc_right = bm_right->stored_clip_gc;
6467 int classic_dxsize = 100;
6468 int classic_dysize = 280;
6469 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6470 DYSIZE == classic_dysize);
6472 if (door_1.anim_mode & ANIM_STATIC_PANEL)
6474 BlitBitmap(bitmap_db_door, drawto,
6475 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6476 DXSIZE, DYSIZE, DX, DY);
6480 BlitBitmap(bitmap_db_door, drawto,
6481 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6482 DXSIZE, DYSIZE - p / 2, DX, DY);
6485 // printf("::: p == %d\n", p);
6486 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6490 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6493 int src1_x = g_right->src_x;
6494 int src1_y = g_right->src_y;
6495 int src2_x = g_left->src_x + g_left->width - i;
6496 int src2_y = g_left->src_y;
6497 int dst1_x = DX + DXSIZE - i;
6502 int height = DYSIZE;
6504 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6505 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6508 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6509 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6512 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6513 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6514 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6515 int dst2_x = DX, dst2_y = DY;
6516 int width = i, height = DYSIZE;
6518 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6519 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6522 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6523 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6527 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6530 int src1_x = g_right->src_x;
6531 int src1_y = g_right->src_y;
6532 int src2_x = g_left->src_x;
6533 int src2_y = g_left->src_y + g_left->height - i;
6535 int dst1_y = DY + DYSIZE - i;
6541 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6542 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6545 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6546 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6549 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6550 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6551 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
6552 int dst2_x = DX, dst2_y = DY;
6553 int width = DXSIZE, height = i;
6555 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6556 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6559 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6560 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6564 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
6566 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6569 int src1_x = g_right->src_x;
6570 int src1_y = g_right->src_y;
6571 int src2_x = g_left->src_x + g_left->width - i;
6572 int src2_y = g_left->src_y;
6573 int dst1_x = DX + DXSIZE - i;
6578 int height1 = 63, height2 = DYSIZE / 2 - height1;
6579 int ypos1 = 0, ypos2 = height2;
6580 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6582 SetClipOrigin(bm_right, gc_right,
6583 dst1_x - src1_x, dst1_y - src1_y + j);
6584 BlitBitmapMasked(bm_right, drawto,
6585 src1_x, src1_y + ypos1, width, height2,
6586 dst1_x, dst1_y + ypos1 + j);
6587 BlitBitmapMasked(bm_right, drawto,
6588 src1_x, src1_y + ypos3, width, height1,
6589 dst1_x, dst1_y + ypos3 + j);
6590 SetClipOrigin(bm_left, gc_left,
6591 dst2_x - src2_x, dst2_y - src2_y - j);
6592 BlitBitmapMasked(bm_left, drawto,
6593 src2_x, src2_y + ypos1 + j, width, height2 - j,
6594 dst2_x, dst2_y + ypos1);
6595 BlitBitmapMasked(bm_left, drawto,
6596 src2_x, src2_y + ypos3, width, height1,
6597 dst2_x, dst2_y + ypos3 - j);
6599 SetClipOrigin(bm_left, gc_left,
6600 dst2_x - src2_x, dst2_y - src2_y - j);
6601 BlitBitmapMasked(bm_left, drawto,
6602 src2_x, src2_y + ypos2, width, height1,
6603 dst2_x, dst2_y + ypos2 - j);
6604 BlitBitmapMasked(bm_left, drawto,
6605 src2_x, src2_y + ypos4, width, height2,
6606 dst2_x, dst2_y + ypos4 - j);
6607 SetClipOrigin(bm_right, gc_right,
6608 dst1_x - src1_x, dst1_y - src1_y + j);
6609 BlitBitmapMasked(bm_right, drawto,
6610 src1_x, src1_y + ypos2, width, height1,
6611 dst1_x, dst1_y + ypos2 + j);
6612 BlitBitmapMasked(bm_right, drawto,
6613 src1_x, src1_y + ypos4, width, height2 - j,
6614 dst1_x, dst1_y + ypos4 + j);
6617 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6618 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6619 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6620 int dst2_x = DX, dst2_y = DY;
6621 int width = i, height = DYSIZE;
6622 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6624 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6625 BlitBitmapMasked(bitmap, drawto,
6626 src1_x, src1_y, width, ypos2,
6627 dst1_x, dst1_y + j);
6628 BlitBitmapMasked(bitmap, drawto,
6629 src1_x, src1_y + ypos3, width, ypos1,
6630 dst1_x, dst1_y + ypos3 + j);
6631 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6632 BlitBitmapMasked(bitmap, drawto,
6633 src2_x, src2_y + j, width, ypos2 - j,
6635 BlitBitmapMasked(bitmap, drawto,
6636 src2_x, src2_y + ypos3, width, ypos1,
6637 dst2_x, dst2_y + ypos3 - j);
6639 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6640 BlitBitmapMasked(bitmap, drawto,
6641 src2_x, src2_y + ypos2, width, ypos1,
6642 dst2_x, dst2_y + ypos2 - j);
6643 BlitBitmapMasked(bitmap, drawto,
6644 src2_x, src2_y + ypos4, width, ypos2,
6645 dst2_x, dst2_y + ypos4 - j);
6646 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6647 BlitBitmapMasked(bitmap, drawto,
6648 src1_x, src1_y + ypos2, width, ypos1,
6649 dst1_x, dst1_y + ypos2 + j);
6650 BlitBitmapMasked(bitmap, drawto,
6651 src1_x, src1_y + ypos4, width, ypos2 - j,
6652 dst1_x, dst1_y + ypos4 + j);
6655 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6656 BlitBitmapMasked(bitmap, drawto,
6657 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6658 DX + DXSIZE - i, DY + j);
6659 BlitBitmapMasked(bitmap, drawto,
6660 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6661 DX + DXSIZE - i, DY + 140 + j);
6662 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6663 DY - (DOOR_GFX_PAGEY1 + j));
6664 BlitBitmapMasked(bitmap, drawto,
6665 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6667 BlitBitmapMasked(bitmap, drawto,
6668 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6671 BlitBitmapMasked(bitmap, drawto,
6672 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6674 BlitBitmapMasked(bitmap, drawto,
6675 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6677 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6678 BlitBitmapMasked(bitmap, drawto,
6679 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6680 DX + DXSIZE - i, DY + 77 + j);
6681 BlitBitmapMasked(bitmap, drawto,
6682 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6683 DX + DXSIZE - i, DY + 203 + j);
6688 redraw_mask |= REDRAW_DOOR_1;
6689 door_1_done = (a == end);
6692 if (door_state & DOOR_ACTION_2 &&
6693 x * door_2.step_offset <= door_size_2)
6695 int a = MIN(x * door_2.step_offset, door_size);
6696 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6697 int i = p + door_skip;
6700 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6701 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6702 Bitmap *bm_left = g_left->bitmap;
6703 Bitmap *bm_right = g_right->bitmap;
6704 GC gc_left = bm_left->stored_clip_gc;
6705 GC gc_right = bm_right->stored_clip_gc;
6708 int classic_vxsize = 100;
6709 int classic_vysize = 100;
6710 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6711 VYSIZE == classic_vysize);
6713 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6715 BlitBitmap(bitmap_db_door, drawto,
6716 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6717 VXSIZE, VYSIZE, VX, VY);
6719 else if (x <= VYSIZE)
6721 BlitBitmap(bitmap_db_door, drawto,
6722 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6723 VXSIZE, VYSIZE - p / 2, VX, VY);
6725 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6728 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6731 int src1_x = g_right->src_x;
6732 int src1_y = g_right->src_y;
6733 int src2_x = g_left->src_x + g_left->width - i;
6734 int src2_y = g_left->src_y;
6735 int dst1_x = VX + VXSIZE - i;
6740 int height = VYSIZE;
6742 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6743 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6746 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6747 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6750 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6751 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6752 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6753 int dst2_x = VX, dst2_y = VY;
6754 int width = i, height = VYSIZE;
6756 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6757 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6760 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6761 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6765 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6768 int src1_x = g_right->src_x;
6769 int src1_y = g_right->src_y;
6770 int src2_x = g_left->src_x;
6771 int src2_y = g_left->src_y + g_left->height - i;
6773 int dst1_y = VY + VYSIZE - i;
6779 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6780 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6783 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6784 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6787 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6788 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6789 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6790 int dst2_x = VX, dst2_y = VY;
6791 int width = VXSIZE, height = i;
6793 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6794 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6797 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6798 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6802 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6804 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6807 int src1_x = g_right->src_x;
6808 int src1_y = g_right->src_y;
6809 int src2_x = g_left->src_x + g_left->width - i;
6810 int src2_y = g_left->src_y;
6811 int dst1_x = VX + VXSIZE - i;
6816 int height = VYSIZE / 2;
6817 int ypos1 = 0, ypos2 = VYSIZE / 2;
6819 SetClipOrigin(bm_right, gc_right,
6820 dst1_x - src1_x, dst1_y - src1_y + j);
6821 BlitBitmapMasked(bm_right, drawto,
6822 src1_x, src1_y + ypos1, width, height,
6823 dst1_x, dst1_y + ypos1 + j);
6824 SetClipOrigin(bm_left, gc_left,
6825 dst2_x - src2_x, dst2_y - src2_y - j);
6826 BlitBitmapMasked(bm_left, drawto,
6827 src2_x, src2_y + ypos1 + j, width, height - j,
6828 dst2_x, dst2_y + ypos1);
6830 SetClipOrigin(bm_left, gc_left,
6831 dst2_x - src2_x, dst2_y - src2_y - j);
6832 BlitBitmapMasked(bm_left, drawto,
6833 src2_x, src2_y + ypos2, width, height,
6834 dst2_x, dst2_y + ypos2 - j);
6835 SetClipOrigin(bm_right, gc_right,
6836 dst1_x - src1_x, dst1_y - src1_y + j);
6837 BlitBitmapMasked(bm_right, drawto,
6838 src1_x, src1_y + ypos2, width, height - j,
6839 dst1_x, dst1_y + ypos2 + j);
6841 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6842 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6843 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6844 int dst2_x = VX, dst2_y = VY;
6845 int width = i, height = VYSIZE;
6846 int ypos = VYSIZE / 2;
6848 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6849 BlitBitmapMasked(bitmap, drawto,
6850 src1_x, src1_y, width, ypos,
6851 dst1_x, dst1_y + j);
6852 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6853 BlitBitmapMasked(bitmap, drawto,
6854 src2_x, src2_y + j, width, ypos - j,
6857 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6858 BlitBitmapMasked(bitmap, drawto,
6859 src2_x, src2_y + ypos, width, ypos,
6860 dst2_x, dst2_y + ypos - j);
6861 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6862 BlitBitmapMasked(bitmap, drawto,
6863 src1_x, src1_y + ypos, width, ypos - j,
6864 dst1_x, dst1_y + ypos + j);
6867 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6868 BlitBitmapMasked(bitmap, drawto,
6869 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6870 VX + VXSIZE - i, VY + j);
6871 SetClipOrigin(bitmap, gc,
6872 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6873 BlitBitmapMasked(bitmap, drawto,
6874 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6877 BlitBitmapMasked(bitmap, drawto,
6878 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6879 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6880 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6881 BlitBitmapMasked(bitmap, drawto,
6882 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6884 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6889 redraw_mask |= REDRAW_DOOR_2;
6890 door_2_done = (a == VXSIZE);
6893 if (!(door_state & DOOR_NO_DELAY))
6897 if (game_status == GAME_MODE_MAIN)
6900 WaitUntilDelayReached(&door_delay, door_delay_value);
6905 if (door_state & DOOR_ACTION_1)
6906 door1 = door_state & DOOR_ACTION_1;
6907 if (door_state & DOOR_ACTION_2)
6908 door2 = door_state & DOOR_ACTION_2;
6910 return (door1 | door2);
6915 void DrawSpecialEditorDoor()
6918 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6919 int top_border_width = gfx1->width;
6920 int top_border_height = gfx1->height;
6921 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6922 int ex = EX - outer_border;
6923 int ey = EY - outer_border;
6924 int vy = VY - outer_border;
6925 int exsize = EXSIZE + 2 * outer_border;
6927 CloseDoor(DOOR_CLOSE_2);
6929 /* draw bigger level editor toolbox window */
6930 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6931 top_border_width, top_border_height, ex, ey - top_border_height);
6932 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6933 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6935 /* draw bigger level editor toolbox window */
6936 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6937 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6939 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6940 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6944 redraw_mask |= REDRAW_ALL;
6947 void UndrawSpecialEditorDoor()
6950 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6951 int top_border_width = gfx1->width;
6952 int top_border_height = gfx1->height;
6953 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6954 int ex = EX - outer_border;
6955 int ey = EY - outer_border;
6956 int ey_top = ey - top_border_height;
6957 int exsize = EXSIZE + 2 * outer_border;
6958 int eysize = EYSIZE + 2 * outer_border;
6960 /* draw normal tape recorder window */
6961 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6963 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6964 ex, ey_top, top_border_width, top_border_height,
6966 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6967 ex, ey, exsize, eysize, ex, ey);
6971 // if screen background is set to "[NONE]", clear editor toolbox window
6972 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6973 ClearRectangle(drawto, ex, ey, exsize, eysize);
6976 /* draw normal tape recorder window */
6977 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6978 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6982 redraw_mask |= REDRAW_ALL;
6986 /* ---------- new tool button stuff ---------------------------------------- */
6993 struct TextPosInfo *pos;
6996 } toolbutton_info[NUM_TOOL_BUTTONS] =
6999 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
7000 TOOL_CTRL_ID_YES, "yes"
7003 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
7004 TOOL_CTRL_ID_NO, "no"
7007 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
7008 TOOL_CTRL_ID_CONFIRM, "confirm"
7011 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
7012 TOOL_CTRL_ID_PLAYER_1, "player 1"
7015 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
7016 TOOL_CTRL_ID_PLAYER_2, "player 2"
7019 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
7020 TOOL_CTRL_ID_PLAYER_3, "player 3"
7023 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
7024 TOOL_CTRL_ID_PLAYER_4, "player 4"
7028 void CreateToolButtons()
7032 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7034 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
7035 struct TextPosInfo *pos = toolbutton_info[i].pos;
7036 struct GadgetInfo *gi;
7037 Bitmap *deco_bitmap = None;
7038 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7039 unsigned int event_mask = GD_EVENT_RELEASED;
7042 int gd_x = gfx->src_x;
7043 int gd_y = gfx->src_y;
7044 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
7045 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
7048 if (global.use_envelope_request)
7049 setRequestPosition(&dx, &dy, TRUE);
7051 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7053 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7055 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
7056 pos->size, &deco_bitmap, &deco_x, &deco_y);
7057 deco_xpos = (gfx->width - pos->size) / 2;
7058 deco_ypos = (gfx->height - pos->size) / 2;
7061 gi = CreateGadget(GDI_CUSTOM_ID, id,
7062 GDI_INFO_TEXT, toolbutton_info[i].infotext,
7063 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
7064 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
7065 GDI_WIDTH, gfx->width,
7066 GDI_HEIGHT, gfx->height,
7067 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7068 GDI_STATE, GD_BUTTON_UNPRESSED,
7069 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
7070 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
7071 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7072 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7073 GDI_DECORATION_SIZE, pos->size, pos->size,
7074 GDI_DECORATION_SHIFTING, 1, 1,
7075 GDI_DIRECT_DRAW, FALSE,
7076 GDI_EVENT_MASK, event_mask,
7077 GDI_CALLBACK_ACTION, HandleToolButtons,
7081 Error(ERR_EXIT, "cannot create gadget");
7083 tool_gadget[id] = gi;
7089 /* graphic position values for tool buttons */
7090 #define TOOL_BUTTON_YES_XPOS 2
7091 #define TOOL_BUTTON_YES_YPOS 250
7092 #define TOOL_BUTTON_YES_GFX_YPOS 0
7093 #define TOOL_BUTTON_YES_XSIZE 46
7094 #define TOOL_BUTTON_YES_YSIZE 28
7095 #define TOOL_BUTTON_NO_XPOS 52
7096 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
7097 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
7098 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
7099 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
7100 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
7101 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
7102 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
7103 #define TOOL_BUTTON_CONFIRM_XSIZE 96
7104 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
7105 #define TOOL_BUTTON_PLAYER_XSIZE 30
7106 #define TOOL_BUTTON_PLAYER_YSIZE 30
7107 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
7108 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
7109 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
7110 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
7111 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7112 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7113 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7114 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7115 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7116 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7117 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7118 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7119 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7120 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7121 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7122 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7123 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7124 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7125 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7126 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7135 } toolbutton_info[NUM_TOOL_BUTTONS] =
7138 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
7139 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
7140 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
7145 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
7146 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
7147 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
7152 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
7153 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
7154 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
7155 TOOL_CTRL_ID_CONFIRM,
7159 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7160 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
7161 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7162 TOOL_CTRL_ID_PLAYER_1,
7166 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7167 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
7168 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7169 TOOL_CTRL_ID_PLAYER_2,
7173 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7174 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
7175 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7176 TOOL_CTRL_ID_PLAYER_3,
7180 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7181 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
7182 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7183 TOOL_CTRL_ID_PLAYER_4,
7188 void CreateToolButtons()
7192 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7194 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
7195 Bitmap *deco_bitmap = None;
7196 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7197 struct GadgetInfo *gi;
7198 unsigned int event_mask;
7199 int gd_xoffset, gd_yoffset;
7200 int gd_x1, gd_x2, gd_y;
7203 event_mask = GD_EVENT_RELEASED;
7205 gd_xoffset = toolbutton_info[i].xpos;
7206 gd_yoffset = toolbutton_info[i].ypos;
7207 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
7208 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
7209 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
7211 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7213 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7215 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
7216 &deco_bitmap, &deco_x, &deco_y);
7217 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
7218 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
7221 gi = CreateGadget(GDI_CUSTOM_ID, id,
7222 GDI_INFO_TEXT, toolbutton_info[i].infotext,
7223 GDI_X, DX + GDI_ACTIVE_POS(toolbutton_info[i].x),
7224 GDI_Y, DY + GDI_ACTIVE_POS(toolbutton_info[i].y),
7225 GDI_WIDTH, toolbutton_info[i].width,
7226 GDI_HEIGHT, toolbutton_info[i].height,
7227 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7228 GDI_STATE, GD_BUTTON_UNPRESSED,
7229 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
7230 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
7231 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7232 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7233 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
7234 GDI_DECORATION_SHIFTING, 1, 1,
7235 GDI_DIRECT_DRAW, FALSE,
7236 GDI_EVENT_MASK, event_mask,
7237 GDI_CALLBACK_ACTION, HandleToolButtons,
7241 Error(ERR_EXIT, "cannot create gadget");
7243 tool_gadget[id] = gi;
7249 void FreeToolButtons()
7253 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7254 FreeGadget(tool_gadget[i]);
7257 static void UnmapToolButtons()
7261 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7262 UnmapGadget(tool_gadget[i]);
7265 static void HandleToolButtons(struct GadgetInfo *gi)
7267 request_gadget_id = gi->custom_id;
7270 static struct Mapping_EM_to_RND_object
7273 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
7274 boolean is_backside; /* backside of moving element */
7280 em_object_mapping_list[] =
7283 Xblank, TRUE, FALSE,
7287 Yacid_splash_eB, FALSE, FALSE,
7288 EL_ACID_SPLASH_RIGHT, -1, -1
7291 Yacid_splash_wB, FALSE, FALSE,
7292 EL_ACID_SPLASH_LEFT, -1, -1
7295 #ifdef EM_ENGINE_BAD_ROLL
7297 Xstone_force_e, FALSE, FALSE,
7298 EL_ROCK, -1, MV_BIT_RIGHT
7301 Xstone_force_w, FALSE, FALSE,
7302 EL_ROCK, -1, MV_BIT_LEFT
7305 Xnut_force_e, FALSE, FALSE,
7306 EL_NUT, -1, MV_BIT_RIGHT
7309 Xnut_force_w, FALSE, FALSE,
7310 EL_NUT, -1, MV_BIT_LEFT
7313 Xspring_force_e, FALSE, FALSE,
7314 EL_SPRING, -1, MV_BIT_RIGHT
7317 Xspring_force_w, FALSE, FALSE,
7318 EL_SPRING, -1, MV_BIT_LEFT
7321 Xemerald_force_e, FALSE, FALSE,
7322 EL_EMERALD, -1, MV_BIT_RIGHT
7325 Xemerald_force_w, FALSE, FALSE,
7326 EL_EMERALD, -1, MV_BIT_LEFT
7329 Xdiamond_force_e, FALSE, FALSE,
7330 EL_DIAMOND, -1, MV_BIT_RIGHT
7333 Xdiamond_force_w, FALSE, FALSE,
7334 EL_DIAMOND, -1, MV_BIT_LEFT
7337 Xbomb_force_e, FALSE, FALSE,
7338 EL_BOMB, -1, MV_BIT_RIGHT
7341 Xbomb_force_w, FALSE, FALSE,
7342 EL_BOMB, -1, MV_BIT_LEFT
7344 #endif /* EM_ENGINE_BAD_ROLL */
7347 Xstone, TRUE, FALSE,
7351 Xstone_pause, FALSE, FALSE,
7355 Xstone_fall, FALSE, FALSE,
7359 Ystone_s, FALSE, FALSE,
7360 EL_ROCK, ACTION_FALLING, -1
7363 Ystone_sB, FALSE, TRUE,
7364 EL_ROCK, ACTION_FALLING, -1
7367 Ystone_e, FALSE, FALSE,
7368 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7371 Ystone_eB, FALSE, TRUE,
7372 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7375 Ystone_w, FALSE, FALSE,
7376 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7379 Ystone_wB, FALSE, TRUE,
7380 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7387 Xnut_pause, FALSE, FALSE,
7391 Xnut_fall, FALSE, FALSE,
7395 Ynut_s, FALSE, FALSE,
7396 EL_NUT, ACTION_FALLING, -1
7399 Ynut_sB, FALSE, TRUE,
7400 EL_NUT, ACTION_FALLING, -1
7403 Ynut_e, FALSE, FALSE,
7404 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7407 Ynut_eB, FALSE, TRUE,
7408 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7411 Ynut_w, FALSE, FALSE,
7412 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7415 Ynut_wB, FALSE, TRUE,
7416 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7419 Xbug_n, TRUE, FALSE,
7423 Xbug_e, TRUE, FALSE,
7424 EL_BUG_RIGHT, -1, -1
7427 Xbug_s, TRUE, FALSE,
7431 Xbug_w, TRUE, FALSE,
7435 Xbug_gon, FALSE, FALSE,
7439 Xbug_goe, FALSE, FALSE,
7440 EL_BUG_RIGHT, -1, -1
7443 Xbug_gos, FALSE, FALSE,
7447 Xbug_gow, FALSE, FALSE,
7451 Ybug_n, FALSE, FALSE,
7452 EL_BUG, ACTION_MOVING, MV_BIT_UP
7455 Ybug_nB, FALSE, TRUE,
7456 EL_BUG, ACTION_MOVING, MV_BIT_UP
7459 Ybug_e, FALSE, FALSE,
7460 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7463 Ybug_eB, FALSE, TRUE,
7464 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7467 Ybug_s, FALSE, FALSE,
7468 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7471 Ybug_sB, FALSE, TRUE,
7472 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7475 Ybug_w, FALSE, FALSE,
7476 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7479 Ybug_wB, FALSE, TRUE,
7480 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7483 Ybug_w_n, FALSE, FALSE,
7484 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7487 Ybug_n_e, FALSE, FALSE,
7488 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7491 Ybug_e_s, FALSE, FALSE,
7492 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7495 Ybug_s_w, FALSE, FALSE,
7496 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7499 Ybug_e_n, FALSE, FALSE,
7500 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7503 Ybug_s_e, FALSE, FALSE,
7504 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7507 Ybug_w_s, FALSE, FALSE,
7508 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7511 Ybug_n_w, FALSE, FALSE,
7512 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7515 Ybug_stone, FALSE, FALSE,
7516 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
7519 Ybug_spring, FALSE, FALSE,
7520 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
7523 Xtank_n, TRUE, FALSE,
7524 EL_SPACESHIP_UP, -1, -1
7527 Xtank_e, TRUE, FALSE,
7528 EL_SPACESHIP_RIGHT, -1, -1
7531 Xtank_s, TRUE, FALSE,
7532 EL_SPACESHIP_DOWN, -1, -1
7535 Xtank_w, TRUE, FALSE,
7536 EL_SPACESHIP_LEFT, -1, -1
7539 Xtank_gon, FALSE, FALSE,
7540 EL_SPACESHIP_UP, -1, -1
7543 Xtank_goe, FALSE, FALSE,
7544 EL_SPACESHIP_RIGHT, -1, -1
7547 Xtank_gos, FALSE, FALSE,
7548 EL_SPACESHIP_DOWN, -1, -1
7551 Xtank_gow, FALSE, FALSE,
7552 EL_SPACESHIP_LEFT, -1, -1
7555 Ytank_n, FALSE, FALSE,
7556 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7559 Ytank_nB, FALSE, TRUE,
7560 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7563 Ytank_e, FALSE, FALSE,
7564 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7567 Ytank_eB, FALSE, TRUE,
7568 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7571 Ytank_s, FALSE, FALSE,
7572 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7575 Ytank_sB, FALSE, TRUE,
7576 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7579 Ytank_w, FALSE, FALSE,
7580 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7583 Ytank_wB, FALSE, TRUE,
7584 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7587 Ytank_w_n, FALSE, FALSE,
7588 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7591 Ytank_n_e, FALSE, FALSE,
7592 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7595 Ytank_e_s, FALSE, FALSE,
7596 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7599 Ytank_s_w, FALSE, FALSE,
7600 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7603 Ytank_e_n, FALSE, FALSE,
7604 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7607 Ytank_s_e, FALSE, FALSE,
7608 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7611 Ytank_w_s, FALSE, FALSE,
7612 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7615 Ytank_n_w, FALSE, FALSE,
7616 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7619 Ytank_stone, FALSE, FALSE,
7620 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
7623 Ytank_spring, FALSE, FALSE,
7624 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
7627 Xandroid, TRUE, FALSE,
7628 EL_EMC_ANDROID, ACTION_ACTIVE, -1
7631 Xandroid_1_n, FALSE, FALSE,
7632 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7635 Xandroid_2_n, FALSE, FALSE,
7636 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7639 Xandroid_1_e, FALSE, FALSE,
7640 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7643 Xandroid_2_e, FALSE, FALSE,
7644 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7647 Xandroid_1_w, FALSE, FALSE,
7648 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7651 Xandroid_2_w, FALSE, FALSE,
7652 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7655 Xandroid_1_s, FALSE, FALSE,
7656 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7659 Xandroid_2_s, FALSE, FALSE,
7660 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7663 Yandroid_n, FALSE, FALSE,
7664 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7667 Yandroid_nB, FALSE, TRUE,
7668 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7671 Yandroid_ne, FALSE, FALSE,
7672 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7675 Yandroid_neB, FALSE, TRUE,
7676 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7679 Yandroid_e, FALSE, FALSE,
7680 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7683 Yandroid_eB, FALSE, TRUE,
7684 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7687 Yandroid_se, FALSE, FALSE,
7688 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7691 Yandroid_seB, FALSE, TRUE,
7692 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7695 Yandroid_s, FALSE, FALSE,
7696 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7699 Yandroid_sB, FALSE, TRUE,
7700 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7703 Yandroid_sw, FALSE, FALSE,
7704 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7707 Yandroid_swB, FALSE, TRUE,
7708 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7711 Yandroid_w, FALSE, FALSE,
7712 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7715 Yandroid_wB, FALSE, TRUE,
7716 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7719 Yandroid_nw, FALSE, FALSE,
7720 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7723 Yandroid_nwB, FALSE, TRUE,
7724 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7727 Xspring, TRUE, FALSE,
7731 Xspring_pause, FALSE, FALSE,
7735 Xspring_e, FALSE, FALSE,
7739 Xspring_w, FALSE, FALSE,
7743 Xspring_fall, FALSE, FALSE,
7747 Yspring_s, FALSE, FALSE,
7748 EL_SPRING, ACTION_FALLING, -1
7751 Yspring_sB, FALSE, TRUE,
7752 EL_SPRING, ACTION_FALLING, -1
7755 Yspring_e, FALSE, FALSE,
7756 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7759 Yspring_eB, FALSE, TRUE,
7760 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7763 Yspring_w, FALSE, FALSE,
7764 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7767 Yspring_wB, FALSE, TRUE,
7768 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7771 Yspring_kill_e, FALSE, FALSE,
7772 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7775 Yspring_kill_eB, FALSE, TRUE,
7776 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7779 Yspring_kill_w, FALSE, FALSE,
7780 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7783 Yspring_kill_wB, FALSE, TRUE,
7784 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7787 Xeater_n, TRUE, FALSE,
7788 EL_YAMYAM_UP, -1, -1
7791 Xeater_e, TRUE, FALSE,
7792 EL_YAMYAM_RIGHT, -1, -1
7795 Xeater_w, TRUE, FALSE,
7796 EL_YAMYAM_LEFT, -1, -1
7799 Xeater_s, TRUE, FALSE,
7800 EL_YAMYAM_DOWN, -1, -1
7803 Yeater_n, FALSE, FALSE,
7804 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7807 Yeater_nB, FALSE, TRUE,
7808 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7811 Yeater_e, FALSE, FALSE,
7812 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7815 Yeater_eB, FALSE, TRUE,
7816 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7819 Yeater_s, FALSE, FALSE,
7820 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7823 Yeater_sB, FALSE, TRUE,
7824 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7827 Yeater_w, FALSE, FALSE,
7828 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7831 Yeater_wB, FALSE, TRUE,
7832 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7835 Yeater_stone, FALSE, FALSE,
7836 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7839 Yeater_spring, FALSE, FALSE,
7840 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7843 Xalien, TRUE, FALSE,
7847 Xalien_pause, FALSE, FALSE,
7851 Yalien_n, FALSE, FALSE,
7852 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7855 Yalien_nB, FALSE, TRUE,
7856 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7859 Yalien_e, FALSE, FALSE,
7860 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7863 Yalien_eB, FALSE, TRUE,
7864 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7867 Yalien_s, FALSE, FALSE,
7868 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7871 Yalien_sB, FALSE, TRUE,
7872 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7875 Yalien_w, FALSE, FALSE,
7876 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7879 Yalien_wB, FALSE, TRUE,
7880 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7883 Yalien_stone, FALSE, FALSE,
7884 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7887 Yalien_spring, FALSE, FALSE,
7888 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7891 Xemerald, TRUE, FALSE,
7895 Xemerald_pause, FALSE, FALSE,
7899 Xemerald_fall, FALSE, FALSE,
7903 Xemerald_shine, FALSE, FALSE,
7904 EL_EMERALD, ACTION_TWINKLING, -1
7907 Yemerald_s, FALSE, FALSE,
7908 EL_EMERALD, ACTION_FALLING, -1
7911 Yemerald_sB, FALSE, TRUE,
7912 EL_EMERALD, ACTION_FALLING, -1
7915 Yemerald_e, FALSE, FALSE,
7916 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7919 Yemerald_eB, FALSE, TRUE,
7920 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7923 Yemerald_w, FALSE, FALSE,
7924 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7927 Yemerald_wB, FALSE, TRUE,
7928 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7931 Yemerald_eat, FALSE, FALSE,
7932 EL_EMERALD, ACTION_COLLECTING, -1
7935 Yemerald_stone, FALSE, FALSE,
7936 EL_NUT, ACTION_BREAKING, -1
7939 Xdiamond, TRUE, FALSE,
7943 Xdiamond_pause, FALSE, FALSE,
7947 Xdiamond_fall, FALSE, FALSE,
7951 Xdiamond_shine, FALSE, FALSE,
7952 EL_DIAMOND, ACTION_TWINKLING, -1
7955 Ydiamond_s, FALSE, FALSE,
7956 EL_DIAMOND, ACTION_FALLING, -1
7959 Ydiamond_sB, FALSE, TRUE,
7960 EL_DIAMOND, ACTION_FALLING, -1
7963 Ydiamond_e, FALSE, FALSE,
7964 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7967 Ydiamond_eB, FALSE, TRUE,
7968 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7971 Ydiamond_w, FALSE, FALSE,
7972 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7975 Ydiamond_wB, FALSE, TRUE,
7976 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7979 Ydiamond_eat, FALSE, FALSE,
7980 EL_DIAMOND, ACTION_COLLECTING, -1
7983 Ydiamond_stone, FALSE, FALSE,
7984 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7987 Xdrip_fall, TRUE, FALSE,
7988 EL_AMOEBA_DROP, -1, -1
7991 Xdrip_stretch, FALSE, FALSE,
7992 EL_AMOEBA_DROP, ACTION_FALLING, -1
7995 Xdrip_stretchB, FALSE, TRUE,
7996 EL_AMOEBA_DROP, ACTION_FALLING, -1
7999 Xdrip_eat, FALSE, FALSE,
8000 EL_AMOEBA_DROP, ACTION_GROWING, -1
8003 Ydrip_s1, FALSE, FALSE,
8004 EL_AMOEBA_DROP, ACTION_FALLING, -1
8007 Ydrip_s1B, FALSE, TRUE,
8008 EL_AMOEBA_DROP, ACTION_FALLING, -1
8011 Ydrip_s2, FALSE, FALSE,
8012 EL_AMOEBA_DROP, ACTION_FALLING, -1
8015 Ydrip_s2B, FALSE, TRUE,
8016 EL_AMOEBA_DROP, ACTION_FALLING, -1
8023 Xbomb_pause, FALSE, FALSE,
8027 Xbomb_fall, FALSE, FALSE,
8031 Ybomb_s, FALSE, FALSE,
8032 EL_BOMB, ACTION_FALLING, -1
8035 Ybomb_sB, FALSE, TRUE,
8036 EL_BOMB, ACTION_FALLING, -1
8039 Ybomb_e, FALSE, FALSE,
8040 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
8043 Ybomb_eB, FALSE, TRUE,
8044 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
8047 Ybomb_w, FALSE, FALSE,
8048 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
8051 Ybomb_wB, FALSE, TRUE,
8052 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
8055 Ybomb_eat, FALSE, FALSE,
8056 EL_BOMB, ACTION_ACTIVATING, -1
8059 Xballoon, TRUE, FALSE,
8063 Yballoon_n, FALSE, FALSE,
8064 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
8067 Yballoon_nB, FALSE, TRUE,
8068 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
8071 Yballoon_e, FALSE, FALSE,
8072 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8075 Yballoon_eB, FALSE, TRUE,
8076 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8079 Yballoon_s, FALSE, FALSE,
8080 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8083 Yballoon_sB, FALSE, TRUE,
8084 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8087 Yballoon_w, FALSE, FALSE,
8088 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8091 Yballoon_wB, FALSE, TRUE,
8092 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8095 Xgrass, TRUE, FALSE,
8096 EL_EMC_GRASS, -1, -1
8099 Ygrass_nB, FALSE, FALSE,
8100 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
8103 Ygrass_eB, FALSE, FALSE,
8104 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
8107 Ygrass_sB, FALSE, FALSE,
8108 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
8111 Ygrass_wB, FALSE, FALSE,
8112 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
8119 Ydirt_nB, FALSE, FALSE,
8120 EL_SAND, ACTION_DIGGING, MV_BIT_UP
8123 Ydirt_eB, FALSE, FALSE,
8124 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
8127 Ydirt_sB, FALSE, FALSE,
8128 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
8131 Ydirt_wB, FALSE, FALSE,
8132 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
8135 Xacid_ne, TRUE, FALSE,
8136 EL_ACID_POOL_TOPRIGHT, -1, -1
8139 Xacid_se, TRUE, FALSE,
8140 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
8143 Xacid_s, TRUE, FALSE,
8144 EL_ACID_POOL_BOTTOM, -1, -1
8147 Xacid_sw, TRUE, FALSE,
8148 EL_ACID_POOL_BOTTOMLEFT, -1, -1
8151 Xacid_nw, TRUE, FALSE,
8152 EL_ACID_POOL_TOPLEFT, -1, -1
8155 Xacid_1, TRUE, FALSE,
8159 Xacid_2, FALSE, FALSE,
8163 Xacid_3, FALSE, FALSE,
8167 Xacid_4, FALSE, FALSE,
8171 Xacid_5, FALSE, FALSE,
8175 Xacid_6, FALSE, FALSE,
8179 Xacid_7, FALSE, FALSE,
8183 Xacid_8, FALSE, FALSE,
8187 Xball_1, TRUE, FALSE,
8188 EL_EMC_MAGIC_BALL, -1, -1
8191 Xball_1B, FALSE, FALSE,
8192 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8195 Xball_2, FALSE, FALSE,
8196 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8199 Xball_2B, FALSE, FALSE,
8200 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8203 Yball_eat, FALSE, FALSE,
8204 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
8207 Ykey_1_eat, FALSE, FALSE,
8208 EL_EM_KEY_1, ACTION_COLLECTING, -1
8211 Ykey_2_eat, FALSE, FALSE,
8212 EL_EM_KEY_2, ACTION_COLLECTING, -1
8215 Ykey_3_eat, FALSE, FALSE,
8216 EL_EM_KEY_3, ACTION_COLLECTING, -1
8219 Ykey_4_eat, FALSE, FALSE,
8220 EL_EM_KEY_4, ACTION_COLLECTING, -1
8223 Ykey_5_eat, FALSE, FALSE,
8224 EL_EMC_KEY_5, ACTION_COLLECTING, -1
8227 Ykey_6_eat, FALSE, FALSE,
8228 EL_EMC_KEY_6, ACTION_COLLECTING, -1
8231 Ykey_7_eat, FALSE, FALSE,
8232 EL_EMC_KEY_7, ACTION_COLLECTING, -1
8235 Ykey_8_eat, FALSE, FALSE,
8236 EL_EMC_KEY_8, ACTION_COLLECTING, -1
8239 Ylenses_eat, FALSE, FALSE,
8240 EL_EMC_LENSES, ACTION_COLLECTING, -1
8243 Ymagnify_eat, FALSE, FALSE,
8244 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
8247 Ygrass_eat, FALSE, FALSE,
8248 EL_EMC_GRASS, ACTION_SNAPPING, -1
8251 Ydirt_eat, FALSE, FALSE,
8252 EL_SAND, ACTION_SNAPPING, -1
8255 Xgrow_ns, TRUE, FALSE,
8256 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
8259 Ygrow_ns_eat, FALSE, FALSE,
8260 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
8263 Xgrow_ew, TRUE, FALSE,
8264 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
8267 Ygrow_ew_eat, FALSE, FALSE,
8268 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
8271 Xwonderwall, TRUE, FALSE,
8272 EL_MAGIC_WALL, -1, -1
8275 XwonderwallB, FALSE, FALSE,
8276 EL_MAGIC_WALL, ACTION_ACTIVE, -1
8279 Xamoeba_1, TRUE, FALSE,
8280 EL_AMOEBA_DRY, ACTION_OTHER, -1
8283 Xamoeba_2, FALSE, FALSE,
8284 EL_AMOEBA_DRY, ACTION_OTHER, -1
8287 Xamoeba_3, FALSE, FALSE,
8288 EL_AMOEBA_DRY, ACTION_OTHER, -1
8291 Xamoeba_4, FALSE, FALSE,
8292 EL_AMOEBA_DRY, ACTION_OTHER, -1
8295 Xamoeba_5, TRUE, FALSE,
8296 EL_AMOEBA_WET, ACTION_OTHER, -1
8299 Xamoeba_6, FALSE, FALSE,
8300 EL_AMOEBA_WET, ACTION_OTHER, -1
8303 Xamoeba_7, FALSE, FALSE,
8304 EL_AMOEBA_WET, ACTION_OTHER, -1
8307 Xamoeba_8, FALSE, FALSE,
8308 EL_AMOEBA_WET, ACTION_OTHER, -1
8311 Xdoor_1, TRUE, FALSE,
8312 EL_EM_GATE_1, -1, -1
8315 Xdoor_2, TRUE, FALSE,
8316 EL_EM_GATE_2, -1, -1
8319 Xdoor_3, TRUE, FALSE,
8320 EL_EM_GATE_3, -1, -1
8323 Xdoor_4, TRUE, FALSE,
8324 EL_EM_GATE_4, -1, -1
8327 Xdoor_5, TRUE, FALSE,
8328 EL_EMC_GATE_5, -1, -1
8331 Xdoor_6, TRUE, FALSE,
8332 EL_EMC_GATE_6, -1, -1
8335 Xdoor_7, TRUE, FALSE,
8336 EL_EMC_GATE_7, -1, -1
8339 Xdoor_8, TRUE, FALSE,
8340 EL_EMC_GATE_8, -1, -1
8343 Xkey_1, TRUE, FALSE,
8347 Xkey_2, TRUE, FALSE,
8351 Xkey_3, TRUE, FALSE,
8355 Xkey_4, TRUE, FALSE,
8359 Xkey_5, TRUE, FALSE,
8360 EL_EMC_KEY_5, -1, -1
8363 Xkey_6, TRUE, FALSE,
8364 EL_EMC_KEY_6, -1, -1
8367 Xkey_7, TRUE, FALSE,
8368 EL_EMC_KEY_7, -1, -1
8371 Xkey_8, TRUE, FALSE,
8372 EL_EMC_KEY_8, -1, -1
8375 Xwind_n, TRUE, FALSE,
8376 EL_BALLOON_SWITCH_UP, -1, -1
8379 Xwind_e, TRUE, FALSE,
8380 EL_BALLOON_SWITCH_RIGHT, -1, -1
8383 Xwind_s, TRUE, FALSE,
8384 EL_BALLOON_SWITCH_DOWN, -1, -1
8387 Xwind_w, TRUE, FALSE,
8388 EL_BALLOON_SWITCH_LEFT, -1, -1
8391 Xwind_nesw, TRUE, FALSE,
8392 EL_BALLOON_SWITCH_ANY, -1, -1
8395 Xwind_stop, TRUE, FALSE,
8396 EL_BALLOON_SWITCH_NONE, -1, -1
8400 EL_EM_EXIT_CLOSED, -1, -1
8403 Xexit_1, TRUE, FALSE,
8404 EL_EM_EXIT_OPEN, -1, -1
8407 Xexit_2, FALSE, FALSE,
8408 EL_EM_EXIT_OPEN, -1, -1
8411 Xexit_3, FALSE, FALSE,
8412 EL_EM_EXIT_OPEN, -1, -1
8415 Xdynamite, TRUE, FALSE,
8416 EL_EM_DYNAMITE, -1, -1
8419 Ydynamite_eat, FALSE, FALSE,
8420 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
8423 Xdynamite_1, TRUE, FALSE,
8424 EL_EM_DYNAMITE_ACTIVE, -1, -1
8427 Xdynamite_2, FALSE, FALSE,
8428 EL_EM_DYNAMITE_ACTIVE, -1, -1
8431 Xdynamite_3, FALSE, FALSE,
8432 EL_EM_DYNAMITE_ACTIVE, -1, -1
8435 Xdynamite_4, FALSE, FALSE,
8436 EL_EM_DYNAMITE_ACTIVE, -1, -1
8439 Xbumper, TRUE, FALSE,
8440 EL_EMC_SPRING_BUMPER, -1, -1
8443 XbumperB, FALSE, FALSE,
8444 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
8447 Xwheel, TRUE, FALSE,
8448 EL_ROBOT_WHEEL, -1, -1
8451 XwheelB, FALSE, FALSE,
8452 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
8455 Xswitch, TRUE, FALSE,
8456 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
8459 XswitchB, FALSE, FALSE,
8460 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
8464 EL_QUICKSAND_EMPTY, -1, -1
8467 Xsand_stone, TRUE, FALSE,
8468 EL_QUICKSAND_FULL, -1, -1
8471 Xsand_stonein_1, FALSE, TRUE,
8472 EL_ROCK, ACTION_FILLING, -1
8475 Xsand_stonein_2, FALSE, TRUE,
8476 EL_ROCK, ACTION_FILLING, -1
8479 Xsand_stonein_3, FALSE, TRUE,
8480 EL_ROCK, ACTION_FILLING, -1
8483 Xsand_stonein_4, FALSE, TRUE,
8484 EL_ROCK, ACTION_FILLING, -1
8488 Xsand_stonesand_1, FALSE, FALSE,
8489 EL_QUICKSAND_EMPTYING, -1, -1
8492 Xsand_stonesand_2, FALSE, FALSE,
8493 EL_QUICKSAND_EMPTYING, -1, -1
8496 Xsand_stonesand_3, FALSE, FALSE,
8497 EL_QUICKSAND_EMPTYING, -1, -1
8500 Xsand_stonesand_4, FALSE, FALSE,
8501 EL_QUICKSAND_EMPTYING, -1, -1
8504 Xsand_stonesand_quickout_1, FALSE, FALSE,
8505 EL_QUICKSAND_EMPTYING, -1, -1
8508 Xsand_stonesand_quickout_2, FALSE, FALSE,
8509 EL_QUICKSAND_EMPTYING, -1, -1
8513 Xsand_stonesand_1, FALSE, FALSE,
8514 EL_QUICKSAND_FULL, -1, -1
8517 Xsand_stonesand_2, FALSE, FALSE,
8518 EL_QUICKSAND_FULL, -1, -1
8521 Xsand_stonesand_3, FALSE, FALSE,
8522 EL_QUICKSAND_FULL, -1, -1
8525 Xsand_stonesand_4, FALSE, FALSE,
8526 EL_QUICKSAND_FULL, -1, -1
8530 Xsand_stoneout_1, FALSE, FALSE,
8531 EL_ROCK, ACTION_EMPTYING, -1
8534 Xsand_stoneout_2, FALSE, FALSE,
8535 EL_ROCK, ACTION_EMPTYING, -1
8539 Xsand_sandstone_1, FALSE, FALSE,
8540 EL_QUICKSAND_FILLING, -1, -1
8543 Xsand_sandstone_2, FALSE, FALSE,
8544 EL_QUICKSAND_FILLING, -1, -1
8547 Xsand_sandstone_3, FALSE, FALSE,
8548 EL_QUICKSAND_FILLING, -1, -1
8551 Xsand_sandstone_4, FALSE, FALSE,
8552 EL_QUICKSAND_FILLING, -1, -1
8556 Xsand_sandstone_1, FALSE, FALSE,
8557 EL_QUICKSAND_FULL, -1, -1
8560 Xsand_sandstone_2, FALSE, FALSE,
8561 EL_QUICKSAND_FULL, -1, -1
8564 Xsand_sandstone_3, FALSE, FALSE,
8565 EL_QUICKSAND_FULL, -1, -1
8568 Xsand_sandstone_4, FALSE, FALSE,
8569 EL_QUICKSAND_FULL, -1, -1
8573 Xplant, TRUE, FALSE,
8574 EL_EMC_PLANT, -1, -1
8577 Yplant, FALSE, FALSE,
8578 EL_EMC_PLANT, -1, -1
8581 Xlenses, TRUE, FALSE,
8582 EL_EMC_LENSES, -1, -1
8585 Xmagnify, TRUE, FALSE,
8586 EL_EMC_MAGNIFIER, -1, -1
8589 Xdripper, TRUE, FALSE,
8590 EL_EMC_DRIPPER, -1, -1
8593 XdripperB, FALSE, FALSE,
8594 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
8597 Xfake_blank, TRUE, FALSE,
8598 EL_INVISIBLE_WALL, -1, -1
8601 Xfake_blankB, FALSE, FALSE,
8602 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
8605 Xfake_grass, TRUE, FALSE,
8606 EL_EMC_FAKE_GRASS, -1, -1
8609 Xfake_grassB, FALSE, FALSE,
8610 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
8613 Xfake_door_1, TRUE, FALSE,
8614 EL_EM_GATE_1_GRAY, -1, -1
8617 Xfake_door_2, TRUE, FALSE,
8618 EL_EM_GATE_2_GRAY, -1, -1
8621 Xfake_door_3, TRUE, FALSE,
8622 EL_EM_GATE_3_GRAY, -1, -1
8625 Xfake_door_4, TRUE, FALSE,
8626 EL_EM_GATE_4_GRAY, -1, -1
8629 Xfake_door_5, TRUE, FALSE,
8630 EL_EMC_GATE_5_GRAY, -1, -1
8633 Xfake_door_6, TRUE, FALSE,
8634 EL_EMC_GATE_6_GRAY, -1, -1
8637 Xfake_door_7, TRUE, FALSE,
8638 EL_EMC_GATE_7_GRAY, -1, -1
8641 Xfake_door_8, TRUE, FALSE,
8642 EL_EMC_GATE_8_GRAY, -1, -1
8645 Xfake_acid_1, TRUE, FALSE,
8646 EL_EMC_FAKE_ACID, -1, -1
8649 Xfake_acid_2, FALSE, FALSE,
8650 EL_EMC_FAKE_ACID, -1, -1
8653 Xfake_acid_3, FALSE, FALSE,
8654 EL_EMC_FAKE_ACID, -1, -1
8657 Xfake_acid_4, FALSE, FALSE,
8658 EL_EMC_FAKE_ACID, -1, -1
8661 Xfake_acid_5, FALSE, FALSE,
8662 EL_EMC_FAKE_ACID, -1, -1
8665 Xfake_acid_6, FALSE, FALSE,
8666 EL_EMC_FAKE_ACID, -1, -1
8669 Xfake_acid_7, FALSE, FALSE,
8670 EL_EMC_FAKE_ACID, -1, -1
8673 Xfake_acid_8, FALSE, FALSE,
8674 EL_EMC_FAKE_ACID, -1, -1
8677 Xsteel_1, TRUE, FALSE,
8678 EL_STEELWALL, -1, -1
8681 Xsteel_2, TRUE, FALSE,
8682 EL_EMC_STEELWALL_2, -1, -1
8685 Xsteel_3, TRUE, FALSE,
8686 EL_EMC_STEELWALL_3, -1, -1
8689 Xsteel_4, TRUE, FALSE,
8690 EL_EMC_STEELWALL_4, -1, -1
8693 Xwall_1, TRUE, FALSE,
8697 Xwall_2, TRUE, FALSE,
8698 EL_EMC_WALL_14, -1, -1
8701 Xwall_3, TRUE, FALSE,
8702 EL_EMC_WALL_15, -1, -1
8705 Xwall_4, TRUE, FALSE,
8706 EL_EMC_WALL_16, -1, -1
8709 Xround_wall_1, TRUE, FALSE,
8710 EL_WALL_SLIPPERY, -1, -1
8713 Xround_wall_2, TRUE, FALSE,
8714 EL_EMC_WALL_SLIPPERY_2, -1, -1
8717 Xround_wall_3, TRUE, FALSE,
8718 EL_EMC_WALL_SLIPPERY_3, -1, -1
8721 Xround_wall_4, TRUE, FALSE,
8722 EL_EMC_WALL_SLIPPERY_4, -1, -1
8725 Xdecor_1, TRUE, FALSE,
8726 EL_EMC_WALL_8, -1, -1
8729 Xdecor_2, TRUE, FALSE,
8730 EL_EMC_WALL_6, -1, -1
8733 Xdecor_3, TRUE, FALSE,
8734 EL_EMC_WALL_4, -1, -1
8737 Xdecor_4, TRUE, FALSE,
8738 EL_EMC_WALL_7, -1, -1
8741 Xdecor_5, TRUE, FALSE,
8742 EL_EMC_WALL_5, -1, -1
8745 Xdecor_6, TRUE, FALSE,
8746 EL_EMC_WALL_9, -1, -1
8749 Xdecor_7, TRUE, FALSE,
8750 EL_EMC_WALL_10, -1, -1
8753 Xdecor_8, TRUE, FALSE,
8754 EL_EMC_WALL_1, -1, -1
8757 Xdecor_9, TRUE, FALSE,
8758 EL_EMC_WALL_2, -1, -1
8761 Xdecor_10, TRUE, FALSE,
8762 EL_EMC_WALL_3, -1, -1
8765 Xdecor_11, TRUE, FALSE,
8766 EL_EMC_WALL_11, -1, -1
8769 Xdecor_12, TRUE, FALSE,
8770 EL_EMC_WALL_12, -1, -1
8773 Xalpha_0, TRUE, FALSE,
8774 EL_CHAR('0'), -1, -1
8777 Xalpha_1, TRUE, FALSE,
8778 EL_CHAR('1'), -1, -1
8781 Xalpha_2, TRUE, FALSE,
8782 EL_CHAR('2'), -1, -1
8785 Xalpha_3, TRUE, FALSE,
8786 EL_CHAR('3'), -1, -1
8789 Xalpha_4, TRUE, FALSE,
8790 EL_CHAR('4'), -1, -1
8793 Xalpha_5, TRUE, FALSE,
8794 EL_CHAR('5'), -1, -1
8797 Xalpha_6, TRUE, FALSE,
8798 EL_CHAR('6'), -1, -1
8801 Xalpha_7, TRUE, FALSE,
8802 EL_CHAR('7'), -1, -1
8805 Xalpha_8, TRUE, FALSE,
8806 EL_CHAR('8'), -1, -1
8809 Xalpha_9, TRUE, FALSE,
8810 EL_CHAR('9'), -1, -1
8813 Xalpha_excla, TRUE, FALSE,
8814 EL_CHAR('!'), -1, -1
8817 Xalpha_quote, TRUE, FALSE,
8818 EL_CHAR('"'), -1, -1
8821 Xalpha_comma, TRUE, FALSE,
8822 EL_CHAR(','), -1, -1
8825 Xalpha_minus, TRUE, FALSE,
8826 EL_CHAR('-'), -1, -1
8829 Xalpha_perio, TRUE, FALSE,
8830 EL_CHAR('.'), -1, -1
8833 Xalpha_colon, TRUE, FALSE,
8834 EL_CHAR(':'), -1, -1
8837 Xalpha_quest, TRUE, FALSE,
8838 EL_CHAR('?'), -1, -1
8841 Xalpha_a, TRUE, FALSE,
8842 EL_CHAR('A'), -1, -1
8845 Xalpha_b, TRUE, FALSE,
8846 EL_CHAR('B'), -1, -1
8849 Xalpha_c, TRUE, FALSE,
8850 EL_CHAR('C'), -1, -1
8853 Xalpha_d, TRUE, FALSE,
8854 EL_CHAR('D'), -1, -1
8857 Xalpha_e, TRUE, FALSE,
8858 EL_CHAR('E'), -1, -1
8861 Xalpha_f, TRUE, FALSE,
8862 EL_CHAR('F'), -1, -1
8865 Xalpha_g, TRUE, FALSE,
8866 EL_CHAR('G'), -1, -1
8869 Xalpha_h, TRUE, FALSE,
8870 EL_CHAR('H'), -1, -1
8873 Xalpha_i, TRUE, FALSE,
8874 EL_CHAR('I'), -1, -1
8877 Xalpha_j, TRUE, FALSE,
8878 EL_CHAR('J'), -1, -1
8881 Xalpha_k, TRUE, FALSE,
8882 EL_CHAR('K'), -1, -1
8885 Xalpha_l, TRUE, FALSE,
8886 EL_CHAR('L'), -1, -1
8889 Xalpha_m, TRUE, FALSE,
8890 EL_CHAR('M'), -1, -1
8893 Xalpha_n, TRUE, FALSE,
8894 EL_CHAR('N'), -1, -1
8897 Xalpha_o, TRUE, FALSE,
8898 EL_CHAR('O'), -1, -1
8901 Xalpha_p, TRUE, FALSE,
8902 EL_CHAR('P'), -1, -1
8905 Xalpha_q, TRUE, FALSE,
8906 EL_CHAR('Q'), -1, -1
8909 Xalpha_r, TRUE, FALSE,
8910 EL_CHAR('R'), -1, -1
8913 Xalpha_s, TRUE, FALSE,
8914 EL_CHAR('S'), -1, -1
8917 Xalpha_t, TRUE, FALSE,
8918 EL_CHAR('T'), -1, -1
8921 Xalpha_u, TRUE, FALSE,
8922 EL_CHAR('U'), -1, -1
8925 Xalpha_v, TRUE, FALSE,
8926 EL_CHAR('V'), -1, -1
8929 Xalpha_w, TRUE, FALSE,
8930 EL_CHAR('W'), -1, -1
8933 Xalpha_x, TRUE, FALSE,
8934 EL_CHAR('X'), -1, -1
8937 Xalpha_y, TRUE, FALSE,
8938 EL_CHAR('Y'), -1, -1
8941 Xalpha_z, TRUE, FALSE,
8942 EL_CHAR('Z'), -1, -1
8945 Xalpha_arrow_e, TRUE, FALSE,
8946 EL_CHAR('>'), -1, -1
8949 Xalpha_arrow_w, TRUE, FALSE,
8950 EL_CHAR('<'), -1, -1
8953 Xalpha_copyr, TRUE, FALSE,
8954 EL_CHAR('©'), -1, -1
8958 Xboom_bug, FALSE, FALSE,
8959 EL_BUG, ACTION_EXPLODING, -1
8962 Xboom_bomb, FALSE, FALSE,
8963 EL_BOMB, ACTION_EXPLODING, -1
8966 Xboom_android, FALSE, FALSE,
8967 EL_EMC_ANDROID, ACTION_OTHER, -1
8970 Xboom_1, FALSE, FALSE,
8971 EL_DEFAULT, ACTION_EXPLODING, -1
8974 Xboom_2, FALSE, FALSE,
8975 EL_DEFAULT, ACTION_EXPLODING, -1
8978 Znormal, FALSE, FALSE,
8982 Zdynamite, FALSE, FALSE,
8986 Zplayer, FALSE, FALSE,
8990 ZBORDER, FALSE, FALSE,
9000 static struct Mapping_EM_to_RND_player
9009 em_player_mapping_list[] =
9013 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
9017 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
9021 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
9025 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
9029 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
9033 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
9037 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
9041 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
9045 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
9049 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
9053 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
9057 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
9061 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
9065 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
9069 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
9073 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
9077 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
9081 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
9085 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
9089 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
9093 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
9097 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
9101 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
9105 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
9109 EL_PLAYER_1, ACTION_DEFAULT, -1,
9113 EL_PLAYER_2, ACTION_DEFAULT, -1,
9117 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
9121 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
9125 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
9129 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
9133 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
9137 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
9141 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
9145 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
9149 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
9153 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
9157 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
9161 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
9165 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
9169 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
9173 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
9177 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
9181 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
9185 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
9189 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
9193 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
9197 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
9201 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
9205 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
9209 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
9213 EL_PLAYER_3, ACTION_DEFAULT, -1,
9217 EL_PLAYER_4, ACTION_DEFAULT, -1,
9226 int map_element_RND_to_EM(int element_rnd)
9228 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
9229 static boolean mapping_initialized = FALSE;
9231 if (!mapping_initialized)
9235 /* return "Xalpha_quest" for all undefined elements in mapping array */
9236 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9237 mapping_RND_to_EM[i] = Xalpha_quest;
9239 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9240 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
9241 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
9242 em_object_mapping_list[i].element_em;
9244 mapping_initialized = TRUE;
9247 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
9248 return mapping_RND_to_EM[element_rnd];
9250 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
9255 int map_element_EM_to_RND(int element_em)
9257 static unsigned short mapping_EM_to_RND[TILE_MAX];
9258 static boolean mapping_initialized = FALSE;
9260 if (!mapping_initialized)
9264 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
9265 for (i = 0; i < TILE_MAX; i++)
9266 mapping_EM_to_RND[i] = EL_UNKNOWN;
9268 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9269 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
9270 em_object_mapping_list[i].element_rnd;
9272 mapping_initialized = TRUE;
9275 if (element_em >= 0 && element_em < TILE_MAX)
9276 return mapping_EM_to_RND[element_em];
9278 Error(ERR_WARN, "invalid EM level element %d", element_em);
9283 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
9285 struct LevelInfo_EM *level_em = level->native_em_level;
9286 struct LEVEL *lev = level_em->lev;
9289 for (i = 0; i < TILE_MAX; i++)
9290 lev->android_array[i] = Xblank;
9292 for (i = 0; i < level->num_android_clone_elements; i++)
9294 int element_rnd = level->android_clone_element[i];
9295 int element_em = map_element_RND_to_EM(element_rnd);
9297 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
9298 if (em_object_mapping_list[j].element_rnd == element_rnd)
9299 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
9303 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
9305 struct LevelInfo_EM *level_em = level->native_em_level;
9306 struct LEVEL *lev = level_em->lev;
9309 level->num_android_clone_elements = 0;
9311 for (i = 0; i < TILE_MAX; i++)
9313 int element_em = lev->android_array[i];
9315 boolean element_found = FALSE;
9317 if (element_em == Xblank)
9320 element_rnd = map_element_EM_to_RND(element_em);
9322 for (j = 0; j < level->num_android_clone_elements; j++)
9323 if (level->android_clone_element[j] == element_rnd)
9324 element_found = TRUE;
9328 level->android_clone_element[level->num_android_clone_elements++] =
9331 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
9336 if (level->num_android_clone_elements == 0)
9338 level->num_android_clone_elements = 1;
9339 level->android_clone_element[0] = EL_EMPTY;
9343 int map_direction_RND_to_EM(int direction)
9345 return (direction == MV_UP ? 0 :
9346 direction == MV_RIGHT ? 1 :
9347 direction == MV_DOWN ? 2 :
9348 direction == MV_LEFT ? 3 :
9352 int map_direction_EM_to_RND(int direction)
9354 return (direction == 0 ? MV_UP :
9355 direction == 1 ? MV_RIGHT :
9356 direction == 2 ? MV_DOWN :
9357 direction == 3 ? MV_LEFT :
9361 int map_element_RND_to_SP(int element_rnd)
9363 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
9365 if (element_rnd >= EL_SP_START &&
9366 element_rnd <= EL_SP_END)
9367 element_sp = element_rnd - EL_SP_START;
9368 else if (element_rnd == EL_EMPTY_SPACE)
9370 else if (element_rnd == EL_INVISIBLE_WALL)
9376 int map_element_SP_to_RND(int element_sp)
9378 int element_rnd = EL_UNKNOWN;
9380 if (element_sp >= 0x00 &&
9382 element_rnd = EL_SP_START + element_sp;
9383 else if (element_sp == 0x28)
9384 element_rnd = EL_INVISIBLE_WALL;
9389 int map_action_SP_to_RND(int action_sp)
9393 case actActive: return ACTION_ACTIVE;
9394 case actImpact: return ACTION_IMPACT;
9395 case actExploding: return ACTION_EXPLODING;
9396 case actDigging: return ACTION_DIGGING;
9397 case actSnapping: return ACTION_SNAPPING;
9398 case actCollecting: return ACTION_COLLECTING;
9399 case actPassing: return ACTION_PASSING;
9400 case actPushing: return ACTION_PUSHING;
9401 case actDropping: return ACTION_DROPPING;
9403 default: return ACTION_DEFAULT;
9407 int get_next_element(int element)
9411 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
9412 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
9413 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
9414 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
9415 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
9416 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
9417 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
9418 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
9419 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
9420 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
9421 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
9423 default: return element;
9428 int el_act_dir2img(int element, int action, int direction)
9430 element = GFX_ELEMENT(element);
9432 if (direction == MV_NONE)
9433 return element_info[element].graphic[action];
9435 direction = MV_DIR_TO_BIT(direction);
9437 return element_info[element].direction_graphic[action][direction];
9440 int el_act_dir2img(int element, int action, int direction)
9442 element = GFX_ELEMENT(element);
9443 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9445 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9446 return element_info[element].direction_graphic[action][direction];
9451 static int el_act_dir2crm(int element, int action, int direction)
9453 element = GFX_ELEMENT(element);
9455 if (direction == MV_NONE)
9456 return element_info[element].crumbled[action];
9458 direction = MV_DIR_TO_BIT(direction);
9460 return element_info[element].direction_crumbled[action][direction];
9463 static int el_act_dir2crm(int element, int action, int direction)
9465 element = GFX_ELEMENT(element);
9466 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9468 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9469 return element_info[element].direction_crumbled[action][direction];
9473 int el_act2img(int element, int action)
9475 element = GFX_ELEMENT(element);
9477 return element_info[element].graphic[action];
9480 int el_act2crm(int element, int action)
9482 element = GFX_ELEMENT(element);
9484 return element_info[element].crumbled[action];
9487 int el_dir2img(int element, int direction)
9489 element = GFX_ELEMENT(element);
9491 return el_act_dir2img(element, ACTION_DEFAULT, direction);
9494 int el2baseimg(int element)
9496 return element_info[element].graphic[ACTION_DEFAULT];
9499 int el2img(int element)
9501 element = GFX_ELEMENT(element);
9503 return element_info[element].graphic[ACTION_DEFAULT];
9506 int el2edimg(int element)
9508 element = GFX_ELEMENT(element);
9510 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9513 int el2preimg(int element)
9515 element = GFX_ELEMENT(element);
9517 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9520 int el2panelimg(int element)
9522 element = GFX_ELEMENT(element);
9524 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9527 int font2baseimg(int font_nr)
9529 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9532 int getBeltNrFromBeltElement(int element)
9534 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9535 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9536 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9539 int getBeltNrFromBeltActiveElement(int element)
9541 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9542 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9543 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9546 int getBeltNrFromBeltSwitchElement(int element)
9548 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9549 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9550 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9553 int getBeltDirNrFromBeltElement(int element)
9555 static int belt_base_element[4] =
9557 EL_CONVEYOR_BELT_1_LEFT,
9558 EL_CONVEYOR_BELT_2_LEFT,
9559 EL_CONVEYOR_BELT_3_LEFT,
9560 EL_CONVEYOR_BELT_4_LEFT
9563 int belt_nr = getBeltNrFromBeltElement(element);
9564 int belt_dir_nr = element - belt_base_element[belt_nr];
9566 return (belt_dir_nr % 3);
9569 int getBeltDirNrFromBeltSwitchElement(int element)
9571 static int belt_base_element[4] =
9573 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9574 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9575 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9576 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9579 int belt_nr = getBeltNrFromBeltSwitchElement(element);
9580 int belt_dir_nr = element - belt_base_element[belt_nr];
9582 return (belt_dir_nr % 3);
9585 int getBeltDirFromBeltElement(int element)
9587 static int belt_move_dir[3] =
9594 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9596 return belt_move_dir[belt_dir_nr];
9599 int getBeltDirFromBeltSwitchElement(int element)
9601 static int belt_move_dir[3] =
9608 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9610 return belt_move_dir[belt_dir_nr];
9613 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9615 static int belt_base_element[4] =
9617 EL_CONVEYOR_BELT_1_LEFT,
9618 EL_CONVEYOR_BELT_2_LEFT,
9619 EL_CONVEYOR_BELT_3_LEFT,
9620 EL_CONVEYOR_BELT_4_LEFT
9623 return belt_base_element[belt_nr] + belt_dir_nr;
9626 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9628 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9630 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9633 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9635 static int belt_base_element[4] =
9637 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9638 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9639 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9640 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9643 return belt_base_element[belt_nr] + belt_dir_nr;
9646 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9648 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9650 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9654 boolean getTeamMode_EM()
9656 return game.team_mode;
9659 int getNumActivePlayers_EM()
9662 int num_players = 0;
9666 return (setup.team_mode ? MAX_PLAYERS : 1);
9668 for (i = 0; i < MAX_PLAYERS; i++)
9669 if (tape.player_participates[i])
9672 return (num_players > 1 ? MAX_PLAYERS : 1);
9676 int num_players = 0;
9679 /* when recording game, activate all connected players */
9683 for (i = 0; i < MAX_PLAYERS; i++)
9684 if (tape.player_participates[i])
9692 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9694 int game_frame_delay_value;
9696 game_frame_delay_value =
9697 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9698 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9701 if (tape.playing && tape.warp_forward && !tape.pausing)
9702 game_frame_delay_value = 0;
9704 return game_frame_delay_value;
9707 unsigned int InitRND(int seed)
9709 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9710 return InitEngineRandom_EM(seed);
9711 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9712 return InitEngineRandom_SP(seed);
9714 return InitEngineRandom_RND(seed);
9718 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9719 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9722 inline static int get_effective_element_EM(int tile, int frame_em)
9724 int element = object_mapping[tile].element_rnd;
9725 int action = object_mapping[tile].action;
9726 boolean is_backside = object_mapping[tile].is_backside;
9727 boolean action_removing = (action == ACTION_DIGGING ||
9728 action == ACTION_SNAPPING ||
9729 action == ACTION_COLLECTING);
9735 case Yacid_splash_eB:
9736 case Yacid_splash_wB:
9737 return (frame_em > 5 ? EL_EMPTY : element);
9741 case Ydiamond_stone:
9742 // if (!game.use_native_emc_graphics_engine)
9750 else /* frame_em == 7 */
9754 case Yacid_splash_eB:
9755 case Yacid_splash_wB:
9758 case Yemerald_stone:
9761 case Ydiamond_stone:
9765 case Xdrip_stretchB:
9784 case Xsand_stonein_1:
9785 case Xsand_stonein_2:
9786 case Xsand_stonein_3:
9787 case Xsand_stonein_4:
9791 return (is_backside || action_removing ? EL_EMPTY : element);
9796 inline static boolean check_linear_animation_EM(int tile)
9800 case Xsand_stonesand_1:
9801 case Xsand_stonesand_quickout_1:
9802 case Xsand_sandstone_1:
9803 case Xsand_stonein_1:
9804 case Xsand_stoneout_1:
9824 case Yacid_splash_eB:
9825 case Yacid_splash_wB:
9826 case Yemerald_stone:
9834 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9835 boolean has_crumbled_graphics,
9836 int crumbled, int sync_frame)
9838 /* if element can be crumbled, but certain action graphics are just empty
9839 space (like instantly snapping sand to empty space in 1 frame), do not
9840 treat these empty space graphics as crumbled graphics in EMC engine */
9841 if (crumbled == IMG_EMPTY_SPACE)
9842 has_crumbled_graphics = FALSE;
9844 if (has_crumbled_graphics)
9846 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9847 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9848 g_crumbled->anim_delay,
9849 g_crumbled->anim_mode,
9850 g_crumbled->anim_start_frame,
9853 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9854 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9856 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9858 g_em->has_crumbled_graphics = TRUE;
9862 g_em->crumbled_bitmap = NULL;
9863 g_em->crumbled_src_x = 0;
9864 g_em->crumbled_src_y = 0;
9865 g_em->crumbled_border_size = 0;
9867 g_em->has_crumbled_graphics = FALSE;
9871 void ResetGfxAnimation_EM(int x, int y, int tile)
9876 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9877 int tile, int frame_em, int x, int y)
9879 int action = object_mapping[tile].action;
9881 int direction = object_mapping[tile].direction;
9882 int effective_element = get_effective_element_EM(tile, frame_em);
9883 int graphic = (direction == MV_NONE ?
9884 el_act2img(effective_element, action) :
9885 el_act_dir2img(effective_element, action, direction));
9886 struct GraphicInfo *g = &graphic_info[graphic];
9889 boolean action_removing = (action == ACTION_DIGGING ||
9890 action == ACTION_SNAPPING ||
9891 action == ACTION_COLLECTING);
9892 boolean action_moving = (action == ACTION_FALLING ||
9893 action == ACTION_MOVING ||
9894 action == ACTION_PUSHING ||
9895 action == ACTION_EATING ||
9896 action == ACTION_FILLING ||
9897 action == ACTION_EMPTYING);
9898 boolean action_falling = (action == ACTION_FALLING ||
9899 action == ACTION_FILLING ||
9900 action == ACTION_EMPTYING);
9902 /* special case: graphic uses "2nd movement tile" and has defined
9903 7 frames for movement animation (or less) => use default graphic
9904 for last (8th) frame which ends the movement animation */
9905 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9907 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9908 graphic = (direction == MV_NONE ?
9909 el_act2img(effective_element, action) :
9910 el_act_dir2img(effective_element, action, direction));
9912 g = &graphic_info[graphic];
9916 if (tile == Xsand_stonesand_1 ||
9917 tile == Xsand_stonesand_2 ||
9918 tile == Xsand_stonesand_3 ||
9919 tile == Xsand_stonesand_4)
9920 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9924 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9928 // printf("::: resetting... [%d]\n", tile);
9931 if (action_removing || check_linear_animation_EM(tile))
9933 GfxFrame[x][y] = frame_em;
9935 // printf("::: resetting... [%d]\n", tile);
9938 else if (action_moving)
9940 boolean is_backside = object_mapping[tile].is_backside;
9944 int direction = object_mapping[tile].direction;
9945 int move_dir = (action_falling ? MV_DOWN : direction);
9950 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9951 if (g->double_movement && frame_em == 0)
9955 // printf("::: resetting... [%d]\n", tile);
9959 if (move_dir == MV_LEFT)
9960 GfxFrame[x - 1][y] = GfxFrame[x][y];
9961 else if (move_dir == MV_RIGHT)
9962 GfxFrame[x + 1][y] = GfxFrame[x][y];
9963 else if (move_dir == MV_UP)
9964 GfxFrame[x][y - 1] = GfxFrame[x][y];
9965 else if (move_dir == MV_DOWN)
9966 GfxFrame[x][y + 1] = GfxFrame[x][y];
9973 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9974 if (tile == Xsand_stonesand_quickout_1 ||
9975 tile == Xsand_stonesand_quickout_2)
9980 if (tile == Xsand_stonesand_1 ||
9981 tile == Xsand_stonesand_2 ||
9982 tile == Xsand_stonesand_3 ||
9983 tile == Xsand_stonesand_4)
9984 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9988 if (graphic_info[graphic].anim_global_sync)
9989 sync_frame = FrameCounter;
9990 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9991 sync_frame = GfxFrame[x][y];
9993 sync_frame = 0; /* playfield border (pseudo steel) */
9995 SetRandomAnimationValue(x, y);
9997 int frame = getAnimationFrame(g->anim_frames,
10000 g->anim_start_frame,
10003 g_em->unique_identifier =
10004 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
10008 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
10009 int tile, int frame_em, int x, int y)
10011 int action = object_mapping[tile].action;
10012 int direction = object_mapping[tile].direction;
10013 boolean is_backside = object_mapping[tile].is_backside;
10014 int effective_element = get_effective_element_EM(tile, frame_em);
10016 int effective_action = action;
10018 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
10020 int graphic = (direction == MV_NONE ?
10021 el_act2img(effective_element, effective_action) :
10022 el_act_dir2img(effective_element, effective_action,
10024 int crumbled = (direction == MV_NONE ?
10025 el_act2crm(effective_element, effective_action) :
10026 el_act_dir2crm(effective_element, effective_action,
10028 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10029 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10030 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10031 struct GraphicInfo *g = &graphic_info[graphic];
10033 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10037 /* special case: graphic uses "2nd movement tile" and has defined
10038 7 frames for movement animation (or less) => use default graphic
10039 for last (8th) frame which ends the movement animation */
10040 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
10042 effective_action = ACTION_DEFAULT;
10043 graphic = (direction == MV_NONE ?
10044 el_act2img(effective_element, effective_action) :
10045 el_act_dir2img(effective_element, effective_action,
10047 crumbled = (direction == MV_NONE ?
10048 el_act2crm(effective_element, effective_action) :
10049 el_act_dir2crm(effective_element, effective_action,
10052 g = &graphic_info[graphic];
10062 if (frame_em == 0) /* reset animation frame for certain elements */
10064 if (check_linear_animation_EM(tile))
10065 GfxFrame[x][y] = 0;
10069 if (graphic_info[graphic].anim_global_sync)
10070 sync_frame = FrameCounter;
10071 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
10072 sync_frame = GfxFrame[x][y];
10074 sync_frame = 0; /* playfield border (pseudo steel) */
10076 SetRandomAnimationValue(x, y);
10081 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10082 i == Xdrip_stretchB ? 7 :
10083 i == Ydrip_s2 ? j + 8 :
10084 i == Ydrip_s2B ? j + 8 :
10086 i == Xacid_2 ? 10 :
10087 i == Xacid_3 ? 20 :
10088 i == Xacid_4 ? 30 :
10089 i == Xacid_5 ? 40 :
10090 i == Xacid_6 ? 50 :
10091 i == Xacid_7 ? 60 :
10092 i == Xacid_8 ? 70 :
10093 i == Xfake_acid_1 ? 0 :
10094 i == Xfake_acid_2 ? 10 :
10095 i == Xfake_acid_3 ? 20 :
10096 i == Xfake_acid_4 ? 30 :
10097 i == Xfake_acid_5 ? 40 :
10098 i == Xfake_acid_6 ? 50 :
10099 i == Xfake_acid_7 ? 60 :
10100 i == Xfake_acid_8 ? 70 :
10102 i == Xball_2B ? j + 8 :
10103 i == Yball_eat ? j + 1 :
10104 i == Ykey_1_eat ? j + 1 :
10105 i == Ykey_2_eat ? j + 1 :
10106 i == Ykey_3_eat ? j + 1 :
10107 i == Ykey_4_eat ? j + 1 :
10108 i == Ykey_5_eat ? j + 1 :
10109 i == Ykey_6_eat ? j + 1 :
10110 i == Ykey_7_eat ? j + 1 :
10111 i == Ykey_8_eat ? j + 1 :
10112 i == Ylenses_eat ? j + 1 :
10113 i == Ymagnify_eat ? j + 1 :
10114 i == Ygrass_eat ? j + 1 :
10115 i == Ydirt_eat ? j + 1 :
10116 i == Xamoeba_1 ? 0 :
10117 i == Xamoeba_2 ? 1 :
10118 i == Xamoeba_3 ? 2 :
10119 i == Xamoeba_4 ? 3 :
10120 i == Xamoeba_5 ? 0 :
10121 i == Xamoeba_6 ? 1 :
10122 i == Xamoeba_7 ? 2 :
10123 i == Xamoeba_8 ? 3 :
10124 i == Xexit_2 ? j + 8 :
10125 i == Xexit_3 ? j + 16 :
10126 i == Xdynamite_1 ? 0 :
10127 i == Xdynamite_2 ? 8 :
10128 i == Xdynamite_3 ? 16 :
10129 i == Xdynamite_4 ? 24 :
10130 i == Xsand_stonein_1 ? j + 1 :
10131 i == Xsand_stonein_2 ? j + 9 :
10132 i == Xsand_stonein_3 ? j + 17 :
10133 i == Xsand_stonein_4 ? j + 25 :
10134 i == Xsand_stoneout_1 && j == 0 ? 0 :
10135 i == Xsand_stoneout_1 && j == 1 ? 0 :
10136 i == Xsand_stoneout_1 && j == 2 ? 1 :
10137 i == Xsand_stoneout_1 && j == 3 ? 2 :
10138 i == Xsand_stoneout_1 && j == 4 ? 2 :
10139 i == Xsand_stoneout_1 && j == 5 ? 3 :
10140 i == Xsand_stoneout_1 && j == 6 ? 4 :
10141 i == Xsand_stoneout_1 && j == 7 ? 4 :
10142 i == Xsand_stoneout_2 && j == 0 ? 5 :
10143 i == Xsand_stoneout_2 && j == 1 ? 6 :
10144 i == Xsand_stoneout_2 && j == 2 ? 7 :
10145 i == Xsand_stoneout_2 && j == 3 ? 8 :
10146 i == Xsand_stoneout_2 && j == 4 ? 9 :
10147 i == Xsand_stoneout_2 && j == 5 ? 11 :
10148 i == Xsand_stoneout_2 && j == 6 ? 13 :
10149 i == Xsand_stoneout_2 && j == 7 ? 15 :
10150 i == Xboom_bug && j == 1 ? 2 :
10151 i == Xboom_bug && j == 2 ? 2 :
10152 i == Xboom_bug && j == 3 ? 4 :
10153 i == Xboom_bug && j == 4 ? 4 :
10154 i == Xboom_bug && j == 5 ? 2 :
10155 i == Xboom_bug && j == 6 ? 2 :
10156 i == Xboom_bug && j == 7 ? 0 :
10157 i == Xboom_bomb && j == 1 ? 2 :
10158 i == Xboom_bomb && j == 2 ? 2 :
10159 i == Xboom_bomb && j == 3 ? 4 :
10160 i == Xboom_bomb && j == 4 ? 4 :
10161 i == Xboom_bomb && j == 5 ? 2 :
10162 i == Xboom_bomb && j == 6 ? 2 :
10163 i == Xboom_bomb && j == 7 ? 0 :
10164 i == Xboom_android && j == 7 ? 6 :
10165 i == Xboom_1 && j == 1 ? 2 :
10166 i == Xboom_1 && j == 2 ? 2 :
10167 i == Xboom_1 && j == 3 ? 4 :
10168 i == Xboom_1 && j == 4 ? 4 :
10169 i == Xboom_1 && j == 5 ? 6 :
10170 i == Xboom_1 && j == 6 ? 6 :
10171 i == Xboom_1 && j == 7 ? 8 :
10172 i == Xboom_2 && j == 0 ? 8 :
10173 i == Xboom_2 && j == 1 ? 8 :
10174 i == Xboom_2 && j == 2 ? 10 :
10175 i == Xboom_2 && j == 3 ? 10 :
10176 i == Xboom_2 && j == 4 ? 10 :
10177 i == Xboom_2 && j == 5 ? 12 :
10178 i == Xboom_2 && j == 6 ? 12 :
10179 i == Xboom_2 && j == 7 ? 12 :
10181 special_animation && j == 4 ? 3 :
10182 effective_action != action ? 0 :
10188 int xxx_effective_action;
10189 int xxx_has_action_graphics;
10192 int element = object_mapping[i].element_rnd;
10193 int action = object_mapping[i].action;
10194 int direction = object_mapping[i].direction;
10195 boolean is_backside = object_mapping[i].is_backside;
10197 boolean action_removing = (action == ACTION_DIGGING ||
10198 action == ACTION_SNAPPING ||
10199 action == ACTION_COLLECTING);
10201 boolean action_exploding = ((action == ACTION_EXPLODING ||
10202 action == ACTION_SMASHED_BY_ROCK ||
10203 action == ACTION_SMASHED_BY_SPRING) &&
10204 element != EL_DIAMOND);
10205 boolean action_active = (action == ACTION_ACTIVE);
10206 boolean action_other = (action == ACTION_OTHER);
10210 int effective_element = get_effective_element_EM(i, j);
10212 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10213 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10215 i == Xdrip_stretch ? element :
10216 i == Xdrip_stretchB ? element :
10217 i == Ydrip_s1 ? element :
10218 i == Ydrip_s1B ? element :
10219 i == Xball_1B ? element :
10220 i == Xball_2 ? element :
10221 i == Xball_2B ? element :
10222 i == Yball_eat ? element :
10223 i == Ykey_1_eat ? element :
10224 i == Ykey_2_eat ? element :
10225 i == Ykey_3_eat ? element :
10226 i == Ykey_4_eat ? element :
10227 i == Ykey_5_eat ? element :
10228 i == Ykey_6_eat ? element :
10229 i == Ykey_7_eat ? element :
10230 i == Ykey_8_eat ? element :
10231 i == Ylenses_eat ? element :
10232 i == Ymagnify_eat ? element :
10233 i == Ygrass_eat ? element :
10234 i == Ydirt_eat ? element :
10235 i == Yemerald_stone ? EL_EMERALD :
10236 i == Ydiamond_stone ? EL_ROCK :
10237 i == Xsand_stonein_1 ? element :
10238 i == Xsand_stonein_2 ? element :
10239 i == Xsand_stonein_3 ? element :
10240 i == Xsand_stonein_4 ? element :
10241 is_backside ? EL_EMPTY :
10242 action_removing ? EL_EMPTY :
10245 int effective_action = (j < 7 ? action :
10246 i == Xdrip_stretch ? action :
10247 i == Xdrip_stretchB ? action :
10248 i == Ydrip_s1 ? action :
10249 i == Ydrip_s1B ? action :
10250 i == Xball_1B ? action :
10251 i == Xball_2 ? action :
10252 i == Xball_2B ? action :
10253 i == Yball_eat ? action :
10254 i == Ykey_1_eat ? action :
10255 i == Ykey_2_eat ? action :
10256 i == Ykey_3_eat ? action :
10257 i == Ykey_4_eat ? action :
10258 i == Ykey_5_eat ? action :
10259 i == Ykey_6_eat ? action :
10260 i == Ykey_7_eat ? action :
10261 i == Ykey_8_eat ? action :
10262 i == Ylenses_eat ? action :
10263 i == Ymagnify_eat ? action :
10264 i == Ygrass_eat ? action :
10265 i == Ydirt_eat ? action :
10266 i == Xsand_stonein_1 ? action :
10267 i == Xsand_stonein_2 ? action :
10268 i == Xsand_stonein_3 ? action :
10269 i == Xsand_stonein_4 ? action :
10270 i == Xsand_stoneout_1 ? action :
10271 i == Xsand_stoneout_2 ? action :
10272 i == Xboom_android ? ACTION_EXPLODING :
10273 action_exploding ? ACTION_EXPLODING :
10274 action_active ? action :
10275 action_other ? action :
10277 int graphic = (el_act_dir2img(effective_element, effective_action,
10279 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10281 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10282 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10283 boolean has_action_graphics = (graphic != base_graphic);
10284 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10285 struct GraphicInfo *g = &graphic_info[graphic];
10287 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10289 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10290 Bitmap *src_bitmap;
10292 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10293 boolean special_animation = (action != ACTION_DEFAULT &&
10294 g->anim_frames == 3 &&
10295 g->anim_delay == 2 &&
10296 g->anim_mode & ANIM_LINEAR);
10297 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10298 i == Xdrip_stretchB ? 7 :
10299 i == Ydrip_s2 ? j + 8 :
10300 i == Ydrip_s2B ? j + 8 :
10302 i == Xacid_2 ? 10 :
10303 i == Xacid_3 ? 20 :
10304 i == Xacid_4 ? 30 :
10305 i == Xacid_5 ? 40 :
10306 i == Xacid_6 ? 50 :
10307 i == Xacid_7 ? 60 :
10308 i == Xacid_8 ? 70 :
10309 i == Xfake_acid_1 ? 0 :
10310 i == Xfake_acid_2 ? 10 :
10311 i == Xfake_acid_3 ? 20 :
10312 i == Xfake_acid_4 ? 30 :
10313 i == Xfake_acid_5 ? 40 :
10314 i == Xfake_acid_6 ? 50 :
10315 i == Xfake_acid_7 ? 60 :
10316 i == Xfake_acid_8 ? 70 :
10318 i == Xball_2B ? j + 8 :
10319 i == Yball_eat ? j + 1 :
10320 i == Ykey_1_eat ? j + 1 :
10321 i == Ykey_2_eat ? j + 1 :
10322 i == Ykey_3_eat ? j + 1 :
10323 i == Ykey_4_eat ? j + 1 :
10324 i == Ykey_5_eat ? j + 1 :
10325 i == Ykey_6_eat ? j + 1 :
10326 i == Ykey_7_eat ? j + 1 :
10327 i == Ykey_8_eat ? j + 1 :
10328 i == Ylenses_eat ? j + 1 :
10329 i == Ymagnify_eat ? j + 1 :
10330 i == Ygrass_eat ? j + 1 :
10331 i == Ydirt_eat ? j + 1 :
10332 i == Xamoeba_1 ? 0 :
10333 i == Xamoeba_2 ? 1 :
10334 i == Xamoeba_3 ? 2 :
10335 i == Xamoeba_4 ? 3 :
10336 i == Xamoeba_5 ? 0 :
10337 i == Xamoeba_6 ? 1 :
10338 i == Xamoeba_7 ? 2 :
10339 i == Xamoeba_8 ? 3 :
10340 i == Xexit_2 ? j + 8 :
10341 i == Xexit_3 ? j + 16 :
10342 i == Xdynamite_1 ? 0 :
10343 i == Xdynamite_2 ? 8 :
10344 i == Xdynamite_3 ? 16 :
10345 i == Xdynamite_4 ? 24 :
10346 i == Xsand_stonein_1 ? j + 1 :
10347 i == Xsand_stonein_2 ? j + 9 :
10348 i == Xsand_stonein_3 ? j + 17 :
10349 i == Xsand_stonein_4 ? j + 25 :
10350 i == Xsand_stoneout_1 && j == 0 ? 0 :
10351 i == Xsand_stoneout_1 && j == 1 ? 0 :
10352 i == Xsand_stoneout_1 && j == 2 ? 1 :
10353 i == Xsand_stoneout_1 && j == 3 ? 2 :
10354 i == Xsand_stoneout_1 && j == 4 ? 2 :
10355 i == Xsand_stoneout_1 && j == 5 ? 3 :
10356 i == Xsand_stoneout_1 && j == 6 ? 4 :
10357 i == Xsand_stoneout_1 && j == 7 ? 4 :
10358 i == Xsand_stoneout_2 && j == 0 ? 5 :
10359 i == Xsand_stoneout_2 && j == 1 ? 6 :
10360 i == Xsand_stoneout_2 && j == 2 ? 7 :
10361 i == Xsand_stoneout_2 && j == 3 ? 8 :
10362 i == Xsand_stoneout_2 && j == 4 ? 9 :
10363 i == Xsand_stoneout_2 && j == 5 ? 11 :
10364 i == Xsand_stoneout_2 && j == 6 ? 13 :
10365 i == Xsand_stoneout_2 && j == 7 ? 15 :
10366 i == Xboom_bug && j == 1 ? 2 :
10367 i == Xboom_bug && j == 2 ? 2 :
10368 i == Xboom_bug && j == 3 ? 4 :
10369 i == Xboom_bug && j == 4 ? 4 :
10370 i == Xboom_bug && j == 5 ? 2 :
10371 i == Xboom_bug && j == 6 ? 2 :
10372 i == Xboom_bug && j == 7 ? 0 :
10373 i == Xboom_bomb && j == 1 ? 2 :
10374 i == Xboom_bomb && j == 2 ? 2 :
10375 i == Xboom_bomb && j == 3 ? 4 :
10376 i == Xboom_bomb && j == 4 ? 4 :
10377 i == Xboom_bomb && j == 5 ? 2 :
10378 i == Xboom_bomb && j == 6 ? 2 :
10379 i == Xboom_bomb && j == 7 ? 0 :
10380 i == Xboom_android && j == 7 ? 6 :
10381 i == Xboom_1 && j == 1 ? 2 :
10382 i == Xboom_1 && j == 2 ? 2 :
10383 i == Xboom_1 && j == 3 ? 4 :
10384 i == Xboom_1 && j == 4 ? 4 :
10385 i == Xboom_1 && j == 5 ? 6 :
10386 i == Xboom_1 && j == 6 ? 6 :
10387 i == Xboom_1 && j == 7 ? 8 :
10388 i == Xboom_2 && j == 0 ? 8 :
10389 i == Xboom_2 && j == 1 ? 8 :
10390 i == Xboom_2 && j == 2 ? 10 :
10391 i == Xboom_2 && j == 3 ? 10 :
10392 i == Xboom_2 && j == 4 ? 10 :
10393 i == Xboom_2 && j == 5 ? 12 :
10394 i == Xboom_2 && j == 6 ? 12 :
10395 i == Xboom_2 && j == 7 ? 12 :
10396 special_animation && j == 4 ? 3 :
10397 effective_action != action ? 0 :
10400 xxx_effective_action = effective_action;
10401 xxx_has_action_graphics = has_action_graphics;
10406 int frame = getAnimationFrame(g->anim_frames,
10409 g->anim_start_frame,
10423 int old_src_x = g_em->src_x;
10424 int old_src_y = g_em->src_y;
10428 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
10429 g->double_movement && is_backside);
10431 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10432 &g_em->src_x, &g_em->src_y, FALSE);
10437 if (tile == Ydiamond_stone)
10438 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
10443 g->anim_start_frame,
10446 g_em->src_x, g_em->src_y,
10447 g_em->src_offset_x, g_em->src_offset_y,
10448 g_em->dst_offset_x, g_em->dst_offset_y,
10460 if (graphic == IMG_BUG_MOVING_RIGHT)
10461 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10462 g->double_movement, is_backside,
10463 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10471 g_em->src_offset_x = 0;
10472 g_em->src_offset_y = 0;
10473 g_em->dst_offset_x = 0;
10474 g_em->dst_offset_y = 0;
10475 g_em->width = TILEX;
10476 g_em->height = TILEY;
10478 g_em->preserve_background = FALSE;
10481 /* (updating the "crumbled" graphic definitions is probably not really needed,
10482 as animations for crumbled graphics can't be longer than one EMC cycle) */
10484 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10489 g_em->crumbled_bitmap = NULL;
10490 g_em->crumbled_src_x = 0;
10491 g_em->crumbled_src_y = 0;
10493 g_em->has_crumbled_graphics = FALSE;
10495 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10497 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10498 g_crumbled->anim_delay,
10499 g_crumbled->anim_mode,
10500 g_crumbled->anim_start_frame,
10503 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10504 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10506 g_em->has_crumbled_graphics = TRUE;
10512 int effective_action = xxx_effective_action;
10513 int has_action_graphics = xxx_has_action_graphics;
10515 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10516 effective_action == ACTION_MOVING ||
10517 effective_action == ACTION_PUSHING ||
10518 effective_action == ACTION_EATING)) ||
10519 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10520 effective_action == ACTION_EMPTYING)))
10523 (effective_action == ACTION_FALLING ||
10524 effective_action == ACTION_FILLING ||
10525 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10526 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10527 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10528 int num_steps = (i == Ydrip_s1 ? 16 :
10529 i == Ydrip_s1B ? 16 :
10530 i == Ydrip_s2 ? 16 :
10531 i == Ydrip_s2B ? 16 :
10532 i == Xsand_stonein_1 ? 32 :
10533 i == Xsand_stonein_2 ? 32 :
10534 i == Xsand_stonein_3 ? 32 :
10535 i == Xsand_stonein_4 ? 32 :
10536 i == Xsand_stoneout_1 ? 16 :
10537 i == Xsand_stoneout_2 ? 16 : 8);
10538 int cx = ABS(dx) * (TILEX / num_steps);
10539 int cy = ABS(dy) * (TILEY / num_steps);
10540 int step_frame = (i == Ydrip_s2 ? j + 8 :
10541 i == Ydrip_s2B ? j + 8 :
10542 i == Xsand_stonein_2 ? j + 8 :
10543 i == Xsand_stonein_3 ? j + 16 :
10544 i == Xsand_stonein_4 ? j + 24 :
10545 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10546 int step = (is_backside ? step_frame : num_steps - step_frame);
10548 if (is_backside) /* tile where movement starts */
10550 if (dx < 0 || dy < 0)
10552 g_em->src_offset_x = cx * step;
10553 g_em->src_offset_y = cy * step;
10557 g_em->dst_offset_x = cx * step;
10558 g_em->dst_offset_y = cy * step;
10561 else /* tile where movement ends */
10563 if (dx < 0 || dy < 0)
10565 g_em->dst_offset_x = cx * step;
10566 g_em->dst_offset_y = cy * step;
10570 g_em->src_offset_x = cx * step;
10571 g_em->src_offset_y = cy * step;
10575 g_em->width = TILEX - cx * step;
10576 g_em->height = TILEY - cy * step;
10579 /* create unique graphic identifier to decide if tile must be redrawn */
10580 /* bit 31 - 16 (16 bit): EM style graphic
10581 bit 15 - 12 ( 4 bit): EM style frame
10582 bit 11 - 6 ( 6 bit): graphic width
10583 bit 5 - 0 ( 6 bit): graphic height */
10584 g_em->unique_identifier =
10585 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10591 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10592 int player_nr, int anim, int frame_em)
10594 int element = player_mapping[player_nr][anim].element_rnd;
10595 int action = player_mapping[player_nr][anim].action;
10596 int direction = player_mapping[player_nr][anim].direction;
10597 int graphic = (direction == MV_NONE ?
10598 el_act2img(element, action) :
10599 el_act_dir2img(element, action, direction));
10600 struct GraphicInfo *g = &graphic_info[graphic];
10603 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10605 stored_player[player_nr].StepFrame = frame_em;
10607 sync_frame = stored_player[player_nr].Frame;
10609 int frame = getAnimationFrame(g->anim_frames,
10612 g->anim_start_frame,
10615 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10616 &g_em->src_x, &g_em->src_y, FALSE);
10619 printf("::: %d: %d, %d [%d]\n",
10621 stored_player[player_nr].Frame,
10622 stored_player[player_nr].StepFrame,
10627 void InitGraphicInfo_EM(void)
10630 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10631 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10636 int num_em_gfx_errors = 0;
10638 if (graphic_info_em_object[0][0].bitmap == NULL)
10640 /* EM graphics not yet initialized in em_open_all() */
10645 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10648 /* always start with reliable default values */
10649 for (i = 0; i < TILE_MAX; i++)
10651 object_mapping[i].element_rnd = EL_UNKNOWN;
10652 object_mapping[i].is_backside = FALSE;
10653 object_mapping[i].action = ACTION_DEFAULT;
10654 object_mapping[i].direction = MV_NONE;
10657 /* always start with reliable default values */
10658 for (p = 0; p < MAX_PLAYERS; p++)
10660 for (i = 0; i < SPR_MAX; i++)
10662 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10663 player_mapping[p][i].action = ACTION_DEFAULT;
10664 player_mapping[p][i].direction = MV_NONE;
10668 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10670 int e = em_object_mapping_list[i].element_em;
10672 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10673 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10675 if (em_object_mapping_list[i].action != -1)
10676 object_mapping[e].action = em_object_mapping_list[i].action;
10678 if (em_object_mapping_list[i].direction != -1)
10679 object_mapping[e].direction =
10680 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10683 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10685 int a = em_player_mapping_list[i].action_em;
10686 int p = em_player_mapping_list[i].player_nr;
10688 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10690 if (em_player_mapping_list[i].action != -1)
10691 player_mapping[p][a].action = em_player_mapping_list[i].action;
10693 if (em_player_mapping_list[i].direction != -1)
10694 player_mapping[p][a].direction =
10695 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10698 for (i = 0; i < TILE_MAX; i++)
10700 int element = object_mapping[i].element_rnd;
10701 int action = object_mapping[i].action;
10702 int direction = object_mapping[i].direction;
10703 boolean is_backside = object_mapping[i].is_backside;
10705 boolean action_removing = (action == ACTION_DIGGING ||
10706 action == ACTION_SNAPPING ||
10707 action == ACTION_COLLECTING);
10709 boolean action_exploding = ((action == ACTION_EXPLODING ||
10710 action == ACTION_SMASHED_BY_ROCK ||
10711 action == ACTION_SMASHED_BY_SPRING) &&
10712 element != EL_DIAMOND);
10713 boolean action_active = (action == ACTION_ACTIVE);
10714 boolean action_other = (action == ACTION_OTHER);
10716 for (j = 0; j < 8; j++)
10719 int effective_element = get_effective_element_EM(i, j);
10721 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10722 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10724 i == Xdrip_stretch ? element :
10725 i == Xdrip_stretchB ? element :
10726 i == Ydrip_s1 ? element :
10727 i == Ydrip_s1B ? element :
10728 i == Xball_1B ? element :
10729 i == Xball_2 ? element :
10730 i == Xball_2B ? element :
10731 i == Yball_eat ? element :
10732 i == Ykey_1_eat ? element :
10733 i == Ykey_2_eat ? element :
10734 i == Ykey_3_eat ? element :
10735 i == Ykey_4_eat ? element :
10736 i == Ykey_5_eat ? element :
10737 i == Ykey_6_eat ? element :
10738 i == Ykey_7_eat ? element :
10739 i == Ykey_8_eat ? element :
10740 i == Ylenses_eat ? element :
10741 i == Ymagnify_eat ? element :
10742 i == Ygrass_eat ? element :
10743 i == Ydirt_eat ? element :
10744 i == Yemerald_stone ? EL_EMERALD :
10745 i == Ydiamond_stone ? EL_ROCK :
10746 i == Xsand_stonein_1 ? element :
10747 i == Xsand_stonein_2 ? element :
10748 i == Xsand_stonein_3 ? element :
10749 i == Xsand_stonein_4 ? element :
10750 is_backside ? EL_EMPTY :
10751 action_removing ? EL_EMPTY :
10754 int effective_action = (j < 7 ? action :
10755 i == Xdrip_stretch ? action :
10756 i == Xdrip_stretchB ? action :
10757 i == Ydrip_s1 ? action :
10758 i == Ydrip_s1B ? action :
10759 i == Xball_1B ? action :
10760 i == Xball_2 ? action :
10761 i == Xball_2B ? action :
10762 i == Yball_eat ? action :
10763 i == Ykey_1_eat ? action :
10764 i == Ykey_2_eat ? action :
10765 i == Ykey_3_eat ? action :
10766 i == Ykey_4_eat ? action :
10767 i == Ykey_5_eat ? action :
10768 i == Ykey_6_eat ? action :
10769 i == Ykey_7_eat ? action :
10770 i == Ykey_8_eat ? action :
10771 i == Ylenses_eat ? action :
10772 i == Ymagnify_eat ? action :
10773 i == Ygrass_eat ? action :
10774 i == Ydirt_eat ? action :
10775 i == Xsand_stonein_1 ? action :
10776 i == Xsand_stonein_2 ? action :
10777 i == Xsand_stonein_3 ? action :
10778 i == Xsand_stonein_4 ? action :
10779 i == Xsand_stoneout_1 ? action :
10780 i == Xsand_stoneout_2 ? action :
10781 i == Xboom_android ? ACTION_EXPLODING :
10782 action_exploding ? ACTION_EXPLODING :
10783 action_active ? action :
10784 action_other ? action :
10786 int graphic = (el_act_dir2img(effective_element, effective_action,
10788 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10790 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10791 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10792 boolean has_action_graphics = (graphic != base_graphic);
10793 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10794 struct GraphicInfo *g = &graphic_info[graphic];
10796 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10798 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10799 Bitmap *src_bitmap;
10801 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10802 boolean special_animation = (action != ACTION_DEFAULT &&
10803 g->anim_frames == 3 &&
10804 g->anim_delay == 2 &&
10805 g->anim_mode & ANIM_LINEAR);
10806 int sync_frame = (i == Xdrip_stretch ? 7 :
10807 i == Xdrip_stretchB ? 7 :
10808 i == Ydrip_s2 ? j + 8 :
10809 i == Ydrip_s2B ? j + 8 :
10811 i == Xacid_2 ? 10 :
10812 i == Xacid_3 ? 20 :
10813 i == Xacid_4 ? 30 :
10814 i == Xacid_5 ? 40 :
10815 i == Xacid_6 ? 50 :
10816 i == Xacid_7 ? 60 :
10817 i == Xacid_8 ? 70 :
10818 i == Xfake_acid_1 ? 0 :
10819 i == Xfake_acid_2 ? 10 :
10820 i == Xfake_acid_3 ? 20 :
10821 i == Xfake_acid_4 ? 30 :
10822 i == Xfake_acid_5 ? 40 :
10823 i == Xfake_acid_6 ? 50 :
10824 i == Xfake_acid_7 ? 60 :
10825 i == Xfake_acid_8 ? 70 :
10827 i == Xball_2B ? j + 8 :
10828 i == Yball_eat ? j + 1 :
10829 i == Ykey_1_eat ? j + 1 :
10830 i == Ykey_2_eat ? j + 1 :
10831 i == Ykey_3_eat ? j + 1 :
10832 i == Ykey_4_eat ? j + 1 :
10833 i == Ykey_5_eat ? j + 1 :
10834 i == Ykey_6_eat ? j + 1 :
10835 i == Ykey_7_eat ? j + 1 :
10836 i == Ykey_8_eat ? j + 1 :
10837 i == Ylenses_eat ? j + 1 :
10838 i == Ymagnify_eat ? j + 1 :
10839 i == Ygrass_eat ? j + 1 :
10840 i == Ydirt_eat ? j + 1 :
10841 i == Xamoeba_1 ? 0 :
10842 i == Xamoeba_2 ? 1 :
10843 i == Xamoeba_3 ? 2 :
10844 i == Xamoeba_4 ? 3 :
10845 i == Xamoeba_5 ? 0 :
10846 i == Xamoeba_6 ? 1 :
10847 i == Xamoeba_7 ? 2 :
10848 i == Xamoeba_8 ? 3 :
10849 i == Xexit_2 ? j + 8 :
10850 i == Xexit_3 ? j + 16 :
10851 i == Xdynamite_1 ? 0 :
10852 i == Xdynamite_2 ? 8 :
10853 i == Xdynamite_3 ? 16 :
10854 i == Xdynamite_4 ? 24 :
10855 i == Xsand_stonein_1 ? j + 1 :
10856 i == Xsand_stonein_2 ? j + 9 :
10857 i == Xsand_stonein_3 ? j + 17 :
10858 i == Xsand_stonein_4 ? j + 25 :
10859 i == Xsand_stoneout_1 && j == 0 ? 0 :
10860 i == Xsand_stoneout_1 && j == 1 ? 0 :
10861 i == Xsand_stoneout_1 && j == 2 ? 1 :
10862 i == Xsand_stoneout_1 && j == 3 ? 2 :
10863 i == Xsand_stoneout_1 && j == 4 ? 2 :
10864 i == Xsand_stoneout_1 && j == 5 ? 3 :
10865 i == Xsand_stoneout_1 && j == 6 ? 4 :
10866 i == Xsand_stoneout_1 && j == 7 ? 4 :
10867 i == Xsand_stoneout_2 && j == 0 ? 5 :
10868 i == Xsand_stoneout_2 && j == 1 ? 6 :
10869 i == Xsand_stoneout_2 && j == 2 ? 7 :
10870 i == Xsand_stoneout_2 && j == 3 ? 8 :
10871 i == Xsand_stoneout_2 && j == 4 ? 9 :
10872 i == Xsand_stoneout_2 && j == 5 ? 11 :
10873 i == Xsand_stoneout_2 && j == 6 ? 13 :
10874 i == Xsand_stoneout_2 && j == 7 ? 15 :
10875 i == Xboom_bug && j == 1 ? 2 :
10876 i == Xboom_bug && j == 2 ? 2 :
10877 i == Xboom_bug && j == 3 ? 4 :
10878 i == Xboom_bug && j == 4 ? 4 :
10879 i == Xboom_bug && j == 5 ? 2 :
10880 i == Xboom_bug && j == 6 ? 2 :
10881 i == Xboom_bug && j == 7 ? 0 :
10882 i == Xboom_bomb && j == 1 ? 2 :
10883 i == Xboom_bomb && j == 2 ? 2 :
10884 i == Xboom_bomb && j == 3 ? 4 :
10885 i == Xboom_bomb && j == 4 ? 4 :
10886 i == Xboom_bomb && j == 5 ? 2 :
10887 i == Xboom_bomb && j == 6 ? 2 :
10888 i == Xboom_bomb && j == 7 ? 0 :
10889 i == Xboom_android && j == 7 ? 6 :
10890 i == Xboom_1 && j == 1 ? 2 :
10891 i == Xboom_1 && j == 2 ? 2 :
10892 i == Xboom_1 && j == 3 ? 4 :
10893 i == Xboom_1 && j == 4 ? 4 :
10894 i == Xboom_1 && j == 5 ? 6 :
10895 i == Xboom_1 && j == 6 ? 6 :
10896 i == Xboom_1 && j == 7 ? 8 :
10897 i == Xboom_2 && j == 0 ? 8 :
10898 i == Xboom_2 && j == 1 ? 8 :
10899 i == Xboom_2 && j == 2 ? 10 :
10900 i == Xboom_2 && j == 3 ? 10 :
10901 i == Xboom_2 && j == 4 ? 10 :
10902 i == Xboom_2 && j == 5 ? 12 :
10903 i == Xboom_2 && j == 6 ? 12 :
10904 i == Xboom_2 && j == 7 ? 12 :
10905 special_animation && j == 4 ? 3 :
10906 effective_action != action ? 0 :
10910 Bitmap *debug_bitmap = g_em->bitmap;
10911 int debug_src_x = g_em->src_x;
10912 int debug_src_y = g_em->src_y;
10915 int frame = getAnimationFrame(g->anim_frames,
10918 g->anim_start_frame,
10921 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10922 g->double_movement && is_backside);
10924 g_em->bitmap = src_bitmap;
10925 g_em->src_x = src_x;
10926 g_em->src_y = src_y;
10927 g_em->src_offset_x = 0;
10928 g_em->src_offset_y = 0;
10929 g_em->dst_offset_x = 0;
10930 g_em->dst_offset_y = 0;
10931 g_em->width = TILEX;
10932 g_em->height = TILEY;
10934 g_em->preserve_background = FALSE;
10937 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10942 g_em->crumbled_bitmap = NULL;
10943 g_em->crumbled_src_x = 0;
10944 g_em->crumbled_src_y = 0;
10945 g_em->crumbled_border_size = 0;
10947 g_em->has_crumbled_graphics = FALSE;
10950 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10951 printf("::: empty crumbled: %d [%s], %d, %d\n",
10952 effective_element, element_info[effective_element].token_name,
10953 effective_action, direction);
10956 /* if element can be crumbled, but certain action graphics are just empty
10957 space (like instantly snapping sand to empty space in 1 frame), do not
10958 treat these empty space graphics as crumbled graphics in EMC engine */
10959 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10961 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10962 g_crumbled->anim_delay,
10963 g_crumbled->anim_mode,
10964 g_crumbled->anim_start_frame,
10967 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10969 g_em->has_crumbled_graphics = TRUE;
10970 g_em->crumbled_bitmap = src_bitmap;
10971 g_em->crumbled_src_x = src_x;
10972 g_em->crumbled_src_y = src_y;
10973 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10977 if (g_em == &graphic_info_em_object[207][0])
10978 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10979 graphic_info_em_object[207][0].crumbled_src_x,
10980 graphic_info_em_object[207][0].crumbled_src_y,
10982 crumbled, frame, src_x, src_y,
10987 g->anim_start_frame,
10989 gfx.anim_random_frame,
10994 printf("::: EMC tile %d is crumbled\n", i);
11000 if (element == EL_ROCK &&
11001 effective_action == ACTION_FILLING)
11002 printf("::: has_action_graphics == %d\n", has_action_graphics);
11005 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
11006 effective_action == ACTION_MOVING ||
11007 effective_action == ACTION_PUSHING ||
11008 effective_action == ACTION_EATING)) ||
11009 (!has_action_graphics && (effective_action == ACTION_FILLING ||
11010 effective_action == ACTION_EMPTYING)))
11013 (effective_action == ACTION_FALLING ||
11014 effective_action == ACTION_FILLING ||
11015 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
11016 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
11017 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
11018 int num_steps = (i == Ydrip_s1 ? 16 :
11019 i == Ydrip_s1B ? 16 :
11020 i == Ydrip_s2 ? 16 :
11021 i == Ydrip_s2B ? 16 :
11022 i == Xsand_stonein_1 ? 32 :
11023 i == Xsand_stonein_2 ? 32 :
11024 i == Xsand_stonein_3 ? 32 :
11025 i == Xsand_stonein_4 ? 32 :
11026 i == Xsand_stoneout_1 ? 16 :
11027 i == Xsand_stoneout_2 ? 16 : 8);
11028 int cx = ABS(dx) * (TILEX / num_steps);
11029 int cy = ABS(dy) * (TILEY / num_steps);
11030 int step_frame = (i == Ydrip_s2 ? j + 8 :
11031 i == Ydrip_s2B ? j + 8 :
11032 i == Xsand_stonein_2 ? j + 8 :
11033 i == Xsand_stonein_3 ? j + 16 :
11034 i == Xsand_stonein_4 ? j + 24 :
11035 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
11036 int step = (is_backside ? step_frame : num_steps - step_frame);
11038 if (is_backside) /* tile where movement starts */
11040 if (dx < 0 || dy < 0)
11042 g_em->src_offset_x = cx * step;
11043 g_em->src_offset_y = cy * step;
11047 g_em->dst_offset_x = cx * step;
11048 g_em->dst_offset_y = cy * step;
11051 else /* tile where movement ends */
11053 if (dx < 0 || dy < 0)
11055 g_em->dst_offset_x = cx * step;
11056 g_em->dst_offset_y = cy * step;
11060 g_em->src_offset_x = cx * step;
11061 g_em->src_offset_y = cy * step;
11065 g_em->width = TILEX - cx * step;
11066 g_em->height = TILEY - cy * step;
11069 /* create unique graphic identifier to decide if tile must be redrawn */
11070 /* bit 31 - 16 (16 bit): EM style graphic
11071 bit 15 - 12 ( 4 bit): EM style frame
11072 bit 11 - 6 ( 6 bit): graphic width
11073 bit 5 - 0 ( 6 bit): graphic height */
11074 g_em->unique_identifier =
11075 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
11079 /* skip check for EMC elements not contained in original EMC artwork */
11080 if (element == EL_EMC_FAKE_ACID)
11083 if (g_em->bitmap != debug_bitmap ||
11084 g_em->src_x != debug_src_x ||
11085 g_em->src_y != debug_src_y ||
11086 g_em->src_offset_x != 0 ||
11087 g_em->src_offset_y != 0 ||
11088 g_em->dst_offset_x != 0 ||
11089 g_em->dst_offset_y != 0 ||
11090 g_em->width != TILEX ||
11091 g_em->height != TILEY)
11093 static int last_i = -1;
11101 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
11102 i, element, element_info[element].token_name,
11103 element_action_info[effective_action].suffix, direction);
11105 if (element != effective_element)
11106 printf(" [%d ('%s')]",
11108 element_info[effective_element].token_name);
11112 if (g_em->bitmap != debug_bitmap)
11113 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
11114 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
11116 if (g_em->src_x != debug_src_x ||
11117 g_em->src_y != debug_src_y)
11118 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11119 j, (is_backside ? 'B' : 'F'),
11120 g_em->src_x, g_em->src_y,
11121 g_em->src_x / 32, g_em->src_y / 32,
11122 debug_src_x, debug_src_y,
11123 debug_src_x / 32, debug_src_y / 32);
11125 if (g_em->src_offset_x != 0 ||
11126 g_em->src_offset_y != 0 ||
11127 g_em->dst_offset_x != 0 ||
11128 g_em->dst_offset_y != 0)
11129 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
11131 g_em->src_offset_x, g_em->src_offset_y,
11132 g_em->dst_offset_x, g_em->dst_offset_y);
11134 if (g_em->width != TILEX ||
11135 g_em->height != TILEY)
11136 printf(" %d (%d): size %d,%d should be %d,%d\n",
11138 g_em->width, g_em->height, TILEX, TILEY);
11140 num_em_gfx_errors++;
11147 for (i = 0; i < TILE_MAX; i++)
11149 for (j = 0; j < 8; j++)
11151 int element = object_mapping[i].element_rnd;
11152 int action = object_mapping[i].action;
11153 int direction = object_mapping[i].direction;
11154 boolean is_backside = object_mapping[i].is_backside;
11155 int graphic_action = el_act_dir2img(element, action, direction);
11156 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
11158 if ((action == ACTION_SMASHED_BY_ROCK ||
11159 action == ACTION_SMASHED_BY_SPRING ||
11160 action == ACTION_EATING) &&
11161 graphic_action == graphic_default)
11163 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
11164 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
11165 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
11166 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
11169 /* no separate animation for "smashed by rock" -- use rock instead */
11170 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
11171 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
11173 g_em->bitmap = g_xx->bitmap;
11174 g_em->src_x = g_xx->src_x;
11175 g_em->src_y = g_xx->src_y;
11176 g_em->src_offset_x = g_xx->src_offset_x;
11177 g_em->src_offset_y = g_xx->src_offset_y;
11178 g_em->dst_offset_x = g_xx->dst_offset_x;
11179 g_em->dst_offset_y = g_xx->dst_offset_y;
11180 g_em->width = g_xx->width;
11181 g_em->height = g_xx->height;
11182 g_em->unique_identifier = g_xx->unique_identifier;
11185 g_em->preserve_background = TRUE;
11190 for (p = 0; p < MAX_PLAYERS; p++)
11192 for (i = 0; i < SPR_MAX; i++)
11194 int element = player_mapping[p][i].element_rnd;
11195 int action = player_mapping[p][i].action;
11196 int direction = player_mapping[p][i].direction;
11198 for (j = 0; j < 8; j++)
11200 int effective_element = element;
11201 int effective_action = action;
11202 int graphic = (direction == MV_NONE ?
11203 el_act2img(effective_element, effective_action) :
11204 el_act_dir2img(effective_element, effective_action,
11206 struct GraphicInfo *g = &graphic_info[graphic];
11207 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
11208 Bitmap *src_bitmap;
11210 int sync_frame = j;
11213 Bitmap *debug_bitmap = g_em->bitmap;
11214 int debug_src_x = g_em->src_x;
11215 int debug_src_y = g_em->src_y;
11218 int frame = getAnimationFrame(g->anim_frames,
11221 g->anim_start_frame,
11224 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
11226 g_em->bitmap = src_bitmap;
11227 g_em->src_x = src_x;
11228 g_em->src_y = src_y;
11229 g_em->src_offset_x = 0;
11230 g_em->src_offset_y = 0;
11231 g_em->dst_offset_x = 0;
11232 g_em->dst_offset_y = 0;
11233 g_em->width = TILEX;
11234 g_em->height = TILEY;
11238 /* skip check for EMC elements not contained in original EMC artwork */
11239 if (element == EL_PLAYER_3 ||
11240 element == EL_PLAYER_4)
11243 if (g_em->bitmap != debug_bitmap ||
11244 g_em->src_x != debug_src_x ||
11245 g_em->src_y != debug_src_y)
11247 static int last_i = -1;
11255 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
11256 p, i, element, element_info[element].token_name,
11257 element_action_info[effective_action].suffix, direction);
11259 if (element != effective_element)
11260 printf(" [%d ('%s')]",
11262 element_info[effective_element].token_name);
11266 if (g_em->bitmap != debug_bitmap)
11267 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
11268 j, (int)(g_em->bitmap), (int)(debug_bitmap));
11270 if (g_em->src_x != debug_src_x ||
11271 g_em->src_y != debug_src_y)
11272 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11274 g_em->src_x, g_em->src_y,
11275 g_em->src_x / 32, g_em->src_y / 32,
11276 debug_src_x, debug_src_y,
11277 debug_src_x / 32, debug_src_y / 32);
11279 num_em_gfx_errors++;
11289 printf("::: [%d errors found]\n", num_em_gfx_errors);
11295 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
11296 boolean any_player_moving,
11297 boolean player_is_dropping)
11299 if (tape.single_step && tape.recording && !tape.pausing)
11302 boolean active_players = FALSE;
11305 for (i = 0; i < MAX_PLAYERS; i++)
11306 if (action[i] != JOY_NO_ACTION)
11307 active_players = TRUE;
11311 if (frame == 0 && !player_is_dropping)
11312 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11316 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
11317 boolean murphy_is_dropping)
11320 printf("::: waiting: %d, dropping: %d\n",
11321 murphy_is_waiting, murphy_is_dropping);
11324 if (tape.single_step && tape.recording && !tape.pausing)
11326 // if (murphy_is_waiting || murphy_is_dropping)
11327 if (murphy_is_waiting)
11330 printf("::: murphy is waiting -> pause mode\n");
11333 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11338 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
11339 int graphic, int sync_frame, int x, int y)
11341 int frame = getGraphicAnimationFrame(graphic, sync_frame);
11343 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
11346 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
11348 return (IS_NEXT_FRAME(sync_frame, graphic));
11351 int getGraphicInfo_Delay(int graphic)
11353 return graphic_info[graphic].anim_delay;
11356 void PlayMenuSoundExt(int sound)
11358 if (sound == SND_UNDEFINED)
11361 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11362 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11365 if (IS_LOOP_SOUND(sound))
11366 PlaySoundLoop(sound);
11371 void PlayMenuSound()
11373 PlayMenuSoundExt(menu.sound[game_status]);
11376 void PlayMenuSoundStereo(int sound, int stereo_position)
11378 if (sound == SND_UNDEFINED)
11381 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11382 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11385 if (IS_LOOP_SOUND(sound))
11386 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
11388 PlaySoundStereo(sound, stereo_position);
11391 void PlayMenuSoundIfLoopExt(int sound)
11393 if (sound == SND_UNDEFINED)
11396 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11397 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11400 if (IS_LOOP_SOUND(sound))
11401 PlaySoundLoop(sound);
11404 void PlayMenuSoundIfLoop()
11406 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
11409 void PlayMenuMusicExt(int music)
11411 if (music == MUS_UNDEFINED)
11414 if (!setup.sound_music)
11420 void PlayMenuMusic()
11422 PlayMenuMusicExt(menu.music[game_status]);
11425 void PlaySoundActivating()
11428 PlaySound(SND_MENU_ITEM_ACTIVATING);
11432 void PlaySoundSelecting()
11435 PlaySound(SND_MENU_ITEM_SELECTING);
11439 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
11441 boolean change_fullscreen = (setup.fullscreen !=
11442 video.fullscreen_enabled);
11443 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
11444 !strEqual(setup.fullscreen_mode,
11445 video.fullscreen_mode_current));
11446 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
11447 setup.window_scaling_percent !=
11448 video.window_scaling_percent);
11450 if (change_window_scaling_percent && video.fullscreen_enabled)
11453 if (!change_window_scaling_percent && !video.fullscreen_available)
11456 #if defined(TARGET_SDL2)
11457 if (change_window_scaling_percent)
11459 SDLSetWindowScaling(setup.window_scaling_percent);
11463 else if (change_fullscreen)
11465 SDLSetWindowFullscreen(setup.fullscreen);
11467 /* set setup value according to successfully changed fullscreen mode */
11468 setup.fullscreen = video.fullscreen_enabled;
11474 if (change_fullscreen ||
11475 change_fullscreen_mode ||
11476 change_window_scaling_percent)
11478 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11480 /* save backbuffer content which gets lost when toggling fullscreen mode */
11481 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11483 if (change_fullscreen_mode)
11485 /* keep fullscreen, but change fullscreen mode (screen resolution) */
11486 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
11489 if (change_window_scaling_percent)
11491 /* keep window mode, but change window scaling */
11492 video.fullscreen_enabled = TRUE; /* force new window scaling */
11495 /* toggle fullscreen */
11496 ChangeVideoModeIfNeeded(setup.fullscreen);
11498 /* set setup value according to successfully changed fullscreen mode */
11499 setup.fullscreen = video.fullscreen_enabled;
11501 /* restore backbuffer content from temporary backbuffer backup bitmap */
11502 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11504 FreeBitmap(tmp_backbuffer);
11507 /* update visible window/screen */
11508 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11510 redraw_mask = REDRAW_ALL;
11515 void ChangeViewportPropertiesIfNeeded()
11518 int *door_1_x = &DX;
11519 int *door_1_y = &DY;
11520 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11521 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11524 int gfx_game_mode = game_status;
11526 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11527 game_status == GAME_MODE_EDITOR ? game_status :
11530 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11532 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11533 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11534 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11535 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11536 int border_size = vp_playfield->border_size;
11537 int new_sx = vp_playfield->x + border_size;
11538 int new_sy = vp_playfield->y + border_size;
11539 int new_sxsize = vp_playfield->width - 2 * border_size;
11540 int new_sysize = vp_playfield->height - 2 * border_size;
11541 int new_real_sx = vp_playfield->x;
11542 int new_real_sy = vp_playfield->y;
11543 int new_full_sxsize = vp_playfield->width;
11544 int new_full_sysize = vp_playfield->height;
11545 int new_dx = vp_door_1->x;
11546 int new_dy = vp_door_1->y;
11547 int new_dxsize = vp_door_1->width;
11548 int new_dysize = vp_door_1->height;
11549 int new_vx = vp_door_2->x;
11550 int new_vy = vp_door_2->y;
11551 int new_vxsize = vp_door_2->width;
11552 int new_vysize = vp_door_2->height;
11553 int new_ex = vp_door_3->x;
11554 int new_ey = vp_door_3->y;
11555 int new_exsize = vp_door_3->width;
11556 int new_eysize = vp_door_3->height;
11559 #if NEW_GAME_TILESIZE
11560 int new_tilesize_var =
11561 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
11563 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11566 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11567 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11568 int new_scr_fieldx = new_sxsize / tilesize;
11569 int new_scr_fieldy = new_sysize / tilesize;
11570 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11571 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11573 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
11574 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11576 boolean init_gfx_buffers = FALSE;
11577 boolean init_video_buffer = FALSE;
11578 boolean init_gadgets_and_toons = FALSE;
11579 boolean init_em_graphics = FALSE;
11582 /* !!! TEST ONLY !!! */
11583 // InitGfxBuffers();
11587 if (viewport.window.width != WIN_XSIZE ||
11588 viewport.window.height != WIN_YSIZE)
11590 WIN_XSIZE = viewport.window.width;
11591 WIN_YSIZE = viewport.window.height;
11594 init_video_buffer = TRUE;
11595 init_gfx_buffers = TRUE;
11597 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11601 SetDrawDeactivationMask(REDRAW_NONE);
11602 SetDrawBackgroundMask(REDRAW_FIELD);
11604 // RedrawBackground();
11608 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11611 if (new_scr_fieldx != SCR_FIELDX ||
11612 new_scr_fieldy != SCR_FIELDY)
11614 /* this always toggles between MAIN and GAME when using small tile size */
11616 SCR_FIELDX = new_scr_fieldx;
11617 SCR_FIELDY = new_scr_fieldy;
11619 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11623 if (new_tilesize_var != TILESIZE_VAR &&
11624 gfx_game_mode == GAME_MODE_PLAYING)
11626 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11628 TILESIZE_VAR = new_tilesize_var;
11630 init_gfx_buffers = TRUE;
11632 // printf("::: tilesize: init_gfx_buffers\n");
11636 if (new_sx != SX ||
11644 new_sxsize != SXSIZE ||
11645 new_sysize != SYSIZE ||
11646 new_dxsize != DXSIZE ||
11647 new_dysize != DYSIZE ||
11648 new_vxsize != VXSIZE ||
11649 new_vysize != VYSIZE ||
11650 new_exsize != EXSIZE ||
11651 new_eysize != EYSIZE ||
11652 new_real_sx != REAL_SX ||
11653 new_real_sy != REAL_SY ||
11654 new_full_sxsize != FULL_SXSIZE ||
11655 new_full_sysize != FULL_SYSIZE ||
11656 new_tilesize_var != TILESIZE_VAR
11659 vp_door_1->x != *door_1_x ||
11660 vp_door_1->y != *door_1_y ||
11661 vp_door_2->x != *door_2_x ||
11662 vp_door_2->y != *door_2_y
11667 if (new_tilesize_var != TILESIZE_VAR)
11669 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
11671 // changing tile size invalidates scroll values of engine snapshots
11672 FreeEngineSnapshot();
11674 // changing tile size requires update of graphic mapping for EM engine
11675 init_em_graphics = TRUE;
11687 SXSIZE = new_sxsize;
11688 SYSIZE = new_sysize;
11689 DXSIZE = new_dxsize;
11690 DYSIZE = new_dysize;
11691 VXSIZE = new_vxsize;
11692 VYSIZE = new_vysize;
11693 EXSIZE = new_exsize;
11694 EYSIZE = new_eysize;
11695 REAL_SX = new_real_sx;
11696 REAL_SY = new_real_sy;
11697 FULL_SXSIZE = new_full_sxsize;
11698 FULL_SYSIZE = new_full_sysize;
11699 TILESIZE_VAR = new_tilesize_var;
11702 printf("::: %d, %d, %d [%d]\n",
11703 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11704 setup.small_game_graphics);
11708 *door_1_x = vp_door_1->x;
11709 *door_1_y = vp_door_1->y;
11710 *door_2_x = vp_door_2->x;
11711 *door_2_y = vp_door_2->y;
11715 init_gfx_buffers = TRUE;
11717 // printf("::: viewports: init_gfx_buffers\n");
11723 if (gfx_game_mode == GAME_MODE_MAIN)
11727 init_gadgets_and_toons = TRUE;
11729 // printf("::: viewports: init_gadgets_and_toons\n");
11737 if (init_gfx_buffers)
11739 // printf("::: init_gfx_buffers\n");
11741 SCR_FIELDX = new_scr_fieldx_buffers;
11742 SCR_FIELDY = new_scr_fieldy_buffers;
11746 SCR_FIELDX = new_scr_fieldx;
11747 SCR_FIELDY = new_scr_fieldy;
11750 if (init_video_buffer)
11752 // printf("::: init_video_buffer\n");
11754 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11756 SetDrawDeactivationMask(REDRAW_NONE);
11757 SetDrawBackgroundMask(REDRAW_FIELD);
11760 if (init_gadgets_and_toons)
11762 // printf("::: init_gadgets_and_toons\n");
11768 if (init_em_graphics)
11770 InitGraphicInfo_EM();
11774 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);