1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
16 #include "libgame/libgame.h"
28 /* select level set with EMC X11 graphics before activating EM GFX debugging */
29 #define DEBUG_EM_GFX 0
31 /* tool button identifiers */
32 #define TOOL_CTRL_ID_YES 0
33 #define TOOL_CTRL_ID_NO 1
34 #define TOOL_CTRL_ID_CONFIRM 2
35 #define TOOL_CTRL_ID_PLAYER_1 3
36 #define TOOL_CTRL_ID_PLAYER_2 4
37 #define TOOL_CTRL_ID_PLAYER_3 5
38 #define TOOL_CTRL_ID_PLAYER_4 6
40 #define NUM_TOOL_BUTTONS 7
42 /* constants for number of doors and door parts */
44 #define NUM_PANELS NUM_DOORS
45 // #define NUM_PANELS 0
46 #define MAX_PARTS_PER_DOOR 8
47 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
48 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
51 struct DoorPartOrderInfo
57 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
59 struct DoorPartControlInfo
63 struct DoorPartPosInfo *pos;
66 static struct DoorPartControlInfo door_part_controls[] =
70 IMG_DOOR_1_GFX_PART_1,
75 IMG_DOOR_1_GFX_PART_2,
80 IMG_DOOR_1_GFX_PART_3,
85 IMG_DOOR_1_GFX_PART_4,
90 IMG_DOOR_1_GFX_PART_5,
95 IMG_DOOR_1_GFX_PART_6,
100 IMG_DOOR_1_GFX_PART_7,
105 IMG_DOOR_1_GFX_PART_8,
111 IMG_DOOR_2_GFX_PART_1,
116 IMG_DOOR_2_GFX_PART_2,
121 IMG_DOOR_2_GFX_PART_3,
126 IMG_DOOR_2_GFX_PART_4,
131 IMG_DOOR_2_GFX_PART_5,
136 IMG_DOOR_2_GFX_PART_6,
141 IMG_DOOR_2_GFX_PART_7,
146 IMG_DOOR_2_GFX_PART_8,
152 IMG_BACKGROUND_PANEL,
169 /* forward declaration for internal use */
170 static void UnmapToolButtons();
171 static void HandleToolButtons(struct GadgetInfo *);
172 static int el_act_dir2crm(int, int, int);
173 static int el_act2crm(int, int);
175 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
176 static int request_gadget_id = -1;
178 static char *print_if_not_empty(int element)
180 static char *s = NULL;
181 char *token_name = element_info[element].token_name;
186 s = checked_malloc(strlen(token_name) + 10 + 1);
188 if (element != EL_EMPTY)
189 sprintf(s, "%d\t['%s']", element, token_name);
191 sprintf(s, "%d", element);
196 void DumpTile(int x, int y)
201 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
207 printf_line("-", 79);
208 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
209 printf_line("-", 79);
211 if (!IN_LEV_FIELD(x, y))
213 printf("(not in level field)\n");
219 printf(" Feld: %d\t['%s']\n", Feld[x][y],
220 element_info[Feld[x][y]].token_name);
221 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
222 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
223 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
224 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
225 printf(" MovPos: %d\n", MovPos[x][y]);
226 printf(" MovDir: %d\n", MovDir[x][y]);
227 printf(" MovDelay: %d\n", MovDelay[x][y]);
228 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
229 printf(" CustomValue: %d\n", CustomValue[x][y]);
230 printf(" GfxElement: %d\n", GfxElement[x][y]);
231 printf(" GfxAction: %d\n", GfxAction[x][y]);
232 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
236 void SetDrawtoField(int mode)
238 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
246 BX2 = SCR_FIELDX + 1;
247 BY2 = SCR_FIELDY + 1;
266 BX2 = SCR_FIELDX + 1;
267 BY2 = SCR_FIELDY + 1;
282 drawto_field = fieldbuffer;
284 else /* DRAW_BACKBUFFER */
290 BX2 = SCR_FIELDX - 1;
291 BY2 = SCR_FIELDY - 1;
295 drawto_field = backbuffer;
301 static void RedrawPlayfield_RND()
303 if (game.envelope_active)
307 DrawLevel(REDRAW_ALL);
311 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
312 // SetDrawBackgroundMask(REDRAW_FIELD); // !!! CHECK THIS !!!
313 SetDrawBackgroundMask(REDRAW_ALL); // !!! CHECK THIS !!!
315 for (x = BX1; x <= BX2; x++)
316 for (y = BY1; y <= BY2; y++)
317 DrawScreenField(x, y);
319 redraw_mask |= REDRAW_FIELD;
325 BlitScreenToBitmap(backbuffer);
327 /* blit playfield from scroll buffer to normal back buffer */
328 if (setup.soft_scrolling)
330 int fx = FX, fy = FY;
332 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
333 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
335 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
341 void RedrawPlayfield()
343 if (game_status != GAME_MODE_PLAYING)
346 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
347 RedrawPlayfield_EM(TRUE);
348 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
349 RedrawPlayfield_SP(TRUE);
350 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
351 RedrawPlayfield_RND();
353 BlitScreenToBitmap(backbuffer);
355 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
361 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
363 if (game_status == GAME_MODE_PLAYING &&
364 level.game_engine_type == GAME_ENGINE_TYPE_EM)
366 /* currently there is no partial redraw -- always redraw whole playfield */
367 RedrawPlayfield_EM(TRUE);
369 /* blit playfield from scroll buffer to normal back buffer for fading in */
370 BlitScreenToBitmap_EM(backbuffer);
372 else if (game_status == GAME_MODE_PLAYING &&
373 level.game_engine_type == GAME_ENGINE_TYPE_SP)
375 /* currently there is no partial redraw -- always redraw whole playfield */
376 RedrawPlayfield_SP(TRUE);
378 /* blit playfield from scroll buffer to normal back buffer for fading in */
379 BlitScreenToBitmap_SP(backbuffer);
381 else if (game_status == GAME_MODE_PLAYING &&
382 !game.envelope_active)
388 width = gfx.sxsize + 2 * TILEX;
389 height = gfx.sysize + 2 * TILEY;
395 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
396 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
398 for (xx = BX1; xx <= BX2; xx++)
399 for (yy = BY1; yy <= BY2; yy++)
400 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
401 DrawScreenField(xx, yy);
405 if (setup.soft_scrolling)
407 int fx = FX, fy = FY;
409 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
410 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
412 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
424 BlitBitmap(drawto, window, x, y, width, height, x, y);
429 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
431 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
433 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
434 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
437 void DrawMaskedBorder_FIELD()
439 if (global.border_status >= GAME_MODE_TITLE &&
440 global.border_status <= GAME_MODE_PLAYING &&
441 border.draw_masked[global.border_status])
442 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
445 void DrawMaskedBorder_DOOR_1()
447 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
448 (global.border_status != GAME_MODE_EDITOR ||
449 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
450 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
453 void DrawMaskedBorder_DOOR_2()
455 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
456 global.border_status != GAME_MODE_EDITOR)
457 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
460 void DrawMaskedBorder_DOOR_3()
462 /* currently not available */
465 void DrawMaskedBorder_ALL()
467 DrawMaskedBorder_FIELD();
468 DrawMaskedBorder_DOOR_1();
469 DrawMaskedBorder_DOOR_2();
470 DrawMaskedBorder_DOOR_3();
473 void DrawMaskedBorder(int redraw_mask)
475 /* never draw masked screen borders on borderless screens */
476 if (effectiveGameStatus() == GAME_MODE_LOADING ||
477 effectiveGameStatus() == GAME_MODE_TITLE)
480 /* never draw masked screen borders when displaying request outside door */
481 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
482 global.use_envelope_request)
485 if (redraw_mask & REDRAW_ALL)
486 DrawMaskedBorder_ALL();
489 if (redraw_mask & REDRAW_FIELD)
490 DrawMaskedBorder_FIELD();
491 if (redraw_mask & REDRAW_DOOR_1)
492 DrawMaskedBorder_DOOR_1();
493 if (redraw_mask & REDRAW_DOOR_2)
494 DrawMaskedBorder_DOOR_2();
495 if (redraw_mask & REDRAW_DOOR_3)
496 DrawMaskedBorder_DOOR_3();
500 static void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
502 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
503 int fx = FX, fy = FY;
504 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
505 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
508 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
509 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
510 int dx_var = dx * TILESIZE_VAR / TILESIZE;
511 int dy_var = dy * TILESIZE_VAR / TILESIZE;
514 // fx += dx * TILESIZE_VAR / TILESIZE;
515 // fy += dy * TILESIZE_VAR / TILESIZE;
517 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
518 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
521 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
522 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
524 if (EVEN(SCR_FIELDX))
526 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
527 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
529 fx += (dx_var > 0 ? TILEX_VAR : 0);
536 if (EVEN(SCR_FIELDY))
538 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
539 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
541 fy += (dy_var > 0 ? TILEY_VAR : 0);
549 printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
552 SBY_Upper, SBY_Lower,
557 if (full_lev_fieldx <= SCR_FIELDX)
559 // printf(":1: PLAYFIELD FITS TO SCREEN [%d, %d, %d]\n", fx, ffx, dx_var);
561 if (EVEN(SCR_FIELDX))
562 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
564 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
566 // printf(":2: PLAYFIELD FITS TO SCREEN [%d, %d, %d]\n", fx, ffx, dx_var);
569 if (full_lev_fieldy <= SCR_FIELDY)
571 if (EVEN(SCR_FIELDY))
572 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
574 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
578 if (border.draw_masked[GAME_MODE_PLAYING])
580 if (buffer != backbuffer)
582 /* copy playfield buffer to backbuffer to add masked border */
583 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
584 DrawMaskedBorder(REDRAW_FIELD);
587 BlitBitmap(backbuffer, target_bitmap,
588 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
593 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
597 void BlitScreenToBitmap(Bitmap *target_bitmap)
599 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
600 BlitScreenToBitmap_EM(target_bitmap);
601 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
602 BlitScreenToBitmap_SP(target_bitmap);
603 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
604 BlitScreenToBitmap_RND(target_bitmap);
610 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
613 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
614 for (x = 0; x < SCR_FIELDX; x++)
615 for (y = 0 ; y < SCR_FIELDY; y++)
616 if (redraw[redraw_x1 + x][redraw_y1 + y])
617 printf("::: - %d, %d [%s]\n",
618 LEVELX(x), LEVELY(y),
619 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
622 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
623 redraw_mask |= REDRAW_FIELD;
626 // never redraw single tiles, always redraw the whole field
627 // (redrawing single tiles up to a certain threshold was faster on old,
628 // now legacy graphics, but slows things down on modern graphics now)
629 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
630 if (redraw_mask & REDRAW_TILES)
631 redraw_mask |= REDRAW_FIELD;
635 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
636 /* (force full redraw) */
637 if (game_status == GAME_MODE_PLAYING)
638 redraw_mask |= REDRAW_FIELD;
641 if (redraw_mask & REDRAW_FIELD)
642 redraw_mask &= ~REDRAW_TILES;
644 if (redraw_mask == REDRAW_NONE)
649 if (redraw_mask & REDRAW_ALL)
650 printf("[REDRAW_ALL]");
651 if (redraw_mask & REDRAW_FIELD)
652 printf("[REDRAW_FIELD]");
653 if (redraw_mask & REDRAW_TILES)
654 printf("[REDRAW_TILES]");
655 if (redraw_mask & REDRAW_DOOR_1)
656 printf("[REDRAW_DOOR_1]");
657 if (redraw_mask & REDRAW_DOOR_2)
658 printf("[REDRAW_DOOR_2]");
659 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
660 printf("[REDRAW_FROM_BACKBUFFER]");
661 printf(" [%d]\n", FrameCounter);
664 if (redraw_mask & REDRAW_TILES &&
665 game_status == GAME_MODE_PLAYING &&
666 border.draw_masked[GAME_MODE_PLAYING])
667 redraw_mask |= REDRAW_FIELD;
669 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
671 static boolean last_frame_skipped = FALSE;
672 boolean skip_even_when_not_scrolling = TRUE;
673 boolean just_scrolling = (ScreenMovDir != 0);
674 boolean verbose = FALSE;
676 if (global.fps_slowdown_factor > 1 &&
677 (FrameCounter % global.fps_slowdown_factor) &&
678 (just_scrolling || skip_even_when_not_scrolling))
680 redraw_mask &= ~REDRAW_MAIN;
682 last_frame_skipped = TRUE;
685 printf("FRAME SKIPPED\n");
689 if (last_frame_skipped)
690 redraw_mask |= REDRAW_FIELD;
692 last_frame_skipped = FALSE;
695 printf("frame not skipped\n");
699 /* synchronize X11 graphics at this point; if we would synchronize the
700 display immediately after the buffer switching (after the XFlush),
701 this could mean that we have to wait for the graphics to complete,
702 although we could go on doing calculations for the next frame */
706 /* never draw masked border to backbuffer when using playfield buffer */
707 if (game_status != GAME_MODE_PLAYING ||
708 redraw_mask & REDRAW_FROM_BACKBUFFER ||
709 buffer == backbuffer)
710 DrawMaskedBorder(redraw_mask);
712 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
714 if (redraw_mask & REDRAW_ALL)
717 if (game_status != GAME_MODE_PLAYING ||
718 redraw_mask & REDRAW_FROM_BACKBUFFER)
721 printf("::: REDRAW_ALL [%d]\n", FrameCounter);
724 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
726 redraw_mask = REDRAW_NONE;
730 redraw_mask &= ~REDRAW_ALL;
734 printf("::: REDRAW_ALL [%d]\n", FrameCounter);
737 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
739 redraw_mask = REDRAW_NONE;
743 if (redraw_mask & REDRAW_FIELD)
746 printf("::: REDRAW_FIELD [%d]\n", FrameCounter);
749 if (game_status != GAME_MODE_PLAYING ||
750 redraw_mask & REDRAW_FROM_BACKBUFFER)
752 BlitBitmap(backbuffer, window,
753 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
758 BlitScreenToBitmap_RND(window);
760 int fx = FX, fy = FY;
763 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
764 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
765 int dx_var = dx * TILESIZE_VAR / TILESIZE;
766 int dy_var = dy * TILESIZE_VAR / TILESIZE;
769 // fx += dx * TILESIZE_VAR / TILESIZE;
770 // fy += dy * TILESIZE_VAR / TILESIZE;
772 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
773 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
776 /* !!! THIS WORKS !!! */
778 printf("::: %d, %d\n", scroll_x, scroll_y);
780 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
781 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
783 if (EVEN(SCR_FIELDX))
785 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
786 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
788 fx += (dx > 0 ? TILEX_VAR : 0);
795 if (EVEN(SCR_FIELDY))
797 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
798 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
800 fy += (dy > 0 ? TILEY_VAR : 0);
807 if (border.draw_masked[GAME_MODE_PLAYING])
809 if (buffer != backbuffer)
811 /* copy playfield buffer to backbuffer to add masked border */
812 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
813 DrawMaskedBorder(REDRAW_FIELD);
816 BlitBitmap(backbuffer, window,
817 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
822 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
828 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
830 (setup.soft_scrolling ?
831 "setup.soft_scrolling" :
832 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
833 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
834 ABS(ScreenGfxPos) == ScrollStepSize ?
835 "ABS(ScreenGfxPos) == ScrollStepSize" :
836 "redraw_tiles > REDRAWTILES_THRESHOLD"));
841 redraw_mask &= ~REDRAW_MAIN;
844 if (redraw_mask & REDRAW_DOORS)
846 if (redraw_mask & REDRAW_DOOR_1)
847 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
849 if (redraw_mask & REDRAW_DOOR_2)
850 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
852 if (redraw_mask & REDRAW_DOOR_3)
853 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
855 redraw_mask &= ~REDRAW_DOORS;
858 if (redraw_mask & REDRAW_MICROLEVEL)
860 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
861 SX, SY + 10 * TILEY);
863 redraw_mask &= ~REDRAW_MICROLEVEL;
866 if (redraw_mask & REDRAW_TILES)
869 printf("::: REDRAW_TILES\n");
875 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
878 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
879 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
882 int dx_var = dx * TILESIZE_VAR / TILESIZE;
883 int dy_var = dy * TILESIZE_VAR / TILESIZE;
885 int fx = FX, fy = FY;
887 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
888 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
890 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
891 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
893 if (EVEN(SCR_FIELDX))
895 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
897 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
906 fx += (dx_var > 0 ? TILEX_VAR : 0);
910 if (EVEN(SCR_FIELDY))
912 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
914 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
923 fy += (dy_var > 0 ? TILEY_VAR : 0);
928 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
931 for (x = 0; x < scr_fieldx; x++)
932 for (y = 0 ; y < scr_fieldy; y++)
933 if (redraw[redraw_x1 + x][redraw_y1 + y])
934 BlitBitmap(buffer, window,
935 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
936 TILEX_VAR, TILEY_VAR,
937 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
940 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
942 for (x = 0; x < SCR_FIELDX; x++)
943 for (y = 0 ; y < SCR_FIELDY; y++)
944 if (redraw[redraw_x1 + x][redraw_y1 + y])
945 BlitBitmap(buffer, window,
946 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
947 TILEX_VAR, TILEY_VAR,
948 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
952 for (x = 0; x < SCR_FIELDX; x++)
953 for (y = 0 ; y < SCR_FIELDY; y++)
954 if (redraw[redraw_x1 + x][redraw_y1 + y])
955 BlitBitmap(buffer, window,
956 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
957 SX + x * TILEX, SY + y * TILEY);
961 if (redraw_mask & REDRAW_FPS) /* display frames per second */
966 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
967 if (!global.fps_slowdown)
970 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
972 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
974 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
980 for (x = 0; x < MAX_BUF_XSIZE; x++)
981 for (y = 0; y < MAX_BUF_YSIZE; y++)
984 redraw_mask = REDRAW_NONE;
987 static void FadeCrossSaveBackbuffer()
989 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
992 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
994 static int fade_type_skip = FADE_TYPE_NONE;
995 void (*draw_border_function)(void) = NULL;
996 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
997 int x, y, width, height;
998 int fade_delay, post_delay;
1000 if (fade_type == FADE_TYPE_FADE_OUT)
1002 if (fade_type_skip != FADE_TYPE_NONE)
1005 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
1008 /* skip all fade operations until specified fade operation */
1009 if (fade_type & fade_type_skip)
1010 fade_type_skip = FADE_TYPE_NONE;
1015 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1017 FadeCrossSaveBackbuffer();
1023 redraw_mask |= fade_mask;
1025 if (fade_type == FADE_TYPE_SKIP)
1028 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
1031 fade_type_skip = fade_mode;
1037 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
1042 fade_delay = fading.fade_delay;
1043 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1046 if (fade_type_skip != FADE_TYPE_NONE)
1049 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
1052 /* skip all fade operations until specified fade operation */
1053 if (fade_type & fade_type_skip)
1054 fade_type_skip = FADE_TYPE_NONE;
1064 if (global.autoplay_leveldir)
1066 // fading.fade_mode = FADE_MODE_NONE;
1073 if (fading.fade_mode == FADE_MODE_NONE)
1081 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
1084 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
1088 if (fade_mask == REDRAW_NONE)
1089 fade_mask = REDRAW_FIELD;
1092 // if (fade_mask & REDRAW_FIELD)
1093 if (fade_mask == REDRAW_FIELD)
1097 width = FULL_SXSIZE;
1098 height = FULL_SYSIZE;
1101 fade_delay = fading.fade_delay;
1102 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1105 if (border.draw_masked_when_fading)
1106 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
1108 DrawMaskedBorder_FIELD(); /* draw once */
1110 else /* REDRAW_ALL */
1118 fade_delay = fading.fade_delay;
1119 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1124 if (!setup.fade_screens ||
1126 fading.fade_mode == FADE_MODE_NONE)
1128 if (!setup.fade_screens || fade_delay == 0)
1131 if (fade_mode == FADE_MODE_FADE_OUT)
1135 if (fade_mode == FADE_MODE_FADE_OUT &&
1136 fading.fade_mode != FADE_MODE_NONE)
1137 ClearRectangle(backbuffer, x, y, width, height);
1143 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1145 redraw_mask &= ~fade_mask;
1147 /* always redraw area that was explicitly marked to fade */
1148 redraw_mask |= fade_mask;
1156 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1157 redraw_mask = REDRAW_NONE;
1158 // (^^^ WRONG; should be "redraw_mask &= ~fade_mask" if done this way)
1167 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
1168 draw_border_function);
1170 redraw_mask &= ~fade_mask;
1173 void FadeIn(int fade_mask)
1175 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1176 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1178 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1181 void FadeOut(int fade_mask)
1183 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1184 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1186 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1188 global.border_status = game_status;
1191 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1193 static struct TitleFadingInfo fading_leave_stored;
1196 fading_leave_stored = fading_leave;
1198 fading = fading_leave_stored;
1201 void FadeSetEnterMenu()
1203 fading = menu.enter_menu;
1206 printf("::: storing enter_menu\n");
1209 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1212 void FadeSetLeaveMenu()
1214 fading = menu.leave_menu;
1217 printf("::: storing leave_menu\n");
1220 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1223 void FadeSetEnterScreen()
1225 fading = menu.enter_screen[game_status];
1228 printf("::: storing leave_screen[%d]\n", game_status);
1231 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
1234 void FadeSetNextScreen()
1236 fading = menu.next_screen;
1239 printf("::: storing next_screen\n");
1242 // (do not overwrite fade mode set by FadeSetEnterScreen)
1243 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
1246 void FadeSetLeaveScreen()
1249 printf("::: recalling last stored value\n");
1252 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
1255 void FadeSetFromType(int type)
1257 if (type & TYPE_ENTER_SCREEN)
1258 FadeSetEnterScreen();
1259 else if (type & TYPE_ENTER)
1261 else if (type & TYPE_LEAVE)
1265 void FadeSetDisabled()
1267 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1269 fading = fading_none;
1272 void FadeSkipNextFadeIn()
1274 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1277 void FadeSkipNextFadeOut()
1279 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1282 void SetWindowBackgroundImageIfDefined(int graphic)
1284 if (graphic_info[graphic].bitmap)
1285 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1288 void SetMainBackgroundImageIfDefined(int graphic)
1290 if (graphic_info[graphic].bitmap)
1291 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1294 void SetDoorBackgroundImageIfDefined(int graphic)
1296 if (graphic_info[graphic].bitmap)
1297 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1300 void SetWindowBackgroundImage(int graphic)
1302 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1303 graphic_info[graphic].bitmap ?
1304 graphic_info[graphic].bitmap :
1305 graphic_info[IMG_BACKGROUND].bitmap);
1308 void SetMainBackgroundImage(int graphic)
1310 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1311 graphic_info[graphic].bitmap ?
1312 graphic_info[graphic].bitmap :
1313 graphic_info[IMG_BACKGROUND].bitmap);
1316 void SetDoorBackgroundImage(int graphic)
1318 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1319 graphic_info[graphic].bitmap ?
1320 graphic_info[graphic].bitmap :
1321 graphic_info[IMG_BACKGROUND].bitmap);
1324 void SetPanelBackground()
1327 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1330 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1331 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1333 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1334 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1335 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1336 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1339 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1340 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1343 SetDoorBackgroundBitmap(bitmap_db_panel);
1346 void DrawBackground(int x, int y, int width, int height)
1348 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1349 /* (when entering hall of fame after playing) */
1351 ClearRectangleOnBackground(drawto, x, y, width, height);
1353 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1359 if (IN_GFX_FIELD_FULL(x, y))
1360 redraw_mask |= REDRAW_FIELD;
1361 else if (IN_GFX_DOOR_1(x, y))
1362 redraw_mask |= REDRAW_DOOR_1;
1363 else if (IN_GFX_DOOR_2(x, y))
1364 redraw_mask |= REDRAW_DOOR_2;
1365 else if (IN_GFX_DOOR_3(x, y))
1366 redraw_mask |= REDRAW_DOOR_3;
1368 /* (this only works for the current arrangement of playfield and panels) */
1370 redraw_mask |= REDRAW_FIELD;
1371 else if (y < gfx.vy)
1372 redraw_mask |= REDRAW_DOOR_1;
1374 redraw_mask |= REDRAW_DOOR_2;
1378 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1379 redraw_mask |= REDRAW_FIELD;
1383 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1385 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1387 if (font->bitmap == NULL)
1390 DrawBackground(x, y, width, height);
1393 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1395 struct GraphicInfo *g = &graphic_info[graphic];
1397 if (g->bitmap == NULL)
1400 DrawBackground(x, y, width, height);
1405 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1406 /* (when entering hall of fame after playing) */
1407 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1409 /* !!! maybe this should be done before clearing the background !!! */
1410 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1412 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1413 SetDrawtoField(DRAW_BUFFERED);
1416 SetDrawtoField(DRAW_BACKBUFFER);
1419 void MarkTileDirty(int x, int y)
1421 int xx = redraw_x1 + x;
1422 int yy = redraw_y1 + y;
1424 if (!redraw[xx][yy])
1427 redraw[xx][yy] = TRUE;
1428 redraw_mask |= REDRAW_TILES;
1431 void SetBorderElement()
1435 BorderElement = EL_EMPTY;
1437 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1439 for (x = 0; x < lev_fieldx; x++)
1441 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1442 BorderElement = EL_STEELWALL;
1444 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1450 void FloodFillLevel(int from_x, int from_y, int fill_element,
1451 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1452 int max_fieldx, int max_fieldy)
1456 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1457 static int safety = 0;
1459 /* check if starting field still has the desired content */
1460 if (field[from_x][from_y] == fill_element)
1465 if (safety > max_fieldx * max_fieldy)
1466 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1468 old_element = field[from_x][from_y];
1469 field[from_x][from_y] = fill_element;
1471 for (i = 0; i < 4; i++)
1473 x = from_x + check[i][0];
1474 y = from_y + check[i][1];
1476 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1477 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1483 void SetRandomAnimationValue(int x, int y)
1485 gfx.anim_random_frame = GfxRandom[x][y];
1488 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1490 /* animation synchronized with global frame counter, not move position */
1491 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1492 sync_frame = FrameCounter;
1494 return getAnimationFrame(graphic_info[graphic].anim_frames,
1495 graphic_info[graphic].anim_delay,
1496 graphic_info[graphic].anim_mode,
1497 graphic_info[graphic].anim_start_frame,
1501 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1502 Bitmap **bitmap, int *x, int *y,
1503 boolean get_backside)
1507 int width_mult, width_div;
1508 int height_mult, height_div;
1512 { 15, 16, 2, 3 }, /* 1 x 1 */
1513 { 7, 8, 2, 3 }, /* 2 x 2 */
1514 { 3, 4, 2, 3 }, /* 4 x 4 */
1515 { 1, 2, 2, 3 }, /* 8 x 8 */
1516 { 0, 1, 2, 3 }, /* 16 x 16 */
1517 { 0, 1, 0, 1 }, /* 32 x 32 */
1519 struct GraphicInfo *g = &graphic_info[graphic];
1520 Bitmap *src_bitmap = g->bitmap;
1521 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1522 int offset_calc_pos = log_2(tilesize);
1523 int width_mult = offset_calc[offset_calc_pos].width_mult;
1524 int width_div = offset_calc[offset_calc_pos].width_div;
1525 int height_mult = offset_calc[offset_calc_pos].height_mult;
1526 int height_div = offset_calc[offset_calc_pos].height_div;
1527 int startx = src_bitmap->width * width_mult / width_div;
1528 int starty = src_bitmap->height * height_mult / height_div;
1530 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1531 tilesize / TILESIZE;
1532 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1533 tilesize / TILESIZE;
1535 int src_x = g->src_x * tilesize / TILESIZE;
1536 int src_y = g->src_y * tilesize / TILESIZE;
1538 int width = g->width * tilesize / TILESIZE;
1539 int height = g->height * tilesize / TILESIZE;
1540 int offset_x = g->offset_x * tilesize / TILESIZE;
1541 int offset_y = g->offset_y * tilesize / TILESIZE;
1543 if (g->offset_y == 0) /* frames are ordered horizontally */
1545 int max_width = g->anim_frames_per_line * width;
1546 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1548 src_x = pos % max_width;
1549 src_y = src_y % height + pos / max_width * height;
1551 else if (g->offset_x == 0) /* frames are ordered vertically */
1553 int max_height = g->anim_frames_per_line * height;
1554 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1556 src_x = src_x % width + pos / max_height * width;
1557 src_y = pos % max_height;
1559 else /* frames are ordered diagonally */
1561 src_x = src_x + frame * offset_x;
1562 src_y = src_y + frame * offset_y;
1565 *bitmap = src_bitmap;
1566 *x = startx + src_x;
1567 *y = starty + src_y;
1570 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1571 int *x, int *y, boolean get_backside)
1573 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1577 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1578 Bitmap **bitmap, int *x, int *y)
1580 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1583 void getFixedGraphicSource(int graphic, int frame,
1584 Bitmap **bitmap, int *x, int *y)
1586 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1589 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1592 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1594 struct GraphicInfo *g = &graphic_info[graphic];
1595 int mini_startx = 0;
1596 int mini_starty = g->bitmap->height * 2 / 3;
1598 *bitmap = g->bitmap;
1599 *x = mini_startx + g->src_x / 2;
1600 *y = mini_starty + g->src_y / 2;
1604 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1605 int *x, int *y, boolean get_backside)
1607 struct GraphicInfo *g = &graphic_info[graphic];
1608 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1609 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1613 if (TILESIZE_VAR != TILESIZE)
1614 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1618 *bitmap = g->bitmap;
1620 if (g->offset_y == 0) /* frames are ordered horizontally */
1622 int max_width = g->anim_frames_per_line * g->width;
1623 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1625 *x = pos % max_width;
1626 *y = src_y % g->height + pos / max_width * g->height;
1628 else if (g->offset_x == 0) /* frames are ordered vertically */
1630 int max_height = g->anim_frames_per_line * g->height;
1631 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1633 *x = src_x % g->width + pos / max_height * g->width;
1634 *y = pos % max_height;
1636 else /* frames are ordered diagonally */
1638 *x = src_x + frame * g->offset_x;
1639 *y = src_y + frame * g->offset_y;
1643 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1645 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1648 void DrawGraphic(int x, int y, int graphic, int frame)
1651 if (!IN_SCR_FIELD(x, y))
1653 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1654 printf("DrawGraphic(): This should never happen!\n");
1660 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1663 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1665 MarkTileDirty(x, y);
1668 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1671 if (!IN_SCR_FIELD(x, y))
1673 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1674 printf("DrawGraphic(): This should never happen!\n");
1679 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1681 MarkTileDirty(x, y);
1684 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1690 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1692 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1694 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1698 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1704 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1705 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1708 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1711 if (!IN_SCR_FIELD(x, y))
1713 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1714 printf("DrawGraphicThruMask(): This should never happen!\n");
1720 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1723 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1726 MarkTileDirty(x, y);
1729 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1732 if (!IN_SCR_FIELD(x, y))
1734 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1735 printf("DrawGraphicThruMask(): This should never happen!\n");
1740 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1742 MarkTileDirty(x, y);
1745 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1751 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1753 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1754 dst_x - src_x, dst_y - src_y);
1756 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1759 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1763 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1764 int graphic, int frame)
1769 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1771 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1772 dst_x - src_x, dst_y - src_y);
1773 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1776 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1778 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1780 MarkTileDirty(x / tilesize, y / tilesize);
1783 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1789 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1790 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1793 void DrawMiniGraphic(int x, int y, int graphic)
1795 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1796 MarkTileDirty(x / 2, y / 2);
1799 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1804 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1805 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1808 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1809 int graphic, int frame,
1810 int cut_mode, int mask_mode)
1815 int width = TILEX, height = TILEY;
1818 if (dx || dy) /* shifted graphic */
1820 if (x < BX1) /* object enters playfield from the left */
1827 else if (x > BX2) /* object enters playfield from the right */
1833 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1839 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1841 else if (dx) /* general horizontal movement */
1842 MarkTileDirty(x + SIGN(dx), y);
1844 if (y < BY1) /* object enters playfield from the top */
1846 if (cut_mode==CUT_BELOW) /* object completely above top border */
1854 else if (y > BY2) /* object enters playfield from the bottom */
1860 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1866 else if (dy > 0 && cut_mode == CUT_ABOVE)
1868 if (y == BY2) /* object completely above bottom border */
1874 MarkTileDirty(x, y + 1);
1875 } /* object leaves playfield to the bottom */
1876 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1878 else if (dy) /* general vertical movement */
1879 MarkTileDirty(x, y + SIGN(dy));
1883 if (!IN_SCR_FIELD(x, y))
1885 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1886 printf("DrawGraphicShifted(): This should never happen!\n");
1892 width = width * TILESIZE_VAR / TILESIZE;
1893 height = height * TILESIZE_VAR / TILESIZE;
1894 cx = cx * TILESIZE_VAR / TILESIZE;
1895 cy = cy * TILESIZE_VAR / TILESIZE;
1896 dx = dx * TILESIZE_VAR / TILESIZE;
1897 dy = dy * TILESIZE_VAR / TILESIZE;
1900 if (width > 0 && height > 0)
1902 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1908 dst_x = FX + x * TILEX_VAR + dx;
1909 dst_y = FY + y * TILEY_VAR + dy;
1911 dst_x = FX + x * TILEX + dx;
1912 dst_y = FY + y * TILEY + dy;
1915 if (mask_mode == USE_MASKING)
1917 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1918 dst_x - src_x, dst_y - src_y);
1919 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1923 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1926 MarkTileDirty(x, y);
1930 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1931 int graphic, int frame,
1932 int cut_mode, int mask_mode)
1938 int width = TILEX_VAR, height = TILEY_VAR;
1940 int width = TILEX, height = TILEY;
1944 int x2 = x + SIGN(dx);
1945 int y2 = y + SIGN(dy);
1947 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1948 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1950 /* movement with two-tile animations must be sync'ed with movement position,
1951 not with current GfxFrame (which can be higher when using slow movement) */
1952 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1953 int anim_frames = graphic_info[graphic].anim_frames;
1955 /* (we also need anim_delay here for movement animations with less frames) */
1956 int anim_delay = graphic_info[graphic].anim_delay;
1957 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1959 int sync_frame = anim_pos * anim_frames / TILESIZE;
1962 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1963 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1965 /* re-calculate animation frame for two-tile movement animation */
1966 frame = getGraphicAnimationFrame(graphic, sync_frame);
1970 printf("::: %d, %d, %d => %d [%d]\n",
1971 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1973 printf("::: %d, %d => %d\n",
1974 anim_pos, anim_frames, sync_frame);
1979 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1980 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1983 /* check if movement start graphic inside screen area and should be drawn */
1984 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1986 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1989 dst_x = FX + x1 * TILEX_VAR;
1990 dst_y = FY + y1 * TILEY_VAR;
1992 dst_x = FX + x1 * TILEX;
1993 dst_y = FY + y1 * TILEY;
1996 if (mask_mode == USE_MASKING)
1998 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1999 dst_x - src_x, dst_y - src_y);
2000 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
2004 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2007 MarkTileDirty(x1, y1);
2010 /* check if movement end graphic inside screen area and should be drawn */
2011 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
2013 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
2016 dst_x = FX + x2 * TILEX_VAR;
2017 dst_y = FY + y2 * TILEY_VAR;
2019 dst_x = FX + x2 * TILEX;
2020 dst_y = FY + y2 * TILEY;
2023 if (mask_mode == USE_MASKING)
2025 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2026 dst_x - src_x, dst_y - src_y);
2027 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
2031 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2034 MarkTileDirty(x2, y2);
2038 static void DrawGraphicShifted(int x, int y, int dx, int dy,
2039 int graphic, int frame,
2040 int cut_mode, int mask_mode)
2044 DrawGraphic(x, y, graphic, frame);
2049 if (graphic_info[graphic].double_movement) /* EM style movement images */
2050 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2052 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2055 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
2056 int frame, int cut_mode)
2058 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
2061 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
2062 int cut_mode, int mask_mode)
2064 int lx = LEVELX(x), ly = LEVELY(y);
2068 if (IN_LEV_FIELD(lx, ly))
2070 SetRandomAnimationValue(lx, ly);
2072 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
2073 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2075 /* do not use double (EM style) movement graphic when not moving */
2076 if (graphic_info[graphic].double_movement && !dx && !dy)
2078 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
2079 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2082 else /* border element */
2084 graphic = el2img(element);
2085 frame = getGraphicAnimationFrame(graphic, -1);
2088 if (element == EL_EXPANDABLE_WALL)
2090 boolean left_stopped = FALSE, right_stopped = FALSE;
2092 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
2093 left_stopped = TRUE;
2094 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
2095 right_stopped = TRUE;
2097 if (left_stopped && right_stopped)
2099 else if (left_stopped)
2101 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
2102 frame = graphic_info[graphic].anim_frames - 1;
2104 else if (right_stopped)
2106 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
2107 frame = graphic_info[graphic].anim_frames - 1;
2112 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
2113 else if (mask_mode == USE_MASKING)
2114 DrawGraphicThruMask(x, y, graphic, frame);
2116 DrawGraphic(x, y, graphic, frame);
2119 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2120 int cut_mode, int mask_mode)
2122 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2123 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2124 cut_mode, mask_mode);
2127 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2130 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2133 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2136 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2139 void DrawLevelElementThruMask(int x, int y, int element)
2141 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2144 void DrawLevelFieldThruMask(int x, int y)
2146 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2149 /* !!! implementation of quicksand is totally broken !!! */
2150 #define IS_CRUMBLED_TILE(x, y, e) \
2151 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
2152 !IS_MOVING(x, y) || \
2153 (e) == EL_QUICKSAND_EMPTYING || \
2154 (e) == EL_QUICKSAND_FAST_EMPTYING))
2156 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2161 int width, height, cx, cy;
2162 int sx = SCREENX(x), sy = SCREENY(y);
2163 int crumbled_border_size = graphic_info[graphic].border_size;
2166 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2168 for (i = 1; i < 4; i++)
2170 int dxx = (i & 1 ? dx : 0);
2171 int dyy = (i & 2 ? dy : 0);
2174 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2177 /* check if neighbour field is of same crumble type */
2178 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2179 graphic_info[graphic].class ==
2180 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2182 /* return if check prevents inner corner */
2183 if (same == (dxx == dx && dyy == dy))
2187 /* if we reach this point, we have an inner corner */
2189 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2192 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2193 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2194 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2195 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2197 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2198 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2200 width = crumbled_border_size;
2201 height = crumbled_border_size;
2202 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2203 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2205 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2206 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2210 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2215 int width, height, bx, by, cx, cy;
2216 int sx = SCREENX(x), sy = SCREENY(y);
2217 int crumbled_border_size = graphic_info[graphic].border_size;
2220 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2222 /* draw simple, sloppy, non-corner-accurate crumbled border */
2225 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
2226 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
2227 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2228 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2230 if (dir == 1 || dir == 2) /* left or right crumbled border */
2232 width = crumbled_border_size;
2234 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2237 else /* top or bottom crumbled border */
2240 height = crumbled_border_size;
2242 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2247 BlitBitmap(src_bitmap, drawto_field,
2248 src_x + cx * TILESIZE_VAR / TILESIZE,
2249 src_y + cy * TILESIZE_VAR / TILESIZE,
2250 width * TILESIZE_VAR / TILESIZE,
2251 height * TILESIZE_VAR / TILESIZE,
2252 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2253 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2255 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2256 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2259 /* (remaining middle border part must be at least as big as corner part) */
2260 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2261 crumbled_border_size >= TILESIZE / 3)
2264 /* correct corners of crumbled border, if needed */
2267 for (i = -1; i <= 1; i+=2)
2269 int xx = x + (dir == 0 || dir == 3 ? i : 0);
2270 int yy = y + (dir == 1 || dir == 2 ? i : 0);
2271 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2274 /* check if neighbour field is of same crumble type */
2275 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2276 graphic_info[graphic].class ==
2277 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2279 /* no crumbled corner, but continued crumbled border */
2281 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2282 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2283 int b1 = (i == 1 ? crumbled_border_size :
2284 TILESIZE - 2 * crumbled_border_size);
2286 width = crumbled_border_size;
2287 height = crumbled_border_size;
2289 if (dir == 1 || dir == 2)
2305 BlitBitmap(src_bitmap, drawto_field,
2306 src_x + bx * TILESIZE_VAR / TILESIZE,
2307 src_y + by * TILESIZE_VAR / TILESIZE,
2308 width * TILESIZE_VAR / TILESIZE,
2309 height * TILESIZE_VAR / TILESIZE,
2310 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2311 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2313 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2314 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2319 if (dir == 1 || dir == 2) /* left or right crumbled border */
2321 for (i = -1; i <= 1; i+=2)
2325 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2328 /* check if neighbour field is of same crumble type */
2329 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2330 graphic_info[graphic].class ==
2331 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2333 /* no crumbled corner, but continued crumbled border */
2335 width = crumbled_border_size;
2336 height = crumbled_border_size;
2337 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2338 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2340 by = (i == 1 ? crumbled_border_size :
2341 TILEY - 2 * crumbled_border_size);
2343 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2344 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2348 else /* top or bottom crumbled border */
2350 for (i = -1; i <= 1; i+=2)
2354 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2357 /* check if neighbour field is of same crumble type */
2358 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2359 graphic_info[graphic].class ==
2360 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2362 /* no crumbled corner, but continued crumbled border */
2364 width = crumbled_border_size;
2365 height = crumbled_border_size;
2366 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2367 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2368 bx = (i == 1 ? crumbled_border_size :
2369 TILEX - 2 * crumbled_border_size);
2372 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2373 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2380 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2382 int sx = SCREENX(x), sy = SCREENY(y);
2385 static int xy[4][2] =
2393 if (!IN_LEV_FIELD(x, y))
2396 element = TILE_GFX_ELEMENT(x, y);
2398 /* crumble field itself */
2399 if (IS_CRUMBLED_TILE(x, y, element))
2401 if (!IN_SCR_FIELD(sx, sy))
2404 for (i = 0; i < 4; i++)
2406 int xx = x + xy[i][0];
2407 int yy = y + xy[i][1];
2409 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2412 /* check if neighbour field is of same crumble type */
2414 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2415 graphic_info[graphic].class ==
2416 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2419 if (IS_CRUMBLED_TILE(xx, yy, element))
2423 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2426 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2427 graphic_info[graphic].anim_frames == 2)
2429 for (i = 0; i < 4; i++)
2431 int dx = (i & 1 ? +1 : -1);
2432 int dy = (i & 2 ? +1 : -1);
2434 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2438 MarkTileDirty(sx, sy);
2440 else /* center field not crumbled -- crumble neighbour fields */
2442 for (i = 0; i < 4; i++)
2444 int xx = x + xy[i][0];
2445 int yy = y + xy[i][1];
2446 int sxx = sx + xy[i][0];
2447 int syy = sy + xy[i][1];
2449 if (!IN_LEV_FIELD(xx, yy) ||
2450 !IN_SCR_FIELD(sxx, syy))
2453 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2456 element = TILE_GFX_ELEMENT(xx, yy);
2458 if (!IS_CRUMBLED_TILE(xx, yy, element))
2461 graphic = el_act2crm(element, ACTION_DEFAULT);
2463 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2465 MarkTileDirty(sxx, syy);
2470 void DrawLevelFieldCrumbled(int x, int y)
2474 if (!IN_LEV_FIELD(x, y))
2478 /* !!! CHECK THIS !!! */
2481 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2482 GFX_CRUMBLED(GfxElement[x][y]))
2485 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2486 GfxElement[x][y] != EL_UNDEFINED &&
2487 GFX_CRUMBLED(GfxElement[x][y]))
2489 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2496 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2498 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2501 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2504 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2507 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2508 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2509 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2510 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2511 int sx = SCREENX(x), sy = SCREENY(y);
2513 DrawGraphic(sx, sy, graphic1, frame1);
2514 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2517 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2519 int sx = SCREENX(x), sy = SCREENY(y);
2520 static int xy[4][2] =
2529 for (i = 0; i < 4; i++)
2531 int xx = x + xy[i][0];
2532 int yy = y + xy[i][1];
2533 int sxx = sx + xy[i][0];
2534 int syy = sy + xy[i][1];
2536 if (!IN_LEV_FIELD(xx, yy) ||
2537 !IN_SCR_FIELD(sxx, syy) ||
2538 !GFX_CRUMBLED(Feld[xx][yy]) ||
2542 DrawLevelField(xx, yy);
2546 static int getBorderElement(int x, int y)
2550 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2551 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2552 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2553 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2554 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2555 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2556 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2558 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2559 int steel_position = (x == -1 && y == -1 ? 0 :
2560 x == lev_fieldx && y == -1 ? 1 :
2561 x == -1 && y == lev_fieldy ? 2 :
2562 x == lev_fieldx && y == lev_fieldy ? 3 :
2563 x == -1 || x == lev_fieldx ? 4 :
2564 y == -1 || y == lev_fieldy ? 5 : 6);
2566 return border[steel_position][steel_type];
2569 void DrawScreenElement(int x, int y, int element)
2571 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2572 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2575 void DrawLevelElement(int x, int y, int element)
2577 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2578 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2581 void DrawScreenField(int x, int y)
2583 int lx = LEVELX(x), ly = LEVELY(y);
2584 int element, content;
2586 if (!IN_LEV_FIELD(lx, ly))
2588 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2591 element = getBorderElement(lx, ly);
2593 DrawScreenElement(x, y, element);
2598 element = Feld[lx][ly];
2599 content = Store[lx][ly];
2601 if (IS_MOVING(lx, ly))
2603 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2604 boolean cut_mode = NO_CUTTING;
2606 if (element == EL_QUICKSAND_EMPTYING ||
2607 element == EL_QUICKSAND_FAST_EMPTYING ||
2608 element == EL_MAGIC_WALL_EMPTYING ||
2609 element == EL_BD_MAGIC_WALL_EMPTYING ||
2610 element == EL_DC_MAGIC_WALL_EMPTYING ||
2611 element == EL_AMOEBA_DROPPING)
2612 cut_mode = CUT_ABOVE;
2613 else if (element == EL_QUICKSAND_FILLING ||
2614 element == EL_QUICKSAND_FAST_FILLING ||
2615 element == EL_MAGIC_WALL_FILLING ||
2616 element == EL_BD_MAGIC_WALL_FILLING ||
2617 element == EL_DC_MAGIC_WALL_FILLING)
2618 cut_mode = CUT_BELOW;
2621 if (lx == 9 && ly == 1)
2622 printf("::: %s [%d] [%d, %d] [%d]\n",
2623 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2624 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2625 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2626 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2627 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2630 if (cut_mode == CUT_ABOVE)
2632 DrawScreenElement(x, y, element);
2634 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2637 DrawScreenElement(x, y, EL_EMPTY);
2640 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2641 else if (cut_mode == NO_CUTTING)
2642 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2645 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2648 if (cut_mode == CUT_BELOW &&
2649 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2650 DrawLevelElement(lx, ly + 1, element);
2654 if (content == EL_ACID)
2656 int dir = MovDir[lx][ly];
2657 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2658 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2660 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2663 else if (IS_BLOCKED(lx, ly))
2668 boolean cut_mode = NO_CUTTING;
2669 int element_old, content_old;
2671 Blocked2Moving(lx, ly, &oldx, &oldy);
2674 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2675 MovDir[oldx][oldy] == MV_RIGHT);
2677 element_old = Feld[oldx][oldy];
2678 content_old = Store[oldx][oldy];
2680 if (element_old == EL_QUICKSAND_EMPTYING ||
2681 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2682 element_old == EL_MAGIC_WALL_EMPTYING ||
2683 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2684 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2685 element_old == EL_AMOEBA_DROPPING)
2686 cut_mode = CUT_ABOVE;
2688 DrawScreenElement(x, y, EL_EMPTY);
2691 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2693 else if (cut_mode == NO_CUTTING)
2694 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2697 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2700 else if (IS_DRAWABLE(element))
2701 DrawScreenElement(x, y, element);
2703 DrawScreenElement(x, y, EL_EMPTY);
2706 void DrawLevelField(int x, int y)
2708 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2709 DrawScreenField(SCREENX(x), SCREENY(y));
2710 else if (IS_MOVING(x, y))
2714 Moving2Blocked(x, y, &newx, &newy);
2715 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2716 DrawScreenField(SCREENX(newx), SCREENY(newy));
2718 else if (IS_BLOCKED(x, y))
2722 Blocked2Moving(x, y, &oldx, &oldy);
2723 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2724 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2728 void DrawMiniElement(int x, int y, int element)
2732 graphic = el2edimg(element);
2733 DrawMiniGraphic(x, y, graphic);
2736 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2738 int x = sx + scroll_x, y = sy + scroll_y;
2740 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2741 DrawMiniElement(sx, sy, EL_EMPTY);
2742 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2743 DrawMiniElement(sx, sy, Feld[x][y]);
2745 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2748 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2749 int x, int y, int xsize, int ysize,
2750 int tile_width, int tile_height)
2754 int dst_x = startx + x * tile_width;
2755 int dst_y = starty + y * tile_height;
2756 int width = graphic_info[graphic].width;
2757 int height = graphic_info[graphic].height;
2758 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
2759 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2760 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
2761 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2762 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2763 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2764 boolean draw_masked = graphic_info[graphic].draw_masked;
2766 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2768 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2770 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2774 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2775 inner_sx + (x - 1) * tile_width % inner_width);
2776 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2777 inner_sy + (y - 1) * tile_height % inner_height);
2781 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2782 dst_x - src_x, dst_y - src_y);
2783 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2787 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2791 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2792 int x, int y, int xsize, int ysize, int font_nr)
2794 int font_width = getFontWidth(font_nr);
2795 int font_height = getFontHeight(font_nr);
2797 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2798 font_width, font_height);
2801 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2803 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2804 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2805 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2806 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2807 boolean no_delay = (tape.warp_forward);
2808 unsigned int anim_delay = 0;
2809 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2810 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2811 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2812 int font_width = getFontWidth(font_nr);
2813 int font_height = getFontHeight(font_nr);
2814 int max_xsize = level.envelope[envelope_nr].xsize;
2815 int max_ysize = level.envelope[envelope_nr].ysize;
2816 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2817 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2818 int xend = max_xsize;
2819 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2820 int xstep = (xstart < xend ? 1 : 0);
2821 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2824 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2826 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2827 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2828 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2829 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2832 SetDrawtoField(DRAW_BUFFERED);
2835 BlitScreenToBitmap(backbuffer);
2837 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2840 SetDrawtoField(DRAW_BACKBUFFER);
2842 for (yy = 0; yy < ysize; yy++)
2843 for (xx = 0; xx < xsize; xx++)
2844 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2847 DrawTextBuffer(sx + font_width, sy + font_height,
2848 level.envelope[envelope_nr].text, font_nr, max_xsize,
2849 xsize - 2, ysize - 2, 0, mask_mode,
2850 level.envelope[envelope_nr].autowrap,
2851 level.envelope[envelope_nr].centered, FALSE);
2853 DrawTextToTextArea(sx + font_width, sy + font_height,
2854 level.envelope[envelope_nr].text, font_nr, max_xsize,
2855 xsize - 2, ysize - 2, mask_mode);
2858 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2861 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2865 void ShowEnvelope(int envelope_nr)
2867 int element = EL_ENVELOPE_1 + envelope_nr;
2868 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2869 int sound_opening = element_info[element].sound[ACTION_OPENING];
2870 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2871 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2872 boolean no_delay = (tape.warp_forward);
2873 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2874 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2875 int anim_mode = graphic_info[graphic].anim_mode;
2876 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2877 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2879 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2881 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2883 if (anim_mode == ANIM_DEFAULT)
2884 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2886 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2889 Delay(wait_delay_value);
2891 WaitForEventToContinue();
2893 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2895 if (anim_mode != ANIM_NONE)
2896 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2898 if (anim_mode == ANIM_DEFAULT)
2899 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2901 game.envelope_active = FALSE;
2903 SetDrawtoField(DRAW_BUFFERED);
2905 redraw_mask |= REDRAW_FIELD;
2909 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2911 int border_size = request.border_size;
2912 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2913 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2914 int sx = sx_center - request.width / 2;
2915 int sy = sy_center - request.height / 2;
2917 if (add_border_size)
2927 void DrawEnvelopeRequest(char *text)
2929 char *text_final = text;
2930 char *text_door_style = NULL;
2931 int graphic = IMG_BACKGROUND_REQUEST;
2932 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2933 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2934 int font_nr = FONT_REQUEST;
2935 int font_width = getFontWidth(font_nr);
2936 int font_height = getFontHeight(font_nr);
2937 int border_size = request.border_size;
2938 int line_spacing = request.line_spacing;
2939 int line_height = font_height + line_spacing;
2940 int text_width = request.width - 2 * border_size;
2941 int text_height = request.height - 2 * border_size;
2942 int line_length = text_width / font_width;
2943 int max_lines = text_height / line_height;
2944 int width = request.width;
2945 int height = request.height;
2946 int tile_size = request.step_offset;
2947 int x_steps = width / tile_size;
2948 int y_steps = height / tile_size;
2952 if (request.wrap_single_words)
2954 char *src_text_ptr, *dst_text_ptr;
2956 text_door_style = checked_malloc(2 * strlen(text) + 1);
2958 src_text_ptr = text;
2959 dst_text_ptr = text_door_style;
2961 while (*src_text_ptr)
2963 if (*src_text_ptr == ' ' ||
2964 *src_text_ptr == '?' ||
2965 *src_text_ptr == '!')
2966 *dst_text_ptr++ = '\n';
2968 if (*src_text_ptr != ' ')
2969 *dst_text_ptr++ = *src_text_ptr;
2974 *dst_text_ptr = '\0';
2976 text_final = text_door_style;
2979 setRequestPosition(&sx, &sy, FALSE);
2981 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2983 for (y = 0; y < y_steps; y++)
2984 for (x = 0; x < x_steps; x++)
2985 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2986 x, y, x_steps, y_steps,
2987 tile_size, tile_size);
2989 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2990 line_length, -1, max_lines, line_spacing, mask_mode,
2991 request.autowrap, request.centered, FALSE);
2993 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2994 RedrawGadget(tool_gadget[i]);
2996 // store readily prepared envelope request for later use when animating
2997 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3001 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3002 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
3004 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3009 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3011 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3017 if (text_door_style)
3018 free(text_door_style);
3023 void AnimateEnvelopeRequest(int anim_mode, int action)
3025 int graphic = IMG_BACKGROUND_REQUEST;
3026 boolean draw_masked = graphic_info[graphic].draw_masked;
3028 int delay_value_normal = request.step_delay;
3029 int delay_value_fast = delay_value_normal / 2;
3031 int delay_value_normal = GameFrameDelay;
3032 int delay_value_fast = FfwdFrameDelay;
3034 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3035 boolean no_delay = (tape.warp_forward);
3036 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
3037 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
3038 unsigned int anim_delay = 0;
3040 int width = request.width;
3041 int height = request.height;
3042 int tile_size = request.step_offset;
3043 int max_xsize = width / tile_size;
3044 int max_ysize = height / tile_size;
3045 int max_xsize_inner = max_xsize - 2;
3046 int max_ysize_inner = max_ysize - 2;
3048 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
3049 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
3050 int xend = max_xsize_inner;
3051 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
3052 int xstep = (xstart < xend ? 1 : 0);
3053 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3056 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3058 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3059 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3060 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
3061 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
3062 int src_x = sx_center - width / 2;
3063 int src_y = sy_center - height / 2;
3064 int dst_x = sx_center - xsize * tile_size / 2;
3065 int dst_y = sy_center - ysize * tile_size / 2;
3066 int xsize_size_left = (xsize - 1) * tile_size;
3067 int ysize_size_top = (ysize - 1) * tile_size;
3068 int max_xsize_pos = (max_xsize - 1) * tile_size;
3069 int max_ysize_pos = (max_ysize - 1) * tile_size;
3072 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3075 for (yy = 0; yy < 2; yy++)
3077 for (xx = 0; xx < 2; xx++)
3079 int src_xx = src_x + xx * max_xsize_pos;
3080 int src_yy = src_y + yy * max_ysize_pos;
3081 int dst_xx = dst_x + xx * xsize_size_left;
3082 int dst_yy = dst_y + yy * ysize_size_top;
3083 int xx_size = (xx ? tile_size : xsize_size_left);
3084 int yy_size = (yy ? tile_size : ysize_size_top);
3087 BlitBitmapMasked(bitmap_db_cross, backbuffer,
3088 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3090 BlitBitmap(bitmap_db_cross, backbuffer,
3091 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3095 BlitBitmap(bitmap_db_cross, backbuffer,
3097 xsize_size_left, ysize_size_top,
3099 BlitBitmap(bitmap_db_cross, backbuffer,
3100 src_x + max_xsize_pos, src_y,
3101 tile_size, ysize_size_top,
3102 dst_x + xsize_size_left, dst_y);
3103 BlitBitmap(bitmap_db_cross, backbuffer,
3104 src_x, src_y + max_ysize_pos,
3105 xsize_size_left, tile_size,
3106 dst_x, dst_y + ysize_size_top);
3107 BlitBitmap(bitmap_db_cross, backbuffer,
3108 src_x + max_xsize_pos, src_y + max_ysize_pos,
3109 tile_size, tile_size,
3110 dst_x + xsize_size_left, dst_y + ysize_size_top);
3114 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3115 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3117 /* CHECK AGAIN (previous code reactivated) */
3118 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3128 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3134 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
3137 int envelope_nr = 0;
3140 int graphic = IMG_BACKGROUND_REQUEST;
3142 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3144 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
3145 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
3146 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3147 boolean no_delay = (tape.warp_forward);
3148 unsigned int anim_delay = 0;
3149 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
3150 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
3152 int max_word_len = maxWordLengthInString(text);
3153 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3155 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3157 int font_width = getFontWidth(font_nr);
3158 int font_height = getFontHeight(font_nr);
3159 int line_spacing = 2 * 1;
3163 int max_xsize = DXSIZE / font_width;
3164 // int max_ysize = DYSIZE / font_height;
3165 int max_ysize = DYSIZE / (font_height + line_spacing);
3167 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3168 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
3172 int max_xsize = level.envelope[envelope_nr].xsize;
3173 int max_ysize = level.envelope[envelope_nr].ysize;
3175 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3176 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3177 int xend = max_xsize;
3178 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3179 int xstep = (xstart < xend ? 1 : 0);
3180 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3185 char *text_copy = getStringCopy(text);
3188 font_nr = FONT_TEXT_2;
3190 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3192 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3193 font_nr = FONT_TEXT_1;
3196 int max_word_len = 0;
3198 char *text_copy = getStringCopy(text);
3200 font_nr = FONT_TEXT_2;
3202 for (text_ptr = text; *text_ptr; text_ptr++)
3204 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3206 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3208 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3209 font_nr = FONT_TEXT_1;
3218 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3219 if (*text_ptr == ' ')
3224 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3225 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3227 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
3228 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3231 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3233 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3234 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3235 int sx = SX + (SXSIZE - xsize * font_width) / 2;
3236 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3237 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3241 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3243 SetDrawtoField(DRAW_BUFFERED);
3246 BlitScreenToBitmap(backbuffer);
3248 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3251 SetDrawtoField(DRAW_BACKBUFFER);
3254 for (yy = 0; yy < ysize; yy++)
3255 for (xx = 0; xx < xsize; xx++)
3256 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3257 getFontWidth(font_nr),
3258 getFontHeight(font_nr) + line_spacing);
3263 DrawTextBuffer(sx + font_width, sy + font_height + 8,
3264 text_copy, font_nr, max_xsize,
3265 xsize - 2, ysize - 2, line_spacing, mask_mode,
3266 FALSE, TRUE, FALSE);
3268 DrawTextBuffer(sx + font_width, sy + font_height,
3269 level.envelope[envelope_nr].text, font_nr, max_xsize,
3270 xsize - 2, ysize - 2, 0, mask_mode,
3271 level.envelope[envelope_nr].autowrap,
3272 level.envelope[envelope_nr].centered, FALSE);
3276 DrawTextToTextArea(sx + font_width, sy + font_height,
3277 level.envelope[envelope_nr].text, font_nr, max_xsize,
3278 xsize - 2, ysize - 2, mask_mode);
3281 /* copy request gadgets to door backbuffer */
3284 if ((ysize - 2) > 13)
3285 BlitBitmap(bitmap_db_door, drawto,
3286 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3287 DOOR_GFX_PAGEY1 + 13 * font_height,
3288 (xsize - 2) * font_width,
3289 (ysize - 2 - 13) * font_height,
3291 sy + font_height * (1 + 13));
3293 if ((ysize - 2) > 13)
3294 BlitBitmap(bitmap_db_door, drawto,
3295 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3296 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3297 (xsize - 2) * font_width,
3298 (ysize - 2 - 13) * (font_height + line_spacing),
3300 sy + (font_height + line_spacing) * (1 + 13));
3302 if ((ysize - 2) > 13)
3303 BlitBitmap(bitmap_db_door, drawto,
3304 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3305 DOOR_GFX_PAGEY1 + 13 * font_height,
3306 (xsize - 2) * font_width,
3307 (ysize - 2 - 13) * font_height,
3309 sy + font_height * (1 + 13));
3313 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3314 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3316 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3326 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3336 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3339 int last_game_status = game_status; /* save current game status */
3340 // int last_draw_background_mask = gfx.draw_background_mask;
3343 int graphic = IMG_BACKGROUND_REQUEST;
3344 int sound_opening = SND_REQUEST_OPENING;
3345 int sound_closing = SND_REQUEST_CLOSING;
3347 int envelope_nr = 0;
3348 int element = EL_ENVELOPE_1 + envelope_nr;
3349 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3350 int sound_opening = element_info[element].sound[ACTION_OPENING];
3351 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3354 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3355 boolean no_delay = (tape.warp_forward);
3356 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3357 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3359 int anim_mode = graphic_info[graphic].anim_mode;
3360 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3361 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3363 char *text_copy = getStringCopy(text);
3366 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3367 if (*text_ptr == ' ')
3372 if (game_status == GAME_MODE_PLAYING)
3376 BlitScreenToBitmap(backbuffer);
3378 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3379 BlitScreenToBitmap_EM(backbuffer);
3380 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3381 BlitScreenToBitmap_SP(backbuffer);
3383 BlitScreenToBitmap_RND(backbuffer);
3386 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3387 BlitScreenToBitmap_EM(backbuffer);
3388 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3389 BlitScreenToBitmap_SP(backbuffer);
3392 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3397 SetDrawtoField(DRAW_BACKBUFFER);
3399 // SetDrawBackgroundMask(REDRAW_NONE);
3401 if (action == ACTION_OPENING)
3403 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3406 if (req_state & REQ_ASK)
3408 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3409 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3411 else if (req_state & REQ_CONFIRM)
3413 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3415 else if (req_state & REQ_PLAYER)
3417 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3418 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3419 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3420 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3425 DrawEnvelopeRequest(text);
3427 DrawEnvelopeRequest(text_copy);
3430 if (game_status != GAME_MODE_MAIN)
3434 /* force DOOR font inside door area */
3435 game_status = GAME_MODE_PSEUDO_DOOR;
3438 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3440 if (action == ACTION_OPENING)
3442 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3444 if (anim_mode == ANIM_DEFAULT)
3445 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3447 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3451 Delay(wait_delay_value);
3453 WaitForEventToContinue();
3458 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3460 if (anim_mode != ANIM_NONE)
3461 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3463 if (anim_mode == ANIM_DEFAULT)
3464 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3467 game.envelope_active = FALSE;
3470 // game_status = last_game_status; /* restore current game status */
3473 /* !!! CHECK AGAIN (SEE BELOW) !!! */
3474 game_status = last_game_status; /* restore current game status */
3477 if (action == ACTION_CLOSING)
3479 if (game_status != GAME_MODE_MAIN)
3482 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3485 SetDrawtoField(DRAW_BUFFERED);
3488 // SetDrawBackgroundMask(last_draw_background_mask);
3491 redraw_mask = REDRAW_FIELD;
3492 // redraw_mask |= REDRAW_ALL;
3494 /* CHECK AGAIN (previous code reactivated) */
3495 redraw_mask |= REDRAW_FIELD;
3499 if (game_status == GAME_MODE_MAIN)
3505 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3506 game_status = last_game_status; /* restore current game status */
3510 if (action == ACTION_CLOSING &&
3511 game_status == GAME_MODE_PLAYING &&
3512 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3513 SetDrawtoField(DRAW_BUFFERED);
3515 if (game_status == GAME_MODE_PLAYING &&
3516 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3517 SetDrawtoField(DRAW_BUFFERED);
3529 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3533 int graphic = el2preimg(element);
3535 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3536 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3539 void DrawLevel(int draw_background_mask)
3544 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3545 SetDrawBackgroundMask(draw_background_mask);
3548 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3549 SetDrawBackgroundMask(REDRAW_FIELD);
3551 SetDrawBackgroundMask(REDRAW_NONE);
3557 for (x = BX1; x <= BX2; x++)
3558 for (y = BY1; y <= BY2; y++)
3559 DrawScreenField(x, y);
3561 redraw_mask |= REDRAW_FIELD;
3564 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3568 for (x = 0; x < size_x; x++)
3569 for (y = 0; y < size_y; y++)
3570 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3572 redraw_mask |= REDRAW_FIELD;
3575 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3577 boolean show_level_border = (BorderElement != EL_EMPTY);
3578 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3579 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3580 int tile_size = preview.tile_size;
3581 int preview_width = preview.xsize * tile_size;
3582 int preview_height = preview.ysize * tile_size;
3583 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3584 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3585 int real_preview_width = real_preview_xsize * tile_size;
3586 int real_preview_height = real_preview_ysize * tile_size;
3587 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3588 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3592 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3597 dst_x += (preview_width - real_preview_width) / 2;
3598 dst_y += (preview_height - real_preview_height) / 2;
3600 DrawBackground(dst_x, dst_y, real_preview_width, real_preview_height);
3602 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3604 dst_x += (preview_width - real_preview_width) / 2;
3605 dst_y += (preview_height - real_preview_height) / 2;
3608 for (x = 0; x < real_preview_xsize; x++)
3610 for (y = 0; y < real_preview_ysize; y++)
3612 int lx = from_x + x + (show_level_border ? -1 : 0);
3613 int ly = from_y + y + (show_level_border ? -1 : 0);
3614 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3615 getBorderElement(lx, ly));
3617 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3618 element, tile_size);
3622 redraw_mask |= REDRAW_MICROLEVEL;
3625 #define MICROLABEL_EMPTY 0
3626 #define MICROLABEL_LEVEL_NAME 1
3627 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3628 #define MICROLABEL_LEVEL_AUTHOR 3
3629 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3630 #define MICROLABEL_IMPORTED_FROM 5
3631 #define MICROLABEL_IMPORTED_BY_HEAD 6
3632 #define MICROLABEL_IMPORTED_BY 7
3634 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3636 int max_text_width = SXSIZE;
3637 int font_width = getFontWidth(font_nr);
3639 if (pos->align == ALIGN_CENTER)
3640 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3641 else if (pos->align == ALIGN_RIGHT)
3642 max_text_width = pos->x;
3644 max_text_width = SXSIZE - pos->x;
3646 return max_text_width / font_width;
3649 static void DrawPreviewLevelLabelExt(int mode)
3651 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3652 char label_text[MAX_OUTPUT_LINESIZE + 1];
3653 int max_len_label_text;
3655 int font_nr = pos->font;
3658 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3661 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3662 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3663 mode == MICROLABEL_IMPORTED_BY_HEAD)
3664 font_nr = pos->font_alt;
3666 int font_nr = FONT_TEXT_2;
3669 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3670 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3671 mode == MICROLABEL_IMPORTED_BY_HEAD)
3672 font_nr = FONT_TEXT_3;
3676 max_len_label_text = getMaxTextLength(pos, font_nr);
3678 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3682 if (pos->size != -1)
3683 max_len_label_text = pos->size;
3686 for (i = 0; i < max_len_label_text; i++)
3687 label_text[i] = ' ';
3688 label_text[max_len_label_text] = '\0';
3690 if (strlen(label_text) > 0)
3693 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3695 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3696 int lypos = MICROLABEL2_YPOS;
3698 DrawText(lxpos, lypos, label_text, font_nr);
3703 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3704 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3705 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3706 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3707 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3708 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3709 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3710 max_len_label_text);
3711 label_text[max_len_label_text] = '\0';
3713 if (strlen(label_text) > 0)
3716 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3718 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3719 int lypos = MICROLABEL2_YPOS;
3721 DrawText(lxpos, lypos, label_text, font_nr);
3725 redraw_mask |= REDRAW_MICROLEVEL;
3728 static void DrawPreviewLevelExt(boolean restart)
3730 static unsigned int scroll_delay = 0;
3731 static unsigned int label_delay = 0;
3732 static int from_x, from_y, scroll_direction;
3733 static int label_state, label_counter;
3734 unsigned int scroll_delay_value = preview.step_delay;
3735 boolean show_level_border = (BorderElement != EL_EMPTY);
3736 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3737 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3738 int last_game_status = game_status; /* save current game status */
3741 /* force PREVIEW font on preview level */
3742 game_status = GAME_MODE_PSEUDO_PREVIEW;
3750 if (preview.anim_mode == ANIM_CENTERED)
3752 if (level_xsize > preview.xsize)
3753 from_x = (level_xsize - preview.xsize) / 2;
3754 if (level_ysize > preview.ysize)
3755 from_y = (level_ysize - preview.ysize) / 2;
3758 from_x += preview.xoffset;
3759 from_y += preview.yoffset;
3761 scroll_direction = MV_RIGHT;
3765 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3766 DrawPreviewLevelLabelExt(label_state);
3768 /* initialize delay counters */
3769 DelayReached(&scroll_delay, 0);
3770 DelayReached(&label_delay, 0);
3772 if (leveldir_current->name)
3774 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3775 char label_text[MAX_OUTPUT_LINESIZE + 1];
3777 int font_nr = pos->font;
3779 int font_nr = FONT_TEXT_1;
3782 int max_len_label_text = getMaxTextLength(pos, font_nr);
3784 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3792 if (pos->size != -1)
3793 max_len_label_text = pos->size;
3796 strncpy(label_text, leveldir_current->name, max_len_label_text);
3797 label_text[max_len_label_text] = '\0';
3800 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3801 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3803 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3804 lypos = SY + MICROLABEL1_YPOS;
3806 DrawText(lxpos, lypos, label_text, font_nr);
3810 game_status = last_game_status; /* restore current game status */
3815 /* scroll preview level, if needed */
3816 if (preview.anim_mode != ANIM_NONE &&
3817 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3818 DelayReached(&scroll_delay, scroll_delay_value))
3820 switch (scroll_direction)
3825 from_x -= preview.step_offset;
3826 from_x = (from_x < 0 ? 0 : from_x);
3829 scroll_direction = MV_UP;
3833 if (from_x < level_xsize - preview.xsize)
3835 from_x += preview.step_offset;
3836 from_x = (from_x > level_xsize - preview.xsize ?
3837 level_xsize - preview.xsize : from_x);
3840 scroll_direction = MV_DOWN;
3846 from_y -= preview.step_offset;
3847 from_y = (from_y < 0 ? 0 : from_y);
3850 scroll_direction = MV_RIGHT;
3854 if (from_y < level_ysize - preview.ysize)
3856 from_y += preview.step_offset;
3857 from_y = (from_y > level_ysize - preview.ysize ?
3858 level_ysize - preview.ysize : from_y);
3861 scroll_direction = MV_LEFT;
3868 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3871 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3872 /* redraw micro level label, if needed */
3873 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3874 !strEqual(level.author, ANONYMOUS_NAME) &&
3875 !strEqual(level.author, leveldir_current->name) &&
3876 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3878 int max_label_counter = 23;
3880 if (leveldir_current->imported_from != NULL &&
3881 strlen(leveldir_current->imported_from) > 0)
3882 max_label_counter += 14;
3883 if (leveldir_current->imported_by != NULL &&
3884 strlen(leveldir_current->imported_by) > 0)
3885 max_label_counter += 14;
3887 label_counter = (label_counter + 1) % max_label_counter;
3888 label_state = (label_counter >= 0 && label_counter <= 7 ?
3889 MICROLABEL_LEVEL_NAME :
3890 label_counter >= 9 && label_counter <= 12 ?
3891 MICROLABEL_LEVEL_AUTHOR_HEAD :
3892 label_counter >= 14 && label_counter <= 21 ?
3893 MICROLABEL_LEVEL_AUTHOR :
3894 label_counter >= 23 && label_counter <= 26 ?
3895 MICROLABEL_IMPORTED_FROM_HEAD :
3896 label_counter >= 28 && label_counter <= 35 ?
3897 MICROLABEL_IMPORTED_FROM :
3898 label_counter >= 37 && label_counter <= 40 ?
3899 MICROLABEL_IMPORTED_BY_HEAD :
3900 label_counter >= 42 && label_counter <= 49 ?
3901 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3903 if (leveldir_current->imported_from == NULL &&
3904 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3905 label_state == MICROLABEL_IMPORTED_FROM))
3906 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3907 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3909 DrawPreviewLevelLabelExt(label_state);
3912 game_status = last_game_status; /* restore current game status */
3915 void DrawPreviewLevelInitial()
3917 DrawPreviewLevelExt(TRUE);
3920 void DrawPreviewLevelAnimation()
3922 DrawPreviewLevelExt(FALSE);
3925 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3926 int graphic, int sync_frame, int mask_mode)
3928 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3930 if (mask_mode == USE_MASKING)
3931 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3933 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3936 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3937 int graphic, int sync_frame,
3940 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3942 if (mask_mode == USE_MASKING)
3943 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3945 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3948 inline void DrawGraphicAnimation(int x, int y, int graphic)
3950 int lx = LEVELX(x), ly = LEVELY(y);
3952 if (!IN_SCR_FIELD(x, y))
3956 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3957 graphic, GfxFrame[lx][ly], NO_MASKING);
3959 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3960 graphic, GfxFrame[lx][ly], NO_MASKING);
3962 MarkTileDirty(x, y);
3965 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3967 int lx = LEVELX(x), ly = LEVELY(y);
3969 if (!IN_SCR_FIELD(x, y))
3972 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3973 graphic, GfxFrame[lx][ly], NO_MASKING);
3974 MarkTileDirty(x, y);
3977 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3979 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3982 void DrawLevelElementAnimation(int x, int y, int element)
3984 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3986 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3989 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3991 int sx = SCREENX(x), sy = SCREENY(y);
3993 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3996 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3999 DrawGraphicAnimation(sx, sy, graphic);
4002 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
4003 DrawLevelFieldCrumbled(x, y);
4005 if (GFX_CRUMBLED(Feld[x][y]))
4006 DrawLevelFieldCrumbled(x, y);
4010 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
4012 int sx = SCREENX(x), sy = SCREENY(y);
4015 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
4018 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
4020 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
4023 DrawGraphicAnimation(sx, sy, graphic);
4025 if (GFX_CRUMBLED(element))
4026 DrawLevelFieldCrumbled(x, y);
4029 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
4031 if (player->use_murphy)
4033 /* this works only because currently only one player can be "murphy" ... */
4034 static int last_horizontal_dir = MV_LEFT;
4035 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
4037 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4038 last_horizontal_dir = move_dir;
4040 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
4042 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
4044 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
4050 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
4053 static boolean equalGraphics(int graphic1, int graphic2)
4055 struct GraphicInfo *g1 = &graphic_info[graphic1];
4056 struct GraphicInfo *g2 = &graphic_info[graphic2];
4058 return (g1->bitmap == g2->bitmap &&
4059 g1->src_x == g2->src_x &&
4060 g1->src_y == g2->src_y &&
4061 g1->anim_frames == g2->anim_frames &&
4062 g1->anim_delay == g2->anim_delay &&
4063 g1->anim_mode == g2->anim_mode);
4066 void DrawAllPlayers()
4070 for (i = 0; i < MAX_PLAYERS; i++)
4071 if (stored_player[i].active)
4072 DrawPlayer(&stored_player[i]);
4075 void DrawPlayerField(int x, int y)
4077 if (!IS_PLAYER(x, y))
4080 DrawPlayer(PLAYERINFO(x, y));
4083 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
4085 void DrawPlayer(struct PlayerInfo *player)
4087 int jx = player->jx;
4088 int jy = player->jy;
4089 int move_dir = player->MovDir;
4090 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
4091 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
4092 int last_jx = (player->is_moving ? jx - dx : jx);
4093 int last_jy = (player->is_moving ? jy - dy : jy);
4094 int next_jx = jx + dx;
4095 int next_jy = jy + dy;
4096 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
4097 boolean player_is_opaque = FALSE;
4098 int sx = SCREENX(jx), sy = SCREENY(jy);
4099 int sxx = 0, syy = 0;
4100 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
4102 int action = ACTION_DEFAULT;
4103 int last_player_graphic = getPlayerGraphic(player, move_dir);
4104 int last_player_frame = player->Frame;
4107 /* GfxElement[][] is set to the element the player is digging or collecting;
4108 remove also for off-screen player if the player is not moving anymore */
4109 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
4110 GfxElement[jx][jy] = EL_UNDEFINED;
4112 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
4116 if (!IN_LEV_FIELD(jx, jy))
4118 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
4119 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
4120 printf("DrawPlayerField(): This should never happen!\n");
4125 if (element == EL_EXPLOSION)
4128 action = (player->is_pushing ? ACTION_PUSHING :
4129 player->is_digging ? ACTION_DIGGING :
4130 player->is_collecting ? ACTION_COLLECTING :
4131 player->is_moving ? ACTION_MOVING :
4132 player->is_snapping ? ACTION_SNAPPING :
4133 player->is_dropping ? ACTION_DROPPING :
4134 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
4136 if (player->is_waiting)
4137 move_dir = player->dir_waiting;
4139 InitPlayerGfxAnimation(player, action, move_dir);
4141 /* ----------------------------------------------------------------------- */
4142 /* draw things in the field the player is leaving, if needed */
4143 /* ----------------------------------------------------------------------- */
4145 if (player->is_moving)
4147 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
4149 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
4151 if (last_element == EL_DYNAMITE_ACTIVE ||
4152 last_element == EL_EM_DYNAMITE_ACTIVE ||
4153 last_element == EL_SP_DISK_RED_ACTIVE)
4154 DrawDynamite(last_jx, last_jy);
4156 DrawLevelFieldThruMask(last_jx, last_jy);
4158 else if (last_element == EL_DYNAMITE_ACTIVE ||
4159 last_element == EL_EM_DYNAMITE_ACTIVE ||
4160 last_element == EL_SP_DISK_RED_ACTIVE)
4161 DrawDynamite(last_jx, last_jy);
4163 /* !!! this is not enough to prevent flickering of players which are
4164 moving next to each others without a free tile between them -- this
4165 can only be solved by drawing all players layer by layer (first the
4166 background, then the foreground etc.) !!! => TODO */
4167 else if (!IS_PLAYER(last_jx, last_jy))
4168 DrawLevelField(last_jx, last_jy);
4171 DrawLevelField(last_jx, last_jy);
4174 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
4175 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4178 if (!IN_SCR_FIELD(sx, sy))
4181 /* ----------------------------------------------------------------------- */
4182 /* draw things behind the player, if needed */
4183 /* ----------------------------------------------------------------------- */
4186 DrawLevelElement(jx, jy, Back[jx][jy]);
4187 else if (IS_ACTIVE_BOMB(element))
4188 DrawLevelElement(jx, jy, EL_EMPTY);
4191 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
4193 int old_element = GfxElement[jx][jy];
4194 int old_graphic = el_act_dir2img(old_element, action, move_dir);
4195 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
4197 if (GFX_CRUMBLED(old_element))
4198 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4200 DrawGraphic(sx, sy, old_graphic, frame);
4202 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4203 player_is_opaque = TRUE;
4207 GfxElement[jx][jy] = EL_UNDEFINED;
4209 /* make sure that pushed elements are drawn with correct frame rate */
4211 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4213 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4214 GfxFrame[jx][jy] = player->StepFrame;
4216 if (player->is_pushing && player->is_moving)
4217 GfxFrame[jx][jy] = player->StepFrame;
4220 DrawLevelField(jx, jy);
4224 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4225 /* ----------------------------------------------------------------------- */
4226 /* draw player himself */
4227 /* ----------------------------------------------------------------------- */
4229 graphic = getPlayerGraphic(player, move_dir);
4231 /* in the case of changed player action or direction, prevent the current
4232 animation frame from being restarted for identical animations */
4233 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4234 player->Frame = last_player_frame;
4236 frame = getGraphicAnimationFrame(graphic, player->Frame);
4240 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4241 sxx = player->GfxPos;
4243 syy = player->GfxPos;
4246 if (!setup.soft_scrolling && ScreenMovPos)
4249 if (player_is_opaque)
4250 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4252 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4254 if (SHIELD_ON(player))
4256 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4257 IMG_SHIELD_NORMAL_ACTIVE);
4258 int frame = getGraphicAnimationFrame(graphic, -1);
4260 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4264 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4267 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4268 sxx = player->GfxPos;
4270 syy = player->GfxPos;
4274 /* ----------------------------------------------------------------------- */
4275 /* draw things the player is pushing, if needed */
4276 /* ----------------------------------------------------------------------- */
4279 printf("::: %d, %d [%d, %d] [%d]\n",
4280 player->is_pushing, player_is_moving, player->GfxAction,
4281 player->is_moving, player_is_moving);
4285 if (player->is_pushing && player->is_moving)
4287 int px = SCREENX(jx), py = SCREENY(jy);
4288 int pxx = (TILEX - ABS(sxx)) * dx;
4289 int pyy = (TILEY - ABS(syy)) * dy;
4290 int gfx_frame = GfxFrame[jx][jy];
4296 if (!IS_MOVING(jx, jy)) /* push movement already finished */
4298 element = Feld[next_jx][next_jy];
4299 gfx_frame = GfxFrame[next_jx][next_jy];
4302 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4305 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4306 frame = getGraphicAnimationFrame(graphic, sync_frame);
4308 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4311 /* draw background element under pushed element (like the Sokoban field) */
4313 if (game.use_masked_pushing && IS_MOVING(jx, jy))
4315 /* this allows transparent pushing animation over non-black background */
4318 DrawLevelElement(jx, jy, Back[jx][jy]);
4320 DrawLevelElement(jx, jy, EL_EMPTY);
4322 if (Back[next_jx][next_jy])
4323 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4325 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4327 else if (Back[next_jx][next_jy])
4328 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4330 if (Back[next_jx][next_jy])
4331 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4335 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4336 jx, px, player->GfxPos, player->StepFrame,
4341 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4345 /* do not draw (EM style) pushing animation when pushing is finished */
4346 /* (two-tile animations usually do not contain start and end frame) */
4347 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4348 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4350 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4352 /* masked drawing is needed for EMC style (double) movement graphics */
4353 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4354 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4359 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4360 /* ----------------------------------------------------------------------- */
4361 /* draw player himself */
4362 /* ----------------------------------------------------------------------- */
4364 graphic = getPlayerGraphic(player, move_dir);
4366 /* in the case of changed player action or direction, prevent the current
4367 animation frame from being restarted for identical animations */
4368 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4369 player->Frame = last_player_frame;
4371 frame = getGraphicAnimationFrame(graphic, player->Frame);
4375 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4376 sxx = player->GfxPos;
4378 syy = player->GfxPos;
4381 if (!setup.soft_scrolling && ScreenMovPos)
4384 if (player_is_opaque)
4385 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4387 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4389 if (SHIELD_ON(player))
4391 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4392 IMG_SHIELD_NORMAL_ACTIVE);
4393 int frame = getGraphicAnimationFrame(graphic, -1);
4395 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4399 /* ----------------------------------------------------------------------- */
4400 /* draw things in front of player (active dynamite or dynabombs) */
4401 /* ----------------------------------------------------------------------- */
4403 if (IS_ACTIVE_BOMB(element))
4405 graphic = el2img(element);
4406 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4408 if (game.emulation == EMU_SUPAPLEX)
4409 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4411 DrawGraphicThruMask(sx, sy, graphic, frame);
4414 if (player_is_moving && last_element == EL_EXPLOSION)
4416 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4417 GfxElement[last_jx][last_jy] : EL_EMPTY);
4418 int graphic = el_act2img(element, ACTION_EXPLODING);
4419 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4420 int phase = ExplodePhase[last_jx][last_jy] - 1;
4421 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4424 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4427 /* ----------------------------------------------------------------------- */
4428 /* draw elements the player is just walking/passing through/under */
4429 /* ----------------------------------------------------------------------- */
4431 if (player_is_moving)
4433 /* handle the field the player is leaving ... */
4434 if (IS_ACCESSIBLE_INSIDE(last_element))
4435 DrawLevelField(last_jx, last_jy);
4436 else if (IS_ACCESSIBLE_UNDER(last_element))
4437 DrawLevelFieldThruMask(last_jx, last_jy);
4440 /* do not redraw accessible elements if the player is just pushing them */
4441 if (!player_is_moving || !player->is_pushing)
4443 /* ... and the field the player is entering */
4444 if (IS_ACCESSIBLE_INSIDE(element))
4445 DrawLevelField(jx, jy);
4446 else if (IS_ACCESSIBLE_UNDER(element))
4447 DrawLevelFieldThruMask(jx, jy);
4450 MarkTileDirty(sx, sy);
4453 /* ------------------------------------------------------------------------- */
4455 void WaitForEventToContinue()
4457 boolean still_wait = TRUE;
4459 /* simulate releasing mouse button over last gadget, if still pressed */
4461 HandleGadgets(-1, -1, 0);
4463 button_status = MB_RELEASED;
4479 case EVENT_BUTTONPRESS:
4480 case EVENT_KEYPRESS:
4484 case EVENT_KEYRELEASE:
4485 ClearPlayerAction();
4489 HandleOtherEvents(&event);
4493 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4500 /* don't eat all CPU time */
4505 #define MAX_REQUEST_LINES 13
4506 #define MAX_REQUEST_LINE_FONT1_LEN 7
4507 #define MAX_REQUEST_LINE_FONT2_LEN 10
4511 static int RequestHandleEvents(unsigned int req_state)
4513 int last_game_status = game_status; /* save current game status */
4517 button_status = MB_RELEASED;
4519 request_gadget_id = -1;
4532 case EVENT_BUTTONPRESS:
4533 case EVENT_BUTTONRELEASE:
4534 case EVENT_MOTIONNOTIFY:
4536 if (event.type == EVENT_MOTIONNOTIFY)
4538 if (!PointerInWindow(window))
4539 continue; /* window and pointer are on different screens */
4544 motion_status = TRUE;
4545 mx = ((MotionEvent *) &event)->x;
4546 my = ((MotionEvent *) &event)->y;
4550 motion_status = FALSE;
4551 mx = ((ButtonEvent *) &event)->x;
4552 my = ((ButtonEvent *) &event)->y;
4553 if (event.type == EVENT_BUTTONPRESS)
4554 button_status = ((ButtonEvent *) &event)->button;
4556 button_status = MB_RELEASED;
4559 /* this sets 'request_gadget_id' */
4560 HandleGadgets(mx, my, button_status);
4562 switch (request_gadget_id)
4564 case TOOL_CTRL_ID_YES:
4567 case TOOL_CTRL_ID_NO:
4570 case TOOL_CTRL_ID_CONFIRM:
4571 result = TRUE | FALSE;
4574 case TOOL_CTRL_ID_PLAYER_1:
4577 case TOOL_CTRL_ID_PLAYER_2:
4580 case TOOL_CTRL_ID_PLAYER_3:
4583 case TOOL_CTRL_ID_PLAYER_4:
4594 case EVENT_KEYPRESS:
4595 switch (GetEventKey((KeyEvent *)&event, TRUE))
4598 if (req_state & REQ_CONFIRM)
4603 #if defined(TARGET_SDL2)
4610 #if defined(TARGET_SDL2)
4620 if (req_state & REQ_PLAYER)
4624 case EVENT_KEYRELEASE:
4625 ClearPlayerAction();
4629 HandleOtherEvents(&event);
4633 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4635 int joy = AnyJoystick();
4637 if (joy & JOY_BUTTON_1)
4639 else if (joy & JOY_BUTTON_2)
4645 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4647 HandleGameActions();
4653 if (!PendingEvent()) /* delay only if no pending events */
4658 game_status = GAME_MODE_PSEUDO_DOOR;
4664 game_status = last_game_status; /* restore current game status */
4672 if (!PendingEvent()) /* delay only if no pending events */
4675 /* don't eat all CPU time */
4685 static boolean RequestDoor(char *text, unsigned int req_state)
4687 unsigned int old_door_state;
4688 int last_game_status = game_status; /* save current game status */
4689 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4690 int font_nr = FONT_TEXT_2;
4695 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4697 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4698 font_nr = FONT_TEXT_1;
4701 if (game_status == GAME_MODE_PLAYING)
4704 BlitScreenToBitmap(backbuffer);
4706 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4707 BlitScreenToBitmap_EM(backbuffer);
4708 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4709 BlitScreenToBitmap_SP(backbuffer);
4713 /* disable deactivated drawing when quick-loading level tape recording */
4714 if (tape.playing && tape.deactivate_display)
4715 TapeDeactivateDisplayOff(TRUE);
4717 SetMouseCursor(CURSOR_DEFAULT);
4719 #if defined(NETWORK_AVALIABLE)
4720 /* pause network game while waiting for request to answer */
4721 if (options.network &&
4722 game_status == GAME_MODE_PLAYING &&
4723 req_state & REQUEST_WAIT_FOR_INPUT)
4724 SendToServer_PausePlaying();
4727 old_door_state = GetDoorState();
4729 /* simulate releasing mouse button over last gadget, if still pressed */
4731 HandleGadgets(-1, -1, 0);
4735 /* draw released gadget before proceeding */
4738 if (old_door_state & DOOR_OPEN_1)
4740 CloseDoor(DOOR_CLOSE_1);
4742 /* save old door content */
4744 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4745 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4747 BlitBitmap(bitmap_db_door, bitmap_db_door,
4748 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4749 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4753 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4754 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4756 /* clear door drawing field */
4757 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4759 /* force DOOR font inside door area */
4760 game_status = GAME_MODE_PSEUDO_DOOR;
4762 /* write text for request */
4763 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4765 char text_line[max_request_line_len + 1];
4771 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4773 tc = *(text_ptr + tx);
4774 // if (!tc || tc == ' ')
4775 if (!tc || tc == ' ' || tc == '?' || tc == '!')
4779 if ((tc == '?' || tc == '!') && tl == 0)
4789 strncpy(text_line, text_ptr, tl);
4792 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4793 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4794 text_line, font_nr);
4796 text_ptr += tl + (tc == ' ' ? 1 : 0);
4797 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4800 game_status = last_game_status; /* restore current game status */
4802 if (req_state & REQ_ASK)
4804 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4805 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4807 else if (req_state & REQ_CONFIRM)
4809 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4811 else if (req_state & REQ_PLAYER)
4813 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4814 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4815 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4816 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4819 /* copy request gadgets to door backbuffer */
4821 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4823 BlitBitmap(drawto, bitmap_db_door,
4824 DX, DY, DXSIZE, DYSIZE,
4825 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4828 OpenDoor(DOOR_OPEN_1);
4830 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4832 if (game_status == GAME_MODE_PLAYING)
4834 SetPanelBackground();
4835 SetDrawBackgroundMask(REDRAW_DOOR_1);
4839 SetDrawBackgroundMask(REDRAW_FIELD);
4845 if (game_status != GAME_MODE_MAIN)
4848 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4850 // ---------- handle request buttons ----------
4851 result = RequestHandleEvents(req_state);
4853 if (game_status != GAME_MODE_MAIN)
4858 if (!(req_state & REQ_STAY_OPEN))
4860 CloseDoor(DOOR_CLOSE_1);
4862 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4863 (req_state & REQ_REOPEN))
4864 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4869 if (game_status == GAME_MODE_PLAYING)
4871 SetPanelBackground();
4872 SetDrawBackgroundMask(REDRAW_DOOR_1);
4876 SetDrawBackgroundMask(REDRAW_FIELD);
4879 #if defined(NETWORK_AVALIABLE)
4880 /* continue network game after request */
4881 if (options.network &&
4882 game_status == GAME_MODE_PLAYING &&
4883 req_state & REQUEST_WAIT_FOR_INPUT)
4884 SendToServer_ContinuePlaying();
4887 /* restore deactivated drawing when quick-loading level tape recording */
4888 if (tape.playing && tape.deactivate_display)
4889 TapeDeactivateDisplayOn();
4894 static boolean RequestEnvelope(char *text, unsigned int req_state)
4901 if (game_status == GAME_MODE_PLAYING)
4905 BlitScreenToBitmap(backbuffer);
4907 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4908 BlitScreenToBitmap_EM(backbuffer);
4909 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4910 BlitScreenToBitmap_SP(backbuffer);
4912 BlitScreenToBitmap_RND(backbuffer);
4915 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4916 BlitScreenToBitmap_EM(backbuffer);
4917 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4918 BlitScreenToBitmap_SP(backbuffer);
4922 /* disable deactivated drawing when quick-loading level tape recording */
4923 if (tape.playing && tape.deactivate_display)
4924 TapeDeactivateDisplayOff(TRUE);
4926 SetMouseCursor(CURSOR_DEFAULT);
4928 #if defined(NETWORK_AVALIABLE)
4929 /* pause network game while waiting for request to answer */
4930 if (options.network &&
4931 game_status == GAME_MODE_PLAYING &&
4932 req_state & REQUEST_WAIT_FOR_INPUT)
4933 SendToServer_PausePlaying();
4936 /* simulate releasing mouse button over last gadget, if still pressed */
4938 HandleGadgets(-1, -1, 0);
4942 // (replace with setting corresponding request background)
4943 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4944 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4946 /* clear door drawing field */
4947 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4950 if (global.use_envelope_request)
4954 CreateToolButtons();
4960 if (req_state & REQ_ASK)
4962 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4963 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4965 else if (req_state & REQ_CONFIRM)
4967 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4969 else if (req_state & REQ_PLAYER)
4971 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4972 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4973 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4974 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4977 if (req_state & REQ_ASK)
4979 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4980 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4982 else if (req_state & REQ_CONFIRM)
4984 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4986 else if (req_state & REQ_PLAYER)
4988 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4989 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4990 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4991 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4996 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4999 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5001 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5002 i == TOOL_CTRL_ID_NO)) ||
5003 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5004 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5005 i == TOOL_CTRL_ID_PLAYER_2 &&
5006 i == TOOL_CTRL_ID_PLAYER_3 &&
5007 i == TOOL_CTRL_ID_PLAYER_4)))
5009 int x = tool_gadget[i]->x + dDX;
5010 int y = tool_gadget[i]->y + dDY;
5012 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5017 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5019 if (game_status == GAME_MODE_PLAYING)
5021 SetPanelBackground();
5022 SetDrawBackgroundMask(REDRAW_DOOR_1);
5026 SetDrawBackgroundMask(REDRAW_FIELD);
5033 if (game_status != GAME_MODE_MAIN)
5037 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5039 // ---------- handle request buttons ----------
5040 result = RequestHandleEvents(req_state);
5042 if (game_status != GAME_MODE_MAIN)
5047 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
5051 if (game_status == GAME_MODE_PLAYING)
5053 SetPanelBackground();
5054 SetDrawBackgroundMask(REDRAW_DOOR_1);
5058 SetDrawBackgroundMask(REDRAW_FIELD);
5061 #if defined(NETWORK_AVALIABLE)
5062 /* continue network game after request */
5063 if (options.network &&
5064 game_status == GAME_MODE_PLAYING &&
5065 req_state & REQUEST_WAIT_FOR_INPUT)
5066 SendToServer_ContinuePlaying();
5069 /* restore deactivated drawing when quick-loading level tape recording */
5070 if (tape.playing && tape.deactivate_display)
5071 TapeDeactivateDisplayOn();
5076 boolean Request(char *text, unsigned int req_state)
5078 if (global.use_envelope_request)
5079 return RequestEnvelope(text, req_state);
5081 return RequestDoor(text, req_state);
5084 #else // =====================================================================
5086 boolean Request(char *text, unsigned int req_state)
5088 int mx, my, ty, result = -1;
5089 unsigned int old_door_state;
5090 int last_game_status = game_status; /* save current game status */
5091 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
5092 int font_nr = FONT_TEXT_2;
5094 int max_word_len = 0;
5100 global.use_envelope_request = 1;
5104 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
5106 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5107 font_nr = FONT_TEXT_1;
5110 for (text_ptr = text; *text_ptr; text_ptr++)
5112 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
5114 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
5116 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5118 font_nr = FONT_TEXT_1;
5120 font_nr = FONT_LEVEL_NUMBER;
5128 if (game_status == GAME_MODE_PLAYING)
5131 BlitScreenToBitmap(backbuffer);
5133 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5134 BlitScreenToBitmap_EM(backbuffer);
5135 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
5136 BlitScreenToBitmap_SP(backbuffer);
5140 /* disable deactivated drawing when quick-loading level tape recording */
5141 if (tape.playing && tape.deactivate_display)
5142 TapeDeactivateDisplayOff(TRUE);
5144 SetMouseCursor(CURSOR_DEFAULT);
5146 #if defined(NETWORK_AVALIABLE)
5147 /* pause network game while waiting for request to answer */
5148 if (options.network &&
5149 game_status == GAME_MODE_PLAYING &&
5150 req_state & REQUEST_WAIT_FOR_INPUT)
5151 SendToServer_PausePlaying();
5154 old_door_state = GetDoorState();
5156 /* simulate releasing mouse button over last gadget, if still pressed */
5158 HandleGadgets(-1, -1, 0);
5162 /* draw released gadget before proceeding */
5166 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
5168 if (old_door_state & DOOR_OPEN_1)
5172 if (!global.use_envelope_request)
5173 CloseDoor(DOOR_CLOSE_1);
5175 CloseDoor(DOOR_CLOSE_1);
5178 /* save old door content */
5179 BlitBitmap(bitmap_db_door, bitmap_db_door,
5180 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5181 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
5185 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
5188 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5190 /* clear door drawing field */
5191 DrawBackground(DX, DY, DXSIZE, DYSIZE);
5193 /* force DOOR font inside door area */
5194 game_status = GAME_MODE_PSEUDO_DOOR;
5196 /* write text for request */
5197 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
5199 char text_line[max_request_line_len + 1];
5205 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
5207 tc = *(text_ptr + tx);
5208 if (!tc || tc == ' ')
5219 strncpy(text_line, text_ptr, tl);
5222 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5223 DY + 8 + ty * (getFontHeight(font_nr) + 2),
5224 text_line, font_nr);
5226 text_ptr += tl + (tc == ' ' ? 1 : 0);
5229 game_status = last_game_status; /* restore current game status */
5232 if (global.use_envelope_request)
5236 CreateToolButtons();
5240 if (req_state & REQ_ASK)
5242 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5243 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5245 else if (req_state & REQ_CONFIRM)
5247 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5249 else if (req_state & REQ_PLAYER)
5251 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5252 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5253 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5254 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5257 /* copy request gadgets to door backbuffer */
5258 BlitBitmap(drawto, bitmap_db_door,
5259 DX, DY, DXSIZE, DYSIZE,
5260 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5263 if (global.use_envelope_request)
5265 ShowEnvelopeRequest(text, ACTION_OPENING);
5267 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5269 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5270 i == TOOL_CTRL_ID_NO)) ||
5271 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5272 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5273 i == TOOL_CTRL_ID_PLAYER_2 &&
5274 i == TOOL_CTRL_ID_PLAYER_3 &&
5275 i == TOOL_CTRL_ID_PLAYER_4)))
5277 int x = tool_gadget[i]->x + dDX;
5278 int y = tool_gadget[i]->y + dDY;
5280 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5287 if (!global.use_envelope_request)
5288 OpenDoor(DOOR_OPEN_1);
5290 OpenDoor(DOOR_OPEN_1);
5293 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5295 if (game_status == GAME_MODE_PLAYING)
5297 SetPanelBackground();
5298 SetDrawBackgroundMask(REDRAW_DOOR_1);
5302 SetDrawBackgroundMask(REDRAW_FIELD);
5309 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5312 if (game_status != GAME_MODE_MAIN)
5316 button_status = MB_RELEASED;
5318 request_gadget_id = -1;
5320 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5332 case EVENT_BUTTONPRESS:
5333 case EVENT_BUTTONRELEASE:
5334 case EVENT_MOTIONNOTIFY:
5336 if (event.type == EVENT_MOTIONNOTIFY)
5338 if (!PointerInWindow(window))
5339 continue; /* window and pointer are on different screens */
5344 motion_status = TRUE;
5345 mx = ((MotionEvent *) &event)->x;
5346 my = ((MotionEvent *) &event)->y;
5350 motion_status = FALSE;
5351 mx = ((ButtonEvent *) &event)->x;
5352 my = ((ButtonEvent *) &event)->y;
5353 if (event.type == EVENT_BUTTONPRESS)
5354 button_status = ((ButtonEvent *) &event)->button;
5356 button_status = MB_RELEASED;
5359 /* this sets 'request_gadget_id' */
5360 HandleGadgets(mx, my, button_status);
5362 switch (request_gadget_id)
5364 case TOOL_CTRL_ID_YES:
5367 case TOOL_CTRL_ID_NO:
5370 case TOOL_CTRL_ID_CONFIRM:
5371 result = TRUE | FALSE;
5374 case TOOL_CTRL_ID_PLAYER_1:
5377 case TOOL_CTRL_ID_PLAYER_2:
5380 case TOOL_CTRL_ID_PLAYER_3:
5383 case TOOL_CTRL_ID_PLAYER_4:
5394 case EVENT_KEYPRESS:
5395 switch (GetEventKey((KeyEvent *)&event, TRUE))
5398 if (req_state & REQ_CONFIRM)
5407 #if defined(TARGET_SDL2)
5417 if (req_state & REQ_PLAYER)
5421 case EVENT_KEYRELEASE:
5422 ClearPlayerAction();
5426 HandleOtherEvents(&event);
5430 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5432 int joy = AnyJoystick();
5434 if (joy & JOY_BUTTON_1)
5436 else if (joy & JOY_BUTTON_2)
5442 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5444 HandleGameActions();
5450 if (!PendingEvent()) /* delay only if no pending events */
5455 game_status = GAME_MODE_PSEUDO_DOOR;
5461 game_status = last_game_status; /* restore current game status */
5469 if (!PendingEvent()) /* delay only if no pending events */
5472 /* don't eat all CPU time */
5479 if (game_status != GAME_MODE_MAIN)
5485 if (global.use_envelope_request)
5486 ShowEnvelopeRequest(text, ACTION_CLOSING);
5490 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5492 if (!(req_state & REQ_STAY_OPEN))
5495 CloseDoor(DOOR_CLOSE_1);
5497 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5498 (req_state & REQ_REOPEN))
5499 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5504 if (game_status == GAME_MODE_PLAYING)
5506 SetPanelBackground();
5507 SetDrawBackgroundMask(REDRAW_DOOR_1);
5511 SetDrawBackgroundMask(REDRAW_FIELD);
5514 #if defined(NETWORK_AVALIABLE)
5515 /* continue network game after request */
5516 if (options.network &&
5517 game_status == GAME_MODE_PLAYING &&
5518 req_state & REQUEST_WAIT_FOR_INPUT)
5519 SendToServer_ContinuePlaying();
5522 /* restore deactivated drawing when quick-loading level tape recording */
5523 if (tape.playing && tape.deactivate_display)
5524 TapeDeactivateDisplayOn();
5531 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5533 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5534 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5537 if (dpo1->sort_priority != dpo2->sort_priority)
5538 compare_result = dpo1->sort_priority - dpo2->sort_priority;
5540 compare_result = dpo1->nr - dpo2->nr;
5542 return compare_result;
5545 void InitGraphicCompatibilityInfo_Doors()
5551 struct DoorInfo *door;
5555 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
5556 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
5558 { -1, -1, -1, NULL }
5560 struct Rect door_rect_list[] =
5562 { DX, DY, DXSIZE, DYSIZE },
5563 { VX, VY, VXSIZE, VYSIZE }
5567 for (i = 0; doors[i].door_token != -1; i++)
5569 int door_token = doors[i].door_token;
5570 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5571 int part_1 = doors[i].part_1;
5572 int part_8 = doors[i].part_8;
5573 int part_2 = part_1 + 1;
5574 int part_3 = part_1 + 2;
5575 struct DoorInfo *door = doors[i].door;
5576 struct Rect *door_rect = &door_rect_list[door_index];
5577 boolean door_gfx_redefined = FALSE;
5579 /* check if any door part graphic definitions have been redefined */
5581 for (j = 0; door_part_controls[j].door_token != -1; j++)
5583 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5584 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
5586 if (dpc->door_token == door_token && fi->redefined)
5587 door_gfx_redefined = TRUE;
5590 /* check for old-style door graphic/animation modifications */
5592 if (!door_gfx_redefined)
5594 if (door->anim_mode & ANIM_STATIC_PANEL)
5596 door->panel.step_xoffset = 0;
5597 door->panel.step_yoffset = 0;
5600 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
5602 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
5603 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
5604 int num_door_steps, num_panel_steps;
5606 /* remove door part graphics other than the two default wings */
5608 for (j = 0; door_part_controls[j].door_token != -1; j++)
5610 struct DoorPartControlInfo *dpc = &door_part_controls[j];
5611 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5613 if (dpc->graphic >= part_3 &&
5614 dpc->graphic <= part_8)
5618 /* set graphics and screen positions of the default wings */
5620 g_part_1->width = door_rect->width;
5621 g_part_1->height = door_rect->height;
5622 g_part_2->width = door_rect->width;
5623 g_part_2->height = door_rect->height;
5624 g_part_2->src_x = door_rect->width;
5625 g_part_2->src_y = g_part_1->src_y;
5627 door->part_2.x = door->part_1.x;
5628 door->part_2.y = door->part_1.y;
5630 if (door->width != -1)
5632 g_part_1->width = door->width;
5633 g_part_2->width = door->width;
5635 // special treatment for graphics and screen position of right wing
5636 g_part_2->src_x += door_rect->width - door->width;
5637 door->part_2.x += door_rect->width - door->width;
5640 if (door->height != -1)
5642 g_part_1->height = door->height;
5643 g_part_2->height = door->height;
5645 // special treatment for graphics and screen position of bottom wing
5646 g_part_2->src_y += door_rect->height - door->height;
5647 door->part_2.y += door_rect->height - door->height;
5650 /* set animation delays for the default wings and panels */
5652 door->part_1.step_delay = door->step_delay;
5653 door->part_2.step_delay = door->step_delay;
5654 door->panel.step_delay = door->step_delay;
5656 /* set animation draw order for the default wings */
5658 door->part_1.sort_priority = 2; /* draw left wing over ... */
5659 door->part_2.sort_priority = 1; /* ... right wing */
5661 /* set animation draw offset for the default wings */
5663 if (door->anim_mode & ANIM_HORIZONTAL)
5665 door->part_1.step_xoffset = door->step_offset;
5666 door->part_1.step_yoffset = 0;
5667 door->part_2.step_xoffset = door->step_offset * -1;
5668 door->part_2.step_yoffset = 0;
5670 num_door_steps = g_part_1->width / door->step_offset;
5672 else // ANIM_VERTICAL
5674 door->part_1.step_xoffset = 0;
5675 door->part_1.step_yoffset = door->step_offset;
5676 door->part_2.step_xoffset = 0;
5677 door->part_2.step_yoffset = door->step_offset * -1;
5679 num_door_steps = g_part_1->height / door->step_offset;
5682 /* set animation draw offset for the default panels */
5684 if (door->step_offset > 1)
5686 num_panel_steps = 2 * door_rect->height / door->step_offset;
5687 door->panel.start_step = num_panel_steps - num_door_steps;
5691 num_panel_steps = door_rect->height / door->step_offset;
5692 door->panel.start_step = num_panel_steps - num_door_steps / 2;
5693 door->panel.step_delay *= 2;
5704 for (i = 0; door_part_controls[i].door_token != -1; i++)
5706 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5707 struct DoorPartOrderInfo *dpo = &door_part_order[i];
5709 /* initialize "start_step_opening" and "start_step_closing", if needed */
5710 if (dpc->pos->start_step_opening == 0 &&
5711 dpc->pos->start_step_closing == 0)
5713 // dpc->pos->start_step_opening = dpc->pos->start_step;
5714 dpc->pos->start_step_closing = dpc->pos->start_step;
5717 /* fill structure for door part draw order (sorted below) */
5719 dpo->sort_priority = dpc->pos->sort_priority;
5722 struct DoorPartPosInfo *pos = dpc->pos;
5724 printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5725 pos->step_xoffset, pos->step_yoffset);
5729 /* sort door part controls according to sort_priority and graphic number */
5730 qsort(door_part_order, MAX_DOOR_PARTS,
5731 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5734 unsigned int OpenDoor(unsigned int door_state)
5736 if (door_state & DOOR_COPY_BACK)
5739 if (door_state & DOOR_OPEN_1)
5740 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5741 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5743 if (door_state & DOOR_OPEN_2)
5744 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5745 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5747 if (door_state & DOOR_OPEN_1)
5748 BlitBitmap(bitmap_db_door, bitmap_db_door,
5749 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5750 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5752 if (door_state & DOOR_OPEN_2)
5753 BlitBitmap(bitmap_db_door, bitmap_db_door,
5754 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5755 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5758 door_state &= ~DOOR_COPY_BACK;
5761 return MoveDoor(door_state);
5764 unsigned int CloseDoor(unsigned int door_state)
5766 unsigned int old_door_state = GetDoorState();
5768 if (!(door_state & DOOR_NO_COPY_BACK))
5771 if (old_door_state & DOOR_OPEN_1)
5772 BlitBitmap(backbuffer, bitmap_db_door_1,
5773 DX, DY, DXSIZE, DYSIZE, 0, 0);
5775 if (old_door_state & DOOR_OPEN_2)
5776 BlitBitmap(backbuffer, bitmap_db_door_2,
5777 VX, VY, VXSIZE, VYSIZE, 0, 0);
5779 if (old_door_state & DOOR_OPEN_1)
5780 BlitBitmap(backbuffer, bitmap_db_door,
5781 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5783 if (old_door_state & DOOR_OPEN_2)
5784 BlitBitmap(backbuffer, bitmap_db_door,
5785 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5788 door_state &= ~DOOR_NO_COPY_BACK;
5791 return MoveDoor(door_state);
5794 unsigned int GetDoorState()
5796 return MoveDoor(DOOR_GET_STATE);
5799 unsigned int SetDoorState(unsigned int door_state)
5801 return MoveDoor(door_state | DOOR_SET_STATE);
5806 // ========== TEST 1 ===========================================================
5808 int euclid(int a, int b)
5810 return (b ? euclid(b, a % b) : a);
5813 unsigned int MoveDoor(unsigned int door_state)
5816 struct XY panel_pos_list[] =
5818 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5819 { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5822 struct Rect door_rect_list[] =
5824 { DX, DY, DXSIZE, DYSIZE },
5825 { VX, VY, VXSIZE, VYSIZE }
5827 static int door1 = DOOR_OPEN_1;
5828 static int door2 = DOOR_CLOSE_2;
5829 unsigned int door_delay = 0;
5830 unsigned int door_delay_value;
5834 if (door_1.width < 0 || door_1.width > DXSIZE)
5835 door_1.width = DXSIZE;
5836 if (door_1.height < 0 || door_1.height > DYSIZE)
5837 door_1.height = DYSIZE;
5838 if (door_2.width < 0 || door_2.width > VXSIZE)
5839 door_2.width = VXSIZE;
5840 if (door_2.height < 0 || door_2.height > VYSIZE)
5841 door_2.height = VYSIZE;
5844 if (door_state == DOOR_GET_STATE)
5845 return (door1 | door2);
5847 if (door_state & DOOR_SET_STATE)
5849 if (door_state & DOOR_ACTION_1)
5850 door1 = door_state & DOOR_ACTION_1;
5851 if (door_state & DOOR_ACTION_2)
5852 door2 = door_state & DOOR_ACTION_2;
5854 return (door1 | door2);
5857 if (!(door_state & DOOR_FORCE_REDRAW))
5859 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5860 door_state &= ~DOOR_OPEN_1;
5861 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5862 door_state &= ~DOOR_CLOSE_1;
5863 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5864 door_state &= ~DOOR_OPEN_2;
5865 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5866 door_state &= ~DOOR_CLOSE_2;
5870 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5873 if (setup.quick_doors)
5875 stepsize = 20; /* must be chosen to always draw last frame */
5876 door_delay_value = 0;
5880 if (global.autoplay_leveldir)
5882 door_state |= DOOR_NO_DELAY;
5883 door_state &= ~DOOR_CLOSE_ALL;
5887 if (game_status == GAME_MODE_EDITOR)
5888 door_state |= DOOR_NO_DELAY;
5891 if (door_state & DOOR_ACTION)
5893 boolean door_panel_drawn[NUM_DOORS];
5894 boolean panel_has_doors[NUM_DOORS];
5895 boolean door_part_skip[MAX_DOOR_PARTS];
5896 boolean door_part_done[MAX_DOOR_PARTS];
5897 boolean door_part_done_all;
5898 int num_steps[MAX_DOOR_PARTS];
5899 int max_move_delay = 0; // delay for complete animations of all doors
5900 int max_step_delay = 0; // delay (ms) between two animation frames
5901 int num_move_steps = 0; // number of animation steps for all doors
5902 int current_move_delay = 0;
5905 for (i = 0; i < NUM_DOORS; i++)
5906 panel_has_doors[i] = FALSE;
5908 for (i = 0; i < MAX_DOOR_PARTS; i++)
5910 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5911 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5912 int door_token = dpc->door_token;
5914 door_part_done[i] = FALSE;
5915 door_part_skip[i] = (!(door_state & door_token) ||
5920 for (i = 0; i < MAX_DOOR_PARTS; i++)
5922 struct DoorPartControlInfo *dpc = &door_part_controls[i];
5923 struct DoorPartPosInfo *pos = dpc->pos;
5924 int start_step = pos->start_step;
5926 printf("::: ---> %d: start_step == %d [%d]\n",
5927 i, start_step, door_part_done[i]);
5931 for (i = 0; i < MAX_DOOR_PARTS; i++)
5933 int nr = door_part_order[i].nr;
5934 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5935 struct DoorPartPosInfo *pos = dpc->pos;
5936 struct GraphicInfo *g = &graphic_info[dpc->graphic];
5937 int door_token = dpc->door_token;
5938 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5939 boolean is_panel = DOOR_PART_IS_PANEL(nr);
5940 int step_xoffset = ABS(pos->step_xoffset);
5941 int step_yoffset = ABS(pos->step_yoffset);
5942 int step_delay = pos->step_delay;
5943 int current_door_state = door_state & door_token;
5944 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
5945 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5946 boolean part_opening = (is_panel ? door_closing : door_opening);
5947 int start_step = (part_opening ? pos->start_step_opening :
5948 pos->start_step_closing);
5949 float move_xsize = (step_xoffset ? g->width : 0);
5950 float move_ysize = (step_yoffset ? g->height : 0);
5951 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5952 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5953 int move_steps = (move_xsteps && move_ysteps ?
5954 MIN(move_xsteps, move_ysteps) :
5955 move_xsteps ? move_xsteps : move_ysteps) - start_step;
5956 int move_delay = move_steps * step_delay;
5958 if (door_part_skip[nr])
5962 panel_has_doors[door_index] = TRUE;
5964 max_move_delay = MAX(max_move_delay, move_delay);
5965 max_step_delay = (max_step_delay == 0 ? step_delay :
5966 euclid(max_step_delay, step_delay));
5967 num_steps[nr] = move_steps;
5971 printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
5972 i, move_delay, start_step, door_part_order[i].nr);
5974 if (DOOR_PART_IS_PANEL(i))
5975 printf("::: %d: move_delay == %d, start_step == %d\n",
5976 i, move_delay, start_step);
5981 num_move_steps = max_move_delay / max_step_delay;
5983 door_delay_value = max_step_delay;
5986 door_delay_value *= 10;
5990 printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
5993 for (k = 0; k < num_move_steps; k++)
5995 door_part_done_all = TRUE;
5997 for (i = 0; i < NUM_DOORS; i++)
5998 door_panel_drawn[i] = FALSE;
6000 for (i = 0; i < MAX_DOOR_PARTS; i++)
6002 int nr = door_part_order[i].nr;
6003 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
6004 struct DoorPartPosInfo *pos = dpc->pos;
6005 struct GraphicInfo *g = &graphic_info[dpc->graphic];
6006 int door_token = dpc->door_token;
6007 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
6008 boolean is_panel = DOOR_PART_IS_PANEL(nr);
6010 struct XY *panel_pos = &panel_pos_list[door_index];
6012 struct Rect *door_rect = &door_rect_list[door_index];
6013 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
6015 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
6016 int current_door_state = door_state & door_token;
6017 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
6018 boolean door_closing = !door_opening;
6019 boolean part_opening = (is_panel ? door_closing : door_opening);
6020 boolean part_closing = !part_opening;
6021 int start_step = (part_opening ? pos->start_step_opening :
6022 pos->start_step_closing);
6023 int step_delay = pos->step_delay;
6024 int step_factor = step_delay / max_step_delay;
6025 int k1 = (step_factor ? k / step_factor + 1 : k);
6026 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
6027 int kk = (k2 < 0 ? 0 : k2);
6028 int src_x, src_y, src_xx, src_yy;
6029 int dst_x, dst_y, dst_xx, dst_yy;
6033 if (k == 0 && is_panel && door_token == DOOR_2)
6034 printf("::: %d, %d\n", g->width, g->height);
6038 if (DOOR_PART_IS_PANEL(nr))
6040 int start_step = pos->start_step;
6042 k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
6043 kk = (k2 < 0 ? 0 : k2);
6049 if (nr != 16 && nr != 0)
6060 if (door_part_skip[nr])
6064 if (!(door_state & door_token))
6071 if (current_move_delay % step_delay)
6077 if (!door_panel_drawn[door_index])
6080 ClearRectangle(drawto, door_rect->x, door_rect->y,
6081 door_rect->width, door_rect->height);
6083 BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
6084 door_rect->width, door_rect->height,
6085 door_rect->x, door_rect->y);
6088 door_panel_drawn[door_index] = TRUE;
6091 // draw opening or closing door parts
6093 if (pos->step_xoffset < 0) // door part on right side
6096 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
6099 if (dst_xx + width > door_rect->width)
6100 width = door_rect->width - dst_xx;
6102 else // door part on left side
6105 dst_xx = pos->x - kk * pos->step_xoffset;
6109 src_xx = ABS(dst_xx);
6113 width = g->width - src_xx;
6115 // printf("::: k == %d [%d] \n", k, start_step);
6118 if (pos->step_yoffset < 0) // door part on bottom side
6121 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
6124 if (dst_yy + height > door_rect->height)
6125 height = door_rect->height - dst_yy;
6127 else // door part on top side
6130 dst_yy = pos->y - kk * pos->step_yoffset;
6134 src_yy = ABS(dst_yy);
6138 height = g->height - src_yy;
6147 src_x = panel_pos->x + src_xx;
6148 src_y = panel_pos->y + src_yy;
6153 src_x = g->src_x + src_xx;
6154 src_y = g->src_y + src_yy;
6157 dst_x = door_rect->x + dst_xx;
6158 dst_y = door_rect->y + dst_yy;
6161 if (DOOR_PART_IS_PANEL(nr))
6163 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6164 width, height, g->width, g->height, src_x, src_y);
6168 if (width >= 0 && width <= g->width &&
6169 height >= 0 && height <= g->height)
6171 if (is_panel || !pos->draw_masked)
6172 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
6175 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
6180 if (DOOR_PART_IS_PANEL(nr))
6182 bitmap = bitmap_db_door;
6183 src_x = panel_pos->x + src_xx;
6184 src_y = panel_pos->y + src_yy;
6186 printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6187 width, height, g->width, g->height, src_x, src_y);
6189 if (width >= 0 && width <= g->width &&
6190 height >= 0 && height <= g->height)
6191 BlitBitmap(bitmap, drawto, src_x, src_y,
6197 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
6200 if ((part_opening && (width < 0 || height < 0)) ||
6201 (part_closing && (width >= g->width && height >= g->height)))
6202 door_part_done[nr] = TRUE;
6204 if ((door_opening && (width < 0 || height < 0)) ||
6205 (door_closing && (width >= g->width && height >= g->height)))
6206 door_part_done[nr] = TRUE;
6210 // continue door part animations, but not panel after door has closed
6211 if (!door_part_done[nr] &&
6212 !(is_panel && door_closing && panel_has_doors[door_index]))
6213 door_part_done_all = FALSE;
6215 // continue door part animations, but not panel after door has closed
6216 if (!door_part_done[nr] && !(is_panel && door_closing))
6217 door_part_done_all = FALSE;
6221 if (!door_part_done[nr])
6222 printf("::: k == %d, nr == %d\n", k, nr);
6226 if (!(door_state & DOOR_NO_DELAY))
6230 if (game_status == GAME_MODE_MAIN)
6233 WaitUntilDelayReached(&door_delay, door_delay_value);
6235 current_move_delay += max_step_delay;
6239 door_part_done_all = TRUE;
6241 for (i = 0; i < MAX_DOOR_PARTS; i++)
6242 if (!door_part_done[i] &&
6243 !(DOOR_PART_IS_PANEL(i) && door_closing))
6244 door_part_done_all = FALSE;
6247 if (door_part_done_all)
6253 if (door_state & DOOR_ACTION_1)
6254 door1 = door_state & DOOR_ACTION_1;
6255 if (door_state & DOOR_ACTION_2)
6256 door2 = door_state & DOOR_ACTION_2;
6259 printf("::: DOORS DONE %08x\n", door_state);
6261 printf("::: GO!\n");
6264 return (door1 | door2);
6269 // ========== OLD ==============================================================
6271 unsigned int MoveDoor(unsigned int door_state)
6273 static int door1 = DOOR_OPEN_1;
6274 static int door2 = DOOR_CLOSE_2;
6275 unsigned int door_delay = 0;
6276 unsigned int door_delay_value;
6280 if (door_1.width < 0 || door_1.width > DXSIZE)
6281 door_1.width = DXSIZE;
6282 if (door_1.height < 0 || door_1.height > DYSIZE)
6283 door_1.height = DYSIZE;
6284 if (door_2.width < 0 || door_2.width > VXSIZE)
6285 door_2.width = VXSIZE;
6286 if (door_2.height < 0 || door_2.height > VYSIZE)
6287 door_2.height = VYSIZE;
6290 if (door_state == DOOR_GET_STATE)
6291 return (door1 | door2);
6293 if (door_state & DOOR_SET_STATE)
6295 if (door_state & DOOR_ACTION_1)
6296 door1 = door_state & DOOR_ACTION_1;
6297 if (door_state & DOOR_ACTION_2)
6298 door2 = door_state & DOOR_ACTION_2;
6300 return (door1 | door2);
6303 if (!(door_state & DOOR_FORCE_REDRAW))
6305 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
6306 door_state &= ~DOOR_OPEN_1;
6307 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
6308 door_state &= ~DOOR_CLOSE_1;
6309 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
6310 door_state &= ~DOOR_OPEN_2;
6311 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
6312 door_state &= ~DOOR_CLOSE_2;
6315 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
6318 // door_delay_value *= 4; // !!! TEST ONLY !!!
6320 if (setup.quick_doors)
6322 stepsize = 20; /* must be chosen to always draw last frame */
6323 door_delay_value = 0;
6326 if (global.autoplay_leveldir)
6328 door_state |= DOOR_NO_DELAY;
6329 door_state &= ~DOOR_CLOSE_ALL;
6333 if (game_status == GAME_MODE_EDITOR)
6334 door_state |= DOOR_NO_DELAY;
6337 if (door_state & DOOR_ACTION)
6340 struct GraphicInfo *g1_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6341 struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6342 struct GraphicInfo *g2_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6343 struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6344 int door_1_left_width = g1_left->width;
6345 int door_1_left_height = g1_left->height;
6346 int door_1_right_width = g1_right->width;
6347 int door_1_right_height = g1_right->height;
6348 int door_2_left_width = g2_left->width;
6349 int door_2_left_height = g2_left->height;
6350 int door_2_right_width = g2_right->width;
6351 int door_2_right_height = g2_right->height;
6352 int door_1_width = MAX(door_1_left_width, door_1_right_width);
6353 int door_1_height = MAX(door_1_left_height, door_1_right_height);
6354 int door_2_width = MAX(door_2_left_width, door_2_right_width);
6355 int door_2_height = MAX(door_2_left_height, door_2_right_height);
6357 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
6358 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
6359 boolean door_1_done = (!handle_door_1);
6360 boolean door_2_done = (!handle_door_2);
6361 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
6362 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
6365 int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
6366 int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
6368 int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6369 int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6372 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
6373 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
6375 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6376 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6377 // int door_size = (handle_door_1 ? door_size_1 : door_size_2);
6378 int door_size = (handle_door_2 ? door_size_2 : door_size_1);
6379 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
6380 int door_skip = max_door_size - door_size;
6381 int end = door_size;
6382 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
6385 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
6387 /* opening door sound has priority over simultaneously closing door */
6388 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
6389 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
6390 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
6391 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
6394 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
6398 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6399 GC gc = bitmap->stored_clip_gc;
6402 if (door_state & DOOR_ACTION_1 &&
6403 x * door_1.step_offset <= door_size_1)
6405 int a = MIN(x * door_1.step_offset, end);
6406 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6410 int i = p + door_skip;
6414 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_1_WING_LEFT];
6415 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6416 Bitmap *bm_left = g_left->bitmap;
6417 Bitmap *bm_right = g_right->bitmap;
6418 GC gc_left = bm_left->stored_clip_gc;
6419 GC gc_right = bm_right->stored_clip_gc;
6422 int classic_dxsize = 100;
6423 int classic_dysize = 280;
6424 boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6425 DYSIZE == classic_dysize);
6427 if (door_1.anim_mode & ANIM_STATIC_PANEL)
6429 BlitBitmap(bitmap_db_door, drawto,
6430 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6431 DXSIZE, DYSIZE, DX, DY);
6435 BlitBitmap(bitmap_db_door, drawto,
6436 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6437 DXSIZE, DYSIZE - p / 2, DX, DY);
6440 // printf("::: p == %d\n", p);
6441 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6445 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6448 int src1_x = g_right->src_x;
6449 int src1_y = g_right->src_y;
6450 int src2_x = g_left->src_x + g_left->width - i;
6451 int src2_y = g_left->src_y;
6452 int dst1_x = DX + DXSIZE - i;
6457 int height = DYSIZE;
6459 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6460 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6463 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6464 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6467 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6468 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6469 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6470 int dst2_x = DX, dst2_y = DY;
6471 int width = i, height = DYSIZE;
6473 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6474 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6477 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6478 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6482 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6485 int src1_x = g_right->src_x;
6486 int src1_y = g_right->src_y;
6487 int src2_x = g_left->src_x;
6488 int src2_y = g_left->src_y + g_left->height - i;
6490 int dst1_y = DY + DYSIZE - i;
6496 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6497 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6500 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6501 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6504 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6505 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6506 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
6507 int dst2_x = DX, dst2_y = DY;
6508 int width = DXSIZE, height = i;
6510 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6511 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6514 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6515 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6519 else if (classic_door_1_size && x <= DXSIZE) /* ANIM_DEFAULT */
6521 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6524 int src1_x = g_right->src_x;
6525 int src1_y = g_right->src_y;
6526 int src2_x = g_left->src_x + g_left->width - i;
6527 int src2_y = g_left->src_y;
6528 int dst1_x = DX + DXSIZE - i;
6533 int height1 = 63, height2 = DYSIZE / 2 - height1;
6534 int ypos1 = 0, ypos2 = height2;
6535 int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6537 SetClipOrigin(bm_right, gc_right,
6538 dst1_x - src1_x, dst1_y - src1_y + j);
6539 BlitBitmapMasked(bm_right, drawto,
6540 src1_x, src1_y + ypos1, width, height2,
6541 dst1_x, dst1_y + ypos1 + j);
6542 BlitBitmapMasked(bm_right, drawto,
6543 src1_x, src1_y + ypos3, width, height1,
6544 dst1_x, dst1_y + ypos3 + j);
6545 SetClipOrigin(bm_left, gc_left,
6546 dst2_x - src2_x, dst2_y - src2_y - j);
6547 BlitBitmapMasked(bm_left, drawto,
6548 src2_x, src2_y + ypos1 + j, width, height2 - j,
6549 dst2_x, dst2_y + ypos1);
6550 BlitBitmapMasked(bm_left, drawto,
6551 src2_x, src2_y + ypos3, width, height1,
6552 dst2_x, dst2_y + ypos3 - j);
6554 SetClipOrigin(bm_left, gc_left,
6555 dst2_x - src2_x, dst2_y - src2_y - j);
6556 BlitBitmapMasked(bm_left, drawto,
6557 src2_x, src2_y + ypos2, width, height1,
6558 dst2_x, dst2_y + ypos2 - j);
6559 BlitBitmapMasked(bm_left, drawto,
6560 src2_x, src2_y + ypos4, width, height2,
6561 dst2_x, dst2_y + ypos4 - j);
6562 SetClipOrigin(bm_right, gc_right,
6563 dst1_x - src1_x, dst1_y - src1_y + j);
6564 BlitBitmapMasked(bm_right, drawto,
6565 src1_x, src1_y + ypos2, width, height1,
6566 dst1_x, dst1_y + ypos2 + j);
6567 BlitBitmapMasked(bm_right, drawto,
6568 src1_x, src1_y + ypos4, width, height2 - j,
6569 dst1_x, dst1_y + ypos4 + j);
6572 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
6573 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
6574 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6575 int dst2_x = DX, dst2_y = DY;
6576 int width = i, height = DYSIZE;
6577 int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6579 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6580 BlitBitmapMasked(bitmap, drawto,
6581 src1_x, src1_y, width, ypos2,
6582 dst1_x, dst1_y + j);
6583 BlitBitmapMasked(bitmap, drawto,
6584 src1_x, src1_y + ypos3, width, ypos1,
6585 dst1_x, dst1_y + ypos3 + j);
6586 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6587 BlitBitmapMasked(bitmap, drawto,
6588 src2_x, src2_y + j, width, ypos2 - j,
6590 BlitBitmapMasked(bitmap, drawto,
6591 src2_x, src2_y + ypos3, width, ypos1,
6592 dst2_x, dst2_y + ypos3 - j);
6594 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6595 BlitBitmapMasked(bitmap, drawto,
6596 src2_x, src2_y + ypos2, width, ypos1,
6597 dst2_x, dst2_y + ypos2 - j);
6598 BlitBitmapMasked(bitmap, drawto,
6599 src2_x, src2_y + ypos4, width, ypos2,
6600 dst2_x, dst2_y + ypos4 - j);
6601 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6602 BlitBitmapMasked(bitmap, drawto,
6603 src1_x, src1_y + ypos2, width, ypos1,
6604 dst1_x, dst1_y + ypos2 + j);
6605 BlitBitmapMasked(bitmap, drawto,
6606 src1_x, src1_y + ypos4, width, ypos2 - j,
6607 dst1_x, dst1_y + ypos4 + j);
6610 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6611 BlitBitmapMasked(bitmap, drawto,
6612 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6613 DX + DXSIZE - i, DY + j);
6614 BlitBitmapMasked(bitmap, drawto,
6615 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6616 DX + DXSIZE - i, DY + 140 + j);
6617 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6618 DY - (DOOR_GFX_PAGEY1 + j));
6619 BlitBitmapMasked(bitmap, drawto,
6620 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6622 BlitBitmapMasked(bitmap, drawto,
6623 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6626 BlitBitmapMasked(bitmap, drawto,
6627 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6629 BlitBitmapMasked(bitmap, drawto,
6630 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6632 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6633 BlitBitmapMasked(bitmap, drawto,
6634 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6635 DX + DXSIZE - i, DY + 77 + j);
6636 BlitBitmapMasked(bitmap, drawto,
6637 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6638 DX + DXSIZE - i, DY + 203 + j);
6643 redraw_mask |= REDRAW_DOOR_1;
6644 door_1_done = (a == end);
6647 if (door_state & DOOR_ACTION_2 &&
6648 x * door_2.step_offset <= door_size_2)
6650 int a = MIN(x * door_2.step_offset, door_size);
6651 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6652 int i = p + door_skip;
6655 struct GraphicInfo *g_left = &graphic_info[IMG_DOOR_2_WING_LEFT];
6656 struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6657 Bitmap *bm_left = g_left->bitmap;
6658 Bitmap *bm_right = g_right->bitmap;
6659 GC gc_left = bm_left->stored_clip_gc;
6660 GC gc_right = bm_right->stored_clip_gc;
6663 int classic_vxsize = 100;
6664 int classic_vysize = 100;
6665 boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6666 VYSIZE == classic_vysize);
6668 if (door_2.anim_mode & ANIM_STATIC_PANEL)
6670 BlitBitmap(bitmap_db_door, drawto,
6671 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6672 VXSIZE, VYSIZE, VX, VY);
6674 else if (x <= VYSIZE)
6676 BlitBitmap(bitmap_db_door, drawto,
6677 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6678 VXSIZE, VYSIZE - p / 2, VX, VY);
6680 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6683 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6686 int src1_x = g_right->src_x;
6687 int src1_y = g_right->src_y;
6688 int src2_x = g_left->src_x + g_left->width - i;
6689 int src2_y = g_left->src_y;
6690 int dst1_x = VX + VXSIZE - i;
6695 int height = VYSIZE;
6697 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6698 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6701 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6702 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6705 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6706 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6707 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6708 int dst2_x = VX, dst2_y = VY;
6709 int width = i, height = VYSIZE;
6711 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6712 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6715 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6716 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6720 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6723 int src1_x = g_right->src_x;
6724 int src1_y = g_right->src_y;
6725 int src2_x = g_left->src_x;
6726 int src2_y = g_left->src_y + g_left->height - i;
6728 int dst1_y = VY + VYSIZE - i;
6734 SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6735 BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6738 SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6739 BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6742 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6743 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6744 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
6745 int dst2_x = VX, dst2_y = VY;
6746 int width = VXSIZE, height = i;
6748 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6749 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6752 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6753 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6757 else if (classic_door_2_size && x <= VXSIZE) /* ANIM_DEFAULT */
6759 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6762 int src1_x = g_right->src_x;
6763 int src1_y = g_right->src_y;
6764 int src2_x = g_left->src_x + g_left->width - i;
6765 int src2_y = g_left->src_y;
6766 int dst1_x = VX + VXSIZE - i;
6771 int height = VYSIZE / 2;
6772 int ypos1 = 0, ypos2 = VYSIZE / 2;
6774 SetClipOrigin(bm_right, gc_right,
6775 dst1_x - src1_x, dst1_y - src1_y + j);
6776 BlitBitmapMasked(bm_right, drawto,
6777 src1_x, src1_y + ypos1, width, height,
6778 dst1_x, dst1_y + ypos1 + j);
6779 SetClipOrigin(bm_left, gc_left,
6780 dst2_x - src2_x, dst2_y - src2_y - j);
6781 BlitBitmapMasked(bm_left, drawto,
6782 src2_x, src2_y + ypos1 + j, width, height - j,
6783 dst2_x, dst2_y + ypos1);
6785 SetClipOrigin(bm_left, gc_left,
6786 dst2_x - src2_x, dst2_y - src2_y - j);
6787 BlitBitmapMasked(bm_left, drawto,
6788 src2_x, src2_y + ypos2, width, height,
6789 dst2_x, dst2_y + ypos2 - j);
6790 SetClipOrigin(bm_right, gc_right,
6791 dst1_x - src1_x, dst1_y - src1_y + j);
6792 BlitBitmapMasked(bm_right, drawto,
6793 src1_x, src1_y + ypos2, width, height - j,
6794 dst1_x, dst1_y + ypos2 + j);
6796 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
6797 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
6798 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6799 int dst2_x = VX, dst2_y = VY;
6800 int width = i, height = VYSIZE;
6801 int ypos = VYSIZE / 2;
6803 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6804 BlitBitmapMasked(bitmap, drawto,
6805 src1_x, src1_y, width, ypos,
6806 dst1_x, dst1_y + j);
6807 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6808 BlitBitmapMasked(bitmap, drawto,
6809 src2_x, src2_y + j, width, ypos - j,
6812 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6813 BlitBitmapMasked(bitmap, drawto,
6814 src2_x, src2_y + ypos, width, ypos,
6815 dst2_x, dst2_y + ypos - j);
6816 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6817 BlitBitmapMasked(bitmap, drawto,
6818 src1_x, src1_y + ypos, width, ypos - j,
6819 dst1_x, dst1_y + ypos + j);
6822 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6823 BlitBitmapMasked(bitmap, drawto,
6824 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6825 VX + VXSIZE - i, VY + j);
6826 SetClipOrigin(bitmap, gc,
6827 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6828 BlitBitmapMasked(bitmap, drawto,
6829 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6832 BlitBitmapMasked(bitmap, drawto,
6833 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6834 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6835 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6836 BlitBitmapMasked(bitmap, drawto,
6837 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6839 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6844 redraw_mask |= REDRAW_DOOR_2;
6845 door_2_done = (a == VXSIZE);
6848 if (!(door_state & DOOR_NO_DELAY))
6852 if (game_status == GAME_MODE_MAIN)
6855 WaitUntilDelayReached(&door_delay, door_delay_value);
6860 if (door_state & DOOR_ACTION_1)
6861 door1 = door_state & DOOR_ACTION_1;
6862 if (door_state & DOOR_ACTION_2)
6863 door2 = door_state & DOOR_ACTION_2;
6865 return (door1 | door2);
6870 void DrawSpecialEditorDoor()
6873 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6874 int top_border_width = gfx1->width;
6875 int top_border_height = gfx1->height;
6876 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6877 int ex = EX - outer_border;
6878 int ey = EY - outer_border;
6879 int vy = VY - outer_border;
6880 int exsize = EXSIZE + 2 * outer_border;
6882 CloseDoor(DOOR_CLOSE_2);
6884 /* draw bigger level editor toolbox window */
6885 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6886 top_border_width, top_border_height, ex, ey - top_border_height);
6887 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6888 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6890 /* draw bigger level editor toolbox window */
6891 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6892 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6894 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6895 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6899 redraw_mask |= REDRAW_ALL;
6902 void UndrawSpecialEditorDoor()
6905 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6906 int top_border_width = gfx1->width;
6907 int top_border_height = gfx1->height;
6908 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6909 int ex = EX - outer_border;
6910 int ey = EY - outer_border;
6911 int ey_top = ey - top_border_height;
6912 int exsize = EXSIZE + 2 * outer_border;
6913 int eysize = EYSIZE + 2 * outer_border;
6915 /* draw normal tape recorder window */
6916 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6918 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6919 ex, ey_top, top_border_width, top_border_height,
6921 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6922 ex, ey, exsize, eysize, ex, ey);
6926 // if screen background is set to "[NONE]", clear editor toolbox window
6927 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6928 ClearRectangle(drawto, ex, ey, exsize, eysize);
6931 /* draw normal tape recorder window */
6932 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6933 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6937 redraw_mask |= REDRAW_ALL;
6941 /* ---------- new tool button stuff ---------------------------------------- */
6948 struct TextPosInfo *pos;
6951 } toolbutton_info[NUM_TOOL_BUTTONS] =
6954 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
6955 TOOL_CTRL_ID_YES, "yes"
6958 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
6959 TOOL_CTRL_ID_NO, "no"
6962 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
6963 TOOL_CTRL_ID_CONFIRM, "confirm"
6966 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
6967 TOOL_CTRL_ID_PLAYER_1, "player 1"
6970 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
6971 TOOL_CTRL_ID_PLAYER_2, "player 2"
6974 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
6975 TOOL_CTRL_ID_PLAYER_3, "player 3"
6978 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
6979 TOOL_CTRL_ID_PLAYER_4, "player 4"
6983 void CreateToolButtons()
6987 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6989 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6990 struct TextPosInfo *pos = toolbutton_info[i].pos;
6991 struct GadgetInfo *gi;
6992 Bitmap *deco_bitmap = None;
6993 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6994 unsigned int event_mask = GD_EVENT_RELEASED;
6997 int gd_x = gfx->src_x;
6998 int gd_y = gfx->src_y;
6999 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
7000 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
7003 if (global.use_envelope_request)
7004 setRequestPosition(&dx, &dy, TRUE);
7006 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7008 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7010 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
7011 pos->size, &deco_bitmap, &deco_x, &deco_y);
7012 deco_xpos = (gfx->width - pos->size) / 2;
7013 deco_ypos = (gfx->height - pos->size) / 2;
7016 gi = CreateGadget(GDI_CUSTOM_ID, id,
7017 GDI_INFO_TEXT, toolbutton_info[i].infotext,
7018 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
7019 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
7020 GDI_WIDTH, gfx->width,
7021 GDI_HEIGHT, gfx->height,
7022 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7023 GDI_STATE, GD_BUTTON_UNPRESSED,
7024 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
7025 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
7026 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7027 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7028 GDI_DECORATION_SIZE, pos->size, pos->size,
7029 GDI_DECORATION_SHIFTING, 1, 1,
7030 GDI_DIRECT_DRAW, FALSE,
7031 GDI_EVENT_MASK, event_mask,
7032 GDI_CALLBACK_ACTION, HandleToolButtons,
7036 Error(ERR_EXIT, "cannot create gadget");
7038 tool_gadget[id] = gi;
7044 /* graphic position values for tool buttons */
7045 #define TOOL_BUTTON_YES_XPOS 2
7046 #define TOOL_BUTTON_YES_YPOS 250
7047 #define TOOL_BUTTON_YES_GFX_YPOS 0
7048 #define TOOL_BUTTON_YES_XSIZE 46
7049 #define TOOL_BUTTON_YES_YSIZE 28
7050 #define TOOL_BUTTON_NO_XPOS 52
7051 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
7052 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
7053 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
7054 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
7055 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
7056 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
7057 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
7058 #define TOOL_BUTTON_CONFIRM_XSIZE 96
7059 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
7060 #define TOOL_BUTTON_PLAYER_XSIZE 30
7061 #define TOOL_BUTTON_PLAYER_YSIZE 30
7062 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
7063 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
7064 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
7065 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
7066 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7067 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7068 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7069 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7070 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7071 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7072 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
7073 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7074 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7075 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7076 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7077 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7078 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7079 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7080 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
7081 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7090 } toolbutton_info[NUM_TOOL_BUTTONS] =
7093 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
7094 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
7095 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
7100 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
7101 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
7102 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
7107 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
7108 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
7109 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
7110 TOOL_CTRL_ID_CONFIRM,
7114 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7115 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
7116 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7117 TOOL_CTRL_ID_PLAYER_1,
7121 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7122 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
7123 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7124 TOOL_CTRL_ID_PLAYER_2,
7128 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7129 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
7130 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7131 TOOL_CTRL_ID_PLAYER_3,
7135 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7136 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
7137 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
7138 TOOL_CTRL_ID_PLAYER_4,
7143 void CreateToolButtons()
7147 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7149 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
7150 Bitmap *deco_bitmap = None;
7151 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7152 struct GadgetInfo *gi;
7153 unsigned int event_mask;
7154 int gd_xoffset, gd_yoffset;
7155 int gd_x1, gd_x2, gd_y;
7158 event_mask = GD_EVENT_RELEASED;
7160 gd_xoffset = toolbutton_info[i].xpos;
7161 gd_yoffset = toolbutton_info[i].ypos;
7162 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
7163 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
7164 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
7166 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7168 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7170 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
7171 &deco_bitmap, &deco_x, &deco_y);
7172 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
7173 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
7176 gi = CreateGadget(GDI_CUSTOM_ID, id,
7177 GDI_INFO_TEXT, toolbutton_info[i].infotext,
7178 GDI_X, DX + GDI_ACTIVE_POS(toolbutton_info[i].x),
7179 GDI_Y, DY + GDI_ACTIVE_POS(toolbutton_info[i].y),
7180 GDI_WIDTH, toolbutton_info[i].width,
7181 GDI_HEIGHT, toolbutton_info[i].height,
7182 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7183 GDI_STATE, GD_BUTTON_UNPRESSED,
7184 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
7185 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
7186 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7187 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7188 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
7189 GDI_DECORATION_SHIFTING, 1, 1,
7190 GDI_DIRECT_DRAW, FALSE,
7191 GDI_EVENT_MASK, event_mask,
7192 GDI_CALLBACK_ACTION, HandleToolButtons,
7196 Error(ERR_EXIT, "cannot create gadget");
7198 tool_gadget[id] = gi;
7204 void FreeToolButtons()
7208 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7209 FreeGadget(tool_gadget[i]);
7212 static void UnmapToolButtons()
7216 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7217 UnmapGadget(tool_gadget[i]);
7220 static void HandleToolButtons(struct GadgetInfo *gi)
7222 request_gadget_id = gi->custom_id;
7225 static struct Mapping_EM_to_RND_object
7228 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
7229 boolean is_backside; /* backside of moving element */
7235 em_object_mapping_list[] =
7238 Xblank, TRUE, FALSE,
7242 Yacid_splash_eB, FALSE, FALSE,
7243 EL_ACID_SPLASH_RIGHT, -1, -1
7246 Yacid_splash_wB, FALSE, FALSE,
7247 EL_ACID_SPLASH_LEFT, -1, -1
7250 #ifdef EM_ENGINE_BAD_ROLL
7252 Xstone_force_e, FALSE, FALSE,
7253 EL_ROCK, -1, MV_BIT_RIGHT
7256 Xstone_force_w, FALSE, FALSE,
7257 EL_ROCK, -1, MV_BIT_LEFT
7260 Xnut_force_e, FALSE, FALSE,
7261 EL_NUT, -1, MV_BIT_RIGHT
7264 Xnut_force_w, FALSE, FALSE,
7265 EL_NUT, -1, MV_BIT_LEFT
7268 Xspring_force_e, FALSE, FALSE,
7269 EL_SPRING, -1, MV_BIT_RIGHT
7272 Xspring_force_w, FALSE, FALSE,
7273 EL_SPRING, -1, MV_BIT_LEFT
7276 Xemerald_force_e, FALSE, FALSE,
7277 EL_EMERALD, -1, MV_BIT_RIGHT
7280 Xemerald_force_w, FALSE, FALSE,
7281 EL_EMERALD, -1, MV_BIT_LEFT
7284 Xdiamond_force_e, FALSE, FALSE,
7285 EL_DIAMOND, -1, MV_BIT_RIGHT
7288 Xdiamond_force_w, FALSE, FALSE,
7289 EL_DIAMOND, -1, MV_BIT_LEFT
7292 Xbomb_force_e, FALSE, FALSE,
7293 EL_BOMB, -1, MV_BIT_RIGHT
7296 Xbomb_force_w, FALSE, FALSE,
7297 EL_BOMB, -1, MV_BIT_LEFT
7299 #endif /* EM_ENGINE_BAD_ROLL */
7302 Xstone, TRUE, FALSE,
7306 Xstone_pause, FALSE, FALSE,
7310 Xstone_fall, FALSE, FALSE,
7314 Ystone_s, FALSE, FALSE,
7315 EL_ROCK, ACTION_FALLING, -1
7318 Ystone_sB, FALSE, TRUE,
7319 EL_ROCK, ACTION_FALLING, -1
7322 Ystone_e, FALSE, FALSE,
7323 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7326 Ystone_eB, FALSE, TRUE,
7327 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
7330 Ystone_w, FALSE, FALSE,
7331 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7334 Ystone_wB, FALSE, TRUE,
7335 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
7342 Xnut_pause, FALSE, FALSE,
7346 Xnut_fall, FALSE, FALSE,
7350 Ynut_s, FALSE, FALSE,
7351 EL_NUT, ACTION_FALLING, -1
7354 Ynut_sB, FALSE, TRUE,
7355 EL_NUT, ACTION_FALLING, -1
7358 Ynut_e, FALSE, FALSE,
7359 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7362 Ynut_eB, FALSE, TRUE,
7363 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
7366 Ynut_w, FALSE, FALSE,
7367 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7370 Ynut_wB, FALSE, TRUE,
7371 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
7374 Xbug_n, TRUE, FALSE,
7378 Xbug_e, TRUE, FALSE,
7379 EL_BUG_RIGHT, -1, -1
7382 Xbug_s, TRUE, FALSE,
7386 Xbug_w, TRUE, FALSE,
7390 Xbug_gon, FALSE, FALSE,
7394 Xbug_goe, FALSE, FALSE,
7395 EL_BUG_RIGHT, -1, -1
7398 Xbug_gos, FALSE, FALSE,
7402 Xbug_gow, FALSE, FALSE,
7406 Ybug_n, FALSE, FALSE,
7407 EL_BUG, ACTION_MOVING, MV_BIT_UP
7410 Ybug_nB, FALSE, TRUE,
7411 EL_BUG, ACTION_MOVING, MV_BIT_UP
7414 Ybug_e, FALSE, FALSE,
7415 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7418 Ybug_eB, FALSE, TRUE,
7419 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
7422 Ybug_s, FALSE, FALSE,
7423 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7426 Ybug_sB, FALSE, TRUE,
7427 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
7430 Ybug_w, FALSE, FALSE,
7431 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7434 Ybug_wB, FALSE, TRUE,
7435 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
7438 Ybug_w_n, FALSE, FALSE,
7439 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7442 Ybug_n_e, FALSE, FALSE,
7443 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7446 Ybug_e_s, FALSE, FALSE,
7447 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7450 Ybug_s_w, FALSE, FALSE,
7451 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7454 Ybug_e_n, FALSE, FALSE,
7455 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7458 Ybug_s_e, FALSE, FALSE,
7459 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7462 Ybug_w_s, FALSE, FALSE,
7463 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7466 Ybug_n_w, FALSE, FALSE,
7467 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7470 Ybug_stone, FALSE, FALSE,
7471 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
7474 Ybug_spring, FALSE, FALSE,
7475 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
7478 Xtank_n, TRUE, FALSE,
7479 EL_SPACESHIP_UP, -1, -1
7482 Xtank_e, TRUE, FALSE,
7483 EL_SPACESHIP_RIGHT, -1, -1
7486 Xtank_s, TRUE, FALSE,
7487 EL_SPACESHIP_DOWN, -1, -1
7490 Xtank_w, TRUE, FALSE,
7491 EL_SPACESHIP_LEFT, -1, -1
7494 Xtank_gon, FALSE, FALSE,
7495 EL_SPACESHIP_UP, -1, -1
7498 Xtank_goe, FALSE, FALSE,
7499 EL_SPACESHIP_RIGHT, -1, -1
7502 Xtank_gos, FALSE, FALSE,
7503 EL_SPACESHIP_DOWN, -1, -1
7506 Xtank_gow, FALSE, FALSE,
7507 EL_SPACESHIP_LEFT, -1, -1
7510 Ytank_n, FALSE, FALSE,
7511 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7514 Ytank_nB, FALSE, TRUE,
7515 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
7518 Ytank_e, FALSE, FALSE,
7519 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7522 Ytank_eB, FALSE, TRUE,
7523 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
7526 Ytank_s, FALSE, FALSE,
7527 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7530 Ytank_sB, FALSE, TRUE,
7531 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
7534 Ytank_w, FALSE, FALSE,
7535 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7538 Ytank_wB, FALSE, TRUE,
7539 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
7542 Ytank_w_n, FALSE, FALSE,
7543 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7546 Ytank_n_e, FALSE, FALSE,
7547 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7550 Ytank_e_s, FALSE, FALSE,
7551 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7554 Ytank_s_w, FALSE, FALSE,
7555 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7558 Ytank_e_n, FALSE, FALSE,
7559 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7562 Ytank_s_e, FALSE, FALSE,
7563 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7566 Ytank_w_s, FALSE, FALSE,
7567 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7570 Ytank_n_w, FALSE, FALSE,
7571 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7574 Ytank_stone, FALSE, FALSE,
7575 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
7578 Ytank_spring, FALSE, FALSE,
7579 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
7582 Xandroid, TRUE, FALSE,
7583 EL_EMC_ANDROID, ACTION_ACTIVE, -1
7586 Xandroid_1_n, FALSE, FALSE,
7587 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7590 Xandroid_2_n, FALSE, FALSE,
7591 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
7594 Xandroid_1_e, FALSE, FALSE,
7595 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7598 Xandroid_2_e, FALSE, FALSE,
7599 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
7602 Xandroid_1_w, FALSE, FALSE,
7603 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7606 Xandroid_2_w, FALSE, FALSE,
7607 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
7610 Xandroid_1_s, FALSE, FALSE,
7611 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7614 Xandroid_2_s, FALSE, FALSE,
7615 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
7618 Yandroid_n, FALSE, FALSE,
7619 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7622 Yandroid_nB, FALSE, TRUE,
7623 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
7626 Yandroid_ne, FALSE, FALSE,
7627 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
7630 Yandroid_neB, FALSE, TRUE,
7631 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
7634 Yandroid_e, FALSE, FALSE,
7635 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7638 Yandroid_eB, FALSE, TRUE,
7639 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
7642 Yandroid_se, FALSE, FALSE,
7643 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
7646 Yandroid_seB, FALSE, TRUE,
7647 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7650 Yandroid_s, FALSE, FALSE,
7651 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7654 Yandroid_sB, FALSE, TRUE,
7655 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
7658 Yandroid_sw, FALSE, FALSE,
7659 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
7662 Yandroid_swB, FALSE, TRUE,
7663 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
7666 Yandroid_w, FALSE, FALSE,
7667 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7670 Yandroid_wB, FALSE, TRUE,
7671 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
7674 Yandroid_nw, FALSE, FALSE,
7675 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
7678 Yandroid_nwB, FALSE, TRUE,
7679 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
7682 Xspring, TRUE, FALSE,
7686 Xspring_pause, FALSE, FALSE,
7690 Xspring_e, FALSE, FALSE,
7694 Xspring_w, FALSE, FALSE,
7698 Xspring_fall, FALSE, FALSE,
7702 Yspring_s, FALSE, FALSE,
7703 EL_SPRING, ACTION_FALLING, -1
7706 Yspring_sB, FALSE, TRUE,
7707 EL_SPRING, ACTION_FALLING, -1
7710 Yspring_e, FALSE, FALSE,
7711 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7714 Yspring_eB, FALSE, TRUE,
7715 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
7718 Yspring_w, FALSE, FALSE,
7719 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7722 Yspring_wB, FALSE, TRUE,
7723 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
7726 Yspring_kill_e, FALSE, FALSE,
7727 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7730 Yspring_kill_eB, FALSE, TRUE,
7731 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
7734 Yspring_kill_w, FALSE, FALSE,
7735 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7738 Yspring_kill_wB, FALSE, TRUE,
7739 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
7742 Xeater_n, TRUE, FALSE,
7743 EL_YAMYAM_UP, -1, -1
7746 Xeater_e, TRUE, FALSE,
7747 EL_YAMYAM_RIGHT, -1, -1
7750 Xeater_w, TRUE, FALSE,
7751 EL_YAMYAM_LEFT, -1, -1
7754 Xeater_s, TRUE, FALSE,
7755 EL_YAMYAM_DOWN, -1, -1
7758 Yeater_n, FALSE, FALSE,
7759 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7762 Yeater_nB, FALSE, TRUE,
7763 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
7766 Yeater_e, FALSE, FALSE,
7767 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7770 Yeater_eB, FALSE, TRUE,
7771 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
7774 Yeater_s, FALSE, FALSE,
7775 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7778 Yeater_sB, FALSE, TRUE,
7779 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
7782 Yeater_w, FALSE, FALSE,
7783 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7786 Yeater_wB, FALSE, TRUE,
7787 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
7790 Yeater_stone, FALSE, FALSE,
7791 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
7794 Yeater_spring, FALSE, FALSE,
7795 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
7798 Xalien, TRUE, FALSE,
7802 Xalien_pause, FALSE, FALSE,
7806 Yalien_n, FALSE, FALSE,
7807 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7810 Yalien_nB, FALSE, TRUE,
7811 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
7814 Yalien_e, FALSE, FALSE,
7815 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7818 Yalien_eB, FALSE, TRUE,
7819 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
7822 Yalien_s, FALSE, FALSE,
7823 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7826 Yalien_sB, FALSE, TRUE,
7827 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
7830 Yalien_w, FALSE, FALSE,
7831 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7834 Yalien_wB, FALSE, TRUE,
7835 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
7838 Yalien_stone, FALSE, FALSE,
7839 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
7842 Yalien_spring, FALSE, FALSE,
7843 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
7846 Xemerald, TRUE, FALSE,
7850 Xemerald_pause, FALSE, FALSE,
7854 Xemerald_fall, FALSE, FALSE,
7858 Xemerald_shine, FALSE, FALSE,
7859 EL_EMERALD, ACTION_TWINKLING, -1
7862 Yemerald_s, FALSE, FALSE,
7863 EL_EMERALD, ACTION_FALLING, -1
7866 Yemerald_sB, FALSE, TRUE,
7867 EL_EMERALD, ACTION_FALLING, -1
7870 Yemerald_e, FALSE, FALSE,
7871 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7874 Yemerald_eB, FALSE, TRUE,
7875 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
7878 Yemerald_w, FALSE, FALSE,
7879 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7882 Yemerald_wB, FALSE, TRUE,
7883 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
7886 Yemerald_eat, FALSE, FALSE,
7887 EL_EMERALD, ACTION_COLLECTING, -1
7890 Yemerald_stone, FALSE, FALSE,
7891 EL_NUT, ACTION_BREAKING, -1
7894 Xdiamond, TRUE, FALSE,
7898 Xdiamond_pause, FALSE, FALSE,
7902 Xdiamond_fall, FALSE, FALSE,
7906 Xdiamond_shine, FALSE, FALSE,
7907 EL_DIAMOND, ACTION_TWINKLING, -1
7910 Ydiamond_s, FALSE, FALSE,
7911 EL_DIAMOND, ACTION_FALLING, -1
7914 Ydiamond_sB, FALSE, TRUE,
7915 EL_DIAMOND, ACTION_FALLING, -1
7918 Ydiamond_e, FALSE, FALSE,
7919 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7922 Ydiamond_eB, FALSE, TRUE,
7923 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
7926 Ydiamond_w, FALSE, FALSE,
7927 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7930 Ydiamond_wB, FALSE, TRUE,
7931 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
7934 Ydiamond_eat, FALSE, FALSE,
7935 EL_DIAMOND, ACTION_COLLECTING, -1
7938 Ydiamond_stone, FALSE, FALSE,
7939 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
7942 Xdrip_fall, TRUE, FALSE,
7943 EL_AMOEBA_DROP, -1, -1
7946 Xdrip_stretch, FALSE, FALSE,
7947 EL_AMOEBA_DROP, ACTION_FALLING, -1
7950 Xdrip_stretchB, FALSE, TRUE,
7951 EL_AMOEBA_DROP, ACTION_FALLING, -1
7954 Xdrip_eat, FALSE, FALSE,
7955 EL_AMOEBA_DROP, ACTION_GROWING, -1
7958 Ydrip_s1, FALSE, FALSE,
7959 EL_AMOEBA_DROP, ACTION_FALLING, -1
7962 Ydrip_s1B, FALSE, TRUE,
7963 EL_AMOEBA_DROP, ACTION_FALLING, -1
7966 Ydrip_s2, FALSE, FALSE,
7967 EL_AMOEBA_DROP, ACTION_FALLING, -1
7970 Ydrip_s2B, FALSE, TRUE,
7971 EL_AMOEBA_DROP, ACTION_FALLING, -1
7978 Xbomb_pause, FALSE, FALSE,
7982 Xbomb_fall, FALSE, FALSE,
7986 Ybomb_s, FALSE, FALSE,
7987 EL_BOMB, ACTION_FALLING, -1
7990 Ybomb_sB, FALSE, TRUE,
7991 EL_BOMB, ACTION_FALLING, -1
7994 Ybomb_e, FALSE, FALSE,
7995 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
7998 Ybomb_eB, FALSE, TRUE,
7999 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
8002 Ybomb_w, FALSE, FALSE,
8003 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
8006 Ybomb_wB, FALSE, TRUE,
8007 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
8010 Ybomb_eat, FALSE, FALSE,
8011 EL_BOMB, ACTION_ACTIVATING, -1
8014 Xballoon, TRUE, FALSE,
8018 Yballoon_n, FALSE, FALSE,
8019 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
8022 Yballoon_nB, FALSE, TRUE,
8023 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
8026 Yballoon_e, FALSE, FALSE,
8027 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8030 Yballoon_eB, FALSE, TRUE,
8031 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
8034 Yballoon_s, FALSE, FALSE,
8035 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8038 Yballoon_sB, FALSE, TRUE,
8039 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
8042 Yballoon_w, FALSE, FALSE,
8043 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8046 Yballoon_wB, FALSE, TRUE,
8047 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
8050 Xgrass, TRUE, FALSE,
8051 EL_EMC_GRASS, -1, -1
8054 Ygrass_nB, FALSE, FALSE,
8055 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
8058 Ygrass_eB, FALSE, FALSE,
8059 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
8062 Ygrass_sB, FALSE, FALSE,
8063 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
8066 Ygrass_wB, FALSE, FALSE,
8067 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
8074 Ydirt_nB, FALSE, FALSE,
8075 EL_SAND, ACTION_DIGGING, MV_BIT_UP
8078 Ydirt_eB, FALSE, FALSE,
8079 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
8082 Ydirt_sB, FALSE, FALSE,
8083 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
8086 Ydirt_wB, FALSE, FALSE,
8087 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
8090 Xacid_ne, TRUE, FALSE,
8091 EL_ACID_POOL_TOPRIGHT, -1, -1
8094 Xacid_se, TRUE, FALSE,
8095 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
8098 Xacid_s, TRUE, FALSE,
8099 EL_ACID_POOL_BOTTOM, -1, -1
8102 Xacid_sw, TRUE, FALSE,
8103 EL_ACID_POOL_BOTTOMLEFT, -1, -1
8106 Xacid_nw, TRUE, FALSE,
8107 EL_ACID_POOL_TOPLEFT, -1, -1
8110 Xacid_1, TRUE, FALSE,
8114 Xacid_2, FALSE, FALSE,
8118 Xacid_3, FALSE, FALSE,
8122 Xacid_4, FALSE, FALSE,
8126 Xacid_5, FALSE, FALSE,
8130 Xacid_6, FALSE, FALSE,
8134 Xacid_7, FALSE, FALSE,
8138 Xacid_8, FALSE, FALSE,
8142 Xball_1, TRUE, FALSE,
8143 EL_EMC_MAGIC_BALL, -1, -1
8146 Xball_1B, FALSE, FALSE,
8147 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8150 Xball_2, FALSE, FALSE,
8151 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8154 Xball_2B, FALSE, FALSE,
8155 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
8158 Yball_eat, FALSE, FALSE,
8159 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
8162 Ykey_1_eat, FALSE, FALSE,
8163 EL_EM_KEY_1, ACTION_COLLECTING, -1
8166 Ykey_2_eat, FALSE, FALSE,
8167 EL_EM_KEY_2, ACTION_COLLECTING, -1
8170 Ykey_3_eat, FALSE, FALSE,
8171 EL_EM_KEY_3, ACTION_COLLECTING, -1
8174 Ykey_4_eat, FALSE, FALSE,
8175 EL_EM_KEY_4, ACTION_COLLECTING, -1
8178 Ykey_5_eat, FALSE, FALSE,
8179 EL_EMC_KEY_5, ACTION_COLLECTING, -1
8182 Ykey_6_eat, FALSE, FALSE,
8183 EL_EMC_KEY_6, ACTION_COLLECTING, -1
8186 Ykey_7_eat, FALSE, FALSE,
8187 EL_EMC_KEY_7, ACTION_COLLECTING, -1
8190 Ykey_8_eat, FALSE, FALSE,
8191 EL_EMC_KEY_8, ACTION_COLLECTING, -1
8194 Ylenses_eat, FALSE, FALSE,
8195 EL_EMC_LENSES, ACTION_COLLECTING, -1
8198 Ymagnify_eat, FALSE, FALSE,
8199 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
8202 Ygrass_eat, FALSE, FALSE,
8203 EL_EMC_GRASS, ACTION_SNAPPING, -1
8206 Ydirt_eat, FALSE, FALSE,
8207 EL_SAND, ACTION_SNAPPING, -1
8210 Xgrow_ns, TRUE, FALSE,
8211 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
8214 Ygrow_ns_eat, FALSE, FALSE,
8215 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
8218 Xgrow_ew, TRUE, FALSE,
8219 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
8222 Ygrow_ew_eat, FALSE, FALSE,
8223 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
8226 Xwonderwall, TRUE, FALSE,
8227 EL_MAGIC_WALL, -1, -1
8230 XwonderwallB, FALSE, FALSE,
8231 EL_MAGIC_WALL, ACTION_ACTIVE, -1
8234 Xamoeba_1, TRUE, FALSE,
8235 EL_AMOEBA_DRY, ACTION_OTHER, -1
8238 Xamoeba_2, FALSE, FALSE,
8239 EL_AMOEBA_DRY, ACTION_OTHER, -1
8242 Xamoeba_3, FALSE, FALSE,
8243 EL_AMOEBA_DRY, ACTION_OTHER, -1
8246 Xamoeba_4, FALSE, FALSE,
8247 EL_AMOEBA_DRY, ACTION_OTHER, -1
8250 Xamoeba_5, TRUE, FALSE,
8251 EL_AMOEBA_WET, ACTION_OTHER, -1
8254 Xamoeba_6, FALSE, FALSE,
8255 EL_AMOEBA_WET, ACTION_OTHER, -1
8258 Xamoeba_7, FALSE, FALSE,
8259 EL_AMOEBA_WET, ACTION_OTHER, -1
8262 Xamoeba_8, FALSE, FALSE,
8263 EL_AMOEBA_WET, ACTION_OTHER, -1
8266 Xdoor_1, TRUE, FALSE,
8267 EL_EM_GATE_1, -1, -1
8270 Xdoor_2, TRUE, FALSE,
8271 EL_EM_GATE_2, -1, -1
8274 Xdoor_3, TRUE, FALSE,
8275 EL_EM_GATE_3, -1, -1
8278 Xdoor_4, TRUE, FALSE,
8279 EL_EM_GATE_4, -1, -1
8282 Xdoor_5, TRUE, FALSE,
8283 EL_EMC_GATE_5, -1, -1
8286 Xdoor_6, TRUE, FALSE,
8287 EL_EMC_GATE_6, -1, -1
8290 Xdoor_7, TRUE, FALSE,
8291 EL_EMC_GATE_7, -1, -1
8294 Xdoor_8, TRUE, FALSE,
8295 EL_EMC_GATE_8, -1, -1
8298 Xkey_1, TRUE, FALSE,
8302 Xkey_2, TRUE, FALSE,
8306 Xkey_3, TRUE, FALSE,
8310 Xkey_4, TRUE, FALSE,
8314 Xkey_5, TRUE, FALSE,
8315 EL_EMC_KEY_5, -1, -1
8318 Xkey_6, TRUE, FALSE,
8319 EL_EMC_KEY_6, -1, -1
8322 Xkey_7, TRUE, FALSE,
8323 EL_EMC_KEY_7, -1, -1
8326 Xkey_8, TRUE, FALSE,
8327 EL_EMC_KEY_8, -1, -1
8330 Xwind_n, TRUE, FALSE,
8331 EL_BALLOON_SWITCH_UP, -1, -1
8334 Xwind_e, TRUE, FALSE,
8335 EL_BALLOON_SWITCH_RIGHT, -1, -1
8338 Xwind_s, TRUE, FALSE,
8339 EL_BALLOON_SWITCH_DOWN, -1, -1
8342 Xwind_w, TRUE, FALSE,
8343 EL_BALLOON_SWITCH_LEFT, -1, -1
8346 Xwind_nesw, TRUE, FALSE,
8347 EL_BALLOON_SWITCH_ANY, -1, -1
8350 Xwind_stop, TRUE, FALSE,
8351 EL_BALLOON_SWITCH_NONE, -1, -1
8355 EL_EM_EXIT_CLOSED, -1, -1
8358 Xexit_1, TRUE, FALSE,
8359 EL_EM_EXIT_OPEN, -1, -1
8362 Xexit_2, FALSE, FALSE,
8363 EL_EM_EXIT_OPEN, -1, -1
8366 Xexit_3, FALSE, FALSE,
8367 EL_EM_EXIT_OPEN, -1, -1
8370 Xdynamite, TRUE, FALSE,
8371 EL_EM_DYNAMITE, -1, -1
8374 Ydynamite_eat, FALSE, FALSE,
8375 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
8378 Xdynamite_1, TRUE, FALSE,
8379 EL_EM_DYNAMITE_ACTIVE, -1, -1
8382 Xdynamite_2, FALSE, FALSE,
8383 EL_EM_DYNAMITE_ACTIVE, -1, -1
8386 Xdynamite_3, FALSE, FALSE,
8387 EL_EM_DYNAMITE_ACTIVE, -1, -1
8390 Xdynamite_4, FALSE, FALSE,
8391 EL_EM_DYNAMITE_ACTIVE, -1, -1
8394 Xbumper, TRUE, FALSE,
8395 EL_EMC_SPRING_BUMPER, -1, -1
8398 XbumperB, FALSE, FALSE,
8399 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
8402 Xwheel, TRUE, FALSE,
8403 EL_ROBOT_WHEEL, -1, -1
8406 XwheelB, FALSE, FALSE,
8407 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
8410 Xswitch, TRUE, FALSE,
8411 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
8414 XswitchB, FALSE, FALSE,
8415 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
8419 EL_QUICKSAND_EMPTY, -1, -1
8422 Xsand_stone, TRUE, FALSE,
8423 EL_QUICKSAND_FULL, -1, -1
8426 Xsand_stonein_1, FALSE, TRUE,
8427 EL_ROCK, ACTION_FILLING, -1
8430 Xsand_stonein_2, FALSE, TRUE,
8431 EL_ROCK, ACTION_FILLING, -1
8434 Xsand_stonein_3, FALSE, TRUE,
8435 EL_ROCK, ACTION_FILLING, -1
8438 Xsand_stonein_4, FALSE, TRUE,
8439 EL_ROCK, ACTION_FILLING, -1
8443 Xsand_stonesand_1, FALSE, FALSE,
8444 EL_QUICKSAND_EMPTYING, -1, -1
8447 Xsand_stonesand_2, FALSE, FALSE,
8448 EL_QUICKSAND_EMPTYING, -1, -1
8451 Xsand_stonesand_3, FALSE, FALSE,
8452 EL_QUICKSAND_EMPTYING, -1, -1
8455 Xsand_stonesand_4, FALSE, FALSE,
8456 EL_QUICKSAND_EMPTYING, -1, -1
8459 Xsand_stonesand_quickout_1, FALSE, FALSE,
8460 EL_QUICKSAND_EMPTYING, -1, -1
8463 Xsand_stonesand_quickout_2, FALSE, FALSE,
8464 EL_QUICKSAND_EMPTYING, -1, -1
8468 Xsand_stonesand_1, FALSE, FALSE,
8469 EL_QUICKSAND_FULL, -1, -1
8472 Xsand_stonesand_2, FALSE, FALSE,
8473 EL_QUICKSAND_FULL, -1, -1
8476 Xsand_stonesand_3, FALSE, FALSE,
8477 EL_QUICKSAND_FULL, -1, -1
8480 Xsand_stonesand_4, FALSE, FALSE,
8481 EL_QUICKSAND_FULL, -1, -1
8485 Xsand_stoneout_1, FALSE, FALSE,
8486 EL_ROCK, ACTION_EMPTYING, -1
8489 Xsand_stoneout_2, FALSE, FALSE,
8490 EL_ROCK, ACTION_EMPTYING, -1
8494 Xsand_sandstone_1, FALSE, FALSE,
8495 EL_QUICKSAND_FILLING, -1, -1
8498 Xsand_sandstone_2, FALSE, FALSE,
8499 EL_QUICKSAND_FILLING, -1, -1
8502 Xsand_sandstone_3, FALSE, FALSE,
8503 EL_QUICKSAND_FILLING, -1, -1
8506 Xsand_sandstone_4, FALSE, FALSE,
8507 EL_QUICKSAND_FILLING, -1, -1
8511 Xsand_sandstone_1, FALSE, FALSE,
8512 EL_QUICKSAND_FULL, -1, -1
8515 Xsand_sandstone_2, FALSE, FALSE,
8516 EL_QUICKSAND_FULL, -1, -1
8519 Xsand_sandstone_3, FALSE, FALSE,
8520 EL_QUICKSAND_FULL, -1, -1
8523 Xsand_sandstone_4, FALSE, FALSE,
8524 EL_QUICKSAND_FULL, -1, -1
8528 Xplant, TRUE, FALSE,
8529 EL_EMC_PLANT, -1, -1
8532 Yplant, FALSE, FALSE,
8533 EL_EMC_PLANT, -1, -1
8536 Xlenses, TRUE, FALSE,
8537 EL_EMC_LENSES, -1, -1
8540 Xmagnify, TRUE, FALSE,
8541 EL_EMC_MAGNIFIER, -1, -1
8544 Xdripper, TRUE, FALSE,
8545 EL_EMC_DRIPPER, -1, -1
8548 XdripperB, FALSE, FALSE,
8549 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
8552 Xfake_blank, TRUE, FALSE,
8553 EL_INVISIBLE_WALL, -1, -1
8556 Xfake_blankB, FALSE, FALSE,
8557 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
8560 Xfake_grass, TRUE, FALSE,
8561 EL_EMC_FAKE_GRASS, -1, -1
8564 Xfake_grassB, FALSE, FALSE,
8565 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
8568 Xfake_door_1, TRUE, FALSE,
8569 EL_EM_GATE_1_GRAY, -1, -1
8572 Xfake_door_2, TRUE, FALSE,
8573 EL_EM_GATE_2_GRAY, -1, -1
8576 Xfake_door_3, TRUE, FALSE,
8577 EL_EM_GATE_3_GRAY, -1, -1
8580 Xfake_door_4, TRUE, FALSE,
8581 EL_EM_GATE_4_GRAY, -1, -1
8584 Xfake_door_5, TRUE, FALSE,
8585 EL_EMC_GATE_5_GRAY, -1, -1
8588 Xfake_door_6, TRUE, FALSE,
8589 EL_EMC_GATE_6_GRAY, -1, -1
8592 Xfake_door_7, TRUE, FALSE,
8593 EL_EMC_GATE_7_GRAY, -1, -1
8596 Xfake_door_8, TRUE, FALSE,
8597 EL_EMC_GATE_8_GRAY, -1, -1
8600 Xfake_acid_1, TRUE, FALSE,
8601 EL_EMC_FAKE_ACID, -1, -1
8604 Xfake_acid_2, FALSE, FALSE,
8605 EL_EMC_FAKE_ACID, -1, -1
8608 Xfake_acid_3, FALSE, FALSE,
8609 EL_EMC_FAKE_ACID, -1, -1
8612 Xfake_acid_4, FALSE, FALSE,
8613 EL_EMC_FAKE_ACID, -1, -1
8616 Xfake_acid_5, FALSE, FALSE,
8617 EL_EMC_FAKE_ACID, -1, -1
8620 Xfake_acid_6, FALSE, FALSE,
8621 EL_EMC_FAKE_ACID, -1, -1
8624 Xfake_acid_7, FALSE, FALSE,
8625 EL_EMC_FAKE_ACID, -1, -1
8628 Xfake_acid_8, FALSE, FALSE,
8629 EL_EMC_FAKE_ACID, -1, -1
8632 Xsteel_1, TRUE, FALSE,
8633 EL_STEELWALL, -1, -1
8636 Xsteel_2, TRUE, FALSE,
8637 EL_EMC_STEELWALL_2, -1, -1
8640 Xsteel_3, TRUE, FALSE,
8641 EL_EMC_STEELWALL_3, -1, -1
8644 Xsteel_4, TRUE, FALSE,
8645 EL_EMC_STEELWALL_4, -1, -1
8648 Xwall_1, TRUE, FALSE,
8652 Xwall_2, TRUE, FALSE,
8653 EL_EMC_WALL_14, -1, -1
8656 Xwall_3, TRUE, FALSE,
8657 EL_EMC_WALL_15, -1, -1
8660 Xwall_4, TRUE, FALSE,
8661 EL_EMC_WALL_16, -1, -1
8664 Xround_wall_1, TRUE, FALSE,
8665 EL_WALL_SLIPPERY, -1, -1
8668 Xround_wall_2, TRUE, FALSE,
8669 EL_EMC_WALL_SLIPPERY_2, -1, -1
8672 Xround_wall_3, TRUE, FALSE,
8673 EL_EMC_WALL_SLIPPERY_3, -1, -1
8676 Xround_wall_4, TRUE, FALSE,
8677 EL_EMC_WALL_SLIPPERY_4, -1, -1
8680 Xdecor_1, TRUE, FALSE,
8681 EL_EMC_WALL_8, -1, -1
8684 Xdecor_2, TRUE, FALSE,
8685 EL_EMC_WALL_6, -1, -1
8688 Xdecor_3, TRUE, FALSE,
8689 EL_EMC_WALL_4, -1, -1
8692 Xdecor_4, TRUE, FALSE,
8693 EL_EMC_WALL_7, -1, -1
8696 Xdecor_5, TRUE, FALSE,
8697 EL_EMC_WALL_5, -1, -1
8700 Xdecor_6, TRUE, FALSE,
8701 EL_EMC_WALL_9, -1, -1
8704 Xdecor_7, TRUE, FALSE,
8705 EL_EMC_WALL_10, -1, -1
8708 Xdecor_8, TRUE, FALSE,
8709 EL_EMC_WALL_1, -1, -1
8712 Xdecor_9, TRUE, FALSE,
8713 EL_EMC_WALL_2, -1, -1
8716 Xdecor_10, TRUE, FALSE,
8717 EL_EMC_WALL_3, -1, -1
8720 Xdecor_11, TRUE, FALSE,
8721 EL_EMC_WALL_11, -1, -1
8724 Xdecor_12, TRUE, FALSE,
8725 EL_EMC_WALL_12, -1, -1
8728 Xalpha_0, TRUE, FALSE,
8729 EL_CHAR('0'), -1, -1
8732 Xalpha_1, TRUE, FALSE,
8733 EL_CHAR('1'), -1, -1
8736 Xalpha_2, TRUE, FALSE,
8737 EL_CHAR('2'), -1, -1
8740 Xalpha_3, TRUE, FALSE,
8741 EL_CHAR('3'), -1, -1
8744 Xalpha_4, TRUE, FALSE,
8745 EL_CHAR('4'), -1, -1
8748 Xalpha_5, TRUE, FALSE,
8749 EL_CHAR('5'), -1, -1
8752 Xalpha_6, TRUE, FALSE,
8753 EL_CHAR('6'), -1, -1
8756 Xalpha_7, TRUE, FALSE,
8757 EL_CHAR('7'), -1, -1
8760 Xalpha_8, TRUE, FALSE,
8761 EL_CHAR('8'), -1, -1
8764 Xalpha_9, TRUE, FALSE,
8765 EL_CHAR('9'), -1, -1
8768 Xalpha_excla, TRUE, FALSE,
8769 EL_CHAR('!'), -1, -1
8772 Xalpha_quote, TRUE, FALSE,
8773 EL_CHAR('"'), -1, -1
8776 Xalpha_comma, TRUE, FALSE,
8777 EL_CHAR(','), -1, -1
8780 Xalpha_minus, TRUE, FALSE,
8781 EL_CHAR('-'), -1, -1
8784 Xalpha_perio, TRUE, FALSE,
8785 EL_CHAR('.'), -1, -1
8788 Xalpha_colon, TRUE, FALSE,
8789 EL_CHAR(':'), -1, -1
8792 Xalpha_quest, TRUE, FALSE,
8793 EL_CHAR('?'), -1, -1
8796 Xalpha_a, TRUE, FALSE,
8797 EL_CHAR('A'), -1, -1
8800 Xalpha_b, TRUE, FALSE,
8801 EL_CHAR('B'), -1, -1
8804 Xalpha_c, TRUE, FALSE,
8805 EL_CHAR('C'), -1, -1
8808 Xalpha_d, TRUE, FALSE,
8809 EL_CHAR('D'), -1, -1
8812 Xalpha_e, TRUE, FALSE,
8813 EL_CHAR('E'), -1, -1
8816 Xalpha_f, TRUE, FALSE,
8817 EL_CHAR('F'), -1, -1
8820 Xalpha_g, TRUE, FALSE,
8821 EL_CHAR('G'), -1, -1
8824 Xalpha_h, TRUE, FALSE,
8825 EL_CHAR('H'), -1, -1
8828 Xalpha_i, TRUE, FALSE,
8829 EL_CHAR('I'), -1, -1
8832 Xalpha_j, TRUE, FALSE,
8833 EL_CHAR('J'), -1, -1
8836 Xalpha_k, TRUE, FALSE,
8837 EL_CHAR('K'), -1, -1
8840 Xalpha_l, TRUE, FALSE,
8841 EL_CHAR('L'), -1, -1
8844 Xalpha_m, TRUE, FALSE,
8845 EL_CHAR('M'), -1, -1
8848 Xalpha_n, TRUE, FALSE,
8849 EL_CHAR('N'), -1, -1
8852 Xalpha_o, TRUE, FALSE,
8853 EL_CHAR('O'), -1, -1
8856 Xalpha_p, TRUE, FALSE,
8857 EL_CHAR('P'), -1, -1
8860 Xalpha_q, TRUE, FALSE,
8861 EL_CHAR('Q'), -1, -1
8864 Xalpha_r, TRUE, FALSE,
8865 EL_CHAR('R'), -1, -1
8868 Xalpha_s, TRUE, FALSE,
8869 EL_CHAR('S'), -1, -1
8872 Xalpha_t, TRUE, FALSE,
8873 EL_CHAR('T'), -1, -1
8876 Xalpha_u, TRUE, FALSE,
8877 EL_CHAR('U'), -1, -1
8880 Xalpha_v, TRUE, FALSE,
8881 EL_CHAR('V'), -1, -1
8884 Xalpha_w, TRUE, FALSE,
8885 EL_CHAR('W'), -1, -1
8888 Xalpha_x, TRUE, FALSE,
8889 EL_CHAR('X'), -1, -1
8892 Xalpha_y, TRUE, FALSE,
8893 EL_CHAR('Y'), -1, -1
8896 Xalpha_z, TRUE, FALSE,
8897 EL_CHAR('Z'), -1, -1
8900 Xalpha_arrow_e, TRUE, FALSE,
8901 EL_CHAR('>'), -1, -1
8904 Xalpha_arrow_w, TRUE, FALSE,
8905 EL_CHAR('<'), -1, -1
8908 Xalpha_copyr, TRUE, FALSE,
8909 EL_CHAR('©'), -1, -1
8913 Xboom_bug, FALSE, FALSE,
8914 EL_BUG, ACTION_EXPLODING, -1
8917 Xboom_bomb, FALSE, FALSE,
8918 EL_BOMB, ACTION_EXPLODING, -1
8921 Xboom_android, FALSE, FALSE,
8922 EL_EMC_ANDROID, ACTION_OTHER, -1
8925 Xboom_1, FALSE, FALSE,
8926 EL_DEFAULT, ACTION_EXPLODING, -1
8929 Xboom_2, FALSE, FALSE,
8930 EL_DEFAULT, ACTION_EXPLODING, -1
8933 Znormal, FALSE, FALSE,
8937 Zdynamite, FALSE, FALSE,
8941 Zplayer, FALSE, FALSE,
8945 ZBORDER, FALSE, FALSE,
8955 static struct Mapping_EM_to_RND_player
8964 em_player_mapping_list[] =
8968 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
8972 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
8976 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
8980 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
8984 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
8988 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
8992 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
8996 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
9000 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
9004 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
9008 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
9012 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
9016 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
9020 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
9024 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
9028 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
9032 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
9036 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
9040 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
9044 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
9048 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
9052 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
9056 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
9060 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
9064 EL_PLAYER_1, ACTION_DEFAULT, -1,
9068 EL_PLAYER_2, ACTION_DEFAULT, -1,
9072 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
9076 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
9080 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
9084 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
9088 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
9092 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
9096 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
9100 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
9104 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
9108 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
9112 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
9116 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
9120 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
9124 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
9128 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
9132 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
9136 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
9140 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
9144 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
9148 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
9152 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
9156 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
9160 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
9164 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
9168 EL_PLAYER_3, ACTION_DEFAULT, -1,
9172 EL_PLAYER_4, ACTION_DEFAULT, -1,
9181 int map_element_RND_to_EM(int element_rnd)
9183 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
9184 static boolean mapping_initialized = FALSE;
9186 if (!mapping_initialized)
9190 /* return "Xalpha_quest" for all undefined elements in mapping array */
9191 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9192 mapping_RND_to_EM[i] = Xalpha_quest;
9194 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9195 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
9196 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
9197 em_object_mapping_list[i].element_em;
9199 mapping_initialized = TRUE;
9202 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
9203 return mapping_RND_to_EM[element_rnd];
9205 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
9210 int map_element_EM_to_RND(int element_em)
9212 static unsigned short mapping_EM_to_RND[TILE_MAX];
9213 static boolean mapping_initialized = FALSE;
9215 if (!mapping_initialized)
9219 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
9220 for (i = 0; i < TILE_MAX; i++)
9221 mapping_EM_to_RND[i] = EL_UNKNOWN;
9223 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9224 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
9225 em_object_mapping_list[i].element_rnd;
9227 mapping_initialized = TRUE;
9230 if (element_em >= 0 && element_em < TILE_MAX)
9231 return mapping_EM_to_RND[element_em];
9233 Error(ERR_WARN, "invalid EM level element %d", element_em);
9238 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
9240 struct LevelInfo_EM *level_em = level->native_em_level;
9241 struct LEVEL *lev = level_em->lev;
9244 for (i = 0; i < TILE_MAX; i++)
9245 lev->android_array[i] = Xblank;
9247 for (i = 0; i < level->num_android_clone_elements; i++)
9249 int element_rnd = level->android_clone_element[i];
9250 int element_em = map_element_RND_to_EM(element_rnd);
9252 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
9253 if (em_object_mapping_list[j].element_rnd == element_rnd)
9254 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
9258 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
9260 struct LevelInfo_EM *level_em = level->native_em_level;
9261 struct LEVEL *lev = level_em->lev;
9264 level->num_android_clone_elements = 0;
9266 for (i = 0; i < TILE_MAX; i++)
9268 int element_em = lev->android_array[i];
9270 boolean element_found = FALSE;
9272 if (element_em == Xblank)
9275 element_rnd = map_element_EM_to_RND(element_em);
9277 for (j = 0; j < level->num_android_clone_elements; j++)
9278 if (level->android_clone_element[j] == element_rnd)
9279 element_found = TRUE;
9283 level->android_clone_element[level->num_android_clone_elements++] =
9286 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
9291 if (level->num_android_clone_elements == 0)
9293 level->num_android_clone_elements = 1;
9294 level->android_clone_element[0] = EL_EMPTY;
9298 int map_direction_RND_to_EM(int direction)
9300 return (direction == MV_UP ? 0 :
9301 direction == MV_RIGHT ? 1 :
9302 direction == MV_DOWN ? 2 :
9303 direction == MV_LEFT ? 3 :
9307 int map_direction_EM_to_RND(int direction)
9309 return (direction == 0 ? MV_UP :
9310 direction == 1 ? MV_RIGHT :
9311 direction == 2 ? MV_DOWN :
9312 direction == 3 ? MV_LEFT :
9316 int map_element_RND_to_SP(int element_rnd)
9318 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
9320 if (element_rnd >= EL_SP_START &&
9321 element_rnd <= EL_SP_END)
9322 element_sp = element_rnd - EL_SP_START;
9323 else if (element_rnd == EL_EMPTY_SPACE)
9325 else if (element_rnd == EL_INVISIBLE_WALL)
9331 int map_element_SP_to_RND(int element_sp)
9333 int element_rnd = EL_UNKNOWN;
9335 if (element_sp >= 0x00 &&
9337 element_rnd = EL_SP_START + element_sp;
9338 else if (element_sp == 0x28)
9339 element_rnd = EL_INVISIBLE_WALL;
9344 int map_action_SP_to_RND(int action_sp)
9348 case actActive: return ACTION_ACTIVE;
9349 case actImpact: return ACTION_IMPACT;
9350 case actExploding: return ACTION_EXPLODING;
9351 case actDigging: return ACTION_DIGGING;
9352 case actSnapping: return ACTION_SNAPPING;
9353 case actCollecting: return ACTION_COLLECTING;
9354 case actPassing: return ACTION_PASSING;
9355 case actPushing: return ACTION_PUSHING;
9356 case actDropping: return ACTION_DROPPING;
9358 default: return ACTION_DEFAULT;
9362 int get_next_element(int element)
9366 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
9367 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
9368 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
9369 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
9370 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
9371 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
9372 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
9373 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
9374 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
9375 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
9376 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
9378 default: return element;
9383 int el_act_dir2img(int element, int action, int direction)
9385 element = GFX_ELEMENT(element);
9387 if (direction == MV_NONE)
9388 return element_info[element].graphic[action];
9390 direction = MV_DIR_TO_BIT(direction);
9392 return element_info[element].direction_graphic[action][direction];
9395 int el_act_dir2img(int element, int action, int direction)
9397 element = GFX_ELEMENT(element);
9398 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9400 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9401 return element_info[element].direction_graphic[action][direction];
9406 static int el_act_dir2crm(int element, int action, int direction)
9408 element = GFX_ELEMENT(element);
9410 if (direction == MV_NONE)
9411 return element_info[element].crumbled[action];
9413 direction = MV_DIR_TO_BIT(direction);
9415 return element_info[element].direction_crumbled[action][direction];
9418 static int el_act_dir2crm(int element, int action, int direction)
9420 element = GFX_ELEMENT(element);
9421 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9423 /* direction_graphic[][] == graphic[] for undefined direction graphics */
9424 return element_info[element].direction_crumbled[action][direction];
9428 int el_act2img(int element, int action)
9430 element = GFX_ELEMENT(element);
9432 return element_info[element].graphic[action];
9435 int el_act2crm(int element, int action)
9437 element = GFX_ELEMENT(element);
9439 return element_info[element].crumbled[action];
9442 int el_dir2img(int element, int direction)
9444 element = GFX_ELEMENT(element);
9446 return el_act_dir2img(element, ACTION_DEFAULT, direction);
9449 int el2baseimg(int element)
9451 return element_info[element].graphic[ACTION_DEFAULT];
9454 int el2img(int element)
9456 element = GFX_ELEMENT(element);
9458 return element_info[element].graphic[ACTION_DEFAULT];
9461 int el2edimg(int element)
9463 element = GFX_ELEMENT(element);
9465 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9468 int el2preimg(int element)
9470 element = GFX_ELEMENT(element);
9472 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9475 int el2panelimg(int element)
9477 element = GFX_ELEMENT(element);
9479 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9482 int font2baseimg(int font_nr)
9484 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9487 int getBeltNrFromBeltElement(int element)
9489 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9490 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9491 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9494 int getBeltNrFromBeltActiveElement(int element)
9496 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9497 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9498 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9501 int getBeltNrFromBeltSwitchElement(int element)
9503 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9504 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9505 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9508 int getBeltDirNrFromBeltElement(int element)
9510 static int belt_base_element[4] =
9512 EL_CONVEYOR_BELT_1_LEFT,
9513 EL_CONVEYOR_BELT_2_LEFT,
9514 EL_CONVEYOR_BELT_3_LEFT,
9515 EL_CONVEYOR_BELT_4_LEFT
9518 int belt_nr = getBeltNrFromBeltElement(element);
9519 int belt_dir_nr = element - belt_base_element[belt_nr];
9521 return (belt_dir_nr % 3);
9524 int getBeltDirNrFromBeltSwitchElement(int element)
9526 static int belt_base_element[4] =
9528 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9529 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9530 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9531 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9534 int belt_nr = getBeltNrFromBeltSwitchElement(element);
9535 int belt_dir_nr = element - belt_base_element[belt_nr];
9537 return (belt_dir_nr % 3);
9540 int getBeltDirFromBeltElement(int element)
9542 static int belt_move_dir[3] =
9549 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9551 return belt_move_dir[belt_dir_nr];
9554 int getBeltDirFromBeltSwitchElement(int element)
9556 static int belt_move_dir[3] =
9563 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9565 return belt_move_dir[belt_dir_nr];
9568 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9570 static int belt_base_element[4] =
9572 EL_CONVEYOR_BELT_1_LEFT,
9573 EL_CONVEYOR_BELT_2_LEFT,
9574 EL_CONVEYOR_BELT_3_LEFT,
9575 EL_CONVEYOR_BELT_4_LEFT
9578 return belt_base_element[belt_nr] + belt_dir_nr;
9581 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9583 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9585 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9588 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9590 static int belt_base_element[4] =
9592 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9593 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9594 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9595 EL_CONVEYOR_BELT_4_SWITCH_LEFT
9598 return belt_base_element[belt_nr] + belt_dir_nr;
9601 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9603 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9605 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9609 boolean getTeamMode_EM()
9611 return game.team_mode;
9614 int getNumActivePlayers_EM()
9617 int num_players = 0;
9621 return (setup.team_mode ? MAX_PLAYERS : 1);
9623 for (i = 0; i < MAX_PLAYERS; i++)
9624 if (tape.player_participates[i])
9627 return (num_players > 1 ? MAX_PLAYERS : 1);
9631 int num_players = 0;
9634 /* when recording game, activate all connected players */
9638 for (i = 0; i < MAX_PLAYERS; i++)
9639 if (tape.player_participates[i])
9647 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9649 int game_frame_delay_value;
9651 game_frame_delay_value =
9652 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9653 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9656 if (tape.playing && tape.warp_forward && !tape.pausing)
9657 game_frame_delay_value = 0;
9659 return game_frame_delay_value;
9662 unsigned int InitRND(int seed)
9664 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9665 return InitEngineRandom_EM(seed);
9666 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9667 return InitEngineRandom_SP(seed);
9669 return InitEngineRandom_RND(seed);
9673 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9674 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9677 inline static int get_effective_element_EM(int tile, int frame_em)
9679 int element = object_mapping[tile].element_rnd;
9680 int action = object_mapping[tile].action;
9681 boolean is_backside = object_mapping[tile].is_backside;
9682 boolean action_removing = (action == ACTION_DIGGING ||
9683 action == ACTION_SNAPPING ||
9684 action == ACTION_COLLECTING);
9690 case Yacid_splash_eB:
9691 case Yacid_splash_wB:
9692 return (frame_em > 5 ? EL_EMPTY : element);
9696 case Ydiamond_stone:
9697 // if (!game.use_native_emc_graphics_engine)
9705 else /* frame_em == 7 */
9709 case Yacid_splash_eB:
9710 case Yacid_splash_wB:
9713 case Yemerald_stone:
9716 case Ydiamond_stone:
9720 case Xdrip_stretchB:
9739 case Xsand_stonein_1:
9740 case Xsand_stonein_2:
9741 case Xsand_stonein_3:
9742 case Xsand_stonein_4:
9746 return (is_backside || action_removing ? EL_EMPTY : element);
9751 inline static boolean check_linear_animation_EM(int tile)
9755 case Xsand_stonesand_1:
9756 case Xsand_stonesand_quickout_1:
9757 case Xsand_sandstone_1:
9758 case Xsand_stonein_1:
9759 case Xsand_stoneout_1:
9779 case Yacid_splash_eB:
9780 case Yacid_splash_wB:
9781 case Yemerald_stone:
9789 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9790 boolean has_crumbled_graphics,
9791 int crumbled, int sync_frame)
9793 /* if element can be crumbled, but certain action graphics are just empty
9794 space (like instantly snapping sand to empty space in 1 frame), do not
9795 treat these empty space graphics as crumbled graphics in EMC engine */
9796 if (crumbled == IMG_EMPTY_SPACE)
9797 has_crumbled_graphics = FALSE;
9799 if (has_crumbled_graphics)
9801 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9802 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9803 g_crumbled->anim_delay,
9804 g_crumbled->anim_mode,
9805 g_crumbled->anim_start_frame,
9808 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9809 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9811 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9813 g_em->has_crumbled_graphics = TRUE;
9817 g_em->crumbled_bitmap = NULL;
9818 g_em->crumbled_src_x = 0;
9819 g_em->crumbled_src_y = 0;
9820 g_em->crumbled_border_size = 0;
9822 g_em->has_crumbled_graphics = FALSE;
9826 void ResetGfxAnimation_EM(int x, int y, int tile)
9831 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9832 int tile, int frame_em, int x, int y)
9834 int action = object_mapping[tile].action;
9836 int direction = object_mapping[tile].direction;
9837 int effective_element = get_effective_element_EM(tile, frame_em);
9838 int graphic = (direction == MV_NONE ?
9839 el_act2img(effective_element, action) :
9840 el_act_dir2img(effective_element, action, direction));
9841 struct GraphicInfo *g = &graphic_info[graphic];
9844 boolean action_removing = (action == ACTION_DIGGING ||
9845 action == ACTION_SNAPPING ||
9846 action == ACTION_COLLECTING);
9847 boolean action_moving = (action == ACTION_FALLING ||
9848 action == ACTION_MOVING ||
9849 action == ACTION_PUSHING ||
9850 action == ACTION_EATING ||
9851 action == ACTION_FILLING ||
9852 action == ACTION_EMPTYING);
9853 boolean action_falling = (action == ACTION_FALLING ||
9854 action == ACTION_FILLING ||
9855 action == ACTION_EMPTYING);
9857 /* special case: graphic uses "2nd movement tile" and has defined
9858 7 frames for movement animation (or less) => use default graphic
9859 for last (8th) frame which ends the movement animation */
9860 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9862 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
9863 graphic = (direction == MV_NONE ?
9864 el_act2img(effective_element, action) :
9865 el_act_dir2img(effective_element, action, direction));
9867 g = &graphic_info[graphic];
9871 if (tile == Xsand_stonesand_1 ||
9872 tile == Xsand_stonesand_2 ||
9873 tile == Xsand_stonesand_3 ||
9874 tile == Xsand_stonesand_4)
9875 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9879 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9883 // printf("::: resetting... [%d]\n", tile);
9886 if (action_removing || check_linear_animation_EM(tile))
9888 GfxFrame[x][y] = frame_em;
9890 // printf("::: resetting... [%d]\n", tile);
9893 else if (action_moving)
9895 boolean is_backside = object_mapping[tile].is_backside;
9899 int direction = object_mapping[tile].direction;
9900 int move_dir = (action_falling ? MV_DOWN : direction);
9905 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9906 if (g->double_movement && frame_em == 0)
9910 // printf("::: resetting... [%d]\n", tile);
9914 if (move_dir == MV_LEFT)
9915 GfxFrame[x - 1][y] = GfxFrame[x][y];
9916 else if (move_dir == MV_RIGHT)
9917 GfxFrame[x + 1][y] = GfxFrame[x][y];
9918 else if (move_dir == MV_UP)
9919 GfxFrame[x][y - 1] = GfxFrame[x][y];
9920 else if (move_dir == MV_DOWN)
9921 GfxFrame[x][y + 1] = GfxFrame[x][y];
9928 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9929 if (tile == Xsand_stonesand_quickout_1 ||
9930 tile == Xsand_stonesand_quickout_2)
9935 if (tile == Xsand_stonesand_1 ||
9936 tile == Xsand_stonesand_2 ||
9937 tile == Xsand_stonesand_3 ||
9938 tile == Xsand_stonesand_4)
9939 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9943 if (graphic_info[graphic].anim_global_sync)
9944 sync_frame = FrameCounter;
9945 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9946 sync_frame = GfxFrame[x][y];
9948 sync_frame = 0; /* playfield border (pseudo steel) */
9950 SetRandomAnimationValue(x, y);
9952 int frame = getAnimationFrame(g->anim_frames,
9955 g->anim_start_frame,
9958 g_em->unique_identifier =
9959 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9963 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9964 int tile, int frame_em, int x, int y)
9966 int action = object_mapping[tile].action;
9967 int direction = object_mapping[tile].direction;
9968 boolean is_backside = object_mapping[tile].is_backside;
9969 int effective_element = get_effective_element_EM(tile, frame_em);
9971 int effective_action = action;
9973 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9975 int graphic = (direction == MV_NONE ?
9976 el_act2img(effective_element, effective_action) :
9977 el_act_dir2img(effective_element, effective_action,
9979 int crumbled = (direction == MV_NONE ?
9980 el_act2crm(effective_element, effective_action) :
9981 el_act_dir2crm(effective_element, effective_action,
9983 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9984 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9985 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9986 struct GraphicInfo *g = &graphic_info[graphic];
9988 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9992 /* special case: graphic uses "2nd movement tile" and has defined
9993 7 frames for movement animation (or less) => use default graphic
9994 for last (8th) frame which ends the movement animation */
9995 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9997 effective_action = ACTION_DEFAULT;
9998 graphic = (direction == MV_NONE ?
9999 el_act2img(effective_element, effective_action) :
10000 el_act_dir2img(effective_element, effective_action,
10002 crumbled = (direction == MV_NONE ?
10003 el_act2crm(effective_element, effective_action) :
10004 el_act_dir2crm(effective_element, effective_action,
10007 g = &graphic_info[graphic];
10017 if (frame_em == 0) /* reset animation frame for certain elements */
10019 if (check_linear_animation_EM(tile))
10020 GfxFrame[x][y] = 0;
10024 if (graphic_info[graphic].anim_global_sync)
10025 sync_frame = FrameCounter;
10026 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
10027 sync_frame = GfxFrame[x][y];
10029 sync_frame = 0; /* playfield border (pseudo steel) */
10031 SetRandomAnimationValue(x, y);
10036 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10037 i == Xdrip_stretchB ? 7 :
10038 i == Ydrip_s2 ? j + 8 :
10039 i == Ydrip_s2B ? j + 8 :
10041 i == Xacid_2 ? 10 :
10042 i == Xacid_3 ? 20 :
10043 i == Xacid_4 ? 30 :
10044 i == Xacid_5 ? 40 :
10045 i == Xacid_6 ? 50 :
10046 i == Xacid_7 ? 60 :
10047 i == Xacid_8 ? 70 :
10048 i == Xfake_acid_1 ? 0 :
10049 i == Xfake_acid_2 ? 10 :
10050 i == Xfake_acid_3 ? 20 :
10051 i == Xfake_acid_4 ? 30 :
10052 i == Xfake_acid_5 ? 40 :
10053 i == Xfake_acid_6 ? 50 :
10054 i == Xfake_acid_7 ? 60 :
10055 i == Xfake_acid_8 ? 70 :
10057 i == Xball_2B ? j + 8 :
10058 i == Yball_eat ? j + 1 :
10059 i == Ykey_1_eat ? j + 1 :
10060 i == Ykey_2_eat ? j + 1 :
10061 i == Ykey_3_eat ? j + 1 :
10062 i == Ykey_4_eat ? j + 1 :
10063 i == Ykey_5_eat ? j + 1 :
10064 i == Ykey_6_eat ? j + 1 :
10065 i == Ykey_7_eat ? j + 1 :
10066 i == Ykey_8_eat ? j + 1 :
10067 i == Ylenses_eat ? j + 1 :
10068 i == Ymagnify_eat ? j + 1 :
10069 i == Ygrass_eat ? j + 1 :
10070 i == Ydirt_eat ? j + 1 :
10071 i == Xamoeba_1 ? 0 :
10072 i == Xamoeba_2 ? 1 :
10073 i == Xamoeba_3 ? 2 :
10074 i == Xamoeba_4 ? 3 :
10075 i == Xamoeba_5 ? 0 :
10076 i == Xamoeba_6 ? 1 :
10077 i == Xamoeba_7 ? 2 :
10078 i == Xamoeba_8 ? 3 :
10079 i == Xexit_2 ? j + 8 :
10080 i == Xexit_3 ? j + 16 :
10081 i == Xdynamite_1 ? 0 :
10082 i == Xdynamite_2 ? 8 :
10083 i == Xdynamite_3 ? 16 :
10084 i == Xdynamite_4 ? 24 :
10085 i == Xsand_stonein_1 ? j + 1 :
10086 i == Xsand_stonein_2 ? j + 9 :
10087 i == Xsand_stonein_3 ? j + 17 :
10088 i == Xsand_stonein_4 ? j + 25 :
10089 i == Xsand_stoneout_1 && j == 0 ? 0 :
10090 i == Xsand_stoneout_1 && j == 1 ? 0 :
10091 i == Xsand_stoneout_1 && j == 2 ? 1 :
10092 i == Xsand_stoneout_1 && j == 3 ? 2 :
10093 i == Xsand_stoneout_1 && j == 4 ? 2 :
10094 i == Xsand_stoneout_1 && j == 5 ? 3 :
10095 i == Xsand_stoneout_1 && j == 6 ? 4 :
10096 i == Xsand_stoneout_1 && j == 7 ? 4 :
10097 i == Xsand_stoneout_2 && j == 0 ? 5 :
10098 i == Xsand_stoneout_2 && j == 1 ? 6 :
10099 i == Xsand_stoneout_2 && j == 2 ? 7 :
10100 i == Xsand_stoneout_2 && j == 3 ? 8 :
10101 i == Xsand_stoneout_2 && j == 4 ? 9 :
10102 i == Xsand_stoneout_2 && j == 5 ? 11 :
10103 i == Xsand_stoneout_2 && j == 6 ? 13 :
10104 i == Xsand_stoneout_2 && j == 7 ? 15 :
10105 i == Xboom_bug && j == 1 ? 2 :
10106 i == Xboom_bug && j == 2 ? 2 :
10107 i == Xboom_bug && j == 3 ? 4 :
10108 i == Xboom_bug && j == 4 ? 4 :
10109 i == Xboom_bug && j == 5 ? 2 :
10110 i == Xboom_bug && j == 6 ? 2 :
10111 i == Xboom_bug && j == 7 ? 0 :
10112 i == Xboom_bomb && j == 1 ? 2 :
10113 i == Xboom_bomb && j == 2 ? 2 :
10114 i == Xboom_bomb && j == 3 ? 4 :
10115 i == Xboom_bomb && j == 4 ? 4 :
10116 i == Xboom_bomb && j == 5 ? 2 :
10117 i == Xboom_bomb && j == 6 ? 2 :
10118 i == Xboom_bomb && j == 7 ? 0 :
10119 i == Xboom_android && j == 7 ? 6 :
10120 i == Xboom_1 && j == 1 ? 2 :
10121 i == Xboom_1 && j == 2 ? 2 :
10122 i == Xboom_1 && j == 3 ? 4 :
10123 i == Xboom_1 && j == 4 ? 4 :
10124 i == Xboom_1 && j == 5 ? 6 :
10125 i == Xboom_1 && j == 6 ? 6 :
10126 i == Xboom_1 && j == 7 ? 8 :
10127 i == Xboom_2 && j == 0 ? 8 :
10128 i == Xboom_2 && j == 1 ? 8 :
10129 i == Xboom_2 && j == 2 ? 10 :
10130 i == Xboom_2 && j == 3 ? 10 :
10131 i == Xboom_2 && j == 4 ? 10 :
10132 i == Xboom_2 && j == 5 ? 12 :
10133 i == Xboom_2 && j == 6 ? 12 :
10134 i == Xboom_2 && j == 7 ? 12 :
10136 special_animation && j == 4 ? 3 :
10137 effective_action != action ? 0 :
10143 int xxx_effective_action;
10144 int xxx_has_action_graphics;
10147 int element = object_mapping[i].element_rnd;
10148 int action = object_mapping[i].action;
10149 int direction = object_mapping[i].direction;
10150 boolean is_backside = object_mapping[i].is_backside;
10152 boolean action_removing = (action == ACTION_DIGGING ||
10153 action == ACTION_SNAPPING ||
10154 action == ACTION_COLLECTING);
10156 boolean action_exploding = ((action == ACTION_EXPLODING ||
10157 action == ACTION_SMASHED_BY_ROCK ||
10158 action == ACTION_SMASHED_BY_SPRING) &&
10159 element != EL_DIAMOND);
10160 boolean action_active = (action == ACTION_ACTIVE);
10161 boolean action_other = (action == ACTION_OTHER);
10165 int effective_element = get_effective_element_EM(i, j);
10167 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10168 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10170 i == Xdrip_stretch ? element :
10171 i == Xdrip_stretchB ? element :
10172 i == Ydrip_s1 ? element :
10173 i == Ydrip_s1B ? element :
10174 i == Xball_1B ? element :
10175 i == Xball_2 ? element :
10176 i == Xball_2B ? element :
10177 i == Yball_eat ? element :
10178 i == Ykey_1_eat ? element :
10179 i == Ykey_2_eat ? element :
10180 i == Ykey_3_eat ? element :
10181 i == Ykey_4_eat ? element :
10182 i == Ykey_5_eat ? element :
10183 i == Ykey_6_eat ? element :
10184 i == Ykey_7_eat ? element :
10185 i == Ykey_8_eat ? element :
10186 i == Ylenses_eat ? element :
10187 i == Ymagnify_eat ? element :
10188 i == Ygrass_eat ? element :
10189 i == Ydirt_eat ? element :
10190 i == Yemerald_stone ? EL_EMERALD :
10191 i == Ydiamond_stone ? EL_ROCK :
10192 i == Xsand_stonein_1 ? element :
10193 i == Xsand_stonein_2 ? element :
10194 i == Xsand_stonein_3 ? element :
10195 i == Xsand_stonein_4 ? element :
10196 is_backside ? EL_EMPTY :
10197 action_removing ? EL_EMPTY :
10200 int effective_action = (j < 7 ? action :
10201 i == Xdrip_stretch ? action :
10202 i == Xdrip_stretchB ? action :
10203 i == Ydrip_s1 ? action :
10204 i == Ydrip_s1B ? action :
10205 i == Xball_1B ? action :
10206 i == Xball_2 ? action :
10207 i == Xball_2B ? action :
10208 i == Yball_eat ? action :
10209 i == Ykey_1_eat ? action :
10210 i == Ykey_2_eat ? action :
10211 i == Ykey_3_eat ? action :
10212 i == Ykey_4_eat ? action :
10213 i == Ykey_5_eat ? action :
10214 i == Ykey_6_eat ? action :
10215 i == Ykey_7_eat ? action :
10216 i == Ykey_8_eat ? action :
10217 i == Ylenses_eat ? action :
10218 i == Ymagnify_eat ? action :
10219 i == Ygrass_eat ? action :
10220 i == Ydirt_eat ? action :
10221 i == Xsand_stonein_1 ? action :
10222 i == Xsand_stonein_2 ? action :
10223 i == Xsand_stonein_3 ? action :
10224 i == Xsand_stonein_4 ? action :
10225 i == Xsand_stoneout_1 ? action :
10226 i == Xsand_stoneout_2 ? action :
10227 i == Xboom_android ? ACTION_EXPLODING :
10228 action_exploding ? ACTION_EXPLODING :
10229 action_active ? action :
10230 action_other ? action :
10232 int graphic = (el_act_dir2img(effective_element, effective_action,
10234 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10236 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10237 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10238 boolean has_action_graphics = (graphic != base_graphic);
10239 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10240 struct GraphicInfo *g = &graphic_info[graphic];
10242 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10244 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10245 Bitmap *src_bitmap;
10247 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10248 boolean special_animation = (action != ACTION_DEFAULT &&
10249 g->anim_frames == 3 &&
10250 g->anim_delay == 2 &&
10251 g->anim_mode & ANIM_LINEAR);
10252 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10253 i == Xdrip_stretchB ? 7 :
10254 i == Ydrip_s2 ? j + 8 :
10255 i == Ydrip_s2B ? j + 8 :
10257 i == Xacid_2 ? 10 :
10258 i == Xacid_3 ? 20 :
10259 i == Xacid_4 ? 30 :
10260 i == Xacid_5 ? 40 :
10261 i == Xacid_6 ? 50 :
10262 i == Xacid_7 ? 60 :
10263 i == Xacid_8 ? 70 :
10264 i == Xfake_acid_1 ? 0 :
10265 i == Xfake_acid_2 ? 10 :
10266 i == Xfake_acid_3 ? 20 :
10267 i == Xfake_acid_4 ? 30 :
10268 i == Xfake_acid_5 ? 40 :
10269 i == Xfake_acid_6 ? 50 :
10270 i == Xfake_acid_7 ? 60 :
10271 i == Xfake_acid_8 ? 70 :
10273 i == Xball_2B ? j + 8 :
10274 i == Yball_eat ? j + 1 :
10275 i == Ykey_1_eat ? j + 1 :
10276 i == Ykey_2_eat ? j + 1 :
10277 i == Ykey_3_eat ? j + 1 :
10278 i == Ykey_4_eat ? j + 1 :
10279 i == Ykey_5_eat ? j + 1 :
10280 i == Ykey_6_eat ? j + 1 :
10281 i == Ykey_7_eat ? j + 1 :
10282 i == Ykey_8_eat ? j + 1 :
10283 i == Ylenses_eat ? j + 1 :
10284 i == Ymagnify_eat ? j + 1 :
10285 i == Ygrass_eat ? j + 1 :
10286 i == Ydirt_eat ? j + 1 :
10287 i == Xamoeba_1 ? 0 :
10288 i == Xamoeba_2 ? 1 :
10289 i == Xamoeba_3 ? 2 :
10290 i == Xamoeba_4 ? 3 :
10291 i == Xamoeba_5 ? 0 :
10292 i == Xamoeba_6 ? 1 :
10293 i == Xamoeba_7 ? 2 :
10294 i == Xamoeba_8 ? 3 :
10295 i == Xexit_2 ? j + 8 :
10296 i == Xexit_3 ? j + 16 :
10297 i == Xdynamite_1 ? 0 :
10298 i == Xdynamite_2 ? 8 :
10299 i == Xdynamite_3 ? 16 :
10300 i == Xdynamite_4 ? 24 :
10301 i == Xsand_stonein_1 ? j + 1 :
10302 i == Xsand_stonein_2 ? j + 9 :
10303 i == Xsand_stonein_3 ? j + 17 :
10304 i == Xsand_stonein_4 ? j + 25 :
10305 i == Xsand_stoneout_1 && j == 0 ? 0 :
10306 i == Xsand_stoneout_1 && j == 1 ? 0 :
10307 i == Xsand_stoneout_1 && j == 2 ? 1 :
10308 i == Xsand_stoneout_1 && j == 3 ? 2 :
10309 i == Xsand_stoneout_1 && j == 4 ? 2 :
10310 i == Xsand_stoneout_1 && j == 5 ? 3 :
10311 i == Xsand_stoneout_1 && j == 6 ? 4 :
10312 i == Xsand_stoneout_1 && j == 7 ? 4 :
10313 i == Xsand_stoneout_2 && j == 0 ? 5 :
10314 i == Xsand_stoneout_2 && j == 1 ? 6 :
10315 i == Xsand_stoneout_2 && j == 2 ? 7 :
10316 i == Xsand_stoneout_2 && j == 3 ? 8 :
10317 i == Xsand_stoneout_2 && j == 4 ? 9 :
10318 i == Xsand_stoneout_2 && j == 5 ? 11 :
10319 i == Xsand_stoneout_2 && j == 6 ? 13 :
10320 i == Xsand_stoneout_2 && j == 7 ? 15 :
10321 i == Xboom_bug && j == 1 ? 2 :
10322 i == Xboom_bug && j == 2 ? 2 :
10323 i == Xboom_bug && j == 3 ? 4 :
10324 i == Xboom_bug && j == 4 ? 4 :
10325 i == Xboom_bug && j == 5 ? 2 :
10326 i == Xboom_bug && j == 6 ? 2 :
10327 i == Xboom_bug && j == 7 ? 0 :
10328 i == Xboom_bomb && j == 1 ? 2 :
10329 i == Xboom_bomb && j == 2 ? 2 :
10330 i == Xboom_bomb && j == 3 ? 4 :
10331 i == Xboom_bomb && j == 4 ? 4 :
10332 i == Xboom_bomb && j == 5 ? 2 :
10333 i == Xboom_bomb && j == 6 ? 2 :
10334 i == Xboom_bomb && j == 7 ? 0 :
10335 i == Xboom_android && j == 7 ? 6 :
10336 i == Xboom_1 && j == 1 ? 2 :
10337 i == Xboom_1 && j == 2 ? 2 :
10338 i == Xboom_1 && j == 3 ? 4 :
10339 i == Xboom_1 && j == 4 ? 4 :
10340 i == Xboom_1 && j == 5 ? 6 :
10341 i == Xboom_1 && j == 6 ? 6 :
10342 i == Xboom_1 && j == 7 ? 8 :
10343 i == Xboom_2 && j == 0 ? 8 :
10344 i == Xboom_2 && j == 1 ? 8 :
10345 i == Xboom_2 && j == 2 ? 10 :
10346 i == Xboom_2 && j == 3 ? 10 :
10347 i == Xboom_2 && j == 4 ? 10 :
10348 i == Xboom_2 && j == 5 ? 12 :
10349 i == Xboom_2 && j == 6 ? 12 :
10350 i == Xboom_2 && j == 7 ? 12 :
10351 special_animation && j == 4 ? 3 :
10352 effective_action != action ? 0 :
10355 xxx_effective_action = effective_action;
10356 xxx_has_action_graphics = has_action_graphics;
10361 int frame = getAnimationFrame(g->anim_frames,
10364 g->anim_start_frame,
10378 int old_src_x = g_em->src_x;
10379 int old_src_y = g_em->src_y;
10383 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
10384 g->double_movement && is_backside);
10386 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10387 &g_em->src_x, &g_em->src_y, FALSE);
10392 if (tile == Ydiamond_stone)
10393 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
10398 g->anim_start_frame,
10401 g_em->src_x, g_em->src_y,
10402 g_em->src_offset_x, g_em->src_offset_y,
10403 g_em->dst_offset_x, g_em->dst_offset_y,
10415 if (graphic == IMG_BUG_MOVING_RIGHT)
10416 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10417 g->double_movement, is_backside,
10418 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10426 g_em->src_offset_x = 0;
10427 g_em->src_offset_y = 0;
10428 g_em->dst_offset_x = 0;
10429 g_em->dst_offset_y = 0;
10430 g_em->width = TILEX;
10431 g_em->height = TILEY;
10433 g_em->preserve_background = FALSE;
10436 /* (updating the "crumbled" graphic definitions is probably not really needed,
10437 as animations for crumbled graphics can't be longer than one EMC cycle) */
10439 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10444 g_em->crumbled_bitmap = NULL;
10445 g_em->crumbled_src_x = 0;
10446 g_em->crumbled_src_y = 0;
10448 g_em->has_crumbled_graphics = FALSE;
10450 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10452 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10453 g_crumbled->anim_delay,
10454 g_crumbled->anim_mode,
10455 g_crumbled->anim_start_frame,
10458 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10459 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10461 g_em->has_crumbled_graphics = TRUE;
10467 int effective_action = xxx_effective_action;
10468 int has_action_graphics = xxx_has_action_graphics;
10470 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10471 effective_action == ACTION_MOVING ||
10472 effective_action == ACTION_PUSHING ||
10473 effective_action == ACTION_EATING)) ||
10474 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10475 effective_action == ACTION_EMPTYING)))
10478 (effective_action == ACTION_FALLING ||
10479 effective_action == ACTION_FILLING ||
10480 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10481 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10482 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10483 int num_steps = (i == Ydrip_s1 ? 16 :
10484 i == Ydrip_s1B ? 16 :
10485 i == Ydrip_s2 ? 16 :
10486 i == Ydrip_s2B ? 16 :
10487 i == Xsand_stonein_1 ? 32 :
10488 i == Xsand_stonein_2 ? 32 :
10489 i == Xsand_stonein_3 ? 32 :
10490 i == Xsand_stonein_4 ? 32 :
10491 i == Xsand_stoneout_1 ? 16 :
10492 i == Xsand_stoneout_2 ? 16 : 8);
10493 int cx = ABS(dx) * (TILEX / num_steps);
10494 int cy = ABS(dy) * (TILEY / num_steps);
10495 int step_frame = (i == Ydrip_s2 ? j + 8 :
10496 i == Ydrip_s2B ? j + 8 :
10497 i == Xsand_stonein_2 ? j + 8 :
10498 i == Xsand_stonein_3 ? j + 16 :
10499 i == Xsand_stonein_4 ? j + 24 :
10500 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10501 int step = (is_backside ? step_frame : num_steps - step_frame);
10503 if (is_backside) /* tile where movement starts */
10505 if (dx < 0 || dy < 0)
10507 g_em->src_offset_x = cx * step;
10508 g_em->src_offset_y = cy * step;
10512 g_em->dst_offset_x = cx * step;
10513 g_em->dst_offset_y = cy * step;
10516 else /* tile where movement ends */
10518 if (dx < 0 || dy < 0)
10520 g_em->dst_offset_x = cx * step;
10521 g_em->dst_offset_y = cy * step;
10525 g_em->src_offset_x = cx * step;
10526 g_em->src_offset_y = cy * step;
10530 g_em->width = TILEX - cx * step;
10531 g_em->height = TILEY - cy * step;
10534 /* create unique graphic identifier to decide if tile must be redrawn */
10535 /* bit 31 - 16 (16 bit): EM style graphic
10536 bit 15 - 12 ( 4 bit): EM style frame
10537 bit 11 - 6 ( 6 bit): graphic width
10538 bit 5 - 0 ( 6 bit): graphic height */
10539 g_em->unique_identifier =
10540 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10546 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10547 int player_nr, int anim, int frame_em)
10549 int element = player_mapping[player_nr][anim].element_rnd;
10550 int action = player_mapping[player_nr][anim].action;
10551 int direction = player_mapping[player_nr][anim].direction;
10552 int graphic = (direction == MV_NONE ?
10553 el_act2img(element, action) :
10554 el_act_dir2img(element, action, direction));
10555 struct GraphicInfo *g = &graphic_info[graphic];
10558 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10560 stored_player[player_nr].StepFrame = frame_em;
10562 sync_frame = stored_player[player_nr].Frame;
10564 int frame = getAnimationFrame(g->anim_frames,
10567 g->anim_start_frame,
10570 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10571 &g_em->src_x, &g_em->src_y, FALSE);
10574 printf("::: %d: %d, %d [%d]\n",
10576 stored_player[player_nr].Frame,
10577 stored_player[player_nr].StepFrame,
10582 void InitGraphicInfo_EM(void)
10585 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10586 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10591 int num_em_gfx_errors = 0;
10593 if (graphic_info_em_object[0][0].bitmap == NULL)
10595 /* EM graphics not yet initialized in em_open_all() */
10600 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10603 /* always start with reliable default values */
10604 for (i = 0; i < TILE_MAX; i++)
10606 object_mapping[i].element_rnd = EL_UNKNOWN;
10607 object_mapping[i].is_backside = FALSE;
10608 object_mapping[i].action = ACTION_DEFAULT;
10609 object_mapping[i].direction = MV_NONE;
10612 /* always start with reliable default values */
10613 for (p = 0; p < MAX_PLAYERS; p++)
10615 for (i = 0; i < SPR_MAX; i++)
10617 player_mapping[p][i].element_rnd = EL_UNKNOWN;
10618 player_mapping[p][i].action = ACTION_DEFAULT;
10619 player_mapping[p][i].direction = MV_NONE;
10623 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10625 int e = em_object_mapping_list[i].element_em;
10627 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10628 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10630 if (em_object_mapping_list[i].action != -1)
10631 object_mapping[e].action = em_object_mapping_list[i].action;
10633 if (em_object_mapping_list[i].direction != -1)
10634 object_mapping[e].direction =
10635 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10638 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10640 int a = em_player_mapping_list[i].action_em;
10641 int p = em_player_mapping_list[i].player_nr;
10643 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10645 if (em_player_mapping_list[i].action != -1)
10646 player_mapping[p][a].action = em_player_mapping_list[i].action;
10648 if (em_player_mapping_list[i].direction != -1)
10649 player_mapping[p][a].direction =
10650 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10653 for (i = 0; i < TILE_MAX; i++)
10655 int element = object_mapping[i].element_rnd;
10656 int action = object_mapping[i].action;
10657 int direction = object_mapping[i].direction;
10658 boolean is_backside = object_mapping[i].is_backside;
10660 boolean action_removing = (action == ACTION_DIGGING ||
10661 action == ACTION_SNAPPING ||
10662 action == ACTION_COLLECTING);
10664 boolean action_exploding = ((action == ACTION_EXPLODING ||
10665 action == ACTION_SMASHED_BY_ROCK ||
10666 action == ACTION_SMASHED_BY_SPRING) &&
10667 element != EL_DIAMOND);
10668 boolean action_active = (action == ACTION_ACTIVE);
10669 boolean action_other = (action == ACTION_OTHER);
10671 for (j = 0; j < 8; j++)
10674 int effective_element = get_effective_element_EM(i, j);
10676 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10677 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10679 i == Xdrip_stretch ? element :
10680 i == Xdrip_stretchB ? element :
10681 i == Ydrip_s1 ? element :
10682 i == Ydrip_s1B ? element :
10683 i == Xball_1B ? element :
10684 i == Xball_2 ? element :
10685 i == Xball_2B ? element :
10686 i == Yball_eat ? element :
10687 i == Ykey_1_eat ? element :
10688 i == Ykey_2_eat ? element :
10689 i == Ykey_3_eat ? element :
10690 i == Ykey_4_eat ? element :
10691 i == Ykey_5_eat ? element :
10692 i == Ykey_6_eat ? element :
10693 i == Ykey_7_eat ? element :
10694 i == Ykey_8_eat ? element :
10695 i == Ylenses_eat ? element :
10696 i == Ymagnify_eat ? element :
10697 i == Ygrass_eat ? element :
10698 i == Ydirt_eat ? element :
10699 i == Yemerald_stone ? EL_EMERALD :
10700 i == Ydiamond_stone ? EL_ROCK :
10701 i == Xsand_stonein_1 ? element :
10702 i == Xsand_stonein_2 ? element :
10703 i == Xsand_stonein_3 ? element :
10704 i == Xsand_stonein_4 ? element :
10705 is_backside ? EL_EMPTY :
10706 action_removing ? EL_EMPTY :
10709 int effective_action = (j < 7 ? action :
10710 i == Xdrip_stretch ? action :
10711 i == Xdrip_stretchB ? action :
10712 i == Ydrip_s1 ? action :
10713 i == Ydrip_s1B ? action :
10714 i == Xball_1B ? action :
10715 i == Xball_2 ? action :
10716 i == Xball_2B ? action :
10717 i == Yball_eat ? action :
10718 i == Ykey_1_eat ? action :
10719 i == Ykey_2_eat ? action :
10720 i == Ykey_3_eat ? action :
10721 i == Ykey_4_eat ? action :
10722 i == Ykey_5_eat ? action :
10723 i == Ykey_6_eat ? action :
10724 i == Ykey_7_eat ? action :
10725 i == Ykey_8_eat ? action :
10726 i == Ylenses_eat ? action :
10727 i == Ymagnify_eat ? action :
10728 i == Ygrass_eat ? action :
10729 i == Ydirt_eat ? action :
10730 i == Xsand_stonein_1 ? action :
10731 i == Xsand_stonein_2 ? action :
10732 i == Xsand_stonein_3 ? action :
10733 i == Xsand_stonein_4 ? action :
10734 i == Xsand_stoneout_1 ? action :
10735 i == Xsand_stoneout_2 ? action :
10736 i == Xboom_android ? ACTION_EXPLODING :
10737 action_exploding ? ACTION_EXPLODING :
10738 action_active ? action :
10739 action_other ? action :
10741 int graphic = (el_act_dir2img(effective_element, effective_action,
10743 int crumbled = (el_act_dir2crm(effective_element, effective_action,
10745 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10746 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10747 boolean has_action_graphics = (graphic != base_graphic);
10748 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10749 struct GraphicInfo *g = &graphic_info[graphic];
10751 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10753 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10754 Bitmap *src_bitmap;
10756 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10757 boolean special_animation = (action != ACTION_DEFAULT &&
10758 g->anim_frames == 3 &&
10759 g->anim_delay == 2 &&
10760 g->anim_mode & ANIM_LINEAR);
10761 int sync_frame = (i == Xdrip_stretch ? 7 :
10762 i == Xdrip_stretchB ? 7 :
10763 i == Ydrip_s2 ? j + 8 :
10764 i == Ydrip_s2B ? j + 8 :
10766 i == Xacid_2 ? 10 :
10767 i == Xacid_3 ? 20 :
10768 i == Xacid_4 ? 30 :
10769 i == Xacid_5 ? 40 :
10770 i == Xacid_6 ? 50 :
10771 i == Xacid_7 ? 60 :
10772 i == Xacid_8 ? 70 :
10773 i == Xfake_acid_1 ? 0 :
10774 i == Xfake_acid_2 ? 10 :
10775 i == Xfake_acid_3 ? 20 :
10776 i == Xfake_acid_4 ? 30 :
10777 i == Xfake_acid_5 ? 40 :
10778 i == Xfake_acid_6 ? 50 :
10779 i == Xfake_acid_7 ? 60 :
10780 i == Xfake_acid_8 ? 70 :
10782 i == Xball_2B ? j + 8 :
10783 i == Yball_eat ? j + 1 :
10784 i == Ykey_1_eat ? j + 1 :
10785 i == Ykey_2_eat ? j + 1 :
10786 i == Ykey_3_eat ? j + 1 :
10787 i == Ykey_4_eat ? j + 1 :
10788 i == Ykey_5_eat ? j + 1 :
10789 i == Ykey_6_eat ? j + 1 :
10790 i == Ykey_7_eat ? j + 1 :
10791 i == Ykey_8_eat ? j + 1 :
10792 i == Ylenses_eat ? j + 1 :
10793 i == Ymagnify_eat ? j + 1 :
10794 i == Ygrass_eat ? j + 1 :
10795 i == Ydirt_eat ? j + 1 :
10796 i == Xamoeba_1 ? 0 :
10797 i == Xamoeba_2 ? 1 :
10798 i == Xamoeba_3 ? 2 :
10799 i == Xamoeba_4 ? 3 :
10800 i == Xamoeba_5 ? 0 :
10801 i == Xamoeba_6 ? 1 :
10802 i == Xamoeba_7 ? 2 :
10803 i == Xamoeba_8 ? 3 :
10804 i == Xexit_2 ? j + 8 :
10805 i == Xexit_3 ? j + 16 :
10806 i == Xdynamite_1 ? 0 :
10807 i == Xdynamite_2 ? 8 :
10808 i == Xdynamite_3 ? 16 :
10809 i == Xdynamite_4 ? 24 :
10810 i == Xsand_stonein_1 ? j + 1 :
10811 i == Xsand_stonein_2 ? j + 9 :
10812 i == Xsand_stonein_3 ? j + 17 :
10813 i == Xsand_stonein_4 ? j + 25 :
10814 i == Xsand_stoneout_1 && j == 0 ? 0 :
10815 i == Xsand_stoneout_1 && j == 1 ? 0 :
10816 i == Xsand_stoneout_1 && j == 2 ? 1 :
10817 i == Xsand_stoneout_1 && j == 3 ? 2 :
10818 i == Xsand_stoneout_1 && j == 4 ? 2 :
10819 i == Xsand_stoneout_1 && j == 5 ? 3 :
10820 i == Xsand_stoneout_1 && j == 6 ? 4 :
10821 i == Xsand_stoneout_1 && j == 7 ? 4 :
10822 i == Xsand_stoneout_2 && j == 0 ? 5 :
10823 i == Xsand_stoneout_2 && j == 1 ? 6 :
10824 i == Xsand_stoneout_2 && j == 2 ? 7 :
10825 i == Xsand_stoneout_2 && j == 3 ? 8 :
10826 i == Xsand_stoneout_2 && j == 4 ? 9 :
10827 i == Xsand_stoneout_2 && j == 5 ? 11 :
10828 i == Xsand_stoneout_2 && j == 6 ? 13 :
10829 i == Xsand_stoneout_2 && j == 7 ? 15 :
10830 i == Xboom_bug && j == 1 ? 2 :
10831 i == Xboom_bug && j == 2 ? 2 :
10832 i == Xboom_bug && j == 3 ? 4 :
10833 i == Xboom_bug && j == 4 ? 4 :
10834 i == Xboom_bug && j == 5 ? 2 :
10835 i == Xboom_bug && j == 6 ? 2 :
10836 i == Xboom_bug && j == 7 ? 0 :
10837 i == Xboom_bomb && j == 1 ? 2 :
10838 i == Xboom_bomb && j == 2 ? 2 :
10839 i == Xboom_bomb && j == 3 ? 4 :
10840 i == Xboom_bomb && j == 4 ? 4 :
10841 i == Xboom_bomb && j == 5 ? 2 :
10842 i == Xboom_bomb && j == 6 ? 2 :
10843 i == Xboom_bomb && j == 7 ? 0 :
10844 i == Xboom_android && j == 7 ? 6 :
10845 i == Xboom_1 && j == 1 ? 2 :
10846 i == Xboom_1 && j == 2 ? 2 :
10847 i == Xboom_1 && j == 3 ? 4 :
10848 i == Xboom_1 && j == 4 ? 4 :
10849 i == Xboom_1 && j == 5 ? 6 :
10850 i == Xboom_1 && j == 6 ? 6 :
10851 i == Xboom_1 && j == 7 ? 8 :
10852 i == Xboom_2 && j == 0 ? 8 :
10853 i == Xboom_2 && j == 1 ? 8 :
10854 i == Xboom_2 && j == 2 ? 10 :
10855 i == Xboom_2 && j == 3 ? 10 :
10856 i == Xboom_2 && j == 4 ? 10 :
10857 i == Xboom_2 && j == 5 ? 12 :
10858 i == Xboom_2 && j == 6 ? 12 :
10859 i == Xboom_2 && j == 7 ? 12 :
10860 special_animation && j == 4 ? 3 :
10861 effective_action != action ? 0 :
10865 Bitmap *debug_bitmap = g_em->bitmap;
10866 int debug_src_x = g_em->src_x;
10867 int debug_src_y = g_em->src_y;
10870 int frame = getAnimationFrame(g->anim_frames,
10873 g->anim_start_frame,
10876 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10877 g->double_movement && is_backside);
10879 g_em->bitmap = src_bitmap;
10880 g_em->src_x = src_x;
10881 g_em->src_y = src_y;
10882 g_em->src_offset_x = 0;
10883 g_em->src_offset_y = 0;
10884 g_em->dst_offset_x = 0;
10885 g_em->dst_offset_y = 0;
10886 g_em->width = TILEX;
10887 g_em->height = TILEY;
10889 g_em->preserve_background = FALSE;
10892 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10897 g_em->crumbled_bitmap = NULL;
10898 g_em->crumbled_src_x = 0;
10899 g_em->crumbled_src_y = 0;
10900 g_em->crumbled_border_size = 0;
10902 g_em->has_crumbled_graphics = FALSE;
10905 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10906 printf("::: empty crumbled: %d [%s], %d, %d\n",
10907 effective_element, element_info[effective_element].token_name,
10908 effective_action, direction);
10911 /* if element can be crumbled, but certain action graphics are just empty
10912 space (like instantly snapping sand to empty space in 1 frame), do not
10913 treat these empty space graphics as crumbled graphics in EMC engine */
10914 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10916 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10917 g_crumbled->anim_delay,
10918 g_crumbled->anim_mode,
10919 g_crumbled->anim_start_frame,
10922 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10924 g_em->has_crumbled_graphics = TRUE;
10925 g_em->crumbled_bitmap = src_bitmap;
10926 g_em->crumbled_src_x = src_x;
10927 g_em->crumbled_src_y = src_y;
10928 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10932 if (g_em == &graphic_info_em_object[207][0])
10933 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10934 graphic_info_em_object[207][0].crumbled_src_x,
10935 graphic_info_em_object[207][0].crumbled_src_y,
10937 crumbled, frame, src_x, src_y,
10942 g->anim_start_frame,
10944 gfx.anim_random_frame,
10949 printf("::: EMC tile %d is crumbled\n", i);
10955 if (element == EL_ROCK &&
10956 effective_action == ACTION_FILLING)
10957 printf("::: has_action_graphics == %d\n", has_action_graphics);
10960 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10961 effective_action == ACTION_MOVING ||
10962 effective_action == ACTION_PUSHING ||
10963 effective_action == ACTION_EATING)) ||
10964 (!has_action_graphics && (effective_action == ACTION_FILLING ||
10965 effective_action == ACTION_EMPTYING)))
10968 (effective_action == ACTION_FALLING ||
10969 effective_action == ACTION_FILLING ||
10970 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10971 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10972 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
10973 int num_steps = (i == Ydrip_s1 ? 16 :
10974 i == Ydrip_s1B ? 16 :
10975 i == Ydrip_s2 ? 16 :
10976 i == Ydrip_s2B ? 16 :
10977 i == Xsand_stonein_1 ? 32 :
10978 i == Xsand_stonein_2 ? 32 :
10979 i == Xsand_stonein_3 ? 32 :
10980 i == Xsand_stonein_4 ? 32 :
10981 i == Xsand_stoneout_1 ? 16 :
10982 i == Xsand_stoneout_2 ? 16 : 8);
10983 int cx = ABS(dx) * (TILEX / num_steps);
10984 int cy = ABS(dy) * (TILEY / num_steps);
10985 int step_frame = (i == Ydrip_s2 ? j + 8 :
10986 i == Ydrip_s2B ? j + 8 :
10987 i == Xsand_stonein_2 ? j + 8 :
10988 i == Xsand_stonein_3 ? j + 16 :
10989 i == Xsand_stonein_4 ? j + 24 :
10990 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10991 int step = (is_backside ? step_frame : num_steps - step_frame);
10993 if (is_backside) /* tile where movement starts */
10995 if (dx < 0 || dy < 0)
10997 g_em->src_offset_x = cx * step;
10998 g_em->src_offset_y = cy * step;
11002 g_em->dst_offset_x = cx * step;
11003 g_em->dst_offset_y = cy * step;
11006 else /* tile where movement ends */
11008 if (dx < 0 || dy < 0)
11010 g_em->dst_offset_x = cx * step;
11011 g_em->dst_offset_y = cy * step;
11015 g_em->src_offset_x = cx * step;
11016 g_em->src_offset_y = cy * step;
11020 g_em->width = TILEX - cx * step;
11021 g_em->height = TILEY - cy * step;
11024 /* create unique graphic identifier to decide if tile must be redrawn */
11025 /* bit 31 - 16 (16 bit): EM style graphic
11026 bit 15 - 12 ( 4 bit): EM style frame
11027 bit 11 - 6 ( 6 bit): graphic width
11028 bit 5 - 0 ( 6 bit): graphic height */
11029 g_em->unique_identifier =
11030 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
11034 /* skip check for EMC elements not contained in original EMC artwork */
11035 if (element == EL_EMC_FAKE_ACID)
11038 if (g_em->bitmap != debug_bitmap ||
11039 g_em->src_x != debug_src_x ||
11040 g_em->src_y != debug_src_y ||
11041 g_em->src_offset_x != 0 ||
11042 g_em->src_offset_y != 0 ||
11043 g_em->dst_offset_x != 0 ||
11044 g_em->dst_offset_y != 0 ||
11045 g_em->width != TILEX ||
11046 g_em->height != TILEY)
11048 static int last_i = -1;
11056 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
11057 i, element, element_info[element].token_name,
11058 element_action_info[effective_action].suffix, direction);
11060 if (element != effective_element)
11061 printf(" [%d ('%s')]",
11063 element_info[effective_element].token_name);
11067 if (g_em->bitmap != debug_bitmap)
11068 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
11069 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
11071 if (g_em->src_x != debug_src_x ||
11072 g_em->src_y != debug_src_y)
11073 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11074 j, (is_backside ? 'B' : 'F'),
11075 g_em->src_x, g_em->src_y,
11076 g_em->src_x / 32, g_em->src_y / 32,
11077 debug_src_x, debug_src_y,
11078 debug_src_x / 32, debug_src_y / 32);
11080 if (g_em->src_offset_x != 0 ||
11081 g_em->src_offset_y != 0 ||
11082 g_em->dst_offset_x != 0 ||
11083 g_em->dst_offset_y != 0)
11084 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
11086 g_em->src_offset_x, g_em->src_offset_y,
11087 g_em->dst_offset_x, g_em->dst_offset_y);
11089 if (g_em->width != TILEX ||
11090 g_em->height != TILEY)
11091 printf(" %d (%d): size %d,%d should be %d,%d\n",
11093 g_em->width, g_em->height, TILEX, TILEY);
11095 num_em_gfx_errors++;
11102 for (i = 0; i < TILE_MAX; i++)
11104 for (j = 0; j < 8; j++)
11106 int element = object_mapping[i].element_rnd;
11107 int action = object_mapping[i].action;
11108 int direction = object_mapping[i].direction;
11109 boolean is_backside = object_mapping[i].is_backside;
11110 int graphic_action = el_act_dir2img(element, action, direction);
11111 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
11113 if ((action == ACTION_SMASHED_BY_ROCK ||
11114 action == ACTION_SMASHED_BY_SPRING ||
11115 action == ACTION_EATING) &&
11116 graphic_action == graphic_default)
11118 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
11119 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
11120 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
11121 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
11124 /* no separate animation for "smashed by rock" -- use rock instead */
11125 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
11126 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
11128 g_em->bitmap = g_xx->bitmap;
11129 g_em->src_x = g_xx->src_x;
11130 g_em->src_y = g_xx->src_y;
11131 g_em->src_offset_x = g_xx->src_offset_x;
11132 g_em->src_offset_y = g_xx->src_offset_y;
11133 g_em->dst_offset_x = g_xx->dst_offset_x;
11134 g_em->dst_offset_y = g_xx->dst_offset_y;
11135 g_em->width = g_xx->width;
11136 g_em->height = g_xx->height;
11137 g_em->unique_identifier = g_xx->unique_identifier;
11140 g_em->preserve_background = TRUE;
11145 for (p = 0; p < MAX_PLAYERS; p++)
11147 for (i = 0; i < SPR_MAX; i++)
11149 int element = player_mapping[p][i].element_rnd;
11150 int action = player_mapping[p][i].action;
11151 int direction = player_mapping[p][i].direction;
11153 for (j = 0; j < 8; j++)
11155 int effective_element = element;
11156 int effective_action = action;
11157 int graphic = (direction == MV_NONE ?
11158 el_act2img(effective_element, effective_action) :
11159 el_act_dir2img(effective_element, effective_action,
11161 struct GraphicInfo *g = &graphic_info[graphic];
11162 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
11163 Bitmap *src_bitmap;
11165 int sync_frame = j;
11168 Bitmap *debug_bitmap = g_em->bitmap;
11169 int debug_src_x = g_em->src_x;
11170 int debug_src_y = g_em->src_y;
11173 int frame = getAnimationFrame(g->anim_frames,
11176 g->anim_start_frame,
11179 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
11181 g_em->bitmap = src_bitmap;
11182 g_em->src_x = src_x;
11183 g_em->src_y = src_y;
11184 g_em->src_offset_x = 0;
11185 g_em->src_offset_y = 0;
11186 g_em->dst_offset_x = 0;
11187 g_em->dst_offset_y = 0;
11188 g_em->width = TILEX;
11189 g_em->height = TILEY;
11193 /* skip check for EMC elements not contained in original EMC artwork */
11194 if (element == EL_PLAYER_3 ||
11195 element == EL_PLAYER_4)
11198 if (g_em->bitmap != debug_bitmap ||
11199 g_em->src_x != debug_src_x ||
11200 g_em->src_y != debug_src_y)
11202 static int last_i = -1;
11210 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
11211 p, i, element, element_info[element].token_name,
11212 element_action_info[effective_action].suffix, direction);
11214 if (element != effective_element)
11215 printf(" [%d ('%s')]",
11217 element_info[effective_element].token_name);
11221 if (g_em->bitmap != debug_bitmap)
11222 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
11223 j, (int)(g_em->bitmap), (int)(debug_bitmap));
11225 if (g_em->src_x != debug_src_x ||
11226 g_em->src_y != debug_src_y)
11227 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11229 g_em->src_x, g_em->src_y,
11230 g_em->src_x / 32, g_em->src_y / 32,
11231 debug_src_x, debug_src_y,
11232 debug_src_x / 32, debug_src_y / 32);
11234 num_em_gfx_errors++;
11244 printf("::: [%d errors found]\n", num_em_gfx_errors);
11250 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
11251 boolean any_player_moving,
11252 boolean player_is_dropping)
11254 if (tape.single_step && tape.recording && !tape.pausing)
11257 boolean active_players = FALSE;
11260 for (i = 0; i < MAX_PLAYERS; i++)
11261 if (action[i] != JOY_NO_ACTION)
11262 active_players = TRUE;
11266 if (frame == 0 && !player_is_dropping)
11267 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11271 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
11272 boolean murphy_is_dropping)
11275 printf("::: waiting: %d, dropping: %d\n",
11276 murphy_is_waiting, murphy_is_dropping);
11279 if (tape.single_step && tape.recording && !tape.pausing)
11281 // if (murphy_is_waiting || murphy_is_dropping)
11282 if (murphy_is_waiting)
11285 printf("::: murphy is waiting -> pause mode\n");
11288 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11293 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
11294 int graphic, int sync_frame, int x, int y)
11296 int frame = getGraphicAnimationFrame(graphic, sync_frame);
11298 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
11301 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
11303 return (IS_NEXT_FRAME(sync_frame, graphic));
11306 int getGraphicInfo_Delay(int graphic)
11308 return graphic_info[graphic].anim_delay;
11311 void PlayMenuSoundExt(int sound)
11313 if (sound == SND_UNDEFINED)
11316 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11317 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11320 if (IS_LOOP_SOUND(sound))
11321 PlaySoundLoop(sound);
11326 void PlayMenuSound()
11328 PlayMenuSoundExt(menu.sound[game_status]);
11331 void PlayMenuSoundStereo(int sound, int stereo_position)
11333 if (sound == SND_UNDEFINED)
11336 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11337 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11340 if (IS_LOOP_SOUND(sound))
11341 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
11343 PlaySoundStereo(sound, stereo_position);
11346 void PlayMenuSoundIfLoopExt(int sound)
11348 if (sound == SND_UNDEFINED)
11351 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11352 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11355 if (IS_LOOP_SOUND(sound))
11356 PlaySoundLoop(sound);
11359 void PlayMenuSoundIfLoop()
11361 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
11364 void PlayMenuMusicExt(int music)
11366 if (music == MUS_UNDEFINED)
11369 if (!setup.sound_music)
11375 void PlayMenuMusic()
11377 PlayMenuMusicExt(menu.music[game_status]);
11380 void PlaySoundActivating()
11383 PlaySound(SND_MENU_ITEM_ACTIVATING);
11387 void PlaySoundSelecting()
11390 PlaySound(SND_MENU_ITEM_SELECTING);
11394 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
11396 boolean change_fullscreen = (setup.fullscreen !=
11397 video.fullscreen_enabled);
11398 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
11399 !strEqual(setup.fullscreen_mode,
11400 video.fullscreen_mode_current));
11401 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
11402 setup.window_scaling_percent !=
11403 video.window_scaling_percent);
11405 if (change_window_scaling_percent && video.fullscreen_enabled)
11408 if (!change_window_scaling_percent && !video.fullscreen_available)
11411 #if defined(TARGET_SDL2)
11412 if (change_window_scaling_percent)
11414 SDLSetWindowScaling(setup.window_scaling_percent);
11418 else if (change_fullscreen)
11420 SDLSetWindowFullscreen(setup.fullscreen);
11422 /* set setup value according to successfully changed fullscreen mode */
11423 setup.fullscreen = video.fullscreen_enabled;
11429 if (change_fullscreen ||
11430 change_fullscreen_mode ||
11431 change_window_scaling_percent)
11433 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11435 /* save backbuffer content which gets lost when toggling fullscreen mode */
11436 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11438 if (change_fullscreen_mode)
11440 /* keep fullscreen, but change fullscreen mode (screen resolution) */
11441 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
11444 if (change_window_scaling_percent)
11446 /* keep window mode, but change window scaling */
11447 video.fullscreen_enabled = TRUE; /* force new window scaling */
11450 /* toggle fullscreen */
11451 ChangeVideoModeIfNeeded(setup.fullscreen);
11453 /* set setup value according to successfully changed fullscreen mode */
11454 setup.fullscreen = video.fullscreen_enabled;
11456 /* restore backbuffer content from temporary backbuffer backup bitmap */
11457 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11459 FreeBitmap(tmp_backbuffer);
11462 /* update visible window/screen */
11463 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11465 redraw_mask = REDRAW_ALL;
11470 void ChangeViewportPropertiesIfNeeded()
11473 int *door_1_x = &DX;
11474 int *door_1_y = &DY;
11475 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11476 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11479 int gfx_game_mode = game_status;
11481 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11482 game_status == GAME_MODE_EDITOR ? game_status :
11485 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11487 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11488 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11489 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11490 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11491 int border_size = vp_playfield->border_size;
11492 int new_sx = vp_playfield->x + border_size;
11493 int new_sy = vp_playfield->y + border_size;
11494 int new_sxsize = vp_playfield->width - 2 * border_size;
11495 int new_sysize = vp_playfield->height - 2 * border_size;
11496 int new_real_sx = vp_playfield->x;
11497 int new_real_sy = vp_playfield->y;
11498 int new_full_sxsize = vp_playfield->width;
11499 int new_full_sysize = vp_playfield->height;
11500 int new_dx = vp_door_1->x;
11501 int new_dy = vp_door_1->y;
11502 int new_dxsize = vp_door_1->width;
11503 int new_dysize = vp_door_1->height;
11504 int new_vx = vp_door_2->x;
11505 int new_vy = vp_door_2->y;
11506 int new_vxsize = vp_door_2->width;
11507 int new_vysize = vp_door_2->height;
11508 int new_ex = vp_door_3->x;
11509 int new_ey = vp_door_3->y;
11510 int new_exsize = vp_door_3->width;
11511 int new_eysize = vp_door_3->height;
11513 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11514 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11515 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11516 int new_scr_fieldx = new_sxsize / tilesize;
11517 int new_scr_fieldy = new_sysize / tilesize;
11518 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11519 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11521 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
11522 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11524 boolean init_gfx_buffers = FALSE;
11525 boolean init_video_buffer = FALSE;
11526 boolean init_gadgets_and_toons = FALSE;
11527 boolean init_em_graphics = FALSE;
11530 /* !!! TEST ONLY !!! */
11531 // InitGfxBuffers();
11535 if (viewport.window.width != WIN_XSIZE ||
11536 viewport.window.height != WIN_YSIZE)
11538 WIN_XSIZE = viewport.window.width;
11539 WIN_YSIZE = viewport.window.height;
11542 init_video_buffer = TRUE;
11543 init_gfx_buffers = TRUE;
11545 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11549 SetDrawDeactivationMask(REDRAW_NONE);
11550 SetDrawBackgroundMask(REDRAW_FIELD);
11552 // RedrawBackground();
11556 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11559 if (new_scr_fieldx != SCR_FIELDX ||
11560 new_scr_fieldy != SCR_FIELDY)
11562 /* this always toggles between MAIN and GAME when using small tile size */
11564 SCR_FIELDX = new_scr_fieldx;
11565 SCR_FIELDY = new_scr_fieldy;
11567 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11571 if (new_tilesize_var != TILESIZE_VAR &&
11572 gfx_game_mode == GAME_MODE_PLAYING)
11574 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11576 TILESIZE_VAR = new_tilesize_var;
11578 init_gfx_buffers = TRUE;
11580 // printf("::: tilesize: init_gfx_buffers\n");
11584 if (new_sx != SX ||
11592 new_sxsize != SXSIZE ||
11593 new_sysize != SYSIZE ||
11594 new_dxsize != DXSIZE ||
11595 new_dysize != DYSIZE ||
11596 new_vxsize != VXSIZE ||
11597 new_vysize != VYSIZE ||
11598 new_exsize != EXSIZE ||
11599 new_eysize != EYSIZE ||
11600 new_real_sx != REAL_SX ||
11601 new_real_sy != REAL_SY ||
11602 new_full_sxsize != FULL_SXSIZE ||
11603 new_full_sysize != FULL_SYSIZE ||
11604 new_tilesize_var != TILESIZE_VAR
11607 vp_door_1->x != *door_1_x ||
11608 vp_door_1->y != *door_1_y ||
11609 vp_door_2->x != *door_2_x ||
11610 vp_door_2->y != *door_2_y
11615 if (new_tilesize_var != TILESIZE_VAR)
11617 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
11619 // changing tile size invalidates scroll values of engine snapshots
11620 FreeEngineSnapshot();
11622 // changing tile size requires update of graphic mapping for EM engine
11623 init_em_graphics = TRUE;
11635 SXSIZE = new_sxsize;
11636 SYSIZE = new_sysize;
11637 DXSIZE = new_dxsize;
11638 DYSIZE = new_dysize;
11639 VXSIZE = new_vxsize;
11640 VYSIZE = new_vysize;
11641 EXSIZE = new_exsize;
11642 EYSIZE = new_eysize;
11643 REAL_SX = new_real_sx;
11644 REAL_SY = new_real_sy;
11645 FULL_SXSIZE = new_full_sxsize;
11646 FULL_SYSIZE = new_full_sysize;
11647 TILESIZE_VAR = new_tilesize_var;
11650 printf("::: %d, %d, %d [%d]\n",
11651 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11652 setup.small_game_graphics);
11656 *door_1_x = vp_door_1->x;
11657 *door_1_y = vp_door_1->y;
11658 *door_2_x = vp_door_2->x;
11659 *door_2_y = vp_door_2->y;
11663 init_gfx_buffers = TRUE;
11665 // printf("::: viewports: init_gfx_buffers\n");
11671 if (gfx_game_mode == GAME_MODE_MAIN)
11675 init_gadgets_and_toons = TRUE;
11677 // printf("::: viewports: init_gadgets_and_toons\n");
11685 if (init_gfx_buffers)
11687 // printf("::: init_gfx_buffers\n");
11689 SCR_FIELDX = new_scr_fieldx_buffers;
11690 SCR_FIELDY = new_scr_fieldy_buffers;
11694 SCR_FIELDX = new_scr_fieldx;
11695 SCR_FIELDY = new_scr_fieldy;
11698 if (init_video_buffer)
11700 // printf("::: init_video_buffer\n");
11702 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11704 SetDrawDeactivationMask(REDRAW_NONE);
11705 SetDrawBackgroundMask(REDRAW_FIELD);
11708 if (init_gadgets_and_toons)
11710 // printf("::: init_gadgets_and_toons\n");
11716 if (init_em_graphics)
11718 InitGraphicInfo_EM();
11722 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);